From 06a7ca221c6ebfe51f63d1f05d52d4c65865c656 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 28 Mar 2018 11:32:44 +0900 Subject: [PATCH 001/263] node-filter does not use ChainNotify (#8231) * node-filter does not use ChainNotify * fixed failing test --- Cargo.lock | 1 - ethcore/node_filter/Cargo.toml | 1 - ethcore/node_filter/src/lib.rs | 59 +++++++++++++--------------------- parity/run.rs | 3 -- 4 files changed, 23 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 211fbbd61c..6e82fc19bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1721,7 +1721,6 @@ dependencies = [ "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", - "ethcore-bytes 0.1.0", "ethcore-io 1.11.0", "ethcore-network-devp2p 1.11.0", "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index c183853d15..da1bcc1cf1 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -8,7 +8,6 @@ authors = ["Parity Technologies "] [dependencies] ethcore = { path = ".."} -ethcore-bytes = { path = "../../util/bytes" } ethcore-network-devp2p = { path = "../../util/network-devp2p" } ethereum-types = "0.2" log = "0.3" diff --git a/ethcore/node_filter/src/lib.rs b/ethcore/node_filter/src/lib.rs index 945f552faf..cbf5f4e5d4 100644 --- a/ethcore/node_filter/src/lib.rs +++ b/ethcore/node_filter/src/lib.rs @@ -18,7 +18,6 @@ extern crate ethabi; extern crate ethcore; -extern crate ethcore_bytes as bytes; extern crate ethcore_network_devp2p as network; extern crate ethereum_types; extern crate lru_cache; @@ -42,8 +41,7 @@ use std::sync::Weak; use lru_cache::LruCache; use parking_lot::Mutex; -use bytes::Bytes; -use ethcore::client::{BlockChainClient, BlockId, ChainNotify}; +use ethcore::client::{BlockChainClient, BlockId}; use ethereum_types::{H256, Address}; use network::{NodeId, ConnectionFilter, ConnectionDirection}; @@ -56,7 +54,7 @@ pub struct NodeFilter { contract: peer_set::PeerSet, client: Weak, contract_address: Address, - permission_cache: Mutex>, + permission_cache: Mutex>, } impl NodeFilter { @@ -64,30 +62,32 @@ impl NodeFilter { pub fn new(client: Weak, contract_address: Address) -> NodeFilter { NodeFilter { contract: peer_set::PeerSet::default(), - client: client, - contract_address: contract_address, + client, + contract_address, permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)), } } - - /// Clear cached permissions. - pub fn clear_cache(&self) { - self.permission_cache.lock().clear(); - } } impl ConnectionFilter for NodeFilter { fn connection_allowed(&self, own_id: &NodeId, connecting_id: &NodeId, _direction: ConnectionDirection) -> bool { + let client = match self.client.upgrade() { + Some(client) => client, + None => return false, + }; + + let block_hash = match client.block_hash(BlockId::Latest) { + Some(block_hash) => block_hash, + None => return false, + }; + + let key = (block_hash, *connecting_id); let mut cache = self.permission_cache.lock(); - if let Some(res) = cache.get_mut(connecting_id) { + if let Some(res) = cache.get_mut(&key) { return *res; } - let client = match self.client.upgrade() { - Some(client) => client, - None => return false, - }; let address = self.contract_address; let own_low = H256::from_slice(&own_id[0..32]); @@ -103,28 +103,17 @@ impl ConnectionFilter for NodeFilter { false }); - cache.insert(*connecting_id, allowed); + cache.insert(key, allowed); allowed } } -impl ChainNotify for NodeFilter { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { - if !imported.is_empty() { - self.clear_cache(); - } - } -} - - #[cfg(test)] mod test { use std::sync::{Arc, Weak}; - use std::str::FromStr; use ethcore::spec::Spec; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::miner::Miner; - use ethereum_types::Address; use network::{ConnectionDirection, ConnectionFilter, NodeId}; use io::IoChannel; use super::NodeFilter; @@ -133,7 +122,7 @@ mod test { /// Contract code: https://gist.github.com/arkpar/467dbcc73cbb85b0997a7a10ffa0695f #[test] fn node_filter() { - let contract_addr = Address::from_str("0000000000000000000000000000000000000005").unwrap(); + let contract_addr = "0000000000000000000000000000000000000005".into(); let data = include_bytes!("../res/node_filter.json"); let tempdir = TempDir::new("").unwrap(); let spec = Spec::load(&tempdir.path(), &data[..]).unwrap(); @@ -147,17 +136,15 @@ mod test { IoChannel::disconnected(), ).unwrap(); let filter = NodeFilter::new(Arc::downgrade(&client) as Weak, contract_addr); - let self1 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002").unwrap(); - let self2 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003").unwrap(); - let node1 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012").unwrap(); - let node2 = NodeId::from_str("00000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022").unwrap(); - let nodex = NodeId::from_str("77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let self1: NodeId = "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002".into(); + let self2: NodeId = "00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003".into(); + let node1: NodeId = "00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012".into(); + let node2: NodeId = "00000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022".into(); + let nodex: NodeId = "77000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(); assert!(filter.connection_allowed(&self1, &node1, ConnectionDirection::Inbound)); assert!(filter.connection_allowed(&self1, &nodex, ConnectionDirection::Inbound)); - filter.clear_cache(); assert!(filter.connection_allowed(&self2, &node1, ConnectionDirection::Inbound)); assert!(filter.connection_allowed(&self2, &node2, ConnectionDirection::Inbound)); - assert!(!filter.connection_allowed(&self2, &nodex, ConnectionDirection::Inbound)); } } diff --git a/parity/run.rs b/parity/run.rs index d485694b9c..19620f9d53 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -692,9 +692,6 @@ pub fn execute_impl(cmd: RunCmd, can_restart: bool, logger: Arc) ).map_err(|e| format!("Sync error: {}", e))?; service.add_notify(chain_notify.clone()); - if let Some(filter) = connection_filter { - service.add_notify(filter); - } // start network if network_enabled { -- GitLab From c4dd15611369fb94891459305f1dc9376d2fce9a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 28 Mar 2018 08:45:36 +0200 Subject: [PATCH 002/263] Remove network stats (#8225) --- util/network-devp2p/src/connection.rs | 15 +----- util/network-devp2p/src/handshake.rs | 10 ++-- util/network-devp2p/src/host.rs | 10 ++-- util/network-devp2p/src/lib.rs | 2 - util/network-devp2p/src/service.rs | 11 +--- util/network-devp2p/src/session.rs | 6 +-- util/network-devp2p/src/stats.rs | 76 --------------------------- util/network-devp2p/tests/tests.rs | 25 --------- 8 files changed, 10 insertions(+), 145 deletions(-) delete mode 100644 util/network-devp2p/src/stats.rs diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index e32439756f..ea3b99d418 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::sync::Arc; use std::collections::VecDeque; use std::net::SocketAddr; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; @@ -28,7 +27,6 @@ use rlp::*; use std::io::{self, Cursor, Read, Write}; use io::{IoContext, StreamToken}; use handshake::Handshake; -use stats::NetworkStats; use rcrypto::blockmodes::*; use rcrypto::aessafe::*; use rcrypto::symmetriccipher::*; @@ -61,8 +59,6 @@ pub struct GenericConnection { send_queue: VecDeque>, /// Event flags this connection expects interest: Ready, - /// Shared network statistics - stats: Arc, /// Registered flag registered: AtomicBool, } @@ -87,7 +83,6 @@ impl GenericConnection { match sock_ref.take(max as u64).try_read(unsafe { self.rec_buf.bytes_mut() }) { Ok(Some(size)) if size != 0 => { unsafe { self.rec_buf.advance_mut(size); } - self.stats.inc_recv(size); trace!(target:"network", "{}: Read {} of {} bytes", self.token, self.rec_buf.len(), self.rec_size); if self.rec_size != 0 && self.rec_buf.len() == self.rec_size { self.rec_size = 0; @@ -141,11 +136,9 @@ impl GenericConnection { match self.socket.try_write(Buf::bytes(&buf)) { Ok(Some(size)) if (pos + size) < send_size => { buf.advance(size); - self.stats.inc_send(size); Ok(WriteStatus::Ongoing) }, Ok(Some(size)) if (pos + size) == send_size => { - self.stats.inc_send(size); trace!(target:"network", "{}: Wrote {} bytes", self.token, send_size); Ok(WriteStatus::Complete) }, @@ -171,7 +164,7 @@ pub type Connection = GenericConnection; impl Connection { /// Create a new connection with given id and socket. - pub fn new(token: StreamToken, socket: TcpStream, stats: Arc) -> Connection { + pub fn new(token: StreamToken, socket: TcpStream) -> Connection { Connection { token: token, socket: socket, @@ -179,7 +172,6 @@ impl Connection { rec_buf: Bytes::new(), rec_size: 0, interest: Ready::hup() | Ready::readable(), - stats: stats, registered: AtomicBool::new(false), } } @@ -213,7 +205,6 @@ impl Connection { rec_size: 0, send_queue: self.send_queue.clone(), interest: Ready::hup(), - stats: self.stats.clone(), registered: AtomicBool::new(false), }) } @@ -507,13 +498,11 @@ mod tests { use std::cmp; use std::collections::VecDeque; use std::io::{Read, Write, Cursor, ErrorKind, Result, Error}; - use std::sync::Arc; use std::sync::atomic::AtomicBool; use mio::{Ready}; use ethcore_bytes::Bytes; use io::*; - use super::super::stats::*; use super::*; pub struct TestSocket { @@ -625,7 +614,6 @@ mod tests { rec_buf: Bytes::new(), rec_size: 0, interest: Ready::hup() | Ready::readable(), - stats: Arc::::new(NetworkStats::new()), registered: AtomicBool::new(false), } } @@ -648,7 +636,6 @@ mod tests { rec_buf: Bytes::new(), rec_size: 0, interest: Ready::hup() | Ready::readable(), - stats: Arc::::new(NetworkStats::new()), registered: AtomicBool::new(false), } } diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 240046a98e..dbd31c5a87 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::sync::Arc; use rand::random; use hash::write_keccak; use mio::tcp::*; @@ -23,7 +22,6 @@ use ethcore_bytes::Bytes; use rlp::*; use connection::{Connection}; use node_table::NodeId; -use stats::NetworkStats; use io::{IoContext, StreamToken}; use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; use crypto::{ecdh, ecies}; @@ -82,10 +80,10 @@ const ECIES_OVERHEAD: usize = 113; impl Handshake { /// Create a new handshake object - pub fn new(token: StreamToken, id: Option<&NodeId>, socket: TcpStream, nonce: &H256, stats: Arc) -> Result { + pub fn new(token: StreamToken, id: Option<&NodeId>, socket: TcpStream, nonce: &H256) -> Result { Ok(Handshake { id: if let Some(id) = id { id.clone()} else { NodeId::new() }, - connection: Connection::new(token, socket, stats), + connection: Connection::new(token, socket), originated: false, state: HandshakeState::New, ecdhe: Random.generate()?, @@ -329,13 +327,11 @@ impl Handshake { #[cfg(test)] mod test { - use std::sync::Arc; use rustc_hex::FromHex; use super::*; use ethereum_types::H256; use io::*; use mio::tcp::TcpStream; - use stats::NetworkStats; use ethkey::Public; fn check_auth(h: &Handshake, version: u64) { @@ -355,7 +351,7 @@ mod test { let addr = "127.0.0.1:50556".parse().unwrap(); let socket = TcpStream::connect(&addr).unwrap(); let nonce = H256::new(); - Handshake::new(0, to, socket, &nonce, Arc::new(NetworkStats::new())).unwrap() + Handshake::new(0, to, socket, &nonce).unwrap() } fn test_io() -> IoContext { diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index c23527c328..87e9a02789 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -39,7 +39,6 @@ use network::{NetworkConfiguration, NetworkIoMessage, ProtocolId, PeerId, Packet use network::{NonReservedPeerMode, NetworkContext as NetworkContextTrait}; use network::HostInfo as HostInfoTrait; use network::{SessionInfo, Error, ErrorKind, DisconnectReason, NetworkProtocolHandler}; -use stats::NetworkStats; use discovery::{Discovery, TableUpdates, NodeEntry}; use ip_utils::{map_external_address, select_public_address}; use path::restrict_permissions_owner; @@ -245,7 +244,6 @@ pub struct Host { handlers: RwLock>>, timers: RwLock>, timer_counter: RwLock, - stats: Arc, reserved_nodes: RwLock>, stopping: AtomicBool, filter: Option>, @@ -253,7 +251,7 @@ pub struct Host { impl Host { /// Create a new instance - pub fn new(mut config: NetworkConfiguration, stats: Arc, filter: Option>) -> Result { + pub fn new(mut config: NetworkConfiguration, filter: Option>) -> Result { let mut listen_address = match config.listen_address { None => SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), DEFAULT_PORT)), Some(addr) => addr, @@ -301,7 +299,6 @@ impl Host { handlers: RwLock::new(HashMap::new()), timers: RwLock::new(HashMap::new()), timer_counter: RwLock::new(USER_TIMER), - stats: stats, reserved_nodes: RwLock::new(HashSet::new()), stopping: AtomicBool::new(false), filter: filter, @@ -616,7 +613,7 @@ impl Host { let mut sessions = self.sessions.write(); let token = sessions.insert_with_opt(|token| { - match Session::new(io, socket, token, id, &nonce, self.stats.clone(), &self.info.read()) { + match Session::new(io, socket, token, id, &nonce, &self.info.read()) { Ok(s) => Some(Arc::new(Mutex::new(s))), Err(e) => { debug!(target: "network", "Session create error: {:?}", e); @@ -793,7 +790,6 @@ impl Host { return; } for p in ready_data { - self.stats.inc_sessions(); let reserved = self.reserved_nodes.read(); if let Some(h) = handlers.get(&p).clone() { h.connected(&NetworkContext::new(io, p, Some(session.clone()), self.sessions.clone(), &reserved), &token); @@ -1150,6 +1146,6 @@ fn host_client_url() { let mut config = NetworkConfiguration::new_local(); let key = "6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2".parse().unwrap(); config.use_secret = Some(key); - let host: Host = Host::new(config, Arc::new(NetworkStats::new()), None).unwrap(); + let host: Host = Host::new(config, None).unwrap(); assert!(host.local_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); } diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 0dfda0b16e..fc3e66e3a5 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -102,12 +102,10 @@ mod session; mod discovery; mod service; mod node_table; -mod stats; mod ip_utils; mod connection_filter; pub use service::NetworkService; -pub use stats::NetworkStats; pub use connection_filter::{ConnectionFilter, ConnectionDirection}; pub use host::NetworkContext; diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 95867f8eb0..711ee95cf3 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -17,7 +17,6 @@ use network::{Error, NetworkConfiguration, NetworkProtocolHandler, NonReservedPeerMode}; use network::{NetworkContext, PeerId, ProtocolId, NetworkIoMessage}; use host::Host; -use stats::NetworkStats; use io::*; use parking_lot::RwLock; use std::sync::Arc; @@ -46,7 +45,6 @@ pub struct NetworkService { io_service: IoService, host_info: String, host: RwLock>>, - stats: Arc, host_handler: Arc, config: NetworkConfiguration, filter: Option>, @@ -58,11 +56,9 @@ impl NetworkService { let host_handler = Arc::new(HostHandler { public_url: RwLock::new(None) }); let io_service = IoService::::start()?; - let stats = Arc::new(NetworkStats::new()); Ok(NetworkService { io_service: io_service, host_info: config.client_version.clone(), - stats: stats, host: RwLock::new(None), config: config, host_handler: host_handler, @@ -91,11 +87,6 @@ impl NetworkService { &self.io_service } - /// Returns network statistics. - pub fn stats(&self) -> &NetworkStats { - &self.stats - } - /// Returns network configuration. pub fn config(&self) -> &NetworkConfiguration { &self.config @@ -117,7 +108,7 @@ impl NetworkService { pub fn start(&self) -> Result<(), Error> { let mut host = self.host.write(); if host.is_none() { - let h = Arc::new(Host::new(self.config.clone(), self.stats.clone(), self.filter.clone())?); + let h = Arc::new(Host::new(self.config.clone(), self.filter.clone())?); self.io_service.register_handler(h.clone())?; *host = Some(h); } diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index 39c96c063e..e82df62ba0 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -16,7 +16,6 @@ use std::{str, io}; use std::net::SocketAddr; -use std::sync::*; use std::collections::HashMap; use std::time::{Duration, Instant}; @@ -32,7 +31,6 @@ use network::{Error, ErrorKind, DisconnectReason, SessionInfo, ProtocolId, PeerC use network::{SessionCapabilityInfo, HostInfo as HostInfoTrait}; use host::*; use node_table::NodeId; -use stats::NetworkStats; use snappy; // Timeout must be less than (interval - 1). @@ -103,10 +101,10 @@ impl Session { /// Create a new session out of comepleted handshake. This clones the handshake connection object /// and leaves the handhsake in limbo to be deregistered from the event loop. pub fn new(io: &IoContext, socket: TcpStream, token: StreamToken, id: Option<&NodeId>, - nonce: &H256, stats: Arc, host: &HostInfo) -> Result + nonce: &H256, host: &HostInfo) -> Result where Message: Send + Clone + Sync + 'static { let originated = id.is_some(); - let mut handshake = Handshake::new(token, id, socket, nonce, stats).expect("Can't create handshake"); + let mut handshake = Handshake::new(token, id, socket, nonce).expect("Can't create handshake"); let local_addr = handshake.connection.local_addr_str(); handshake.start(io, host, originated)?; Ok(Session { diff --git a/util/network-devp2p/src/stats.rs b/util/network-devp2p/src/stats.rs deleted file mode 100644 index d4dbfe0432..0000000000 --- a/util/network-devp2p/src/stats.rs +++ /dev/null @@ -1,76 +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 . - -//! Network Statistics -use std::sync::atomic::*; - -/// Network statistics structure -#[derive(Default, Debug)] -pub struct NetworkStats { - /// Bytes received - recv: AtomicUsize, - /// Bytes sent - send: AtomicUsize, - /// Total number of sessions created - sessions: AtomicUsize, -} - -impl NetworkStats { - /// Increase bytes received. - #[inline] - pub fn inc_recv(&self, size: usize) { - self.recv.fetch_add(size, Ordering::Relaxed); - } - - /// Increase bytes sent. - #[inline] - pub fn inc_send(&self, size: usize) { - self.send.fetch_add(size, Ordering::Relaxed); - } - - /// Increase number of sessions. - #[inline] - pub fn inc_sessions(&self) { - self.sessions.fetch_add(1, Ordering::Relaxed); - } - - /// Get bytes sent. - #[inline] - pub fn send(&self) -> usize { - self.send.load(Ordering::Relaxed) - } - - /// Get bytes received. - #[inline] - pub fn recv(&self) -> usize { - self.recv.load(Ordering::Relaxed) - } - - /// Get total number of sessions created. - #[inline] - pub fn sessions(&self) -> usize { - self.sessions.load(Ordering::Relaxed) - } - - /// Create a new empty instance. - pub fn new() -> NetworkStats { - NetworkStats { - recv: AtomicUsize::new(0), - send: AtomicUsize::new(0), - sessions: AtomicUsize::new(0), - } - } -} diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index e964a9a8b5..3aed1b9fc4 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -#[macro_use] -extern crate log; extern crate parking_lot; extern crate ethcore_bytes; extern crate ethcore_io as io; @@ -109,29 +107,6 @@ fn net_service() { service.register_protocol(Arc::new(TestProtocol::new(false)), *b"myp", 1, &[1u8]).unwrap(); } -#[test] -fn net_connect() { - ::ethcore_logger::init_log(); - let key1 = Random.generate().unwrap(); - let mut config1 = NetworkConfiguration::new_local(); - config1.use_secret = Some(key1.secret().clone()); - config1.boot_nodes = vec![ ]; - let mut service1 = NetworkService::new(config1, None).unwrap(); - service1.start().unwrap(); - let handler1 = TestProtocol::register(&mut service1, false); - let mut config2 = NetworkConfiguration::new_local(); - info!("net_connect: local URL: {}", service1.local_url().unwrap()); - config2.boot_nodes = vec![ service1.local_url().unwrap() ]; - let mut service2 = NetworkService::new(config2, None).unwrap(); - service2.start().unwrap(); - let handler2 = TestProtocol::register(&mut service2, false); - while !handler1.got_packet() && !handler2.got_packet() && (service1.stats().sessions() == 0 || service2.stats().sessions() == 0) { - thread::sleep(Duration::from_millis(50)); - } - assert!(service1.stats().sessions() >= 1); - assert!(service2.stats().sessions() >= 1); -} - #[test] fn net_start_stop() { let config = NetworkConfiguration::new_local(); -- GitLab From 2632310b6aa34961552b45472c66ba7c0b4cb030 Mon Sep 17 00:00:00 2001 From: Thibaut S <33178835+Tbaut@users.noreply.github.com> Date: Wed, 28 Mar 2018 10:42:55 +0200 Subject: [PATCH 003/263] Update CLI help for jsonrpc-apis, ws-apis and ipc-apis (#8234) * jsonrpc-api, ws-apis and ipc-apis update * Better wording * Clarify what "safe" has --- parity/cli/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 5ae6c8d3da..b81dcda4e0 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -452,7 +452,7 @@ usage! { ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--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, pubsub, parity_pubsub, shh, shh_pubsub, signer, secretstore. You can also disable a specific API by putting '-' in the front: all,-personal.", + "Specify the APIs available through the JSONRPC interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", ARG arg_jsonrpc_hosts: (String) = "none", or |c: &Config| c.rpc.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), "--jsonrpc-hosts=[HOSTS]", @@ -485,7 +485,7 @@ usage! { ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--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, pubsub, parity_pubsub, shh, shh_pubsub, signer, secretstore.", + "Specify the APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", ARG arg_ws_origins: (String) = "parity://*,chrome-extension://*,moz-extension://*", or |c: &Config| c.websockets.as_ref()?.origins.as_ref().map(|vec| vec.join(",")), "--ws-origins=[URL]", @@ -506,7 +506,7 @@ usage! { ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces,rpc,shh,shh_pubsub", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--ipc-apis=[APIS]", - "Specify custom API set available via JSON-RPC over IPC.", + "Specify custom API set available via JSON-RPC over IPC using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", ["API and console options – Dapps"] FLAG flag_no_dapps: (bool) = false, or |c: &Config| c.dapps.as_ref()?.disable.clone(), -- GitLab From 23ea4798e08bafc5954bf1a0a457e7c763c73af7 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 28 Mar 2018 18:59:16 +0900 Subject: [PATCH 004/263] fixed ethcore tx_filter (#8200) --- ethcore/src/tx_filter.rs | 63 ++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index 12e6fe3ebb..a4fa8a0874 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -16,11 +16,10 @@ //! Smart contract based transaction filter. -use std::collections::HashMap; -use std::collections::hash_map::Entry; use ethereum_types::{H256, Address}; -use client::{BlockInfo, CallContract, BlockId, ChainNotify}; -use bytes::Bytes; +use lru_cache::LruCache; + +use client::{BlockInfo, CallContract, BlockId}; use parking_lot::Mutex; use spec::CommonParams; use transaction::{Action, SignedTransaction}; @@ -43,7 +42,7 @@ mod tx_permissions { pub struct TransactionFilter { contract: transact_acl::TransactAcl, contract_address: Address, - permission_cache: Mutex>, + permission_cache: Mutex>, } impl TransactionFilter { @@ -53,19 +52,14 @@ impl TransactionFilter { TransactionFilter { contract: transact_acl::TransactAcl::default(), contract_address: address, - permission_cache: Mutex::new(HashMap::new()), + permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)), } ) } - /// Clear cached permissions. - pub fn clear_cache(&self) { - self.permission_cache.lock().clear(); - } - /// Check if transaction is allowed at given block. pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool { - let mut cache = self.permission_cache.lock(); let len = cache.len(); + let mut cache = self.permission_cache.lock(); let tx_type = match transaction.action { Action::Create => tx_permissions::CREATE, @@ -75,35 +69,28 @@ impl TransactionFilter { tx_permissions::BASIC } }; + let sender = transaction.sender(); - match cache.entry((*parent_hash, sender)) { - Entry::Occupied(entry) => *entry.get() & tx_type != 0, - Entry::Vacant(entry) => { - let contract_address = self.contract_address; - let permissions = self.contract.functions() - .allowed_tx_types() - .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) - .map(|p| p.low_u32()) - .unwrap_or_else(|e| { - debug!("Error callling tx permissions contract: {:?}", e); - tx_permissions::NONE - }); - - if len < MAX_CACHE_SIZE { - entry.insert(permissions); - } - trace!("Permissions required: {}, got: {}", tx_type, permissions); - permissions & tx_type != 0 - } - } - } -} + let key = (*parent_hash, sender); -impl ChainNotify for TransactionFilter { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { - if !imported.is_empty() { - self.clear_cache(); + if let Some(permissions) = cache.get_mut(&key) { + return *permissions & tx_type != 0; } + + let contract_address = self.contract_address; + let permissions = self.contract.functions() + .allowed_tx_types() + .call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)) + .map(|p| p.low_u32()) + .unwrap_or_else(|e| { + debug!("Error callling tx permissions contract: {:?}", e); + tx_permissions::NONE + }); + + cache.insert((*parent_hash, sender), permissions); + + trace!("Permissions required: {}, got: {}", tx_type, permissions); + permissions & tx_type != 0 } } -- GitLab From 0c7f998c257b682575c7f96c87b1cff8ef51f997 Mon Sep 17 00:00:00 2001 From: Varunram Ganesh Date: Wed, 28 Mar 2018 17:41:49 +0530 Subject: [PATCH 005/263] Update musicoin spec in line with gmc v2.6.2 (#8242) --- ethcore/res/ethereum/musicoin.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ethcore/res/ethereum/musicoin.json b/ethcore/res/ethereum/musicoin.json index efe81c5882..6d5f6835bd 100644 --- a/ethcore/res/ethereum/musicoin.json +++ b/ethcore/res/ethereum/musicoin.json @@ -10,9 +10,9 @@ "homesteadTransition":"0x118c30", "eip100bTransition":"0x21e88e", "eip150Transition":"0x21e88e", - "eip160Transition":"0x7fffffffffffff", - "eip161abcTransition":"0x7fffffffffffff", - "eip161dTransition":"0x7fffffffffffff", + "eip160Transition":"0x21e88e", + "eip161abcTransition":"0x21e88e", + "eip161dTransition":"0x21e88e", "eip649Transition":"0x21e88e", "blockReward":"0x1105a0185b50a80000", "mcip3Transition":"0x124f81", @@ -40,8 +40,7 @@ "eip211Transition":"0x21e88e", "eip214Transition":"0x21e88e", "eip658Transition":"0x21e88e", - "maxCodeSize":"0x6000", - "maxCodeSizeTransition": "0x7fffffffffffff" + "maxCodeSize":"0x6000" }, "genesis":{ "seal":{ -- GitLab From 6e49ff1d98cdcc52733f9ea93dd95a6d487b3279 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 29 Mar 2018 04:04:08 +0900 Subject: [PATCH 006/263] Add test for ethstore-cli, fixes #8027 (#8187) * Add test for ethstore-cli, fixes #8027 remove println * Update test.sh --- Cargo.lock | 1 + ethstore/cli/Cargo.toml | 3 ++ ethstore/cli/tests/cli.rs | 83 +++++++++++++++++++++++++++++++++++++++ test.sh | 10 ++++- 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 ethstore/cli/tests/cli.rs diff --git a/Cargo.lock b/Cargo.lock index 6e82fc19bd..0b43ab79f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -869,6 +869,7 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/ethstore/cli/Cargo.toml b/ethstore/cli/Cargo.toml index f164f0a672..bd5db86216 100644 --- a/ethstore/cli/Cargo.toml +++ b/ethstore/cli/Cargo.toml @@ -18,3 +18,6 @@ panic_hook = { path = "../../util/panic_hook" } name = "ethstore" path = "src/main.rs" doc = false + +[dev-dependencies] +tempdir = "0.3.5" diff --git a/ethstore/cli/tests/cli.rs b/ethstore/cli/tests/cli.rs new file mode 100644 index 0000000000..a740b95c28 --- /dev/null +++ b/ethstore/cli/tests/cli.rs @@ -0,0 +1,83 @@ +// 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 . + +extern crate tempdir; +use std::process::Command; +use tempdir::TempDir; +use std::fs::File; +use std::io::Write; + +fn run(args: &[&str]) -> String { + let output = Command::new("cargo") + .args(&["run", "--"]) + .args(args) + .output() + .unwrap(); + assert!(output.status.success()); + String::from_utf8(output.stdout).unwrap() +} + +#[test] +fn cli_cmd() { + Command::new("cargo") + .arg("build") + .output() + .unwrap(); + + let dir = TempDir::new("test-vault").unwrap(); + + let mut passwd = File::create(dir.path().join("test-password")).unwrap(); + writeln!(passwd, "password").unwrap(); + + let mut passwd2 = File::create(dir.path().join("test-vault-addr")).unwrap(); + writeln!(passwd2, "password2").unwrap(); + + let test_password_buf = dir.path().join("test-password"); + let test_password: &str = test_password_buf.to_str().unwrap(); + let dir_str: &str = dir.path().to_str().unwrap(); + let test_vault_addr_buf = dir.path().join("test-vault-addr"); + let test_vault_addr = test_vault_addr_buf.to_str().unwrap(); + + run(&["create-vault", "test-vault", test_password, "--dir", dir_str]); + + let output = run(&["insert", "7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5", + test_vault_addr, + "--dir", dir_str, + "--vault", "test-vault", + "--vault-pwd", test_password]); + let address = output.trim(); + + let output = run(&["list", + "--dir", dir_str, + "--vault", "test-vault", + "--vault-pwd", test_password]); + assert_eq!(output, " 0: 0xa8fa5dd30a87bb9e3288d604eb74949c515ab66e\n"); + + let output = run(&["sign", &address[2..], + test_vault_addr, + "7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5", + "--dir", dir_str, + "--vault", "test-vault", + "--vault-pwd", test_password]); + assert_eq!(output, "0x54ab6e5cf0c5cb40043fdca5d15d611a3a94285414a076dafecc8dc9c04183f413296a3defff61092c0bb478dc9887ec01070e1275234211208fb8f4be4a9b0101\n"); + + + let output = run(&["public", &address[2..], test_vault_addr, + "--dir", dir_str, + "--vault", "test-vault", + "--vault-pwd", test_password]); + assert_eq!(output, "0x35f222d88b80151857a2877826d940104887376a94c1cbd2c8c7c192eb701df88a18a4ecb8b05b1466c5b3706042027b5e079fe3a3683e66d822b0e047aa3418\n"); +} diff --git a/test.sh b/test.sh index 69204fef2f..ada9525cb7 100755 --- a/test.sh +++ b/test.sh @@ -24,10 +24,16 @@ esac set -e +# Validate --no-default-features build +echo "________Validate build________" +cargo check --no-default-features + # Validate chainspecs +echo "________Validate chainspecs________" ./scripts/validate_chainspecs.sh +# Running test's +echo "________Running Parity Full Test Suite________" + cargo test -j 8 $OPTIONS --features "$FEATURES" --all --exclude evmjit $1 -# Validate --no-default-features build -cargo check --no-default-features -- GitLab From e3f7b70c3805c4dba6720b39af27d2a1d67afc8c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 29 Mar 2018 10:19:45 +0100 Subject: [PATCH 007/263] Replace all Rlp usages with UntrustedRlp except for ethcore views (#8233) * Replace Rlp with UntrustedRlp and unsafely unwrap All Rlp methods return Result<_,DecoderError> now, so for this first pass each will be marked with `expect("TODO")`. In the next pass we can categorise figure out how to handle each case. * Handle DecoderError for tendermint message * Unwrap rlp results in TestBlockcChainClient Rlp should be valid since created manually in tests * Replace `use rlp::*` with explicit imports * Remove rlp decode unwraps from light cli request * Structured rlp encoding for curr best and latest in header chain * Propogate decoder errors from send_packet * Fix body uncles rlp index * Use BodyView in sync and `expect` rlp errors * Revert bbf28f removing original Rlp for this phase This can be done again in the next phase, in order that we can leave the ethcore views unchanged * Restore legacy Rlp and UntrustedRlp Use legacy Rlp for ethcore views. Will redo replacing Rlp with UntrustedRlp in a subsequent PR * Fix tests * Replace boilerplate Encodable/Decodable with derive * Use BlockView instead of Rlp, remove unwrap * Remove rlp test_cli unwraps by using BlockView instead of Rlp directly * Remove unneccesary change to use borrowed hash * Construct sync block using new_from_header_and_body --- ethcore/light/src/client/header_chain.rs | 34 +++++++++++++++-------- ethcore/light/src/net/request_credits.rs | 2 +- ethcore/light/src/net/tests/mod.rs | 2 +- ethcore/light/src/on_demand/request.rs | 19 ++++--------- ethcore/src/blockchain/blockchain.rs | 2 +- ethcore/src/client/test_client.rs | 16 ++++++----- ethcore/src/encoded.rs | 17 +++++++++++- ethcore/src/engines/tendermint/message.rs | 4 +-- ethcore/src/header.rs | 2 +- ethcore/src/state/account.rs | 2 +- ethcore/src/trace/types/flat.rs | 2 +- ethcore/src/trace/types/trace.rs | 2 +- ethcore/src/views/block.rs | 10 +++++++ ethcore/src/views/body.rs | 11 +++++++- ethcore/transaction/src/transaction.rs | 1 - ethcore/types/src/receipt.rs | 2 +- ethcore/types/src/snapshot_manifest.rs | 2 +- sync/src/block_sync.rs | 2 +- sync/src/blocks.rs | 15 ++++------ sync/src/chain.rs | 2 +- util/network-devp2p/src/connection.rs | 2 +- util/network-devp2p/src/discovery.rs | 27 ++++++++++-------- util/network-devp2p/src/handshake.rs | 2 +- util/network-devp2p/src/host.rs | 3 +- util/network-devp2p/src/node_table.rs | 2 +- util/network-devp2p/src/session.rs | 2 +- 26 files changed, 113 insertions(+), 74 deletions(-) diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 3bbd6cb950..84b7916eef 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -41,7 +41,7 @@ use ethcore::engines::epoch::{ PendingTransition as PendingEpochTransition }; -use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; use plain_hasher::H256FastMap; @@ -74,6 +74,22 @@ pub struct BlockDescriptor { pub total_difficulty: U256, } +// best block data +#[derive(RlpEncodable, RlpDecodable)] +struct BestAndLatest { + best_num: u64, + latest_num: u64 +} + +impl BestAndLatest { + fn new(best_num: u64, latest_num: u64) -> Self { + BestAndLatest { + best_num, + latest_num, + } + } +} + // candidate block description. struct Candidate { hash: H256, @@ -212,12 +228,9 @@ impl HeaderChain { let decoded_header = spec.genesis_header(); let chain = if let Some(current) = db.get(col, CURRENT_KEY)? { - let (best_number, highest_number) = { - let rlp = Rlp::new(¤t); - (rlp.val_at(0), rlp.val_at(1)) - }; + let curr : BestAndLatest = ::rlp::decode(¤t); - let mut cur_number = highest_number; + let mut cur_number = curr.latest_num; let mut candidates = BTreeMap::new(); // load all era entries, referenced headers within them, @@ -245,7 +258,7 @@ impl HeaderChain { // fill best block block descriptor. let best_block = { - let era = match candidates.get(&best_number) { + let era = match candidates.get(&curr.best_num) { Some(era) => era, None => return Err(Error::Database("Database corrupt: highest block referenced but no data.".into())), }; @@ -253,7 +266,7 @@ impl HeaderChain { let best = &era.candidates[0]; BlockDescriptor { hash: best.hash, - number: best_number, + number: curr.best_num, total_difficulty: best.total_difficulty, } }; @@ -542,9 +555,8 @@ impl HeaderChain { // write the best and latest eras to the database. { let latest_num = *candidates.iter().rev().next().expect("at least one era just inserted; qed").0; - let mut stream = RlpStream::new_list(2); - stream.append(&best_num).append(&latest_num); - transaction.put(self.col, CURRENT_KEY, &stream.out()) + let curr = BestAndLatest::new(best_num, latest_num); + transaction.put(self.col, CURRENT_KEY, &::rlp::encode(&curr)) } Ok(pending) } diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index f97ce85bcd..c35a292227 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -29,7 +29,7 @@ use request::{self, Request}; use super::error::Error; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, Decodable, Encodable, DecoderError}; use ethereum_types::U256; use std::time::{Duration, Instant}; diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index c3c792b786..4beb32833f 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -31,7 +31,7 @@ use provider::Provider; use request; use request::*; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream}; use ethereum_types::{H256, U256, Address}; use std::sync::Arc; diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index e7303ad884..8b184cc1d8 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -439,13 +439,7 @@ impl CheckedRequest { block_header .and_then(|hdr| cache.block_body(&block_hash).map(|b| (hdr, b))) .map(|(hdr, body)| { - let mut stream = RlpStream::new_list(3); - let body = body.rlp(); - stream.append_raw(&hdr.rlp().as_raw(), 1); - stream.append_raw(&body.at(0).as_raw(), 1); - stream.append_raw(&body.at(1).as_raw(), 1); - - Response::Body(encoded::Block::new(stream.out())) + Response::Body(encoded::Block::new_from_header_and_body(&hdr.view(), &body.view())) }) } CheckedRequest::Code(_, ref req) => { @@ -778,25 +772,22 @@ impl Body { pub fn check_response(&self, cache: &Mutex<::cache::Cache>, body: &encoded::Body) -> Result { // check the integrity of the the body against the header let header = self.0.as_ref()?; - let tx_root = ::triehash::ordered_trie_root(body.rlp().at(0).iter().map(|r| r.as_raw())); + let tx_root = ::triehash::ordered_trie_root(body.transactions_rlp().iter().map(|r| r.as_raw())); if tx_root != header.transactions_root() { return Err(Error::WrongTrieRoot(header.transactions_root(), tx_root)); } - let uncles_hash = keccak(body.rlp().at(1).as_raw()); + let uncles_hash = keccak(body.uncles_rlp().as_raw()); if uncles_hash != header.uncles_hash() { return Err(Error::WrongHash(header.uncles_hash(), uncles_hash)); } // concatenate the header and the body. - let mut stream = RlpStream::new_list(3); - stream.append_raw(header.rlp().as_raw(), 1); - stream.append_raw(body.rlp().at(0).as_raw(), 1); - stream.append_raw(body.rlp().at(1).as_raw(), 1); + let block = encoded::Block::new_from_header_and_body(&header.view(), &body.view()); cache.lock().insert_block_body(header.hash(), body.clone()); - Ok(encoded::Block::new(stream.out())) + Ok(block) } } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 09be1143f2..86a1c522a1 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -25,7 +25,7 @@ use heapsize::HeapSizeOf; use ethereum_types::{H256, Bloom, U256}; use parking_lot::{Mutex, RwLock}; use bytes::Bytes; -use rlp::*; +use rlp::{Rlp, RlpStream}; use rlp_compress::{compress, decompress, blocks_swapper}; use header::*; use transaction::*; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index b806183a2c..69d8c70d6b 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -29,7 +29,7 @@ use journaldb; use kvdb::DBValue; use kvdb_memorydb; use bytes::Bytes; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream}; use ethkey::{Generator, Random}; use transaction::{self, Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action}; use blockchain::{TreeRoute, BlockReceipts}; @@ -66,6 +66,7 @@ use encoded; use engines::EthEngine; use trie; use state::StateInfo; +use views::BlockView; /// Test client. pub struct TestBlockChainClient { @@ -469,7 +470,7 @@ impl ChainInfo for TestBlockChainClient { impl BlockInfo for TestBlockChainClient { fn block_header(&self, id: BlockId) -> Option { self.block_hash(id) - .and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) + .and_then(|hash| self.blocks.read().get(&hash).map(|r| BlockView::new(r).header_rlp().as_raw().to_vec())) .map(encoded::Header::new) } @@ -510,7 +511,7 @@ impl RegistryInfo for TestBlockChainClient { impl ImportBlock for TestBlockChainClient { fn import_block(&self, b: Bytes) -> Result { - let header = Rlp::new(&b).val_at::(0); + let header = BlockView::new(&b).header(); let h = header.hash(); let number: usize = header.number() as usize; if number > self.blocks.read().len() { @@ -519,7 +520,7 @@ impl ImportBlock for TestBlockChainClient { if number > 0 { match self.blocks.read().get(header.parent_hash()) { Some(parent) => { - let parent = Rlp::new(parent).val_at::(0); + let parent = BlockView::new(parent).header(); if parent.number() != (header.number() - 1) { panic!("Unexpected block parent"); } @@ -544,7 +545,7 @@ impl ImportBlock for TestBlockChainClient { while n > 0 && self.numbers.read()[&n] != parent_hash { *self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone(); n -= 1; - parent_hash = Rlp::new(&self.blocks.read()[&parent_hash]).val_at::(0).parent_hash().clone(); + parent_hash = BlockView::new(&self.blocks.read()[&parent_hash]).header().parent_hash().clone(); } } } @@ -683,9 +684,10 @@ impl BlockChainClient for TestBlockChainClient { fn block_body(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| { + let block = BlockView::new(r); let mut stream = RlpStream::new_list(2); - stream.append_raw(Rlp::new(r).at(1).as_raw(), 1); - stream.append_raw(Rlp::new(r).at(2).as_raw(), 1); + stream.append_raw(block.transactions_rlp().as_raw(), 1); + stream.append_raw(block.uncles_rlp().as_raw(), 1); encoded::Body::new(stream.out()) })) } diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 098a90a8ab..5d3d316063 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -31,7 +31,7 @@ use views; use hash::keccak; use heapsize::HeapSizeOf; use ethereum_types::{H256, Bloom, U256, Address}; -use rlp::Rlp; +use rlp::{Rlp, RlpStream}; /// Owning header view. #[derive(Debug, Clone, PartialEq, Eq)] @@ -144,6 +144,9 @@ impl Body { // forwarders to borrowed view. impl Body { + /// Get raw rlp of transactions + pub fn transactions_rlp(&self) -> Rlp { self.view().transactions_rlp() } + /// Get a vector of all transactions. pub fn transactions(&self) -> Vec { self.view().transactions() } @@ -156,6 +159,9 @@ impl Body { /// The hash of each transaction in the block. pub fn transaction_hashes(&self) -> Vec { self.view().transaction_hashes() } + /// Get raw rlp of uncle headers + pub fn uncles_rlp(&self) -> Rlp { self.view().uncles_rlp() } + /// Decode uncle headers. pub fn uncles(&self) -> Vec { self.view().uncles() } @@ -181,6 +187,15 @@ impl Block { /// Create a new owning block view. The raw bytes passed in must be an rlp-encoded block. pub fn new(raw: Vec) -> Self { Block(raw) } + /// Create a new owning block view by concatenating the encoded header and body + pub fn new_from_header_and_body(header: &views::HeaderView, body: &views::BodyView) -> Self { + let mut stream = RlpStream::new_list(3); + stream.append_raw(header.rlp().as_raw(), 1); + stream.append_raw(body.transactions_rlp().as_raw(), 1); + stream.append_raw(body.uncles_rlp().as_raw(), 1); + Block::new(stream.out()) + } + /// Get a borrowed view of the whole block. #[inline] pub fn view(&self) -> views::BlockView { views::BlockView::new(&self.0) } diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index 1f71f41bcb..eac08df9bc 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -23,7 +23,7 @@ use bytes::Bytes; use super::{Height, View, BlockHash, Step}; use error::Error; use header::Header; -use rlp::{Rlp, UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; +use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; use ethkey::{recover, public_to_address}; use super::super::vote_collector::Message; @@ -100,7 +100,7 @@ impl ConsensusMessage { pub fn verify(&self) -> Result { let full_rlp = ::rlp::encode(self); - let block_info = Rlp::new(&full_rlp).at(1); + let block_info = UntrustedRlp::new(&full_rlp).at(1)?; let public_key = recover(&self.signature.into(), &keccak(block_info.as_raw()))?; Ok(public_to_address(&public_key)) } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index f6f5090ef8..7980da2788 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -23,7 +23,7 @@ use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak}; use heapsize::HeapSizeOf; use ethereum_types::{H256, U256, Address, Bloom}; use bytes::Bytes; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable}; pub use types::BlockNumber; diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index f70b3eb6a8..e08ad7b185 100755 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -27,7 +27,7 @@ use bytes::{Bytes, ToPretty}; use trie; use trie::{SecTrieDB, Trie, TrieFactory, TrieError}; use pod_account::*; -use rlp::*; +use rlp::{RlpStream, encode}; use lru_cache::LruCache; use basic_account::BasicAccount; diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index e97f4d3235..e3f66e170b 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -17,7 +17,7 @@ //! Flat trace module use std::collections::VecDeque; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, Decodable, Encodable, DecoderError}; use heapsize::HeapSizeOf; use ethereum_types::Bloom; use super::trace::{Action, Res}; diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index 18fe329c44..e6db17603d 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -18,7 +18,7 @@ use ethereum_types::{U256, Address, Bloom, BloomInput}; use bytes::Bytes; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable}; use vm::ActionParams; use evm::CallType; diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index c60cc07c54..f6bb92873c 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -91,6 +91,11 @@ impl<'a> BlockView<'a> { }).collect() } + /// Return the raw rlp for the transactions in the given block. + pub fn transactions_rlp(&self) -> Rlp<'a> { + self.rlp.at(1) + } + /// Return number of transactions in given block, without deserializing them. pub fn transactions_count(&self) -> usize { self.rlp.at(1).iter().count() @@ -125,6 +130,11 @@ impl<'a> BlockView<'a> { }) } + /// Returns raw rlp for the uncles in the given block + pub fn uncles_rlp(&self) -> Rlp<'a> { + self.rlp.at(2) + } + /// Return list of uncles of given block. pub fn uncles(&self) -> Vec
{ self.rlp.list_at(2) diff --git a/ethcore/src/views/body.rs b/ethcore/src/views/body.rs index 433f7c2b68..d23f1a1d77 100644 --- a/ethcore/src/views/body.rs +++ b/ethcore/src/views/body.rs @@ -68,11 +68,15 @@ impl<'a> BodyView<'a> { }).collect() } + /// Return the raw rlp for the transactions in the given block. + pub fn transactions_rlp(&self) -> Rlp<'a> { + self.rlp.at(0) + } + /// Return number of transactions in given block, without deserializing them. pub fn transactions_count(&self) -> usize { self.rlp.at(0).item_count() } - /// Return List of transactions in given block. pub fn transaction_views(&self) -> Vec> { self.rlp.at(0).iter().map(TransactionView::new_from_rlp).collect() @@ -99,6 +103,11 @@ impl<'a> BodyView<'a> { }) } + /// Returns raw rlp for the uncles in the given block + pub fn uncles_rlp(&self) -> Rlp<'a> { + self.rlp.at(1) + } + /// Return list of uncles of given block. pub fn uncles(&self) -> Vec
{ self.rlp.list_at(1) diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index f206c549a7..d458e1f602 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -25,7 +25,6 @@ use evm::Schedule; use hash::keccak; use heapsize::HeapSizeOf; use rlp::{self, RlpStream, UntrustedRlp, DecoderError, Encodable}; -// use rlp::*; type Bytes = Vec; type BlockNumber = u64; diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index 29b2e909b9..8aee993653 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -18,7 +18,7 @@ use ethereum_types::{H256, U256, Address, Bloom}; use heapsize::HeapSizeOf; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; use {BlockNumber}; use log_entry::{LogEntry, LocalizedLogEntry}; diff --git a/ethcore/types/src/snapshot_manifest.rs b/ethcore/types/src/snapshot_manifest.rs index 72f83afeb2..7f41f9994d 100644 --- a/ethcore/types/src/snapshot_manifest.rs +++ b/ethcore/types/src/snapshot_manifest.rs @@ -17,7 +17,7 @@ //! Snapshot manifest type definition use ethereum_types::H256; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, DecoderError}; use bytes::Bytes; /// Manifest data. diff --git a/sync/src/block_sync.rs b/sync/src/block_sync.rs index 9e72c9d53d..5cf81b2e86 100644 --- a/sync/src/block_sync.rs +++ b/sync/src/block_sync.rs @@ -22,7 +22,7 @@ use std::collections::{HashSet, VecDeque}; use std::cmp; use heapsize::HeapSizeOf; use ethereum_types::H256; -use rlp::*; +use rlp::UntrustedRlp; use ethcore::views::{BlockView}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockStatus, BlockId, BlockImportError}; diff --git a/sync/src/blocks.rs b/sync/src/blocks.rs index 65244a4e71..37aa579ef9 100644 --- a/sync/src/blocks.rs +++ b/sync/src/blocks.rs @@ -22,8 +22,10 @@ use heapsize::HeapSizeOf; use ethereum_types::H256; use triehash::ordered_trie_root; use bytes::Bytes; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, DecoderError}; use network; +use ethcore::encoded::Block; +use ethcore::views::{HeaderView, BodyView}; use ethcore::header::Header as BlockHeader; known_heap_size!(0, HeaderId); @@ -290,15 +292,10 @@ impl BlockCollection { } for block in blocks { - let mut block_rlp = RlpStream::new_list(3); - block_rlp.append_raw(&block.header, 1); - { - let body = Rlp::new(block.body.as_ref().expect("blocks contains only full blocks; qed")); - block_rlp.append_raw(body.at(0).as_raw(), 1); - block_rlp.append_raw(body.at(1).as_raw(), 1); - } + let body = BodyView::new(block.body.as_ref().expect("blocks contains only full blocks; qed")); + let block_view = Block::new_from_header_and_body(&HeaderView::new(&block.header), &body); drained.push(BlockAndReceipts { - block: block_rlp.out(), + block: block_view.rlp().as_raw().to_vec(), receipts: block.receipts.clone(), }); } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index a4d72ac96b..6b5f370d39 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -97,7 +97,7 @@ use ethereum_types::{H256, U256}; use plain_hasher::H256FastMap; use parking_lot::RwLock; use bytes::Bytes; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, DecoderError, Encodable}; use network::{self, PeerId, PacketId}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo}; diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index ea3b99d418..4d775b215f 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -23,7 +23,7 @@ use mio::deprecated::{Handler, EventLoop, TryRead, TryWrite}; use mio::tcp::*; use ethereum_types::{H128, H256, H512}; use ethcore_bytes::*; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream}; use std::io::{self, Cursor, Read, Write}; use io::{IoContext, StreamToken}; use handshake::Handshake; diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index 4a43ab3eb6..fa32f89f9a 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -25,7 +25,7 @@ use mio::deprecated::{Handler, EventLoop}; use mio::udp::*; use hash::keccak; use ethereum_types::{H256, H520}; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, encode_list}; use node_table::*; use network::{Error, ErrorKind}; use io::{StreamToken, IoContext}; @@ -216,7 +216,8 @@ impl Discovery { let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::>(); for r in nearest { let rlp = encode_list(&(&[self.discovery_id.clone()][..])); - self.send_packet(PACKET_FIND_NODE, &r.endpoint.udp_address(), &rlp); + self.send_packet(PACKET_FIND_NODE, &r.endpoint.udp_address(), &rlp) + .unwrap_or_else(|e| warn!("Error sending node discovery packet for {:?}: {:?}", &r.endpoint, e)); self.discovery_nodes.insert(r.id.clone()); tried_count += 1; trace!(target: "discovery", "Sent FindNode to {:?}", &r.endpoint); @@ -251,16 +252,17 @@ impl Discovery { self.public_endpoint.to_rlp_list(&mut rlp); node.to_rlp_list(&mut rlp); trace!(target: "discovery", "Sent Ping to {:?}", &node); - self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain()); + self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain()) + .unwrap_or_else(|e| warn!("Error sending Ping packet: {:?}", e)) } - fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) { + fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) -> Result<(), Error> { let mut rlp = RlpStream::new(); rlp.append_raw(&[packet_id], 1); - let source = Rlp::new(payload); - rlp.begin_list(source.item_count() + 1); - for i in 0 .. source.item_count() { - rlp.append_raw(source.at(i).as_raw(), 1); + let source = UntrustedRlp::new(payload); + rlp.begin_list(source.item_count()? + 1); + for i in 0 .. source.item_count()? { + rlp.append_raw(source.at(i)?.as_raw(), 1); } let timestamp = 60 + SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as u32; rlp.append(×tamp); @@ -269,9 +271,9 @@ impl Discovery { let hash = keccak(bytes.as_ref()); let signature = match sign(&self.secret, &hash) { Ok(s) => s, - Err(_) => { + Err(e) => { warn!("Error signing UDP packet"); - return; + return Err(Error::from(e)); } }; let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65); @@ -281,6 +283,7 @@ impl Discovery { let signed_hash = keccak(&packet[32..]); packet[0..32].clone_from_slice(&signed_hash); self.send_to(packet, address.clone()); + Ok(()) } fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { @@ -425,7 +428,7 @@ impl Discovery { let mut response = RlpStream::new_list(2); dest.to_rlp_list(&mut response); response.append(&echo_hash); - self.send_packet(PACKET_PONG, from, &response.drain()); + self.send_packet(PACKET_PONG, from, &response.drain())?; Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) } @@ -456,7 +459,7 @@ impl Discovery { } let mut packets = Discovery::prepare_neighbours_packets(&nearest); for p in packets.drain(..) { - self.send_packet(PACKET_NEIGHBOURS, from, &p); + self.send_packet(PACKET_NEIGHBOURS, from, &p)?; } trace!(target: "discovery", "Sent {} Neighbours to {:?}", nearest.len(), &from); Ok(None) diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index dbd31c5a87..020b65477b 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -19,7 +19,7 @@ use hash::write_keccak; use mio::tcp::*; use ethereum_types::{H256, H520}; use ethcore_bytes::Bytes; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream}; use connection::{Connection}; use node_table::NodeId; use io::{IoContext, StreamToken}; diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 87e9a02789..9df2d0b389 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -30,7 +30,8 @@ use mio::*; use mio::deprecated::{EventLoop}; use mio::tcp::*; use ethereum_types::H256; -use rlp::*; +use rlp::{RlpStream, Encodable}; + use session::{Session, SessionData}; use io::*; use PROTOCOL_VERSION; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 244f518f21..6be9ae12eb 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -22,7 +22,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::{fs, mem, slice}; use ethereum_types::H512; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, DecoderError}; use network::{Error, ErrorKind, AllowIP, IpFilter}; use discovery::{TableUpdates, NodeEntry}; use ip_utils::*; diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index e82df62ba0..179d706d7e 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -23,7 +23,7 @@ use mio::*; use mio::deprecated::{Handler, EventLoop}; use mio::tcp::*; use ethereum_types::H256; -use rlp::*; +use rlp::{UntrustedRlp, RlpStream, EMPTY_LIST_RLP}; use connection::{EncryptedConnection, Packet, Connection, MAX_PAYLOAD_SIZE}; use handshake::Handshake; use io::{IoContext, StreamToken}; -- GitLab From 899c1a4b0e69fa3b8d267cc2141eb89f94da1ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 29 Mar 2018 11:20:27 +0200 Subject: [PATCH 008/263] Warp-only sync with warp-barrier [blocknumber] flag. (#8228) * Warp-only sync with warp-after [blocknumber] flag. * Fix tests. * Fix configuration tests. * Rename to warp barrier. --- parity/cli/mod.rs | 7 +++++ parity/configuration.rs | 2 ++ parity/run.rs | 9 ++++-- sync/src/api.rs | 39 ++++++++++++++++++++++-- sync/src/chain.rs | 53 ++++++++++++++++++++++++--------- sync/src/tests/chain.rs | 4 +-- sync/src/tests/snapshot.rs | 4 +-- util/network-devp2p/src/host.rs | 5 ++-- 8 files changed, 99 insertions(+), 24 deletions(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index b81dcda4e0..691bdd6144 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -393,6 +393,10 @@ usage! { "--no-serve-light", "Disable serving of light peers.", + ARG arg_warp_barrier: (Option) = None, or |c: &Config| c.network.as_ref()?.warp_barrier.clone(), + "--warp-barrier=[NUM]", + "When warp enabled never attempt regular sync before warping to block NUM.", + ARG arg_port: (u16) = 30303u16, or |c: &Config| c.network.as_ref()?.port.clone(), "--port=[PORT]", "Override the port on which the node should listen.", @@ -1044,6 +1048,7 @@ struct Ui { #[serde(deny_unknown_fields)] struct Network { warp: Option, + warp_barrier: Option, port: Option, min_peers: Option, max_peers: Option, @@ -1625,6 +1630,7 @@ mod tests { flag_geth: false, flag_testnet: false, flag_import_geth_keys: false, + arg_warp_barrier: None, arg_datadir: None, arg_networkid: None, arg_peers: None, @@ -1730,6 +1736,7 @@ mod tests { }), network: Some(Network { warp: Some(false), + warp_barrier: None, port: None, min_peers: Some(10), max_peers: Some(20), diff --git a/parity/configuration.rs b/parity/configuration.rs index 39c18f1389..bff8390391 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -368,6 +368,7 @@ impl Configuration { wal: wal, vm_type: vm_type, warp_sync: warp_sync, + warp_barrier: self.args.arg_warp_barrier, public_node: public_node, geth_compatibility: geth_compatibility, net_settings: self.network_settings()?, @@ -1401,6 +1402,7 @@ mod tests { network_id: None, public_node: false, warp_sync: true, + warp_barrier: None, acc_conf: Default::default(), gas_pricer_conf: Default::default(), miner_extras: Default::default(), diff --git a/parity/run.rs b/parity/run.rs index 19620f9d53..e7fb41cd7e 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -101,6 +101,7 @@ pub struct RunCmd { pub net_conf: ethsync::NetworkConfiguration, pub network_id: Option, pub warp_sync: bool, + pub warp_barrier: Option, pub public_node: bool, pub acc_conf: AccountsConfig, pub gas_pricer_conf: GasPricerConfig, @@ -513,7 +514,7 @@ pub fn execute_impl(cmd: RunCmd, can_restart: bool, logger: Arc) } sync_config.fork_block = spec.fork_block(); - let mut warp_sync = cmd.warp_sync; + let mut warp_sync = spec.engine.supports_warp() && cmd.warp_sync; if warp_sync { // Logging is not initialized yet, so we print directly to stderr if fat_db { @@ -527,7 +528,11 @@ pub fn execute_impl(cmd: RunCmd, can_restart: bool, logger: Arc) warp_sync = false; } } - sync_config.warp_sync = spec.engine.supports_warp() && warp_sync; + sync_config.warp_sync = match (warp_sync, cmd.warp_barrier) { + (true, Some(block)) => ethsync::WarpSync::OnlyAndAfter(block), + (true, _) => ethsync::WarpSync::Enabled, + _ => ethsync::WarpSync::Disabled, + }; sync_config.download_old_blocks = cmd.download_old_blocks; sync_config.serve_light = cmd.serve_light; diff --git a/sync/src/api.rs b/sync/src/api.rs index 38543de15c..735b6eb033 100644 --- a/sync/src/api.rs +++ b/sync/src/api.rs @@ -45,6 +45,41 @@ pub const ETH_PROTOCOL: ProtocolId = *b"eth"; /// Ethereum light protocol pub const LIGHT_PROTOCOL: ProtocolId = *b"pip"; +/// Determine warp sync status. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum WarpSync { + /// Warp sync is enabled. + Enabled, + /// Warp sync is disabled. + Disabled, + /// Only warp sync is allowed (no regular sync) and only after given block number. + OnlyAndAfter(BlockNumber), +} + +impl WarpSync { + /// Returns true if warp sync is enabled. + pub fn is_enabled(&self) -> bool { + match *self { + WarpSync::Enabled => true, + WarpSync::OnlyAndAfter(_) => true, + WarpSync::Disabled => false, + } + } + + /// Returns `true` if we are in warp-only mode. + /// + /// i.e. we will never fall back to regular sync + /// until given block number is reached by + /// successfuly finding and restoring from a snapshot. + pub fn is_warp_only(&self) -> bool { + if let WarpSync::OnlyAndAfter(_) = *self { + true + } else { + false + } + } +} + /// Sync configuration #[derive(Debug, Clone, Copy)] pub struct SyncConfig { @@ -61,7 +96,7 @@ pub struct SyncConfig { /// Fork block to check pub fork_block: Option<(BlockNumber, H256)>, /// Enable snapshot sync - pub warp_sync: bool, + pub warp_sync: WarpSync, /// Enable light client server. pub serve_light: bool, } @@ -75,7 +110,7 @@ impl Default for SyncConfig { subprotocol_name: ETH_PROTOCOL, light_subprotocol_name: LIGHT_PROTOCOL, fork_block: None, - warp_sync: false, + warp_sync: WarpSync::Disabled, serve_light: false, } } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 6b5f370d39..305922d5af 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -105,7 +105,7 @@ use ethcore::error::*; use ethcore::snapshot::{ManifestData, RestorationStatus}; use transaction::PendingTransaction; use sync_io::SyncIo; -use super::SyncConfig; +use super::{WarpSync, SyncConfig}; use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction}; use rand::Rng; use snapshot::{Snapshot, ChunkType}; @@ -385,7 +385,7 @@ pub struct ChainSync { /// Enable ancient block downloading download_old_blocks: bool, /// Enable warp sync. - enable_warp_sync: bool, + warp_sync: WarpSync, } type RlpResponseResult = Result, PacketDecodeError>; @@ -394,9 +394,16 @@ impl ChainSync { /// Create a new instance of syncing strategy. pub fn new(config: SyncConfig, chain: &BlockChainClient) -> ChainSync { let chain_info = chain.chain_info(); + let best_block = chain.chain_info().best_block_number; + let state = match config.warp_sync { + WarpSync::Enabled => SyncState::WaitingPeers, + WarpSync::OnlyAndAfter(block) if block > best_block => SyncState::WaitingPeers, + _ => SyncState::Idle, + }; + let mut sync = ChainSync { - state: if config.warp_sync { SyncState::WaitingPeers } else { SyncState::Idle }, - starting_block: chain.chain_info().best_block_number, + state, + starting_block: best_block, highest_block: None, peers: HashMap::new(), handshaking_peers: HashMap::new(), @@ -410,7 +417,7 @@ impl ChainSync { snapshot: Snapshot::new(), sync_start_time: None, transactions_stats: TransactionsStats::default(), - enable_warp_sync: config.warp_sync, + warp_sync: config.warp_sync, }; sync.update_targets(chain); sync @@ -508,10 +515,12 @@ impl ChainSync { } fn maybe_start_snapshot_sync(&mut self, io: &mut SyncIo) { - if !self.enable_warp_sync || io.snapshot_service().supported_versions().is_none() { + if !self.warp_sync.is_enabled() || io.snapshot_service().supported_versions().is_none() { + trace!(target: "sync", "Skipping warp sync. Disabled or not supported."); return; } if self.state != SyncState::WaitingPeers && self.state != SyncState::Blocks && self.state != SyncState::Waiting { + trace!(target: "sync", "Skipping warp sync. State: {:?}", self.state); return; } // Make sure the snapshot block is not too far away from best block and network best block and @@ -520,11 +529,16 @@ impl ChainSync { let fork_block = self.fork_block.as_ref().map(|&(n, _)| n).unwrap_or(0); let (best_hash, max_peers, snapshot_peers) = { + let expected_warp_block = match self.warp_sync { + WarpSync::OnlyAndAfter(block) => block, + _ => 0, + }; //collect snapshot infos from peers let snapshots = self.peers.iter() .filter(|&(_, p)| p.is_allowed() && p.snapshot_number.map_or(false, |sn| our_best_block < sn && (sn - our_best_block) > SNAPSHOT_RESTORE_THRESHOLD && sn > fork_block && + sn > expected_warp_block && self.highest_block.map_or(true, |highest| highest >= sn && (highest - sn) <= SNAPSHOT_RESTORE_THRESHOLD) )) .filter_map(|(p, peer)| peer.snapshot_hash.map(|hash| (p, hash.clone()))) @@ -554,7 +568,7 @@ impl ChainSync { trace!(target: "sync", "Starting unconfirmed snapshot sync {:?} with {:?}", hash, peers); self.start_snapshot_sync(io, peers); } - } else if timeout { + } else if timeout && !self.warp_sync.is_warp_only() { trace!(target: "sync", "No snapshots found, starting full sync"); self.state = SyncState::Idle; self.continue_sync(io); @@ -626,10 +640,6 @@ impl ChainSync { block_set: None, }; - if self.sync_start_time.is_none() { - self.sync_start_time = Some(Instant::now()); - } - trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{}, snapshot:{:?})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis, peer.snapshot_number); if io.is_expired() { @@ -658,6 +668,10 @@ impl ChainSync { return Ok(()); } + if self.sync_start_time.is_none() { + self.sync_start_time = Some(Instant::now()); + } + self.peers.insert(peer_id.clone(), peer); // Don't activate peer immediatelly when searching for common block. // Let the current sync round complete first. @@ -1167,9 +1181,14 @@ impl ChainSync { self.sync_peer(io, p, false); } } - if (self.state != SyncState::WaitingPeers && self.state != SyncState::SnapshotWaiting && self.state != SyncState::Waiting && self.state != SyncState::Idle) - && !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.block_set != Some(BlockSet::OldBlocks) && p.can_sync()) { + if + self.state != SyncState::WaitingPeers && + self.state != SyncState::SnapshotWaiting && + self.state != SyncState::Waiting && + self.state != SyncState::Idle && + !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.block_set != Some(BlockSet::OldBlocks) && p.can_sync()) + { self.complete_sync(io); } } @@ -1220,7 +1239,13 @@ impl ChainSync { if force || higher_difficulty || self.old_blocks.is_some() { match self.state { SyncState::WaitingPeers => { - trace!(target: "sync", "Checking snapshot sync: {} vs {}", peer_snapshot_number, chain_info.best_block_number); + trace!( + target: "sync", + "Checking snapshot sync: {} vs {} (peer: {})", + peer_snapshot_number, + chain_info.best_block_number, + peer_id + ); self.maybe_start_snapshot_sync(io); }, SyncState::Idle | SyncState::Blocks | SyncState::NewBlocks => { diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 517ff0d99a..6b5ef65da1 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use ethcore::client::{TestBlockChainClient, BlockChainClient, BlockId, EachBlockWith, ChainInfo, BlockInfo}; use chain::{SyncState}; use super::helpers::*; -use SyncConfig; +use {SyncConfig, WarpSync}; #[test] fn two_peers() { @@ -161,7 +161,7 @@ fn status_empty() { let net = TestNet::new(2); assert_eq!(net.peer(0).sync.read().status().state, SyncState::Idle); let mut config = SyncConfig::default(); - config.warp_sync = true; + config.warp_sync = WarpSync::Enabled; let net = TestNet::new_with_config(2, config); assert_eq!(net.peer(0).sync.read().status().state, SyncState::WaitingPeers); } diff --git a/sync/src/tests/snapshot.rs b/sync/src/tests/snapshot.rs index 516e3d7e2f..2f6441f4f2 100644 --- a/sync/src/tests/snapshot.rs +++ b/sync/src/tests/snapshot.rs @@ -24,7 +24,7 @@ use ethcore::snapshot::{SnapshotService, ManifestData, RestorationStatus}; use ethcore::header::BlockNumber; use ethcore::client::{EachBlockWith}; use super::helpers::*; -use SyncConfig; +use {SyncConfig, WarpSync}; pub struct TestSnapshotService { manifest: Option, @@ -127,7 +127,7 @@ impl SnapshotService for TestSnapshotService { fn snapshot_sync() { ::env_logger::init().ok(); let mut config = SyncConfig::default(); - config.warp_sync = true; + config.warp_sync = WarpSync::Enabled; let mut net = TestNet::new_with_config(5, config); let snapshot_service = Arc::new(TestSnapshotService::new_with_snapshot(16, H256::new(), 500000)); for i in 0..4 { diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 9df2d0b389..51990b6f51 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -594,11 +594,11 @@ impl Host { }; match TcpStream::connect(&address) { Ok(socket) => { - trace!(target: "network", "Connecting to {:?}", address); + trace!(target: "network", "{}: Connecting to {:?}", id, address); socket }, Err(e) => { - debug!(target: "network", "Can't connect to address {:?}: {:?}", address, e); + debug!(target: "network", "{}: Can't connect to address {:?}: {:?}", id, address, e); return; } } @@ -614,6 +614,7 @@ impl Host { let mut sessions = self.sessions.write(); let token = sessions.insert_with_opt(|token| { + trace!(target: "network", "{}: Initiating session {:?}", token, id); match Session::new(io, socket, token, id, &nonce, &self.info.read()) { Ok(s) => Some(Arc::new(Mutex::new(s))), Err(e) => { -- GitLab From 7f9589d678632ac4d412f54380ffbd82a9df59f6 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 29 Mar 2018 14:33:57 +0200 Subject: [PATCH 009/263] Fix warning about --no-hardcoded-sync being printed when it shouldn't (#8261) --- parity/run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/run.rs b/parity/run.rs index e7fb41cd7e..9b64a40d9d 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -575,7 +575,7 @@ pub fn execute_impl(cmd: RunCmd, can_restart: bool, logger: Arc) } // display warning if using --no-hardcoded-sync - if !cmd.no_hardcoded_sync { + if cmd.no_hardcoded_sync { warn!("The --no-hardcoded-sync flag has no effect if you don't use --light"); } -- GitLab From cab073ba008d85aae626f63a050aa4332fa75532 Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Thu, 29 Mar 2018 15:48:57 +0300 Subject: [PATCH 010/263] Add missing license header for runtime.rs (#8252) * Add missing license header for runtime.rs * Update year --- ethcore/wasm/src/runtime.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ethcore/wasm/src/runtime.rs b/ethcore/wasm/src/runtime.rs index 71fafd671e..d99ab8645a 100644 --- a/ethcore/wasm/src/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use ethereum_types::{U256, H256, Address}; use vm::{self, CallType}; use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError, Trap, TrapKind}; -- GitLab From 443115f8852448fe0d64f484160050c1bdcec792 Mon Sep 17 00:00:00 2001 From: Ryan Leung Date: Fri, 30 Mar 2018 16:31:54 +0800 Subject: [PATCH 011/263] Update `app_dirs` to 1.2.1 (#8268) * use app_dirs2 * update app_dirs to 1.2.1 --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- util/dir/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b43ab79f7..6b5a273cc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "app_dirs" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -318,7 +318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "dir" version = "0.1.0" dependencies = [ - "app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", ] @@ -1873,7 +1873,7 @@ name = "parity" version = "1.11.0" dependencies = [ "ansi_term 0.10.2 (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.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)", "daemonize 0.2.3 (git+https://github.com/paritytech/daemonize)", @@ -3579,7 +3579,7 @@ dependencies = [ [metadata] "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" -"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4" +"checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" diff --git a/Cargo.toml b/Cargo.toml index d1c7b250cf..8ffab0be56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ toml = "0.4" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -app_dirs = "1.1.1" +app_dirs = "1.2.1" futures = "0.1" futures-cpupool = "0.1" fdlimit = "0.1" diff --git a/util/dir/Cargo.toml b/util/dir/Cargo.toml index c94086386c..c82a0347c0 100644 --- a/util/dir/Cargo.toml +++ b/util/dir/Cargo.toml @@ -6,4 +6,4 @@ authors = ["Parity Technologies "] [dependencies] ethereum-types = "0.2" journaldb = { path = "../journaldb" } -app_dirs = "1.1.1" +app_dirs = "1.2.1" -- GitLab From 1e6d889fc7edab9978ff661c96ab6d37b4571ce3 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 31 Mar 2018 17:06:16 +0800 Subject: [PATCH 012/263] eth_uninstallFilter should return false for non-existent filter (#8280) * eth_uninstallFilter should return false for non-existent filter * Use shorter form is_some() --- rpc/src/v1/helpers/poll_manager.rs | 4 ++-- rpc/src/v1/impls/eth_filter.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index ab44dc35f9..f367f669fd 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -74,8 +74,8 @@ impl PollManager where T: Timer { } /// Removes poll info. - pub fn remove_poll(&mut self, id: &PollId) { - self.polls.remove(id); + pub fn remove_poll(&mut self, id: &PollId) -> bool { + self.polls.remove(id).is_some() } } diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 0ff9f4c20f..6c3d6837eb 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -242,7 +242,6 @@ impl EthFilter for T { } fn uninstall_filter(&self, index: Index) -> Result { - self.polls().lock().remove_poll(&index.value()); - Ok(true) + Ok(self.polls().lock().remove_poll(&index.value())) } } -- GitLab From 68a08df9c31026bbbd1edb5f94cbae6bf71b4ee3 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 31 Mar 2018 21:41:53 +0800 Subject: [PATCH 013/263] Typo fix: Mode doc - RLP should be client (#8283) --- ethcore/src/client/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 3c26c46212..b337bf4319 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -74,10 +74,10 @@ impl FromStr for DatabaseCompactionProfile { pub enum Mode { /// Always on. Active, - /// Goes offline after RLP is inactive for some (given) time, but + /// Goes offline after client is inactive for some (given) time, but /// comes back online after a while of inactivity. Passive(Duration, Duration), - /// Goes offline after RLP is inactive for some (given) time and + /// Goes offline after client is inactive for some (given) time and /// stays inactive. Dark(Duration), /// Always off. -- GitLab From 9c9ddaccec6229fe7acafa22177df419cb558542 Mon Sep 17 00:00:00 2001 From: Ryan Leung Date: Mon, 2 Apr 2018 16:47:56 +0800 Subject: [PATCH 014/263] use constant durations (#8278) * use constant durations * fix CI * address comments --- dapps/node-health/src/health.rs | 6 +- dapps/src/handlers/fetch.rs | 6 +- ethcore/light/src/net/mod.rs | 14 ++-- miner/src/external.rs | 4 +- parity/light_helpers/queue_cull.rs | 4 +- .../client_sessions/generation_session.rs | 10 +-- .../src/key_server_cluster/cluster.rs | 78 ++++++++++--------- .../key_server_cluster/cluster_sessions.rs | 26 +++---- util/fetch/src/client.rs | 6 +- util/network-devp2p/src/discovery.rs | 4 +- util/network-devp2p/src/session.rs | 10 +-- whisper/src/net/mod.rs | 4 +- 12 files changed, 88 insertions(+), 84 deletions(-) diff --git a/dapps/node-health/src/health.rs b/dapps/node-health/src/health.rs index ec53d2e294..ab52b22330 100644 --- a/dapps/node-health/src/health.rs +++ b/dapps/node-health/src/health.rs @@ -17,7 +17,7 @@ //! Reporting node's health. use std::sync::Arc; -use std::time; +use std::time::Duration; use futures::Future; use futures::sync::oneshot; use types::{HealthInfo, HealthStatus, Health}; @@ -26,7 +26,7 @@ use parity_reactor::Remote; use parking_lot::Mutex; use {SyncStatus}; -const TIMEOUT_SECS: u64 = 5; +const TIMEOUT: Duration = Duration::from_secs(5); const PROOF: &str = "Only one closure is invoked."; /// A struct enabling you to query for node's health. @@ -57,7 +57,7 @@ impl NodeHealth { let _ = tx.lock().take().expect(PROOF).send(Ok(result)); Ok(()) }), - time::Duration::from_secs(TIMEOUT_SECS), + TIMEOUT, move || { let _ = tx2.lock().take().expect(PROOF).send(Err(())); }, diff --git a/dapps/src/handlers/fetch.rs b/dapps/src/handlers/fetch.rs index 179bb4884c..94fe608819 100644 --- a/dapps/src/handlers/fetch.rs +++ b/dapps/src/handlers/fetch.rs @@ -32,7 +32,7 @@ use handlers::{ContentHandler, StreamingHandler}; use page::local; use {Embeddable}; -const FETCH_TIMEOUT: u64 = 300; +const FETCH_TIMEOUT: Duration = Duration::from_secs(300); pub enum ValidatorResponse { Local(local::Dapp), @@ -57,7 +57,7 @@ impl Default for FetchControl { FetchControl { abort: Arc::new(AtomicBool::new(false)), listeners: Arc::new(Mutex::new(Vec::new())), - deadline: Instant::now() + Duration::from_secs(FETCH_TIMEOUT), + deadline: Instant::now() + FETCH_TIMEOUT, } } } @@ -193,7 +193,7 @@ impl Errors { ContentHandler::error( StatusCode::GatewayTimeout, "Download Timeout", - &format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT), + &format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT.as_secs()), None, self.embeddable_on.clone(), ) diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 60fe172e23..abdf91ae44 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -73,7 +73,7 @@ const RECALCULATE_COSTS_TIMEOUT: TimerToken = 3; const RECALCULATE_COSTS_INTERVAL_MS: u64 = 60 * 60 * 1000; // minimum interval between updates. -const UPDATE_INTERVAL_MS: u64 = 5000; +const UPDATE_INTERVAL: Duration = Duration::from_millis(5000); /// Supported protocol versions. pub const PROTOCOL_VERSIONS: &'static [u8] = &[1]; @@ -109,8 +109,10 @@ mod packet { // timeouts for different kinds of requests. all values are in milliseconds. mod timeout { - pub const HANDSHAKE: u64 = 2500; - pub const ACKNOWLEDGE_UPDATE: u64 = 5000; + use std::time::Duration; + + pub const HANDSHAKE: Duration = Duration::from_millis(2500); + pub const ACKNOWLEDGE_UPDATE: Duration = Duration::from_millis(5000); pub const BASE: u64 = 1500; // base timeout for packet. // timeouts per request within packet. @@ -470,7 +472,7 @@ impl LightProtocol { // the timer approach will skip 1 (possibly 2) in rare occasions. if peer_info.sent_head == announcement.head_hash || peer_info.status.head_num >= announcement.head_num || - now - peer_info.last_update < Duration::from_millis(UPDATE_INTERVAL_MS) { + now - peer_info.last_update < UPDATE_INTERVAL { continue } @@ -606,7 +608,7 @@ impl LightProtocol { let mut pending = self.pending_peers.write(); let slowpokes: Vec<_> = pending.iter() .filter(|&(_, ref peer)| { - peer.last_update + Duration::from_millis(timeout::HANDSHAKE) <= now + peer.last_update + timeout::HANDSHAKE <= now }) .map(|(&p, _)| p) .collect(); @@ -619,7 +621,7 @@ impl LightProtocol { } // request and update ack timeouts - let ack_duration = Duration::from_millis(timeout::ACKNOWLEDGE_UPDATE); + let ack_duration = timeout::ACKNOWLEDGE_UPDATE; { for (peer_id, peer) in self.peers.read().iter() { let peer = peer.lock(); diff --git a/miner/src/external.rs b/miner/src/external.rs index cbd830cd55..b49a9a4e2c 100644 --- a/miner/src/external.rs +++ b/miner/src/external.rs @@ -53,11 +53,11 @@ impl ExternalMiner { } } -const ENTRY_TIMEOUT: u64 = 2; +const ENTRY_TIMEOUT: Duration = Duration::from_secs(2); impl ExternalMinerService for ExternalMiner { fn submit_hashrate(&self, hashrate: U256, id: H256) { - self.hashrates.lock().insert(id, (Instant::now() + Duration::from_secs(ENTRY_TIMEOUT), hashrate)); + self.hashrates.lock().insert(id, (Instant::now() + ENTRY_TIMEOUT, hashrate)); } fn hashrate(&self) -> U256 { diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index 091953ad5e..9acf2bf1f9 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -38,7 +38,7 @@ const TOKEN: TimerToken = 1; const TIMEOUT_MS: u64 = 1000 * 60 * 10; // But make each attempt last only 9 minutes -const PURGE_TIMEOUT_MS: u64 = 1000 * 60 * 9; +const PURGE_TIMEOUT: Duration = Duration::from_millis(1000 * 60 * 9); /// Periodically culls the transaction queue of mined transactions. pub struct QueueCull { @@ -100,6 +100,6 @@ impl IoHandler for QueueCull future::Either::B(future::ok(())) }, } - }, Duration::from_millis(PURGE_TIMEOUT_MS), || {}) + }, PURGE_TIMEOUT, || {}) } } diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs index 1f1df70ce3..30a35cbf6b 100644 --- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs @@ -16,7 +16,7 @@ use std::collections::{BTreeSet, BTreeMap, VecDeque}; use std::fmt::{Debug, Formatter, Error as FmtError}; -use std::time; +use std::time::Duration; use std::sync::Arc; use parking_lot::{Condvar, Mutex}; use ethereum_types::Address; @@ -252,7 +252,7 @@ impl SessionImpl { } /// Wait for session completion. - pub fn wait(&self, timeout: Option) -> Result { + pub fn wait(&self, timeout: Option) -> Result { Self::wait_session(&self.completed, &self.data, timeout, |data| data.joint_public_and_secret.clone() .map(|r| r.map(|r| r.0.clone()))) } @@ -932,9 +932,9 @@ pub fn check_threshold(threshold: usize, nodes: &BTreeSet) -> Result<(), #[cfg(test)] pub mod tests { - use std::time; use std::sync::Arc; use std::collections::{BTreeSet, BTreeMap, VecDeque}; + use std::time::Duration; use tokio_core::reactor::Core; use ethereum_types::Address; use ethkey::{Random, Generator, Public, KeyPair}; @@ -1386,12 +1386,12 @@ pub mod tests { run_clusters(&clusters); // establish connections - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, Duration::from_millis(300), || clusters.iter().all(all_connections_established)); // run session to completion let session_id = SessionId::default(); let session = clusters[0].client().new_generation_session(session_id, Public::default(), threshold).unwrap(); - loop_until(&mut core, time::Duration::from_millis(1000), || session.joint_public_and_secret().is_some()); + loop_until(&mut core, Duration::from_millis(1000), || session.joint_public_and_secret().is_some()); } } diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs index 2dcefea25a..22590f1a7e 100644 --- a/secret_store/src/key_server_cluster/cluster.rs +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::io; -use std::time; +use std::time::{Duration, Instant}; use std::sync::Arc; use std::collections::{BTreeMap, BTreeSet}; use std::collections::btree_map::Entry; @@ -53,10 +53,10 @@ const MAINTAIN_INTERVAL: u64 = 10; /// When no messages have been received from node within KEEP_ALIVE_SEND_INTERVAL seconds, /// we must send KeepAlive message to the node to check if it still responds to messages. -const KEEP_ALIVE_SEND_INTERVAL: u64 = 30; +const KEEP_ALIVE_SEND_INTERVAL: Duration = Duration::from_secs(30); /// When no messages have been received from node within KEEP_ALIVE_DISCONNECT_INTERVAL seconds, /// we must treat this node as non-responding && disconnect from it. -const KEEP_ALIVE_DISCONNECT_INTERVAL: u64 = 60; +const KEEP_ALIVE_DISCONNECT_INTERVAL: Duration = Duration::from_secs(60); /// Empty future. pub type BoxedEmptyFuture = Box + Send>; @@ -220,7 +220,7 @@ pub struct Connection { /// Connection key. key: KeyPair, /// Last message time. - last_message_time: Mutex, + last_message_time: Mutex, } impl ClusterCore { @@ -324,7 +324,7 @@ impl ClusterCore { /// Schedule mainatain procedures. fn schedule_maintain(handle: &Handle, data: Arc) { let d = data.clone(); - let interval: BoxedEmptyFuture = Box::new(Interval::new(time::Duration::new(MAINTAIN_INTERVAL, 0), handle) + let interval: BoxedEmptyFuture = Box::new(Interval::new(Duration::new(MAINTAIN_INTERVAL, 0), handle) .expect("failed to create interval") .and_then(move |_| Ok(ClusterCore::maintain(data.clone()))) .for_each(|_| Ok(())) @@ -374,12 +374,12 @@ impl ClusterCore { fn keep_alive(data: Arc) { data.sessions.sessions_keep_alive(); for connection in data.connections.active_connections() { - let last_message_diff = time::Instant::now() - connection.last_message_time(); - if last_message_diff > time::Duration::from_secs(KEEP_ALIVE_DISCONNECT_INTERVAL) { + let last_message_diff = Instant::now() - connection.last_message_time(); + if last_message_diff > KEEP_ALIVE_DISCONNECT_INTERVAL { data.connections.remove(data.clone(), connection.node_id(), connection.is_inbound()); data.sessions.on_connection_timeout(connection.node_id()); } - else if last_message_diff > time::Duration::from_secs(KEEP_ALIVE_SEND_INTERVAL) { + else if last_message_diff > KEEP_ALIVE_SEND_INTERVAL { data.spawn(connection.send_message(Message::Cluster(ClusterMessage::KeepAlive(message::KeepAlive {})))); } } @@ -434,7 +434,7 @@ impl ClusterCore { /// Process single message from the connection. fn process_connection_message(data: Arc, connection: Arc, message: Message) { - connection.set_last_message_time(time::Instant::now()); + connection.set_last_message_time(Instant::now()); trace!(target: "secretstore_net", "{}: received message {} from {}", data.self_key_pair.public(), message, connection.node_id()); // error is ignored as we only process errors on session level match message { @@ -799,7 +799,7 @@ impl Connection { is_inbound: is_inbound, stream: connection.stream, key: connection.key, - last_message_time: Mutex::new(time::Instant::now()), + last_message_time: Mutex::new(Instant::now()), }) } @@ -811,11 +811,11 @@ impl Connection { &self.node_id } - pub fn last_message_time(&self) -> time::Instant { + pub fn last_message_time(&self) -> Instant { *self.last_message_time.lock() } - pub fn set_last_message_time(&self, last_message_time: time::Instant) { + pub fn set_last_message_time(&self, last_message_time: Instant) { *self.last_message_time.lock() = last_message_time; } @@ -1085,7 +1085,7 @@ fn make_socket_address(address: &str, port: u16) -> Result { #[cfg(test)] pub mod tests { use std::sync::Arc; - use std::time; + use std::time::{Duration, Instant}; use std::collections::{BTreeSet, VecDeque}; use parking_lot::Mutex; use tokio_core::reactor::Core; @@ -1104,6 +1104,8 @@ pub mod tests { use key_server_cluster::key_version_negotiation_session::{SessionImpl as KeyVersionNegotiationSession, IsolatedSessionTransport as KeyVersionNegotiationSessionTransport}; + const TIMEOUT: Duration = Duration::from_millis(300); + #[derive(Default)] pub struct DummyClusterClient; @@ -1192,15 +1194,15 @@ pub mod tests { } } - pub fn loop_until(core: &mut Core, timeout: time::Duration, predicate: F) where F: Fn() -> bool { - let start = time::Instant::now(); + pub fn loop_until(core: &mut Core, timeout: Duration, predicate: F) where F: Fn() -> bool { + let start = Instant::now(); loop { - core.turn(Some(time::Duration::from_millis(1))); + core.turn(Some(Duration::from_millis(1))); if predicate() { break; } - if time::Instant::now() - start > timeout { + if Instant::now() - start > timeout { panic!("no result in {:?}", timeout); } } @@ -1248,7 +1250,7 @@ pub mod tests { let mut core = Core::new().unwrap(); let clusters = make_clusters(&core, 6010, 3); run_clusters(&clusters); - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); } #[test] @@ -1269,14 +1271,14 @@ pub mod tests { let mut core = Core::new().unwrap(); let clusters = make_clusters(&core, 6016, 3); run_clusters(&clusters); - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // ask one of nodes to produce faulty generation sessions clusters[1].client().make_faulty_generation_sessions(); // start && wait for generation session to fail let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || session.joint_public_and_secret().is_some() + loop_until(&mut core, TIMEOUT, || session.joint_public_and_secret().is_some() && clusters[0].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_err()); @@ -1285,7 +1287,7 @@ pub mod tests { if let Some(session) = clusters[i].client().generation_session(&SessionId::default()) { // wait for both session completion && session removal (session completion event is fired // before session is removed from its own container by cluster) - loop_until(&mut core, time::Duration::from_millis(300), || session.joint_public_and_secret().is_some() + loop_until(&mut core, TIMEOUT, || session.joint_public_and_secret().is_some() && clusters[i].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_err()); } @@ -1298,14 +1300,14 @@ pub mod tests { let mut core = Core::new().unwrap(); let clusters = make_clusters(&core, 6025, 3); run_clusters(&clusters); - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // ask one of nodes to produce faulty generation sessions clusters[0].client().make_faulty_generation_sessions(); // start && wait for generation session to fail let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || session.joint_public_and_secret().is_some() + loop_until(&mut core, TIMEOUT, || session.joint_public_and_secret().is_some() && clusters[0].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_err()); @@ -1314,7 +1316,7 @@ pub mod tests { if let Some(session) = clusters[i].client().generation_session(&SessionId::default()) { // wait for both session completion && session removal (session completion event is fired // before session is removed from its own container by cluster) - loop_until(&mut core, time::Duration::from_millis(300), || session.joint_public_and_secret().is_some() + loop_until(&mut core, TIMEOUT, || session.joint_public_and_secret().is_some() && clusters[i].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_err()); } @@ -1327,11 +1329,11 @@ pub mod tests { let mut core = Core::new().unwrap(); let clusters = make_clusters(&core, 6019, 3); run_clusters(&clusters); - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // start && wait for generation session to complete let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || (session.state() == GenerationSessionState::Finished + loop_until(&mut core, TIMEOUT, || (session.state() == GenerationSessionState::Finished || session.state() == GenerationSessionState::Failed) && clusters[0].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_ok()); @@ -1339,7 +1341,7 @@ pub mod tests { // check that session is either removed from all nodes, or nonexistent (already removed) for i in 1..3 { if let Some(session) = clusters[i].client().generation_session(&SessionId::default()) { - loop_until(&mut core, time::Duration::from_millis(300), || (session.state() == GenerationSessionState::Finished + loop_until(&mut core, TIMEOUT, || (session.state() == GenerationSessionState::Finished || session.state() == GenerationSessionState::Failed) && clusters[i].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_err()); @@ -1352,7 +1354,7 @@ pub mod tests { let mut core = Core::new().unwrap(); let clusters = make_clusters(&core, 6022, 3); run_clusters(&clusters); - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // generation session { @@ -1388,11 +1390,11 @@ pub mod tests { let mut core = Core::new().unwrap(); let clusters = make_clusters(&core, 6028, 3); run_clusters(&clusters); - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // start && wait for generation session to complete let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || (session.state() == GenerationSessionState::Finished + loop_until(&mut core, TIMEOUT, || (session.state() == GenerationSessionState::Finished || session.state() == GenerationSessionState::Failed) && clusters[0].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_ok()); @@ -1406,7 +1408,7 @@ pub mod tests { let session0 = clusters[0].client().new_schnorr_signing_session(Default::default(), signature.into(), None, Default::default()).unwrap(); let session = clusters[0].data.sessions.schnorr_signing_sessions.first().unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished() && (0..3).all(|i| + loop_until(&mut core, TIMEOUT, || session.is_finished() && (0..3).all(|i| clusters[i].data.sessions.schnorr_signing_sessions.is_empty())); session0.wait().unwrap(); @@ -1415,7 +1417,7 @@ pub mod tests { let session2 = clusters[2].client().new_schnorr_signing_session(Default::default(), signature.into(), None, Default::default()).unwrap(); let session = clusters[2].data.sessions.schnorr_signing_sessions.first().unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished() && (0..3).all(|i| + loop_until(&mut core, TIMEOUT, || session.is_finished() && (0..3).all(|i| clusters[i].data.sessions.schnorr_signing_sessions.is_empty())); session2.wait().unwrap(); @@ -1427,7 +1429,7 @@ pub mod tests { let session1 = clusters[0].client().new_schnorr_signing_session(Default::default(), signature.into(), None, Default::default()).unwrap(); let session = clusters[0].data.sessions.schnorr_signing_sessions.first().unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished()); + loop_until(&mut core, TIMEOUT, || session.is_finished()); session1.wait().unwrap_err(); } @@ -1437,11 +1439,11 @@ pub mod tests { let mut core = Core::new().unwrap(); let clusters = make_clusters(&core, 6041, 4); run_clusters(&clusters); - loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // start && wait for generation session to complete let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); - loop_until(&mut core, time::Duration::from_millis(300), || (session.state() == GenerationSessionState::Finished + loop_until(&mut core, TIMEOUT, || (session.state() == GenerationSessionState::Finished || session.state() == GenerationSessionState::Failed) && clusters[0].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_ok()); @@ -1455,7 +1457,7 @@ pub mod tests { let session0 = clusters[0].client().new_ecdsa_signing_session(Default::default(), signature.into(), None, H256::random()).unwrap(); let session = clusters[0].data.sessions.ecdsa_signing_sessions.first().unwrap(); - loop_until(&mut core, time::Duration::from_millis(1000), || session.is_finished() && (0..3).all(|i| + loop_until(&mut core, Duration::from_millis(1000), || session.is_finished() && (0..3).all(|i| clusters[i].data.sessions.ecdsa_signing_sessions.is_empty())); session0.wait().unwrap(); @@ -1463,7 +1465,7 @@ pub mod tests { let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap(); let session2 = clusters[2].client().new_ecdsa_signing_session(Default::default(), signature.into(), None, H256::random()).unwrap(); let session = clusters[2].data.sessions.ecdsa_signing_sessions.first().unwrap(); - loop_until(&mut core, time::Duration::from_millis(1000), || session.is_finished() && (0..3).all(|i| + loop_until(&mut core, Duration::from_millis(1000), || session.is_finished() && (0..3).all(|i| clusters[i].data.sessions.ecdsa_signing_sessions.is_empty())); session2.wait().unwrap(); @@ -1474,7 +1476,7 @@ pub mod tests { let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap(); let session1 = clusters[0].client().new_ecdsa_signing_session(Default::default(), signature.into(), None, H256::random()).unwrap(); let session = clusters[0].data.sessions.ecdsa_signing_sessions.first().unwrap(); - loop_until(&mut core, time::Duration::from_millis(1000), || session.is_finished()); + loop_until(&mut core, Duration::from_millis(1000), || session.is_finished()); session1.wait().unwrap_err(); } } diff --git a/secret_store/src/key_server_cluster/cluster_sessions.rs b/secret_store/src/key_server_cluster/cluster_sessions.rs index 86e38a879a..cdd0c19585 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::time; +use std::time::{Duration, Instant}; use std::sync::{Arc, Weak}; use std::sync::atomic::AtomicBool; use std::collections::{VecDeque, BTreeMap, BTreeSet}; @@ -43,9 +43,9 @@ use key_server_cluster::cluster_sessions_creator::{GenerationSessionCreator, Enc /// we must treat this session as stalled && finish it with an error. /// This timeout is for cases when node is responding to KeepAlive messages, but intentionally ignores /// session messages. -const SESSION_TIMEOUT_INTERVAL: u64 = 60; +const SESSION_TIMEOUT_INTERVAL: Duration = Duration::from_secs(60); /// Interval to send session-level KeepAlive-messages. -const SESSION_KEEP_ALIVE_INTERVAL: u64 = 30; +const SESSION_KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(30); lazy_static! { /// Servers set change session id (there could be at most 1 session => hardcoded id). @@ -84,7 +84,7 @@ pub trait ClusterSession { fn on_message(&self, sender: &NodeId, message: &Message) -> Result<(), Error>; /// 'Wait for session completion' helper. - fn wait_session Option>>(completion_event: &Condvar, session_data: &Mutex, timeout: Option, result_reader: F) -> Result { + fn wait_session Option>>(completion_event: &Condvar, session_data: &Mutex, timeout: Option, result_reader: F) -> Result { let mut locked_data = session_data.lock(); match result_reader(&locked_data) { Some(result) => result, @@ -170,9 +170,9 @@ pub struct QueuedSession { /// Cluster view. pub cluster_view: Arc, /// Last keep alive time. - pub last_keep_alive_time: time::Instant, + pub last_keep_alive_time: Instant, /// Last received message time. - pub last_message_time: time::Instant, + pub last_message_time: Instant, /// Generation session. pub session: Arc, /// Messages queue. @@ -291,7 +291,7 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C sessions.get_mut(session_id) .map(|s| { if update_last_message_time { - s.last_message_time = time::Instant::now(); + s.last_message_time = Instant::now(); } s.session.clone() }) @@ -319,8 +319,8 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C let queued_session = QueuedSession { master: master, cluster_view: cluster, - last_keep_alive_time: time::Instant::now(), - last_message_time: time::Instant::now(), + last_keep_alive_time: Instant::now(), + last_message_time: Instant::now(), session: session.clone(), queue: VecDeque::new(), }; @@ -353,7 +353,7 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C for sid in sessions.keys().cloned().collect::>() { let remove_session = { let session = sessions.get(&sid).expect("enumerating only existing sessions; qed"); - if time::Instant::now() - session.last_message_time > time::Duration::from_secs(SESSION_TIMEOUT_INTERVAL) { + if Instant::now() - session.last_message_time > SESSION_TIMEOUT_INTERVAL { session.session.on_session_timeout(); session.session.is_finished() } else { @@ -401,8 +401,8 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C impl ClusterSessionsContainer where S: ClusterSession, SC: ClusterSessionCreator, SessionId: From { pub fn send_keep_alive(&self, session_id: &S::Id, self_node_id: &NodeId) { if let Some(session) = self.sessions.write().get_mut(session_id) { - let now = time::Instant::now(); - if self_node_id == &session.master && now - session.last_keep_alive_time > time::Duration::from_secs(SESSION_KEEP_ALIVE_INTERVAL) { + let now = Instant::now(); + if self_node_id == &session.master && now - session.last_keep_alive_time > SESSION_KEEP_ALIVE_INTERVAL { session.last_keep_alive_time = now; // since we send KeepAlive message to prevent nodes from disconnecting // && worst thing that can happen if node is disconnected is that session is failed @@ -416,7 +416,7 @@ impl ClusterSessionsContainer where S: ClusterSession, SC: C pub fn on_keep_alive(&self, session_id: &S::Id, sender: &NodeId) { if let Some(session) = self.sessions.write().get_mut(session_id) { - let now = time::Instant::now(); + let now = Instant::now(); // we only accept keep alive from master node of ServersSetChange session if sender == &session.master { session.last_keep_alive_time = now; diff --git a/util/fetch/src/client.rs b/util/fetch/src/client.rs index c57a362ca9..fee3130c42 100644 --- a/util/fetch/src/client.rs +++ b/util/fetch/src/client.rs @@ -34,7 +34,7 @@ use tokio_core::reactor; use url::{self, Url}; const MAX_SIZE: usize = 64 * 1024 * 1024; -const MAX_SECS: u64 = 5; +const MAX_SECS: Duration = Duration::from_secs(5); const MAX_REDR: usize = 5; /// A handle to abort requests. @@ -55,7 +55,7 @@ impl Default for Abort { Abort { abort: Arc::new(AtomicBool::new(false)), size: MAX_SIZE, - time: Duration::from_secs(MAX_SECS), + time: MAX_SECS, redir: MAX_REDR, } } @@ -66,7 +66,7 @@ impl From> for Abort { Abort { abort: a, size: MAX_SIZE, - time: Duration::from_secs(MAX_SECS), + time: MAX_SECS, redir: MAX_REDR, } } diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index fa32f89f9a..2828b8f19f 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -47,7 +47,7 @@ const PACKET_PONG: u8 = 2; const PACKET_FIND_NODE: u8 = 3; const PACKET_NEIGHBOURS: u8 = 4; -const PING_TIMEOUT_MS: u64 = 300; +const PING_TIMEOUT: Duration = Duration::from_millis(300); const MAX_NODES_PING: usize = 32; // Max nodes to add/ping at once #[derive(Clone, Debug)] @@ -513,7 +513,7 @@ impl Discovery { for bucket in &mut self.node_buckets { bucket.nodes.retain(|node| { if let Some(timeout) = node.timeout { - if !force && now.duration_since(timeout) < Duration::from_millis(PING_TIMEOUT_MS) { + if !force && now.duration_since(timeout) < PING_TIMEOUT { true } else { diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index 179d706d7e..6353a90946 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -34,8 +34,8 @@ use node_table::NodeId; use snappy; // Timeout must be less than (interval - 1). -const PING_TIMEOUT_SEC: u64 = 60; -const PING_INTERVAL_SEC: u64 = 120; +const PING_TIMEOUT_SEC: Duration = Duration::from_secs(60); +const PING_INTERVAL_SEC: Duration = Duration::from_secs(120); const MIN_PROTOCOL_VERSION: u32 = 4; const MIN_COMPRESSION_PROTOCOL_VERSION: u32 = 5; @@ -298,12 +298,12 @@ impl Session { return true; } let timed_out = if let Some(pong) = self.pong_time { - pong.duration_since(self.ping_time) > Duration::from_secs(PING_TIMEOUT_SEC) + pong.duration_since(self.ping_time) > PING_TIMEOUT_SEC } else { - self.ping_time.elapsed() > Duration::from_secs(PING_TIMEOUT_SEC) + self.ping_time.elapsed() > PING_TIMEOUT_SEC }; - if !timed_out && self.ping_time.elapsed() > Duration::from_secs(PING_INTERVAL_SEC) { + if !timed_out && self.ping_time.elapsed() > PING_INTERVAL_SEC { if let Err(e) = self.send_ping(io) { debug!("Error sending ping message: {:?}", e); } diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index 621da8fa1d..28f3fee55a 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -45,7 +45,7 @@ pub const PROTOCOL_VERSION: usize = 6; pub const SUPPORTED_VERSIONS: &'static [u8] = &[PROTOCOL_VERSION as u8]; // maximum tolerated delay between messages packets. -const MAX_TOLERATED_DELAY_MS: u64 = 5000; +const MAX_TOLERATED_DELAY: Duration = Duration::from_millis(5000); /// Number of packets. A bunch are reserved. pub const PACKET_COUNT: u8 = 128; @@ -469,7 +469,7 @@ impl Network { peer_data.note_evicted(&pruned_hashes); let punish_timeout = |last_activity: &SystemTime| { - if *last_activity + Duration::from_millis(MAX_TOLERATED_DELAY_MS) <= now { + if *last_activity + MAX_TOLERATED_DELAY <= now { debug!(target: "whisper", "Disconnecting peer {} due to excessive timeout.", peer_id); io.disconnect_peer(*peer_id); } -- GitLab From f1b7d8ab3421f9be36ff088e769a6f03f230388a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 2 Apr 2018 17:04:14 +0800 Subject: [PATCH 015/263] Return null number for pending block in eth_getBlockByNumber (#8281) * Return null number for pending block in eth_getBlockByNumber * Inline false in client_query * block hash for pending should be null * logsBloom should be null for pending blocks * Fix test due to logsBloom type change --- rpc/src/v1/impls/eth.rs | 23 ++++++++++++++++------- rpc/src/v1/impls/light/eth.rs | 4 ++-- rpc/src/v1/types/block.rs | 6 +++--- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index bd7e09ea73..bcfa59c7ee 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -180,9 +180,9 @@ impl EthClient Result> { let client = &self.client; - let client_query = |id| (client.block(id), client.block_total_difficulty(id), client.block_extra_info(id)); + let client_query = |id| (client.block(id), client.block_total_difficulty(id), client.block_extra_info(id), false); - let (block, difficulty, extra) = match id { + let (block, difficulty, extra, is_pending) = match id { BlockNumberOrId::Number(BlockNumber::Pending) => { let info = self.client.chain_info(); let pending_block = self.miner.pending_block(info.best_block_number); @@ -199,7 +199,7 @@ impl EthClient { @@ -221,7 +221,10 @@ impl EthClient None, + false => Some(view.hash().into()), + }, size: Some(block.rlp().as_raw().len().into()), parent_hash: view.parent_hash().into(), uncles_hash: view.uncles_hash().into(), @@ -230,10 +233,16 @@ impl EthClient None, + false => Some(view.number().into()), + }, gas_used: view.gas_used().into(), gas_limit: view.gas_limit().into(), - logs_bloom: view.log_bloom().into(), + logs_bloom: match is_pending { + true => None, + false => Some(view.log_bloom().into()), + }, timestamp: view.timestamp().into(), difficulty: view.difficulty().into(), total_difficulty: Some(total_difficulty.into()), @@ -368,7 +377,7 @@ impl EthClient EthClient { number: Some(header.number().into()), gas_used: header.gas_used().clone().into(), gas_limit: header.gas_limit().clone().into(), - logs_bloom: header.log_bloom().clone().into(), + logs_bloom: Some(header.log_bloom().clone().into()), timestamp: header.timestamp().into(), difficulty: header.difficulty().clone().into(), total_difficulty: score.map(Into::into), @@ -570,7 +570,7 @@ fn extract_uncle_at_index(block: encoded::Block, index: Ind number: Some(uncle.number().into()), gas_used: uncle.gas_used().clone().into(), gas_limit: uncle.gas_limit().clone().into(), - logs_bloom: uncle.log_bloom().clone().into(), + logs_bloom: Some(uncle.log_bloom().clone().into()), timestamp: uncle.timestamp().into(), difficulty: uncle.difficulty().clone().into(), total_difficulty: None, diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index cd2d83e0e9..d9c1b247c3 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -80,7 +80,7 @@ pub struct Block { pub extra_data: Bytes, /// Logs bloom #[serde(rename="logsBloom")] - pub logs_bloom: H2048, + pub logs_bloom: Option, /// Timestamp pub timestamp: U256, /// Difficulty @@ -254,7 +254,7 @@ mod tests { gas_used: U256::default(), gas_limit: U256::default(), extra_data: Bytes::default(), - logs_bloom: H2048::default(), + logs_bloom: Some(H2048::default()), timestamp: U256::default(), difficulty: U256::default(), total_difficulty: Some(U256::default()), @@ -292,7 +292,7 @@ mod tests { gas_used: U256::default(), gas_limit: U256::default(), extra_data: Bytes::default(), - logs_bloom: H2048::default(), + logs_bloom: Some(H2048::default()), timestamp: U256::default(), difficulty: U256::default(), total_difficulty: Some(U256::default()), -- GitLab From 5ea4c22868b5c894be9cf0296906e1727ff06964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 2 Apr 2018 12:30:26 +0200 Subject: [PATCH 016/263] Supress TemporaryInvalid verification failures. (#8256) --- ethcore/src/verification/queue/kind.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index b437dba7a0..898435eb26 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -69,7 +69,7 @@ pub mod blocks { use super::{Kind, BlockLike}; use engines::EthEngine; - use error::Error; + use error::{Error, BlockError}; use header::Header; use verification::{PreverifiedBlock, verify_block_basic, verify_block_unordered}; @@ -88,6 +88,10 @@ pub mod blocks { fn create(input: Self::Input, engine: &EthEngine) -> Result { match verify_block_basic(&input.header, &input.bytes, engine) { Ok(()) => Ok(input), + Err(Error::Block(BlockError::TemporarilyInvalid(oob))) => { + debug!(target: "client", "Block received too early {}: {:?}", input.hash(), oob); + Err(BlockError::TemporarilyInvalid(oob).into()) + }, Err(e) => { warn!(target: "client", "Stage 1 block verification failed for {}: {:?}", input.hash(), e); Err(e) -- GitLab From c1cced3662b698022bd02627c2499a04dd9f3e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 2 Apr 2018 12:33:09 +0200 Subject: [PATCH 017/263] Allow customization of max WS connections. (#8257) * Allow customization of max WS connections. * remove superflous line. * Add test for CLI argument parsing. --- parity/cli/mod.rs | 7 +++++++ parity/configuration.rs | 15 ++++++++++++++- parity/rpc.rs | 3 +++ rpc/src/lib.rs | 2 ++ rpc/src/tests/ws.rs | 1 + 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 691bdd6144..04a4a21e1a 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -499,6 +499,10 @@ usage! { "--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\".", + ARG arg_ws_max_connections: (usize) = 100usize, or |c: &Config| c.websockets.as_ref()?.max_connections, + "--ws-max-connections=[CONN]", + "Maximal number of allowed concurrent WS connections.", + ["API and console options – IPC"] FLAG flag_no_ipc: (bool) = false, or |c: &Config| c.ipc.as_ref()?.disable.clone(), "--no-ipc", @@ -1087,6 +1091,7 @@ struct Ws { apis: Option>, origins: Option>, hosts: Option>, + max_connections: Option, } #[derive(Default, Debug, PartialEq, Deserialize)] @@ -1520,6 +1525,7 @@ mod tests { arg_ws_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(), arg_ws_origins: "none".into(), arg_ws_hosts: "none".into(), + arg_ws_max_connections: 100, // IPC flag_no_ipc: false, @@ -1759,6 +1765,7 @@ mod tests { apis: None, origins: Some(vec!["none".into()]), hosts: None, + max_connections: None, }), rpc: Some(Rpc { disable: Some(true), diff --git a/parity/configuration.rs b/parity/configuration.rs index bff8390391..2661e90f6a 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -922,6 +922,7 @@ impl Configuration { support_token_api, ui_address: ui.address(), dapps_address: http.address(), + max_connections: self.args.arg_ws_max_connections, }; Ok(conf) @@ -1361,7 +1362,8 @@ mod tests { signer_path: expected.into(), ui_address: None, dapps_address: Some("127.0.0.1:8545".into()), - support_token_api: true + support_token_api: true, + max_connections: 100, }, UiConfiguration { enabled: false, interface: "127.0.0.1".into(), @@ -1374,6 +1376,17 @@ mod tests { } )); } + #[test] + fn test_ws_max_connections() { + let args = vec!["parity", "--ws-max-connections", "1"]; + let conf = parse(&args); + + assert_eq!(conf.ws_config().unwrap(), WsConfiguration { + max_connections: 1, + ..Default::default() + }); + } + #[test] fn test_run_cmd() { let args = vec!["parity"]; diff --git a/parity/rpc.rs b/parity/rpc.rs index 41b10ba872..a1b2271c44 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -146,6 +146,7 @@ pub struct WsConfiguration { pub interface: String, pub port: u16, pub apis: ApiSet, + pub max_connections: usize, pub origins: Option>, pub hosts: Option>, pub signer_path: PathBuf, @@ -162,6 +163,7 @@ impl Default for WsConfiguration { interface: "127.0.0.1".into(), port: 8546, apis: ApiSet::UnsafeContext, + max_connections: 100, origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]), hosts: Some(Vec::new()), signer_path: replace_home(&data_dir, "$BASE/signer").into(), @@ -240,6 +242,7 @@ pub fn new_ws( remote.clone(), allowed_origins, allowed_hosts, + conf.max_connections, rpc::WsExtractor::new(path.clone()), rpc::WsExtractor::new(path.clone()), rpc::WsStats::new(deps.stats.clone()), diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 95a0b424b9..a08a1a88a8 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -175,6 +175,7 @@ pub fn start_ws( remote: tokio_core::reactor::Remote, allowed_origins: ws::DomainsValidation, allowed_hosts: ws::DomainsValidation, + max_connections: usize, extractor: T, middleware: V, stats: U, @@ -191,6 +192,7 @@ pub fn start_ws( .request_middleware(middleware) .allowed_origins(allowed_origins) .allowed_hosts(allowed_hosts) + .max_connections(max_connections) .session_stats(stats) .start(addr) } diff --git a/rpc/src/tests/ws.rs b/rpc/src/tests/ws.rs index 6d48748458..1db7a91e98 100644 --- a/rpc/src/tests/ws.rs +++ b/rpc/src/tests/ws.rs @@ -40,6 +40,7 @@ pub fn serve() -> (Server, usize, GuardedAuthCodes) { remote, ws::DomainsValidation::Disabled, ws::DomainsValidation::Disabled, + 5, extractors::WsExtractor::new(Some(&authcodes.path)), extractors::WsExtractor::new(Some(&authcodes.path)), extractors::WsStats::new(stats), -- GitLab From 9108a3bb50fb757a35110f0c3d8e8d6331ffb2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 2 Apr 2018 13:12:52 +0200 Subject: [PATCH 018/263] Bump ethabi & ethereum-types. (#8258) * Bump ethabi & ethereum-types. * Fix test. * Fix hex encodings. --- Cargo.lock | 132 +++++++++++++------------- Cargo.toml | 2 +- dapps/Cargo.toml | 2 +- dapps/src/tests/helpers/registrar.rs | 2 +- ethcore/Cargo.toml | 2 +- ethcore/evm/Cargo.toml | 2 +- ethcore/light/Cargo.toml | 2 +- ethcore/light/src/net/tests/mod.rs | 2 +- ethcore/node_filter/Cargo.toml | 2 +- ethcore/transaction/Cargo.toml | 2 +- ethcore/types/Cargo.toml | 2 +- ethcore/vm/Cargo.toml | 2 +- ethcore/wasm/Cargo.toml | 2 +- ethcore/wasm/run/Cargo.toml | 2 +- ethcore/wasm/run/src/runner.rs | 10 +- ethcrypto/Cargo.toml | 2 +- ethkey/Cargo.toml | 2 +- ethkey/cli/src/main.rs | 6 +- ethkey/src/secret.rs | 10 +- ethstore/Cargo.toml | 2 +- ethstore/cli/src/main.rs | 8 +- evmbin/Cargo.toml | 2 +- hash-fetch/Cargo.toml | 2 +- hw/Cargo.toml | 2 +- ipfs/Cargo.toml | 2 +- json/Cargo.toml | 2 +- machine/Cargo.toml | 2 +- miner/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- rpc/src/tests/ws.rs | 4 +- rpc/src/v1/tests/eth.rs | 12 +-- rpc/src/v1/tests/mocked/eth.rs | 30 +++--- rpc/src/v1/tests/mocked/eth_pubsub.rs | 4 +- rpc/src/v1/tests/mocked/parity.rs | 4 +- rpc/src/v1/tests/mocked/parity_set.rs | 2 +- rpc/src/v1/tests/mocked/personal.rs | 22 ++--- rpc/src/v1/tests/mocked/signer.rs | 16 ++-- rpc/src/v1/tests/mocked/signing.rs | 32 +++---- rpc_client/src/client.rs | 2 +- secret_store/Cargo.toml | 2 +- stratum/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- test.sh | 30 +++--- transaction-pool/Cargo.toml | 2 +- updater/Cargo.toml | 2 +- updater/src/updater.rs | 2 +- util/bloomchain/Cargo.toml | 2 +- util/dir/Cargo.toml | 2 +- util/dir/src/lib.rs | 2 +- util/error/Cargo.toml | 2 +- util/hash/Cargo.toml | 2 +- util/hash/src/lib.rs | 2 +- util/hashdb/Cargo.toml | 2 +- util/journaldb/Cargo.toml | 2 +- util/kvdb-rocksdb/Cargo.toml | 2 +- util/memorydb/Cargo.toml | 2 +- util/network-devp2p/Cargo.toml | 2 +- util/network-devp2p/src/host.rs | 2 +- util/network-devp2p/src/node_table.rs | 4 +- util/network/Cargo.toml | 2 +- util/patricia_trie/Cargo.toml | 2 +- util/plain_hasher/Cargo.toml | 2 +- util/rlp/Cargo.toml | 2 +- util/trie-standardmap/Cargo.toml | 2 +- util/triehash/Cargo.toml | 2 +- whisper/Cargo.toml | 2 +- 66 files changed, 220 insertions(+), 206 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b5a273cc1..278f4b673f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,7 +154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "bloomchain" version = "0.2.0" dependencies = [ - "ethbloom 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -242,7 +242,7 @@ name = "common-types" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -319,7 +319,7 @@ name = "dir" version = "0.1.0" dependencies = [ "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", ] @@ -387,11 +387,11 @@ dependencies = [ [[package]] name = "ethabi" -version = "5.1.0" +version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -409,7 +409,7 @@ name = "ethabi-derive" version = "5.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -431,12 +431,12 @@ dependencies = [ [[package]] name = "ethbloom" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -451,7 +451,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", @@ -462,7 +462,7 @@ dependencies = [ "ethcore-miner 1.11.0", "ethcore-stratum 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -548,7 +548,7 @@ dependencies = [ "ethcore-io 1.11.0", "ethcore-network 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -601,12 +601,12 @@ name = "ethcore-miner" version = "1.11.0" dependencies = [ "common-types 0.1.0", - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -627,7 +627,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-io 1.11.0", "ethcrypto 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -646,7 +646,7 @@ dependencies = [ "ethcore-logger 1.11.0", "ethcore-network 1.11.0", "ethcrypto 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -674,14 +674,14 @@ name = "ethcore-secretstore" version = "1.0.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", "ethcrypto 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ethsync 1.11.0", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -726,7 +726,7 @@ version = "1.11.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.11.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -741,7 +741,7 @@ dependencies = [ name = "ethcore-transaction" version = "0.1.0" dependencies = [ - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "evm 0.1.0", @@ -757,7 +757,7 @@ name = "ethcrypto" version = "0.1.0" dependencies = [ "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -766,16 +766,16 @@ dependencies = [ [[package]] name = "ethereum-types" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ethbloom 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -790,7 +790,7 @@ dependencies = [ name = "ethjson" version = "0.1.0" dependencies = [ - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -804,7 +804,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -835,7 +835,7 @@ version = "0.2.0" dependencies = [ "dir 0.1.0", "ethcrypto 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -884,7 +884,7 @@ dependencies = [ "ethcore-network 1.11.0", "ethcore-network-devp2p 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -907,7 +907,7 @@ name = "evm" version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "evmjit 1.11.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -927,7 +927,7 @@ dependencies = [ "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "evm 0.1.0", "panic_hook 0.1.0", @@ -969,7 +969,7 @@ dependencies = [ [[package]] name = "fixed-hash" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1067,7 +1067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "hardware-wallet" version = "1.11.0" dependencies = [ - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", @@ -1083,7 +1083,7 @@ name = "hashdb" version = "0.1.1" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1274,7 +1274,7 @@ version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -1389,7 +1389,7 @@ name = "keccak-hash" version = "0.1.0" dependencies = [ "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1425,7 +1425,7 @@ name = "kvdb-rocksdb" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1569,7 +1569,7 @@ version = "0.1.1" dependencies = [ "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -1718,13 +1718,13 @@ dependencies = [ name = "node-filter" version = "1.11.0" dependencies = [ - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-io 1.11.0", "ethcore-network-devp2p 1.11.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1892,7 +1892,7 @@ dependencies = [ "ethcore-service 0.1.0", "ethcore-stratum 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ethsync 1.11.0", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1952,7 +1952,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-devtools 1.11.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2012,11 +2012,11 @@ dependencies = [ name = "parity-hash-fetch" version = "1.11.0" dependencies = [ - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2039,7 +2039,7 @@ dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2068,7 +2068,7 @@ dependencies = [ name = "parity-machine" version = "0.1.0" dependencies = [ - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2096,7 +2096,7 @@ dependencies = [ "ethcore-network 1.11.0", "ethcore-transaction 0.1.0", "ethcrypto 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -2222,12 +2222,12 @@ dependencies = [ name = "parity-updater" version = "1.11.0" dependencies = [ - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethsync 1.11.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-hash-fetch 1.11.0", @@ -2268,7 +2268,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-network 1.11.0", "ethcrypto 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2330,7 +2330,7 @@ dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2386,7 +2386,7 @@ name = "plain_hasher" version = "0.1.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2484,7 +2484,7 @@ version = "0.1.0" dependencies = [ "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.11.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2623,7 +2623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "registrar" version = "0.0.1" dependencies = [ - "ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2656,7 +2656,7 @@ version = "0.2.1" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3237,7 +3237,7 @@ name = "transaction-pool" version = "1.11.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3263,7 +3263,7 @@ name = "trie-standardmap" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "rlp 0.2.1", ] @@ -3273,7 +3273,7 @@ name = "triehash" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "rlp 0.2.1", "trie-standardmap 0.1.0", @@ -3286,7 +3286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "uint" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3393,7 +3393,7 @@ name = "util-error" version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3434,7 +3434,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3453,7 +3453,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.11.0", - "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3622,14 +3622,14 @@ dependencies = [ "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "" -"checksum ethabi 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d8385a48c8ed984778dcca27efc0de162a191a14ed733a41a07d9b0cfaa999e" +"checksum ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05e33a914b94b763f0a92333e4e5c95c095563f06ef7d6b295b3d3c2cf31e21f" "checksum ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca2263c24359e827348ac99aa1f2e28ba5bab0d6c0b83941fa252de8a9e9c073" "checksum ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "057f76ceb314191b2e7fcd6e2129d75816e80912e73ccc8324baa3b9e259bce3" -"checksum ethbloom 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f240172b976e2421fa5485e45cd45287bbdb56d742aa3a1d77005c49071a8518" -"checksum ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bad6fb0e4ab648f4d8d8314c340c47f9e805b085b78be1b8da4676534cb419df" +"checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" +"checksum ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53eabbad504e438e20b6559fd070d79b92cb31c02f994c7ecb05e9b2df716013" "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" -"checksum fixed-hash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21c520ebc46522d519aec9cba2b7115d49cea707d771b772c46bec61aa0daeb8" +"checksum fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "362f32e2fbc5ed45f01a23ca074f936bb3aee4122a66e7118e8c3e965d96104c" "checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -3819,7 +3819,7 @@ dependencies = [ "checksum transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "715254c8f0811be1a79ad3ea5e6fa3c8eddec2b03d7f5ba78cf093e56d79c24f" "checksum trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)" = "" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum uint 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53a4340c35703f926ec365c6797bb4a7a10bb6b9affe29ca385c9d804401f5e3" +"checksum uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6477b2716357758c176c36719023e1f9726974d762150e4fc0a9c8c75488c343" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" diff --git a/Cargo.toml b/Cargo.toml index 8ffab0be56..a89708c278 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ ethcore-network = { path = "util/network" } ethcore-service = { path = "ethcore/service" } ethcore-stratum = { path = "stratum" } ethcore-transaction = { path = "ethcore/transaction" } -ethereum-types = "0.2" +ethereum-types = "0.3" node-filter = { path = "ethcore/node_filter" } ethkey = { path = "ethkey" } node-health = { path = "dapps/node-health" } diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index e5b25a203f..d63150b0a5 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -29,7 +29,7 @@ jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "pa jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } ethcore-bytes = { path = "../util/bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" fetch = { path = "../util/fetch" } node-health = { path = "./node-health" } parity-hash-fetch = { path = "../hash-fetch" } diff --git a/dapps/src/tests/helpers/registrar.rs b/dapps/src/tests/helpers/registrar.rs index 8668d43b13..e770146f5a 100644 --- a/dapps/src/tests/helpers/registrar.rs +++ b/dapps/src/tests/helpers/registrar.rs @@ -55,7 +55,7 @@ impl FakeRegistrar { pub fn set_result(&self, hash: H256, result: Result) { self.responses.lock().insert( - (URLHINT.into(), format!("{}{:?}", URLHINT_RESOLVE, hash)), + (URLHINT.into(), format!("{}{:x}", URLHINT_RESOLVE, hash)), result ); } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 065bbc5cc5..2c769fac24 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -24,7 +24,7 @@ ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } ethcore-stratum = { path = "../stratum" } ethcore-transaction = { path = "./transaction" } -ethereum-types = "0.2" +ethereum-types = "0.3" memory-cache = { path = "../util/memory_cache" } ethabi = "5.1" ethabi-derive = "5.0" diff --git a/ethcore/evm/Cargo.toml b/ethcore/evm/Cargo.toml index 6efc05f4e2..898b2a70a5 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] [dependencies] bit-set = "0.4" -ethereum-types = "0.2" +ethereum-types = "0.3" evmjit = { path = "../../evmjit", optional = true } heapsize = "0.4" lazy_static = "1.0" diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index b8f5d5fb54..9de1ceb9e7 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -11,7 +11,7 @@ log = "0.3" ethcore = { path = ".."} ethcore-bytes = { path = "../../util/bytes" } ethcore-transaction = { path = "../transaction" } -ethereum-types = "0.2" +ethereum-types = "0.3" memorydb = { path = "../../util/memorydb" } patricia-trie = { path = "../../util/patricia_trie" } ethcore-network = { path = "../../util/network" } diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index 4beb32833f..397576ae42 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -405,7 +405,7 @@ fn get_block_receipts() { // by the test client in that case. let block_hashes: Vec = (0..1000) .map(|i| provider.client.block_header(BlockId::Number(i)).unwrap().hash()) - .filter(|hash| format!("{}", hash).starts_with("f")) + .filter(|hash| format!("{}", hash).starts_with("0xf")) .take(10) .collect(); diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index da1bcc1cf1..a726448bd1 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Parity Technologies "] [dependencies] ethcore = { path = ".."} ethcore-network-devp2p = { path = "../../util/network-devp2p" } -ethereum-types = "0.2" +ethereum-types = "0.3" log = "0.3" parking_lot = "0.5" ethabi = "5.1" diff --git a/ethcore/transaction/Cargo.toml b/ethcore/transaction/Cargo.toml index 7b45cae479..79e7282c38 100644 --- a/ethcore/transaction/Cargo.toml +++ b/ethcore/transaction/Cargo.toml @@ -12,7 +12,7 @@ heapsize = "0.4" keccak-hash = { path = "../../util/hash" } rlp = { path = "../../util/rlp" } unexpected = { path = "../../util/unexpected" } -ethereum-types = "0.2" +ethereum-types = "0.3" [dev-dependencies] rustc-hex= "1.0" diff --git a/ethcore/types/Cargo.toml b/ethcore/types/Cargo.toml index a14929f47e..92cc74551d 100644 --- a/ethcore/types/Cargo.toml +++ b/ethcore/types/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Parity Technologies "] rlp = { path = "../../util/rlp" } rlp_derive = { path = "../../util/rlp_derive" } ethcore-bytes = { path = "../../util/bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" ethjson = { path = "../../json" } keccak-hash = { path = "../../util/hash" } heapsize = "0.4" diff --git a/ethcore/vm/Cargo.toml b/ethcore/vm/Cargo.toml index 41ff98d0a0..c5d31f58e6 100644 --- a/ethcore/vm/Cargo.toml +++ b/ethcore/vm/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.0" ethcore-bytes = { path = "../../util/bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" patricia-trie = { path = "../../util/patricia_trie" } log = "0.3" common-types = { path = "../types" } diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index fc820a67d4..10a5134d45 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.0" -ethereum-types = "0.2" +ethereum-types = "0.3" log = "0.3" parity-wasm = "0.27" libc = "0.2" diff --git a/ethcore/wasm/run/Cargo.toml b/ethcore/wasm/run/Cargo.toml index 91cbfb996c..514849f2af 100644 --- a/ethcore/wasm/run/Cargo.toml +++ b/ethcore/wasm/run/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Parity Technologies "] serde = "1" serde_json = "1" serde_derive = "1" -ethereum-types = "0.2" +ethereum-types = "0.3" ethjson = { path = "../../../json" } vm = { path = "../../vm" } wasm = { path = "../" } diff --git a/ethcore/wasm/run/src/runner.rs b/ethcore/wasm/run/src/runner.rs index a30efc6f08..5ae0f941a4 100644 --- a/ethcore/wasm/run/src/runner.rs +++ b/ethcore/wasm/run/src/runner.rs @@ -79,17 +79,17 @@ impl fmt::Display for Fail { write!( f, "Storage key {} value mismatch, expected {}, got: {}", - key.as_ref().to_vec().to_hex(), - expected.as_ref().to_vec().to_hex(), - actual.as_ref().to_vec().to_hex(), + key.to_vec().to_hex(), + expected.to_vec().to_hex(), + actual.to_vec().to_hex(), ), StorageMismatch { ref key, ref expected, actual: None} => write!( f, "No expected storage value for key {} found, expected {}", - key.as_ref().to_vec().to_hex(), - expected.as_ref().to_vec().to_hex(), + key.to_vec().to_hex(), + expected.to_vec().to_hex(), ), Nonconformity(SpecNonconformity::Address) => diff --git a/ethcrypto/Cargo.toml b/ethcrypto/Cargo.toml index dfa351023c..887b44ab4f 100644 --- a/ethcrypto/Cargo.toml +++ b/ethcrypto/Cargo.toml @@ -8,7 +8,7 @@ rust-crypto = "0.2.36" tiny-keccak = "1.3" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true } ethkey = { path = "../ethkey", optional = true } -ethereum-types = "0.2" +ethereum-types = "0.3" subtle = "0.5" [features] diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index a3e903271b..51052bdca6 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Parity Technologies "] byteorder = "1.0" edit-distance = "2.0" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } -ethereum-types = "0.2" +ethereum-types = "0.3" lazy_static = "1.0" log = "0.3" parity-wordlist = "1.2" diff --git a/ethkey/cli/src/main.rs b/ethkey/cli/src/main.rs index 9298788f06..0dfc8aecde 100644 --- a/ethkey/cli/src/main.rs +++ b/ethkey/cli/src/main.rs @@ -180,9 +180,9 @@ fn display(result: (KeyPair, Option), mode: DisplayMode) -> String { Some(extra_data) => format!("{}\n{}", extra_data, keypair), None => format!("{}", keypair) }, - DisplayMode::Secret => format!("{:?}", keypair.secret()), - DisplayMode::Public => format!("{:?}", keypair.public()), - DisplayMode::Address => format!("{:?}", keypair.address()), + DisplayMode::Secret => format!("{:x}", keypair.secret()), + DisplayMode::Public => format!("{:x}", keypair.public()), + DisplayMode::Address => format!("{:x}", keypair.address()), } } diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index 6e0548264f..9b2faee7c6 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -29,13 +29,19 @@ pub struct Secret { impl ToHex for Secret { fn to_hex(&self) -> String { - self.inner.to_hex() + format!("{:x}", self.inner) + } +} + +impl fmt::LowerHex for Secret { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(fmt) } } impl fmt::Debug for Secret { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}", self.inner) + self.inner.fmt(fmt) } } diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index a504c7f2a5..34f61a8f75 100755 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -18,7 +18,7 @@ time = "0.1.34" itertools = "0.5" parking_lot = "0.5" ethcrypto = { path = "../ethcrypto" } -ethereum-types = "0.2" +ethereum-types = "0.3" dir = { path = "../util/dir" } smallvec = "0.4" parity-wordlist = "1.0" diff --git a/ethstore/cli/src/main.rs b/ethstore/cli/src/main.rs index 45f9f6920e..8ebb206a0b 100644 --- a/ethstore/cli/src/main.rs +++ b/ethstore/cli/src/main.rs @@ -191,7 +191,7 @@ fn open_args_vault_account(store: &EthStore, address: Address, args: &Args) -> R fn format_accounts(accounts: &[Address]) -> String { accounts.iter() .enumerate() - .map(|(i, a)| format!("{:2}: 0x{:?}", i, a)) + .map(|(i, a)| format!("{:2}: 0x{:x}", i, a)) .collect::>() .join("\n") } @@ -220,7 +220,7 @@ fn execute(command: I) -> Result where I: IntoIterator(command: I) -> Result where I: IntoIterator>(); @@ -272,7 +272,7 @@ fn execute(command: I) -> Result where I: IntoIterator"] [dependencies] ethcore = { path = "../ethcore" } ethcore-bytes = { path = "../util/bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } rlp = { path = "../util/rlp" } diff --git a/json/Cargo.toml b/json/Cargo.toml index 6e84e6da3a..0668caf8b2 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] -ethereum-types = "0.2" +ethereum-types = "0.3" rustc-hex = "1.0" serde = "1.0" serde_json = "1.0" diff --git a/machine/Cargo.toml b/machine/Cargo.toml index 037bc55bf8..ee56b9de87 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -5,4 +5,4 @@ description = "Generalization of a state machine for consensus engines" authors = ["Parity Technologies "] [dependencies] -ethereum-types = "0.2" +ethereum-types = "0.3" diff --git a/miner/Cargo.toml b/miner/Cargo.toml index b9f44cd6e0..a3464cf7d0 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -16,7 +16,7 @@ ethabi-contract = "5.0" ethabi-derive = "5.0" ethash = { path = "../ethash" } ethcore-transaction = { path = "../ethcore/transaction" } -ethereum-types = "0.2" +ethereum-types = "0.3" ethkey = { path = "../ethkey" } futures = "0.1" heapsize = "0.4" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index bb23b2ec3d..433f46d139 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -45,7 +45,7 @@ ethcore-light = { path = "../ethcore/light" } ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } ethcore-transaction = { path = "../ethcore/transaction" } -ethereum-types = "0.2" +ethereum-types = "0.3" ethcrypto = { path = "../ethcrypto" } ethjson = { path = "../json" } diff --git a/rpc/src/tests/ws.rs b/rpc/src/tests/ws.rs index 1db7a91e98..429ff6d3c4 100644 --- a/rpc/src/tests/ws.rs +++ b/rpc/src/tests/ws.rs @@ -120,7 +120,7 @@ mod testing { Host: 127.0.0.1:{}\r\n\ Connection: Close\r\n\ Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n\ - Sec-WebSocket-Protocol: {:?}_{}\r\n\ + Sec-WebSocket-Protocol: {:x}_{}\r\n\ Sec-WebSocket-Version: 13\r\n\ \r\n\ {{}} @@ -150,7 +150,7 @@ mod testing { Host: 127.0.0.1:{}\r\n\ Connection: Close\r\n\ Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n\ - Sec-WebSocket-Protocol:{:?}_{}\r\n\ + Sec-WebSocket-Protocol:{:x}_{}\r\n\ Sec-WebSocket-Version: 13\r\n\ \r\n\ {{}} diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 84dd64644d..bb03808c58 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -337,7 +337,7 @@ fn eth_transaction_count() { let req_before = r#"{ "jsonrpc": "2.0", "method": "eth_getTransactionCount", - "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "params": [""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "latest"], "id": 15 }"#; @@ -349,7 +349,7 @@ fn eth_transaction_count() { "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x30000", "gasPrice": "0x1", @@ -365,7 +365,7 @@ fn eth_transaction_count() { let req_after_latest = r#"{ "jsonrpc": "2.0", "method": "eth_getTransactionCount", - "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "params": [""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "latest"], "id": 17 }"#; @@ -377,7 +377,7 @@ fn eth_transaction_count() { let req_after_pending = r#"{ "jsonrpc": "2.0", "method": "eth_getTransactionCount", - "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "pending"], + "params": [""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "pending"], "id": 18 }"#; @@ -403,7 +403,7 @@ fn verify_transaction_counts(name: String, chain: BlockChain) { "jsonrpc": "2.0", "method": "eth_getBlockTransactionCountByHash", "params": [ - ""#.to_owned() + format!("0x{:?}", hash).as_ref() + r#"" + ""#.to_owned() + format!("0x{:x}", hash).as_ref() + r#"" ], "id": "# + format!("{}", *id).as_ref() + r#" }"#; @@ -463,7 +463,7 @@ fn starting_nonce_test() { { "jsonrpc": "2.0", "method": "eth_getTransactionCount", - "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "params": [""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "latest"], "id": 15 } "#) diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index e901993bdd..99c67286eb 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -337,7 +337,7 @@ fn rpc_eth_sign() { "jsonrpc": "2.0", "method": "eth_sign", "params": [ - ""#.to_owned() + &format!("0x{:?}", account) + r#"", + ""#.to_owned() + &format!("0x{:x}", account) + r#"", "0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f" ], "id": 1 @@ -349,7 +349,7 @@ fn rpc_eth_sign() { #[test] fn rpc_eth_author() { - let make_res = |addr| r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", addr) + r#"","id":1}"#; + let make_res = |addr| r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:x}", addr) + r#"","id":1}"#; let tester = EthTester::default(); let req = r#"{ @@ -402,7 +402,7 @@ fn rpc_eth_accounts() { // with current policy it should return the account let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned() + &format!("0x{:?}", address) + r#""],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned() + &format!("0x{:x}", address) + r#""],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); tester.accounts_provider.set_new_dapps_addresses(Some(vec![1.into()])).unwrap(); @@ -811,7 +811,7 @@ fn rpc_eth_send_transaction() { "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -831,7 +831,7 @@ fn rpc_eth_send_transaction() { let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap(); let t = t.with_signature(signature, None); - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", t.hash()).as_ref() + r#"","id":1}"#; assert_eq!(tester.io.handle_request_sync(&request), Some(response)); @@ -848,7 +848,7 @@ fn rpc_eth_send_transaction() { let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap(); let t = t.with_signature(signature, None); - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", t.hash()).as_ref() + r#"","id":1}"#; assert_eq!(tester.io.handle_request_sync(&request), Some(response)); } @@ -862,7 +862,7 @@ fn rpc_eth_sign_transaction() { "jsonrpc": "2.0", "method": "eth_signTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -890,12 +890,12 @@ fn rpc_eth_sign_transaction() { r#""blockHash":null,"blockNumber":null,"# + &format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) + r#""condition":null,"creates":null,"# + - &format!("\"from\":\"0x{:?}\",", &address) + + &format!("\"from\":\"0x{:x}\",", &address) + r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# + - &format!("\"hash\":\"0x{:?}\",", t.hash()) + + &format!("\"hash\":\"0x{:x}\",", t.hash()) + r#""input":"0x","# + r#""nonce":"0x1","# + - &format!("\"publicKey\":\"0x{:?}\",", t.recover_public().unwrap()) + + &format!("\"publicKey\":\"0x{:x}\",", t.recover_public().unwrap()) + &format!("\"r\":\"0x{:x}\",", U256::from(signature.r())) + &format!("\"raw\":\"0x{}\",", rlp.to_hex()) + &format!("\"s\":\"0x{:x}\",", U256::from(signature.s())) + @@ -918,7 +918,7 @@ fn rpc_eth_send_transaction_with_bad_to() { "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "to": "", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -941,7 +941,7 @@ fn rpc_eth_send_transaction_error() { "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -999,7 +999,7 @@ fn rpc_eth_send_raw_transaction() { "id": 1 }"#; - let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", t.hash()) + r#"","id":1}"#; + let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:x}", t.hash()) + r#"","id":1}"#; assert_eq!(tester.io.handle_request_sync(&req), Some(res)); } @@ -1150,7 +1150,7 @@ fn rpc_get_work_should_timeout() { // Request without providing timeout. This should work since we're disabling timeout. let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; let work_response = format!( - r#"{{"jsonrpc":"2.0","result":["0x{:?}","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000","0x1"],"id":1}}"#, + r#"{{"jsonrpc":"2.0","result":["0x{:x}","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000","0x1"],"id":1}}"#, hash, ); assert_eq!(eth_tester.io.handle_request_sync(request), Some(work_response.to_owned())); @@ -1158,7 +1158,7 @@ fn rpc_get_work_should_timeout() { // Request with timeout of 0 seconds. This should work since we're disabling timeout. let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [0], "id": 1}"#; let work_response = format!( - r#"{{"jsonrpc":"2.0","result":["0x{:?}","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000","0x1"],"id":1}}"#, + r#"{{"jsonrpc":"2.0","result":["0x{:x}","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000","0x1"],"id":1}}"#, hash, ); assert_eq!(eth_tester.io.handle_request_sync(request), Some(work_response.to_owned())); diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index 1a0186c97e..15b178d504 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -128,7 +128,7 @@ fn should_subscribe_to_logs() { handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], 0); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() - + &format!("0x{:?}", tx_hash) + + &format!("0x{:x}", tx_hash) + r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); @@ -136,7 +136,7 @@ fn should_subscribe_to_logs() { handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], 0); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() - + &format!("0x{:?}", tx_hash) + + &format!("0x{:x}", tx_hash) + r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"removed"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 4b75e07fed..332221b081 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -407,7 +407,7 @@ fn rpc_parity_pending_transactions() { fn rpc_parity_encrypt() { let deps = Dependencies::new(); let io = deps.default_client(); - let key = format!("{:?}", Random.generate().unwrap().public()); + let key = format!("{:x}", Random.generate().unwrap().public()); let request = r#"{"jsonrpc": "2.0", "method": "parity_encryptMessage", "params":["0x"#.to_owned() + &key + r#"", "0x01"], "id": 1}"#; assert!(io.handle_request_sync(&request).unwrap().contains("result"), "Should return success."); @@ -461,7 +461,7 @@ fn rpc_parity_next_nonce() { let request = r#"{ "jsonrpc": "2.0", "method": "parity_nextNonce", - "params": [""#.to_owned() + &format!("0x{:?}", address) + r#""], + "params": [""#.to_owned() + &format!("0x{:x}", address) + r#""], "id": 1 }"#; let response1 = r#"{"jsonrpc":"2.0","result":"0x0","id":1}"#; diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index f92841ee8b..549811bd58 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -234,7 +234,7 @@ fn rpc_parity_remove_transaction() { let signed = tx.fake_sign(2.into()); let hash = signed.hash(); - let request = r#"{"jsonrpc": "2.0", "method": "parity_removeTransaction", "params":[""#.to_owned() + &format!("0x{:?}", hash) + r#""], "id": 1}"#; + let request = r#"{"jsonrpc": "2.0", "method": "parity_removeTransaction", "params":[""#.to_owned() + &format!("0x{:x}", hash) + r#""], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#; miner.pending_transactions.lock().insert(hash, signed); diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 6dd1da567f..502a590582 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -77,7 +77,7 @@ fn accounts() { let tester = setup(); let address = tester.accounts.new_account("").unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned() + &format!("0x{:?}", address) + r#""],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned() + &format!("0x{:x}", address) + r#""],"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } @@ -92,7 +92,7 @@ fn new_account() { let accounts = tester.accounts.accounts().unwrap(); assert_eq!(accounts.len(), 1); let address = accounts[0]; - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"","id":1}"#; assert_eq!(res, Some(response)); } @@ -106,7 +106,7 @@ fn invalid_password_test(method: &str) "jsonrpc": "2.0", "method": ""#.to_owned() + method + r#"", "params": [{ - "from": ""# + format!("0x{:?}", address).as_ref() + r#"", + "from": ""# + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -131,7 +131,7 @@ fn sign() { "method": "personal_sign", "params": [ ""#.to_owned() + format!("0x{}", data.to_hex()).as_ref() + r#"", - ""# + format!("0x{:?}", address).as_ref() + r#"", + ""# + format!("0x{:x}", address).as_ref() + r#"", "password123" ], "id": 1 @@ -156,7 +156,7 @@ fn sign_with_invalid_password() { "method": "personal_sign", "params": [ "0x0000000000000000000000000000000000000000000000000000000000000005", - ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "" ], "id": 1 @@ -195,7 +195,7 @@ fn sign_and_send_test(method: &str) { "jsonrpc": "2.0", "method": ""#.to_owned() + method + r#"", "params": [{ - "from": ""# + format!("0x{:?}", address).as_ref() + r#"", + "from": ""# + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -216,7 +216,7 @@ fn sign_and_send_test(method: &str) { let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap(); let t = t.with_signature(signature, None); - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", t.hash()).as_ref() + r#"","id":1}"#; assert_eq!(tester.io.handle_request_sync(request.as_ref()), Some(response)); @@ -234,7 +234,7 @@ fn sign_and_send_test(method: &str) { let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap(); let t = t.with_signature(signature, None); - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", t.hash()).as_ref() + r#"","id":1}"#; assert_eq!(tester.io.handle_request_sync(request.as_ref()), Some(response)); } @@ -259,7 +259,7 @@ fn ec_recover() { "id": 1 }"#; - let address = format!("0x{:?}", address); + let address = format!("0x{:x}", address); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &address + r#"","id":1}"#; assert_eq!(tester.io.handle_request_sync(request.as_ref()), Some(response.into())); @@ -294,7 +294,7 @@ fn should_unlock_not_account_temporarily_if_allow_perm_is_disabled() { "jsonrpc": "2.0", "method": "personal_unlockAccount", "params": [ - ""#.to_owned() + &format!("0x{:?}", address) + r#"", + ""#.to_owned() + &format!("0x{:x}", address) + r#"", "password123", "0x100" ], @@ -315,7 +315,7 @@ fn should_unlock_account_permanently() { "jsonrpc": "2.0", "method": "personal_unlockAccount", "params": [ - ""#.to_owned() + &format!("0x{:?}", address) + r#"", + ""#.to_owned() + &format!("0x{:x}", address) + r#"", "password123", null ], diff --git a/rpc/src/v1/tests/mocked/signer.rs b/rpc/src/v1/tests/mocked/signer.rs index da531a00f1..bee28b35ec 100644 --- a/rpc/src/v1/tests/mocked/signer.rs +++ b/rpc/src/v1/tests/mocked/signer.rs @@ -216,7 +216,7 @@ fn should_confirm_transaction_and_dispatch() { "params":["0x1", {"gasPrice":"0x1000","gas":"0x50505"}, "test"], "id":1 }"#; - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", t.hash()).as_ref() + r#"","id":1}"#; // then assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); @@ -261,11 +261,11 @@ fn should_alter_the_sender_and_nonce() { "jsonrpc":"2.0", "method":"signer_confirmRequest", "params":["0x1", {"sender":""#.to_owned() - + &format!("0x{:?}", address) + + &format!("0x{:x}", address) + r#"","gasPrice":"0x1000","gas":"0x50505"}, "test"], "id":1 }"#; - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", t.hash()) + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:x}", t.hash()) + r#"","id":1}"#; // then assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); @@ -312,7 +312,7 @@ fn should_confirm_transaction_with_token() { "id":1 }"#; let response = r#"{"jsonrpc":"2.0","result":{"result":""#.to_owned() + - format!("0x{:?}", t.hash()).as_ref() + + format!("0x{:x}", t.hash()).as_ref() + r#"","token":""#; // then @@ -361,7 +361,7 @@ fn should_confirm_transaction_with_rlp() { "params":["0x1", "0x"#.to_owned() + &rlp.to_hex() + r#""], "id":1 }"#; - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", t.hash()).as_ref() + r#"","id":1}"#; // then assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); @@ -460,12 +460,12 @@ fn should_confirm_sign_transaction_with_rlp() { r#""blockHash":null,"blockNumber":null,"# + &format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) + r#""condition":null,"creates":null,"# + - &format!("\"from\":\"0x{:?}\",", &address) + + &format!("\"from\":\"0x{:x}\",", &address) + r#""gas":"0x989680","gasPrice":"0x1000","# + - &format!("\"hash\":\"0x{:?}\",", t.hash()) + + &format!("\"hash\":\"0x{:x}\",", t.hash()) + r#""input":"0x","# + r#""nonce":"0x0","# + - &format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) + + &format!("\"publicKey\":\"0x{:x}\",", t.public_key().unwrap()) + &format!("\"r\":\"0x{:x}\",", U256::from(signature.r())) + &format!("\"raw\":\"0x{}\",", rlp.to_hex()) + &format!("\"s\":\"0x{:x}\",", U256::from(signature.s())) + diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 5bf5119ec6..11e1ac44d4 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -95,7 +95,7 @@ fn should_add_sign_to_queue() { "jsonrpc": "2.0", "method": "eth_sign", "params": [ - ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "0x0000000000000000000000000000000000000000000000000000000000000005" ], "id": 1 @@ -132,7 +132,7 @@ fn should_post_sign_to_queue() { "jsonrpc": "2.0", "method": "parity_postSign", "params": [ - ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "0x0000000000000000000000000000000000000000000000000000000000000005" ], "id": 1 @@ -153,7 +153,7 @@ fn should_check_status_of_request() { "jsonrpc": "2.0", "method": "parity_postSign", "params": [ - ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "0x0000000000000000000000000000000000000000000000000000000000000005" ], "id": 1 @@ -182,7 +182,7 @@ fn should_check_status_of_request_when_its_resolved() { "jsonrpc": "2.0", "method": "parity_postSign", "params": [ - ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "0x0000000000000000000000000000000000000000000000000000000000000005" ], "id": 1 @@ -219,7 +219,7 @@ fn should_sign_if_account_is_unlocked() { "jsonrpc": "2.0", "method": "eth_sign", "params": [ - ""#.to_owned() + format!("0x{:?}", acc).as_ref() + r#"", + ""#.to_owned() + format!("0x{:x}", acc).as_ref() + r#"", ""# + format!("0x{}", data.to_hex()).as_ref() + r#"" ], "id": 1 @@ -241,7 +241,7 @@ fn should_add_transaction_to_queue() { "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -282,7 +282,7 @@ fn should_add_sign_transaction_to_the_queue() { "jsonrpc": "2.0", "method": "eth_signTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", address).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -311,12 +311,12 @@ fn should_add_sign_transaction_to_the_queue() { r#""blockHash":null,"blockNumber":null,"# + &format!("\"chainId\":{},", t.chain_id().map_or("null".to_owned(), |n| format!("{}", n))) + r#""condition":null,"creates":null,"# + - &format!("\"from\":\"0x{:?}\",", &address) + + &format!("\"from\":\"0x{:x}\",", &address) + r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# + - &format!("\"hash\":\"0x{:?}\",", t.hash()) + + &format!("\"hash\":\"0x{:x}\",", t.hash()) + r#""input":"0x","# + r#""nonce":"0x1","# + - &format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) + + &format!("\"publicKey\":\"0x{:x}\",", t.public_key().unwrap()) + &format!("\"r\":\"0x{:x}\",", U256::from(signature.r())) + &format!("\"raw\":\"0x{}\",", rlp.to_hex()) + &format!("\"s\":\"0x{:x}\",", U256::from(signature.s())) + @@ -370,7 +370,7 @@ fn should_dispatch_transaction_if_account_is_unlock() { "jsonrpc": "2.0", "method": "eth_sendTransaction", "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", acc).as_ref() + r#"", + "from": ""#.to_owned() + format!("0x{:x}", acc).as_ref() + r#"", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "gas": "0x76c0", "gasPrice": "0x9184e72a000", @@ -378,7 +378,7 @@ fn should_dispatch_transaction_if_account_is_unlock() { }], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:x}", t.hash()).as_ref() + r#"","id":1}"#; // then assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); @@ -395,7 +395,7 @@ fn should_decrypt_message_if_account_is_unlocked() { // First encrypt message - let request = format!("{}0x{:?}{}", + let request = format!("{}0x{:x}{}", r#"{"jsonrpc": "2.0", "method": "parity_encryptMessage", "params":[""#, public, r#"", "0x01020304"], "id": 1}"# @@ -403,7 +403,7 @@ fn should_decrypt_message_if_account_is_unlocked() { let encrypted: Success = serde_json::from_str(&tester.io.handle_request_sync(&request).unwrap()).unwrap(); // then call decrypt - let request = format!("{}{:?}{}{}{}", + let request = format!("{}{:x}{}{}{}", r#"{"jsonrpc": "2.0", "method": "parity_decryptMessage", "params":["0x"#, address, r#"","#, @@ -428,7 +428,7 @@ fn should_add_decryption_to_the_queue() { let request = r#"{ "jsonrpc": "2.0", "method": "parity_decryptMessage", - "params": ["0x"#.to_owned() + &format!("{:?}", acc.address()) + r#"", + "params": ["0x"#.to_owned() + &format!("{:x}", acc.address()) + r#"", "0x012345"], "id": 1 }"#; @@ -459,7 +459,7 @@ fn should_compose_transaction() { let tester = eth_signing(); let acc = Random.generate().unwrap(); assert_eq!(tester.signer.requests().len(), 0); - let from = format!("{:?}", acc.address()); + let from = format!("{:x}", acc.address()); // when let request = r#"{ diff --git a/rpc_client/src/client.rs b/rpc_client/src/client.rs index 8f330629b2..17a8d9d724 100644 --- a/rpc_client/src/client.rs +++ b/rpc_client/src/client.rs @@ -74,7 +74,7 @@ impl Handler for RpcHandler { })?; let secs = timestamp.as_secs(); let hashed = keccak(format!("{}:{}", self.auth_code, secs)); - let proto = format!("{:?}_{}", hashed, secs); + let proto = format!("{:x}_{}", hashed, secs); r.add_protocol(&proto); Ok(r) }, diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index 10b690b6d9..3b60a3c6c5 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -24,7 +24,7 @@ tokio-proto = "0.1" url = "1.0" ethcore = { path = "../ethcore" } ethcore-bytes = { path = "../util/bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" ethsync = { path = "../sync" } kvdb = { path = "../util/kvdb" } kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } diff --git a/stratum/Cargo.toml b/stratum/Cargo.toml index 0faed61863..5f66cfd49c 100644 --- a/stratum/Cargo.toml +++ b/stratum/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Parity Technologies "] [dependencies] ethcore-logger = { path = "../logger" } -ethereum-types = "0.2" +ethereum-types = "0.3" keccak-hash = { path = "../util/hash" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index e82dd710de..1c1bd467b6 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -15,7 +15,7 @@ ethcore-io = { path = "../util/io" } ethcore-light = { path = "../ethcore/light" } ethcore-transaction = { path = "../ethcore/transaction" } ethcore = { path = "../ethcore" } -ethereum-types = "0.2" +ethereum-types = "0.3" plain_hasher = { path = "../util/plain_hasher" } rlp = { path = "../util/rlp" } keccak-hash = { path = "../util/hash" } diff --git a/test.sh b/test.sh index ada9525cb7..7e98001887 100755 --- a/test.sh +++ b/test.sh @@ -3,27 +3,33 @@ FEATURES="json-tests" OPTIONS="--release" +VALIDATE=1 case $1 in - --no-json) + --no-json) FEATURES="ipc" shift # past argument=value ;; - --no-release) - OPTIONS="" - shift - ;; - --no-run) - OPTIONS="--no-run" - shift - ;; - *) - # unknown option + --no-release) + OPTIONS="" + shift + ;; + --no-validate) + VALIDATE=0 + shift + ;; + --no-run) + OPTIONS="--no-run" + shift + ;; + *) + # unknown option ;; esac set -e +if [ "$VALIDATE" -eq "1" ]; then # Validate --no-default-features build echo "________Validate build________" cargo check --no-default-features @@ -31,6 +37,8 @@ cargo check --no-default-features # Validate chainspecs echo "________Validate chainspecs________" ./scripts/validate_chainspecs.sh +fi + # Running test's echo "________Running Parity Full Test Suite________" diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index 49bf2db64d..b9db0f6d21 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -9,4 +9,4 @@ authors = ["Parity Technologies "] error-chain = "0.11" log = "0.3" smallvec = "0.4" -ethereum-types = "0.2" +ethereum-types = "0.3" diff --git a/updater/Cargo.toml b/updater/Cargo.toml index 0621fbc676..29fba27ffd 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -15,7 +15,7 @@ semver = "0.6" ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } ethcore-bytes = { path = "../util/bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" parking_lot = "0.5" parity-hash-fetch = { path = "../hash-fetch" } parity-version = { path = "../util/version" } diff --git a/updater/src/updater.rs b/updater/src/updater.rs index ba7a42c875..914516bb47 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -249,7 +249,7 @@ impl Updater { } fn update_file_name(v: &VersionInfo) -> String { - format!("parity-{}.{}.{}-{:?}", v.version.major, v.version.minor, v.version.patch, v.hash) + format!("parity-{}.{}.{}-{:x}", v.version.major, v.version.minor, v.version.patch, v.hash) } fn updates_path(&self, name: &str) -> PathBuf { diff --git a/util/bloomchain/Cargo.toml b/util/bloomchain/Cargo.toml index a9bd8432c4..6bcf6a9b14 100644 --- a/util/bloomchain/Cargo.toml +++ b/util/bloomchain/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" keywords = ["ethereum", "ethcore", "bloom", "chain", "filter"] [dependencies] -ethbloom = "0.4" +ethbloom = "0.5" [dev-dependencies] rustc-hex = "1.0" diff --git a/util/dir/Cargo.toml b/util/dir/Cargo.toml index c82a0347c0..5963833a7e 100644 --- a/util/dir/Cargo.toml +++ b/util/dir/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] -ethereum-types = "0.2" +ethereum-types = "0.3" journaldb = { path = "../journaldb" } app_dirs = "1.2.1" diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index 39175d000f..765572b42c 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -156,7 +156,7 @@ impl DatabaseDirectories { /// Base DB directory for the given fork. // TODO: remove in 1.7 pub fn legacy_fork_path(&self) -> PathBuf { - Path::new(&self.legacy_path).join(format!("{:?}{}", H64::from(self.genesis_hash), self.fork_name.as_ref().map(|f| format!("-{}", f)).unwrap_or_default())) + Path::new(&self.legacy_path).join(format!("{:x}{}", H64::from(self.genesis_hash), self.fork_name.as_ref().map(|f| format!("-{}", f)).unwrap_or_default())) } /// Spec root directory for the given fork. diff --git a/util/error/Cargo.toml b/util/error/Cargo.toml index ffbd8e4a7c..d9da3e5c51 100644 --- a/util/error/Cargo.toml +++ b/util/error/Cargo.toml @@ -6,6 +6,6 @@ authors = ["Parity Technologies "] [dependencies] rlp = { path = "../rlp" } kvdb = { path = "../kvdb" } -ethereum-types = "0.2" +ethereum-types = "0.3" error-chain = { version = "0.11", default-features = false } rustc-hex = "1.0" diff --git a/util/hash/Cargo.toml b/util/hash/Cargo.toml index c7fee36e01..da91cd733c 100644 --- a/util/hash/Cargo.toml +++ b/util/hash/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Parity Technologies "] build = "build.rs" [dependencies] -ethereum-types = "0.2" +ethereum-types = "0.3" tiny-keccak = "1.3" [build-dependencies] diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs index 0982c11da4..d00396501e 100644 --- a/util/hash/src/lib.rs +++ b/util/hash/src/lib.rs @@ -105,6 +105,6 @@ mod tests { let hash = keccak_buffer(&mut file).unwrap(); // then - assert_eq!(format!("{:?}", hash), "68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"); + assert_eq!(format!("{:x}", hash), "68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"); } } diff --git a/util/hashdb/Cargo.toml b/util/hashdb/Cargo.toml index e6250fb56a..d4e055f9ff 100644 --- a/util/hashdb/Cargo.toml +++ b/util/hashdb/Cargo.toml @@ -7,4 +7,4 @@ license = "GPL-3.0" [dependencies] elastic-array = "0.10" -ethereum-types = "0.2" +ethereum-types = "0.3" diff --git a/util/journaldb/Cargo.toml b/util/journaldb/Cargo.toml index d3d4708f04..dea70bd6a4 100644 --- a/util/journaldb/Cargo.toml +++ b/util/journaldb/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL3" [dependencies] ethcore-bytes = { path = "../bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" hashdb = { path = "../hashdb" } heapsize = "0.4" kvdb = { path = "../kvdb" } diff --git a/util/kvdb-rocksdb/Cargo.toml b/util/kvdb-rocksdb/Cargo.toml index 89a2f6403f..07016b68a2 100644 --- a/util/kvdb-rocksdb/Cargo.toml +++ b/util/kvdb-rocksdb/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] [dependencies] elastic-array = "0.10" -ethereum-types = "0.2" +ethereum-types = "0.3" kvdb = { path = "../kvdb" } log = "0.3" num_cpus = "1.0" diff --git a/util/memorydb/Cargo.toml b/util/memorydb/Cargo.toml index e5feabe5fb..da83227814 100644 --- a/util/memorydb/Cargo.toml +++ b/util/memorydb/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-3.0" bigint = "4.0" elastic-array = "0.10" heapsize = "0.4" -ethereum-types = "0.2" +ethereum-types = "0.3" keccak-hash = { version = "0.1.0", path = "../hash" } hashdb = { version = "0.1.1", path = "../hashdb" } plain_hasher = { path = "../plain_hasher" } diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 7d86ce7a07..466ff95161 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -22,7 +22,7 @@ rustc-hex = "1.0" ethcore-io = { path = "../io" } ethcore-bytes = { path = "../bytes" } ethcore-network = { path = "../network" } -ethereum-types = "0.2" +ethereum-types = "0.3" ethkey = { path = "../../ethkey" } ethcrypto = { path = "../../ethcrypto" } rlp = { path = "../rlp" } diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 51990b6f51..7056c67f6c 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -1099,7 +1099,7 @@ fn save_key(path: &Path, key: &Secret) { if let Err(e) = restrict_permissions_owner(path, true, false) { warn!(target: "network", "Failed to modify permissions of the file ({})", e); } - if let Err(e) = file.write(&key.hex().into_bytes()) { + if let Err(e) = file.write(&key.hex().into_bytes()[2..]) { warn!("Error writing key file: {:?}", e); } } diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 6be9ae12eb..470bf5cde0 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -169,9 +169,9 @@ impl Node { impl Display for Node { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if self.endpoint.udp_port != self.endpoint.address.port() { - write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port)?; + write!(f, "enode://{:x}@{}+{}", self.id, self.endpoint.address, self.endpoint.udp_port)?; } else { - write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address)?; + write!(f, "enode://{:x}@{}", self.id, self.endpoint.address)?; } Ok(()) } diff --git a/util/network/Cargo.toml b/util/network/Cargo.toml index 7f9b30400b..7d3d48b5af 100644 --- a/util/network/Cargo.toml +++ b/util/network/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Parity Technologies "] [dependencies] ethcore-io = { path = "../io" } -ethereum-types = "0.2" +ethereum-types = "0.3" ethkey = { path = "../../ethkey" } ethcrypto = { path = "../../ethcrypto" } rlp = { path = "../rlp" } diff --git a/util/patricia_trie/Cargo.toml b/util/patricia_trie/Cargo.toml index 318db6b998..48b06b2146 100644 --- a/util/patricia_trie/Cargo.toml +++ b/util/patricia_trie/Cargo.toml @@ -10,7 +10,7 @@ elastic-array = "0.10" log = "0.3" rand = "0.4" ethcore-bytes = { version = "0.1.0", path = "../bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" keccak-hash = { version = "0.1.0", path = "../hash" } hashdb = { version = "0.1.1", path = "../hashdb" } rlp = { version = "0.2.1", path = "../rlp" } diff --git a/util/plain_hasher/Cargo.toml b/util/plain_hasher/Cargo.toml index d79ea4c5e4..d909f8f9d6 100644 --- a/util/plain_hasher/Cargo.toml +++ b/util/plain_hasher/Cargo.toml @@ -9,4 +9,4 @@ homepage = "https://github.com/paritytech/plain_hasher" [dependencies] crunchy = "0.1.6" -ethereum-types = "0.2" +ethereum-types = "0.3" diff --git a/util/rlp/Cargo.toml b/util/rlp/Cargo.toml index ecb3b39312..3bde7206ff 100644 --- a/util/rlp/Cargo.toml +++ b/util/rlp/Cargo.toml @@ -8,6 +8,6 @@ authors = ["Parity Technologies "] [dependencies] elastic-array = "0.10" -ethereum-types = "0.2" +ethereum-types = "0.3" rustc-hex = "1.0" byteorder = "1.0" diff --git a/util/trie-standardmap/Cargo.toml b/util/trie-standardmap/Cargo.toml index caa915c542..1177f30752 100644 --- a/util/trie-standardmap/Cargo.toml +++ b/util/trie-standardmap/Cargo.toml @@ -6,6 +6,6 @@ description = "Standard test map for profiling tries" [dependencies] ethcore-bytes = { path = "../bytes" } -ethereum-types = "0.2" +ethereum-types = "0.3" keccak-hash = { path = "../hash" } rlp = { path = "../rlp" } diff --git a/util/triehash/Cargo.toml b/util/triehash/Cargo.toml index 52af5911d4..ee42b9d825 100644 --- a/util/triehash/Cargo.toml +++ b/util/triehash/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" [dependencies] elastic-array = "0.10" rlp = { version = "0.2.1", path = "../rlp" } -ethereum-types = "0.2" +ethereum-types = "0.3" keccak-hash = { version = "0.1", path = "../hash" } [dev-dependencies] diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index 35d15fa76e..b972bf5cf1 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -7,7 +7,7 @@ description = "Whisper Protocol implementation for Parity" [dependencies] bitflags = "0.9" byteorder = "1.0.0" -ethereum-types = "0.2" +ethereum-types = "0.3" ethcore-network = { path = "../util/network" } ethcrypto = { path = "../ethcrypto" } ethkey = { path = "../ethkey" } -- GitLab From 54c9c382e7b9e893eaacfd6930c7082dbb0973e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 2 Apr 2018 14:06:07 +0100 Subject: [PATCH 019/263] Revert "ci: disable link-dead-code in coverage build (#8118)" (#8287) This reverts commit 4d1cb01da0ceff3b025c0f030da7aae86441206a. --- scripts/cov.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cov.sh b/scripts/cov.sh index 80fe045ca1..bd733703ce 100755 --- a/scripts/cov.sh +++ b/scripts/cov.sh @@ -12,7 +12,7 @@ ### Running coverage set -x -cargo test --all --exclude evmjit --no-run || exit $? +RUSTFLAGS="-C link-dead-code" cargo test --all --exclude evmjit --no-run || exit $? KCOV_TARGET="target/cov" KCOV_FLAGS="--verify" EXCLUDE="/usr/lib,/usr/include,$HOME/.cargo,$HOME/.multirust,rocksdb,secp256k1" -- GitLab From d477670cb9b566defe8824a35f5c4c0a7ac39a1b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 3 Apr 2018 15:32:38 +0800 Subject: [PATCH 020/263] Typo fix: todo with no content (#8292) --- ethcore/src/client/test_client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 69d8c70d6b..3c48b2a3e9 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -311,7 +311,7 @@ impl TestBlockChainClient { self.blocks.write().insert(hash, rlp.out()); } - /// TODO: + /// Get block hash with `delta` as offset from the most recent blocks. pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { let blocks_read = self.numbers.read(); let index = blocks_read.len() - delta; -- GitLab From 9f775a7673bb4e3d6197703d248b0c120eee3fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 3 Apr 2018 10:01:28 +0200 Subject: [PATCH 021/263] Remove RefCell from Header (#8227) * Cache RLP and header hashes. * Refactor header - WiP * Avoid decoding laster header. * Pre-compute hashes for Sealed/Locked block. * Use accrue bloom. Closes ##8241 --- ethcore/light/src/on_demand/tests.rs | 15 +- ethcore/src/block.rs | 56 ++--- ethcore/src/blockchain/best_block.rs | 17 +- ethcore/src/blockchain/blockchain.rs | 120 ++++++----- ethcore/src/blockchain/update.rs | 2 - ethcore/src/client/client.rs | 65 +++--- ethcore/src/client/test_client.rs | 3 +- ethcore/src/client/traits.rs | 2 +- ethcore/src/engines/validator_set/contract.rs | 2 +- .../engines/validator_set/safe_contract.rs | 10 +- ethcore/src/header.rs | 193 +++++++++++------- ethcore/src/miner/miner.rs | 4 +- ethcore/src/snapshot/block.rs | 3 +- ethcore/src/snapshot/consensus/authority.rs | 4 +- ethcore/src/snapshot/consensus/work.rs | 9 +- ethcore/src/snapshot/mod.rs | 10 +- ethcore/src/tests/client.rs | 2 +- ethcore/src/verification/verification.rs | 8 +- rpc/src/v1/impls/eth.rs | 4 +- sync/src/chain.rs | 2 +- 20 files changed, 299 insertions(+), 232 deletions(-) diff --git a/ethcore/light/src/on_demand/tests.rs b/ethcore/light/src/on_demand/tests.rs index 999f2e669a..95aec273f8 100644 --- a/ethcore/light/src/on_demand/tests.rs +++ b/ethcore/light/src/on_demand/tests.rs @@ -17,8 +17,7 @@ //! Tests for the on-demand service. use cache::Cache; -use ethcore::encoded; -use ethcore::header::{Header, Seal}; +use ethcore::header::Header; use futures::Future; use network::{PeerId, NodeId}; use net::*; @@ -148,7 +147,7 @@ fn single_request() { }); let header = Header::default(); - let encoded = encoded::Header::new(header.rlp(Seal::With)); + let encoded = header.encoded(); let recv = harness.service.request_raw( &Context::NoOp, @@ -209,7 +208,7 @@ fn reassign() { }); let header = Header::default(); - let encoded = encoded::Header::new(header.rlp(Seal::With)); + let encoded = header.encoded(); let recv = harness.service.request_raw( &Context::NoOp, @@ -257,7 +256,7 @@ fn partial_response() { let mut hdr = Header::default(); hdr.set_number(num); - let encoded = encoded::Header::new(hdr.rlp(Seal::With)); + let encoded = hdr.encoded(); (hdr, encoded) }; @@ -316,7 +315,7 @@ fn part_bad_part_good() { let mut hdr = Header::default(); hdr.set_number(num); - let encoded = encoded::Header::new(hdr.rlp(Seal::With)); + let encoded = hdr.encoded(); (hdr, encoded) }; @@ -413,7 +412,7 @@ fn back_references() { }); let header = Header::default(); - let encoded = encoded::Header::new(header.rlp(Seal::With)); + let encoded = header.encoded(); let recv = harness.service.request_raw( &Context::NoOp, @@ -470,7 +469,7 @@ fn fill_from_cache() { }); let header = Header::default(); - let encoded = encoded::Header::new(header.rlp(Seal::With)); + let encoded = header.encoded(); let recv = harness.service.request_raw( &Context::NoOp, diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index a0318d3e18..f8ccb91964 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -31,7 +31,7 @@ use vm::{EnvInfo, LastHashes}; use engines::EthEngine; use error::{Error, BlockError}; use factory::Factories; -use header::{Header, Seal}; +use header::Header; use receipt::{Receipt, TransactionOutcome}; use state::State; use state_db::StateDB; @@ -57,10 +57,10 @@ impl Block { UntrustedRlp::new(b).as_val::().is_ok() } - /// Get the RLP-encoding of the block with or without the seal. - pub fn rlp_bytes(&self, seal: Seal) -> Bytes { + /// Get the RLP-encoding of the block with the seal. + pub fn rlp_bytes(&self) -> Bytes { let mut block_rlp = RlpStream::new_list(3); - self.header.stream_rlp(&mut block_rlp, seal); + block_rlp.append(&self.header); block_rlp.append_list(&self.transactions); block_rlp.append_list(&self.uncles); block_rlp.out() @@ -269,7 +269,6 @@ impl<'x> OpenBlock<'x> { r.block.header.set_author(author); r.block.header.set_timestamp_now(parent.timestamp()); r.block.header.set_extra_data(extra_data); - r.block.header.note_dirty(); let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit); let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target); @@ -284,7 +283,9 @@ impl<'x> OpenBlock<'x> { } /// Alter the timestamp of the block. - pub fn set_timestamp(&mut self, timestamp: u64) { self.block.header.set_timestamp(timestamp); } + pub fn set_timestamp(&mut self, timestamp: u64) { + self.block.header.set_timestamp(timestamp); + } /// Removes block gas limit. pub fn remove_gas_limit(&mut self) { @@ -374,8 +375,11 @@ impl<'x> OpenBlock<'x> { s.block.header.set_uncles_hash(keccak(&uncle_bytes)); s.block.header.set_state_root(s.block.state.root().clone()); s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes()))); - s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator - s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used)); + s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| { + b.accrue_bloom(&r.log_bloom); + b + })); + s.block.header.set_gas_used(s.block.receipts.last().map_or_else(U256::zero, |r| r.gas_used)); ClosedBlock { block: s.block, @@ -395,6 +399,7 @@ impl<'x> OpenBlock<'x> { if let Err(e) = s.block.state.commit() { warn!("Encountered error on state commit: {}", e); } + if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP { s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes()))); } @@ -407,8 +412,11 @@ impl<'x> OpenBlock<'x> { } s.block.header.set_state_root(s.block.state.root().clone()); - s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator - s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used)); + s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| { + b.accrue_bloom(&r.log_bloom); + b + })); + s.block.header.set_gas_used(s.block.receipts.last().map_or_else(U256::zero, |r| r.gas_used)); LockedBlock { block: s.block, @@ -435,7 +443,7 @@ impl<'x> IsBlock for LockedBlock { impl ClosedBlock { /// Get the hash of the header without seal arguments. - pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) } + pub fn hash(&self) -> H256 { self.header().bare_hash() } /// Turn this into a `LockedBlock`, unable to be reopened again. pub fn lock(self) -> LockedBlock { @@ -459,7 +467,7 @@ impl ClosedBlock { impl LockedBlock { /// Get the hash of the header without seal arguments. - pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) } + pub fn hash(&self) -> H256 { self.header().bare_hash() } /// Provide a valid seal in order to turn this into a `SealedBlock`. /// @@ -472,6 +480,7 @@ impl LockedBlock { Mismatch { expected: expected_seal_fields, found: seal.len() })); } s.block.header.set_seal(seal); + s.block.header.compute_hash(); Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) } @@ -485,6 +494,7 @@ impl LockedBlock { ) -> Result { let mut s = self; s.block.header.set_seal(seal); + s.block.header.compute_hash(); // TODO: passing state context to avoid engines owning it? match engine.verify_local_seal(&s.block.header) { @@ -492,16 +502,6 @@ impl LockedBlock { _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), } } - - /// Remove state root from transaction receipts to make them EIP-98 compatible. - pub fn strip_receipts(self) -> LockedBlock { - let mut block = self; - for receipt in &mut block.block.receipts { - receipt.outcome = TransactionOutcome::Unknown; - } - block.block.header.set_receipts_root(ordered_trie_root(block.block.receipts.iter().map(|r| r.rlp_bytes()))); - block - } } impl Drain for LockedBlock { @@ -515,7 +515,7 @@ impl SealedBlock { /// Get the RLP-encoding of the block. pub fn rlp_bytes(&self) -> Bytes { let mut block_rlp = RlpStream::new_list(3); - self.block.header.stream_rlp(&mut block_rlp, Seal::With); + block_rlp.append(&self.block.header); block_rlp.append_list(&self.block.transactions); block_rlp.append_raw(&self.uncle_bytes, 1); block_rlp.out() @@ -545,6 +545,7 @@ pub fn enact( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, + strip_receipts: bool, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { @@ -574,6 +575,12 @@ pub fn enact( b.push_uncle(u.clone())?; } + if strip_receipts { + for receipt in &mut b.block.receipts { + receipt.outcome = TransactionOutcome::Unknown; + } + } + Ok(b.close_and_lock()) } @@ -616,6 +623,8 @@ pub fn enact_verified( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, + // Remove state root from transaction receipts to make them EIP-98 compatible. + strip_receipts: bool, ) -> Result { let view = BlockView::new(&block.bytes); @@ -630,6 +639,7 @@ pub fn enact_verified( last_hashes, factories, is_epoch_begin, + strip_receipts, ) } diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index 1436ced275..d5a6ce91a4 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . use ethereum_types::{H256, U256}; -use bytes::Bytes; -use header::BlockNumber; +use encoded; +use header::{Header, BlockNumber}; /// Contains information on a best block that is specific to the consensus engine. /// @@ -24,18 +24,13 @@ use header::BlockNumber; /// combined difficulty (usually the block with the highest block number). /// /// Sometimes refered as 'latest block'. -#[derive(Default)] pub struct BestBlock { - /// Best block hash. - pub hash: H256, - /// Best block number. - pub number: BlockNumber, - /// Best block timestamp. - pub timestamp: u64, + /// Best block decoded header. + pub header: Header, + /// Best block uncompressed bytes. + pub block: encoded::Block, /// Best block total difficulty. pub total_difficulty: U256, - /// Best block uncompressed bytes - pub block: Bytes, } /// Best ancient block info. If the blockchain has a gap this keeps track of where it starts. diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 86a1c522a1..ae5ac18eb9 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -90,11 +90,6 @@ pub trait BlockProvider { /// Get receipts of block with given hash. fn block_receipts(&self, hash: &H256) -> Option; - /// Get the partial-header of a block. - fn block_header(&self, hash: &H256) -> Option
{ - self.block_header_data(hash).map(|header| header.decode()) - } - /// Get the header RLP of a block. fn block_header_data(&self, hash: &H256) -> Option; @@ -115,7 +110,7 @@ pub trait BlockProvider { /// Get the number of given block's hash. fn block_number(&self, hash: &H256) -> Option { - self.block_details(hash).map(|details| details.number) + self.block_header_data(hash).map(|header| header.number()) } /// Get transaction with given transaction hash. @@ -144,8 +139,8 @@ pub trait BlockProvider { } /// Returns the header of the genesis block. - fn genesis_header(&self) -> Header { - self.block_header(&self.genesis_hash()) + fn genesis_header(&self) -> encoded::Header { + self.block_header_data(&self.genesis_hash()) .expect("Genesis header always stored; qed") } @@ -193,8 +188,8 @@ pub struct BlockChain { first_block: Option, // block cache - block_headers: RwLock>, - block_bodies: RwLock>, + block_headers: RwLock>, + block_bodies: RwLock>, // extra caches block_details: RwLock>, @@ -251,17 +246,15 @@ impl BlockProvider for BlockChain { { let read = self.block_headers.read(); if let Some(v) = read.get(hash) { - return Some(encoded::Header::new(v.clone())); + return Some(v.clone()); } } // Check if it's the best block { let best_block = self.best_block.read(); - if &best_block.hash == hash { - return Some(encoded::Header::new( - Rlp::new(&best_block.block).at(0).as_raw().to_vec() - )) + if &best_block.header.hash() == hash { + return Some(best_block.header.encoded()) } } @@ -269,12 +262,12 @@ impl BlockProvider for BlockChain { let b = self.db.get(db::COL_HEADERS, hash) .expect("Low level database error. Some issue with disk?")?; - let bytes = decompress(&b, blocks_swapper()).into_vec(); + let header = encoded::Header::new(decompress(&b, blocks_swapper()).into_vec()); let mut write = self.block_headers.write(); - write.insert(*hash, bytes.clone()); + write.insert(*hash, header.clone()); self.cache_man.lock().note_used(CacheId::BlockHeader(*hash)); - Some(encoded::Header::new(bytes)) + Some(header) } /// Get block body data @@ -283,15 +276,15 @@ impl BlockProvider for BlockChain { { let read = self.block_bodies.read(); if let Some(v) = read.get(hash) { - return Some(encoded::Body::new(v.clone())); + return Some(v.clone()); } } // Check if it's the best block { let best_block = self.best_block.read(); - if &best_block.hash == hash { - return Some(encoded::Body::new(Self::block_to_body(&best_block.block))); + if &best_block.header.hash() == hash { + return Some(encoded::Body::new(Self::block_to_body(best_block.block.rlp().as_raw()))); } } @@ -299,12 +292,12 @@ impl BlockProvider for BlockChain { let b = self.db.get(db::COL_BODIES, hash) .expect("Low level database error. Some issue with disk?")?; - let bytes = decompress(&b, blocks_swapper()).into_vec(); + let body = encoded::Body::new(decompress(&b, blocks_swapper()).into_vec()); let mut write = self.block_bodies.write(); - write.insert(*hash, bytes.clone()); + write.insert(*hash, body.clone()); self.cache_man.lock().note_used(CacheId::BlockBody(*hash)); - Some(encoded::Body::new(bytes)) + Some(body) } /// Get the familial details concerning a block. @@ -476,7 +469,12 @@ impl BlockChain { elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX, }, first_block: None, - best_block: RwLock::new(BestBlock::default()), + best_block: RwLock::new(BestBlock { + // BestBlock will be overwritten anyway. + header: Default::default(), + total_difficulty: Default::default(), + block: encoded::Block::new(genesis.into()), + }), best_ancient_block: RwLock::new(None), block_headers: RwLock::new(HashMap::new()), block_bodies: RwLock::new(HashMap::new()), @@ -527,11 +525,21 @@ impl BlockChain { { // Fetch best block details - let best_block_number = bc.block_number(&best_block_hash).unwrap(); let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty; - let best_block_rlp = bc.block(&best_block_hash).unwrap().into_inner(); - let best_block_timestamp = BlockView::new(&best_block_rlp).header().timestamp(); + let best_block_rlp = bc.block(&best_block_hash).unwrap(); + // and write them + let mut best_block = bc.best_block.write(); + *best_block = BestBlock { + total_difficulty: best_block_total_difficulty, + header: best_block_rlp.decode_header(), + block: best_block_rlp, + }; + } + + { + let best_block_number = bc.best_block.read().header.number(); + // Fetch first and best ancient block details let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.into_vec()); let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h)); let best_ancient_number; @@ -574,15 +582,6 @@ impl BlockChain { } // and write them - let mut best_block = bc.best_block.write(); - *best_block = BestBlock { - number: best_block_number, - total_difficulty: best_block_total_difficulty, - hash: best_block_hash, - timestamp: best_block_timestamp, - block: best_block_rlp, - }; - if let (Some(hash), Some(number)) = (best_ancient, best_ancient_number) { let mut best_ancient_block = bc.best_ancient_block.write(); *best_ancient_block = Some(BestAncientBlock { @@ -737,7 +736,6 @@ impl BlockChain { blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), info: info, - timestamp: header.timestamp(), block: bytes }, is_best); @@ -786,7 +784,6 @@ impl BlockChain { blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), info: info, - timestamp: header.timestamp(), block: bytes, }, is_best); true @@ -936,7 +933,6 @@ impl BlockChain { blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), info: info.clone(), - timestamp: header.timestamp(), block: bytes, }, true); @@ -1028,12 +1024,11 @@ impl BlockChain { let mut best_block = self.pending_best_block.write(); if is_best && update.info.location != BlockLocation::Branch { batch.put(db::COL_EXTRA, b"best", &update.info.hash); + let block = encoded::Block::new(update.block.to_vec()); *best_block = Some(BestBlock { - hash: update.info.hash, - number: update.info.number, total_difficulty: update.info.total_difficulty, - timestamp: update.timestamp, - block: update.block.to_vec(), + header: block.decode_header(), + block, }); } @@ -1105,8 +1100,9 @@ impl BlockChain { } /// Given a block's `parent`, find every block header which represents a valid possible uncle. - pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { - self.find_uncle_hashes(parent, uncle_generations).map(|v| v.into_iter().filter_map(|h| self.block_header(&h)).collect()) + pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { + self.find_uncle_hashes(parent, uncle_generations) + .map(|v| v.into_iter().filter_map(|h| self.block_header_data(&h)).collect()) } /// Given a block's `parent`, find every block hash which represents a valid possible uncle. @@ -1307,17 +1303,17 @@ impl BlockChain { /// Get best block hash. pub fn best_block_hash(&self) -> H256 { - self.best_block.read().hash + self.best_block.read().header.hash() } /// Get best block number. pub fn best_block_number(&self) -> BlockNumber { - self.best_block.read().number + self.best_block.read().header.number() } /// Get best block timestamp. pub fn best_block_timestamp(&self) -> u64 { - self.best_block.read().timestamp + self.best_block.read().header.timestamp() } /// Get best block total difficulty. @@ -1326,10 +1322,8 @@ impl BlockChain { } /// Get best block header - pub fn best_block_header(&self) -> encoded::Header { - let block = self.best_block.read(); - let raw = BlockView::new(&block.block).header_view().rlp().as_raw().to_vec(); - encoded::Header::new(raw) + pub fn best_block_header(&self) -> Header { + self.best_block.read().header.clone() } /// Get current cache size. @@ -1402,12 +1396,12 @@ impl BlockChain { let best_block = self.best_block.read(); let best_ancient_block = self.best_ancient_block.read(); BlockChainInfo { - total_difficulty: best_block.total_difficulty.clone(), - pending_total_difficulty: best_block.total_difficulty.clone(), + total_difficulty: best_block.total_difficulty, + pending_total_difficulty: best_block.total_difficulty, genesis_hash: self.genesis_hash(), - best_block_hash: best_block.hash, - best_block_number: best_block.number, - best_block_timestamp: best_block.timestamp, + best_block_hash: best_block.header.hash(), + best_block_number: best_block.header.number(), + best_block_timestamp: best_block.header.timestamp(), first_block_hash: self.first_block(), first_block_number: From::from(self.first_block_number()), ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash), @@ -1539,7 +1533,11 @@ mod tests { let b4b = b3a.add_block_with_difficulty(9); let b5b = b4a.add_block_with_difficulty(9); - let uncle_headers = vec![b4b.last().header(), b3b.last().header(), b2b.last().header()]; + let uncle_headers = vec![ + b4b.last().header().encoded(), + b3b.last().header().encoded(), + b2b.last().header().encoded(), + ]; let b4a_hash = b4a.last().hash(); let generator = BlockGenerator::new( @@ -1862,10 +1860,10 @@ mod tests { assert_eq!(bc.best_block_number(), 2999); let best_hash = bc.best_block_hash(); - let mut block_header = bc.block_header(&best_hash); + let mut block_header = bc.block_header_data(&best_hash); while !block_header.is_none() { - block_header = bc.block_header(block_header.unwrap().parent_hash()); + block_header = bc.block_header_data(&block_header.unwrap().parent_hash()); } assert!(bc.cache_size().blocks > 1024 * 1024); diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 467ccc8d17..a5251c1ed8 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -9,8 +9,6 @@ use blooms::{BloomGroup, GroupPosition}; pub struct ExtrasUpdate<'a> { /// Block info. pub info: BlockInfo, - /// Block timestamp. - pub timestamp: u64, /// Current block uncompressed rlp bytes pub block: &'a [u8], /// Modified block hashes. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c4c2b6a2ee..c7ad18dcbd 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -362,16 +362,15 @@ impl Importer { let engine = &*self.engine; let header = &block.header; - let chain = client.chain.read(); // Check the block isn't so old we won't be able to enact it. - let best_block_number = chain.best_block_number(); + let best_block_number = client.chain.read().best_block_number(); if client.pruning_info().earliest_state > header.number() { warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number); return Err(()); } // Check if parent is in chain - let parent = match chain.block_header(header.parent_hash()) { + let parent = match client.block_header_decoded(BlockId::Hash(*header.parent_hash())) { Some(h) => h, None => { warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash()); @@ -379,6 +378,7 @@ impl Importer { } }; + let chain = client.chain.read(); // Verify Block Family let verify_family_result = self.verifier.verify_block_family( header, @@ -408,6 +408,7 @@ impl Importer { let db = client.state_db.read().boxed_clone_canon(header.parent_hash()); let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some(); + let strip_receipts = header.number() < engine.params().validate_receipts_transition; let enact_result = enact_verified(block, engine, client.tracedb.read().tracing_enabled(), @@ -416,15 +417,13 @@ impl Importer { last_hashes, client.factories.clone(), is_epoch_begin, + strip_receipts, ); - let mut locked_block = enact_result.map_err(|e| { + + let locked_block = enact_result.map_err(|e| { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); })?; - if header.number() < engine.params().validate_receipts_transition && header.receipts_root() != locked_block.block().header().receipts_root() { - locked_block = locked_block.strip_receipts(); - } - // Final Verification if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) { warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); @@ -655,7 +654,7 @@ impl Importer { fn check_epoch_end<'a>(&self, header: &'a Header, chain: &BlockChain, client: &Client) { let is_epoch_end = self.engine.is_epoch_end( header, - &(|hash| chain.block_header(&hash)), + &(|hash| client.block_header_decoded(BlockId::Hash(hash))), &(|hash| chain.get_pending_transition(hash)), // TODO: limit to current epoch. ); @@ -724,7 +723,7 @@ impl Client { config.history }; - if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.journal_db().contains(h.state_root())) { + if !chain.block_header_data(&chain.best_block_hash()).map_or(true, |h| state_db.journal_db().contains(&h.state_root())) { warn!("State root not found for block #{} ({:x})", chain.best_block_number(), chain.best_block_hash()); } @@ -1000,7 +999,7 @@ impl Client { let header = self.best_block_header(); State::from_existing( self.state_db.read().boxed_clone_canon(&header.hash()), - header.state_root(), + *header.state_root(), self.engine.account_start_nonce(header.number()), self.factories.clone() ) @@ -1260,6 +1259,23 @@ impl Client { BlockId::Latest => Some(self.chain.read().best_block_number()), } } + + /// Retrieve a decoded header given `BlockId` + /// + /// This method optimizes access patterns for latest block header + /// to avoid excessive RLP encoding, decoding and hashing. + fn block_header_decoded(&self, id: BlockId) -> Option
{ + match id { + BlockId::Latest + => Some(self.chain.read().best_block_header()), + BlockId::Hash(ref hash) if hash == &self.chain.read().best_block_hash() + => Some(self.chain.read().best_block_header()), + BlockId::Number(number) if number == self.chain.read().best_block_number() + => Some(self.chain.read().best_block_header()), + _ + => self.block_header(id).map(|h| h.decode()), + } + } } impl snapshot::DatabaseRestore for Client { @@ -1315,16 +1331,14 @@ impl BlockInfo for Client { Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash)) } - fn best_block_header(&self) -> encoded::Header { + fn best_block_header(&self) -> Header { self.chain.read().best_block_header() } fn block(&self, id: BlockId) -> Option { let chain = self.chain.read(); - Self::block_hash(&chain, id).and_then(|hash| { - chain.block(&hash) - }) + Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash)) } fn code_hash(&self, address: &Address, id: BlockId) -> Option { @@ -1360,11 +1374,11 @@ impl CallContract for Client { fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result { let state_pruned = || CallError::StatePruned.to_string(); let state = &mut self.state_at(block_id).ok_or_else(&state_pruned)?; - let header = self.block_header(block_id).ok_or_else(&state_pruned)?; + let header = self.block_header_decoded(block_id).ok_or_else(&state_pruned)?; let transaction = self.contract_call_tx(block_id, address, data); - self.call(&transaction, Default::default(), state, &header.decode()) + self.call(&transaction, Default::default(), state, &header) .map_err(|e| format!("{:?}", e)) .map(|executed| executed.output) } @@ -1918,8 +1932,8 @@ impl BlockChainClient for Client { } fn block_extra_info(&self, id: BlockId) -> Option> { - self.block_header(id) - .map(|header| self.engine.extra_info(&header.decode())) + self.block_header_decoded(id) + .map(|header| self.engine.extra_info(&header)) } fn uncle_extra_info(&self, id: UncleId) -> Option> { @@ -1973,8 +1987,8 @@ impl ReopenBlock for Client { for h in uncles { if !block.uncles().iter().any(|header| header.hash() == h) { - let uncle = chain.block_header(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed"); - block.push_uncle(uncle).expect("pushing up to maximum_uncle_count; + let uncle = chain.block_header_data(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed"); + block.push_uncle(uncle.decode()).expect("pushing up to maximum_uncle_count; push_uncle is not ok only if more than maximum_uncle_count is pushed; so all push_uncle are Ok; qed"); @@ -1991,9 +2005,8 @@ impl PrepareOpenBlock for Client { fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { let engine = &*self.engine; let chain = self.chain.read(); - let h = chain.best_block_hash(); - let best_header = &chain.block_header(&h) - .expect("h is best block hash: so its header must exist: qed"); + let best_header = chain.best_block_header(); + let h = best_header.hash(); let is_epoch_begin = chain.epoch_transition(best_header.number(), h).is_some(); let mut open_block = OpenBlock::new( @@ -2001,7 +2014,7 @@ impl PrepareOpenBlock for Client { self.factories.clone(), self.tracedb.read().tracing_enabled(), self.state_db.read().boxed_clone_canon(&h), - best_header, + &best_header, self.build_last_hashes(&h), author, gas_range_target, @@ -2016,7 +2029,7 @@ impl PrepareOpenBlock for Client { .into_iter() .take(engine.maximum_uncle_count(open_block.header().number())) .foreach(|h| { - open_block.push_uncle(h).expect("pushing maximum_uncle_count; + open_block.push_uncle(h.decode()).expect("pushing maximum_uncle_count; open_block was just created; push_uncle is not ok only if more than maximum_uncle_count is pushed; so all push_uncle are Ok; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 3c48b2a3e9..eed6c5e5b5 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -474,9 +474,10 @@ impl BlockInfo for TestBlockChainClient { .map(encoded::Header::new) } - fn best_block_header(&self) -> encoded::Header { + fn best_block_header(&self) -> Header { self.block_header(BlockId::Hash(self.chain_info().best_block_hash)) .expect("Best block always has header.") + .decode() } fn block(&self, id: BlockId) -> Option { diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 1228f87683..901ba30db3 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -121,7 +121,7 @@ pub trait BlockInfo { fn block_header(&self, id: BlockId) -> Option; /// Get the best block header. - fn best_block_header(&self) -> encoded::Header; + fn best_block_header(&self) -> Header; /// Get raw block data by block header hash. fn block(&self, id: BlockId) -> Option; diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index 0e27d594d5..319d96db93 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -201,7 +201,7 @@ mod tests { "0000000000000000000000007d577a597b2742b498cb5cf0c26cdcd726d39e6e" ); // Simulate a misbehaving validator by handling a double proposal. - let header = client.best_block_header().decode(); + let header = client.best_block_header(); assert!(client.engine().verify_block_family(&header, &header).is_err()); // Seal a block. client.engine().step(); diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 490a762a61..668feac26f 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -20,7 +20,7 @@ use std::sync::{Weak, Arc}; use hash::keccak; use ethereum_types::{H256, U256, Address, Bloom}; -use parking_lot::{Mutex, RwLock}; +use parking_lot::RwLock; use bytes::Bytes; use memory_cache::MemoryLruCache; @@ -53,19 +53,19 @@ lazy_static! { // only "first" proofs are such. struct StateProof { contract_address: Address, - header: Mutex
, + header: Header, provider: validator_set::ValidatorSet, } impl ::engines::StateDependentProof for StateProof { fn generate_proof(&self, caller: &Call) -> Result, String> { - prove_initial(&self.provider, self.contract_address, &*self.header.lock(), caller) + prove_initial(&self.provider, self.contract_address, &self.header, caller) } fn check_proof(&self, machine: &EthereumMachine, 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(){ + if &header != &self.header { return Err("wrong header in proof".into()); } @@ -325,7 +325,7 @@ impl ValidatorSet for ValidatorSafeContract { debug!(target: "engine", "signalling transition to fresh contract."); let state_proof = Arc::new(StateProof { contract_address: self.contract_address, - header: Mutex::new(header.clone()), + header: header.clone(), provider: validator_set::ValidatorSet::default(), }); return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>)); diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 7980da2788..80f1646ad8 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -17,7 +17,6 @@ //! Block header. use std::cmp; -use std::cell::RefCell; use std::time::{SystemTime, UNIX_EPOCH}; use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak}; use heapsize::HeapSizeOf; @@ -28,7 +27,8 @@ use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable}; pub use types::BlockNumber; /// Semantic boolean for when a seal/signature is included. -pub enum Seal { +#[derive(Debug, Clone, Copy)] +enum Seal { /// The seal/signature is included. With, /// The seal/signature is not included. @@ -75,14 +75,18 @@ pub struct Header { /// Vector of post-RLP-encoded fields. seal: Vec, - /// The memoized hash of the RLP representation *including* the seal fields. - hash: RefCell>, - /// The memoized hash of the RLP representation *without* the seal fields. - bare_hash: RefCell>, + /// Memoized hash of that header and the seal. + hash: Option, } impl PartialEq for Header { fn eq(&self, c: &Header) -> bool { + if let (&Some(ref h1), &Some(ref h2)) = (&self.hash, &c.hash) { + if h1 == h2 { + return true + } + } + self.parent_hash == c.parent_hash && self.timestamp == c.timestamp && self.number == c.number && @@ -120,51 +124,57 @@ impl Default for Header { difficulty: U256::default(), seal: vec![], - hash: RefCell::new(None), - bare_hash: RefCell::new(None), + hash: None, } } } impl Header { /// Create a new, default-valued, header. - pub fn new() -> Self { - Self::default() - } + pub fn new() -> Self { Self::default() } /// Get the parent_hash field of the header. pub fn parent_hash(&self) -> &H256 { &self.parent_hash } + /// Get the timestamp field of the header. pub fn timestamp(&self) -> u64 { self.timestamp } + /// Get the number field of the header. pub fn number(&self) -> BlockNumber { self.number } + /// Get the author field of the header. pub fn author(&self) -> &Address { &self.author } /// Get the extra data field of the header. pub fn extra_data(&self) -> &Bytes { &self.extra_data } - /// Get a mutable reference to extra_data - pub fn extra_data_mut(&mut self) -> &mut Bytes { self.note_dirty(); &mut self.extra_data } /// Get the state root field of the header. pub fn state_root(&self) -> &H256 { &self.state_root } + /// Get the receipts root field of the header. pub fn receipts_root(&self) -> &H256 { &self.receipts_root } + /// Get the log bloom field of the header. pub fn log_bloom(&self) -> &Bloom { &self.log_bloom } + /// Get the transactions root field of the header. pub fn transactions_root(&self) -> &H256 { &self.transactions_root } + /// Get the uncles hash field of the header. pub fn uncles_hash(&self) -> &H256 { &self.uncles_hash } + /// Get the gas used field of the header. pub fn gas_used(&self) -> &U256 { &self.gas_used } + /// Get the gas limit field of the header. pub fn gas_limit(&self) -> &U256 { &self.gas_limit } /// Get the difficulty field of the header. pub fn difficulty(&self) -> &U256 { &self.difficulty } + /// Get the seal field of the header. pub fn seal(&self) -> &[Bytes] { &self.seal } + /// Get the seal field with RLP-decoded values as bytes. pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(&'a self) -> Result { self.seal.iter().map(|rlp| { @@ -172,78 +182,126 @@ impl Header { }).collect() } - // TODO: seal_at, set_seal_at &c. + /// Get a mutable reference to extra_data + #[cfg(test)] + pub fn extra_data_mut(&mut self) -> &mut Bytes { + self.hash = None; + &mut self.extra_data + } /// Set the number field of the header. - pub fn set_parent_hash(&mut self, a: H256) { self.parent_hash = a; self.note_dirty(); } + pub fn set_parent_hash(&mut self, a: H256) { + change_field(&mut self.hash, &mut self.parent_hash, a); + } + /// Set the uncles hash field of the header. - pub fn set_uncles_hash(&mut self, a: H256) { self.uncles_hash = a; self.note_dirty(); } + pub fn set_uncles_hash(&mut self, a: H256) { + change_field(&mut self.hash, &mut self.uncles_hash, a); + + } /// Set the state root field of the header. - pub fn set_state_root(&mut self, a: H256) { self.state_root = a; self.note_dirty(); } + pub fn set_state_root(&mut self, a: H256) { + change_field(&mut self.hash, &mut self.state_root, a); + } + /// Set the transactions root field of the header. - pub fn set_transactions_root(&mut self, a: H256) { self.transactions_root = a; self.note_dirty() } + pub fn set_transactions_root(&mut self, a: H256) { + change_field(&mut self.hash, &mut self.transactions_root, a); + } + /// Set the receipts root field of the header. - pub fn set_receipts_root(&mut self, a: H256) { self.receipts_root = a; self.note_dirty() } + pub fn set_receipts_root(&mut self, a: H256) { + change_field(&mut self.hash, &mut self.receipts_root, a); + } + /// Set the log bloom field of the header. - pub fn set_log_bloom(&mut self, a: Bloom) { self.log_bloom = a; self.note_dirty() } + pub fn set_log_bloom(&mut self, a: Bloom) { + change_field(&mut self.hash, &mut self.log_bloom, a); + } + /// Set the timestamp field of the header. - pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } + pub fn set_timestamp(&mut self, a: u64) { + change_field(&mut self.hash, &mut self.timestamp, a); + } + /// Set the timestamp field of the header to the current time. - pub fn set_timestamp_now(&mut self, but_later_than: u64) { let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default(); self.timestamp = cmp::max(now.as_secs() as u64, but_later_than + 1); self.note_dirty(); } + pub fn set_timestamp_now(&mut self, but_later_than: u64) { + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default(); + self.set_timestamp(cmp::max(now.as_secs() as u64, but_later_than + 1)); + } + /// Set the number field of the header. - pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } + pub fn set_number(&mut self, a: BlockNumber) { + change_field(&mut self.hash, &mut self.number, a); + } + /// Set the author field of the header. - pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } } + pub fn set_author(&mut self, a: Address) { + change_field(&mut self.hash, &mut self.author, a); + } /// Set the extra data field of the header. - pub fn set_extra_data(&mut self, a: Bytes) { if a != self.extra_data { self.extra_data = a; self.note_dirty(); } } + pub fn set_extra_data(&mut self, a: Bytes) { + change_field(&mut self.hash, &mut self.extra_data, a); + } /// Set the gas used field of the header. - pub fn set_gas_used(&mut self, a: U256) { self.gas_used = a; self.note_dirty(); } + pub fn set_gas_used(&mut self, a: U256) { + change_field(&mut self.hash, &mut self.gas_used, a); + } + /// Set the gas limit field of the header. - pub fn set_gas_limit(&mut self, a: U256) { self.gas_limit = a; self.note_dirty(); } + pub fn set_gas_limit(&mut self, a: U256) { + change_field(&mut self.hash, &mut self.gas_limit, a); + } /// Set the difficulty field of the header. - pub fn set_difficulty(&mut self, a: U256) { self.difficulty = a; self.note_dirty(); } + pub fn set_difficulty(&mut self, a: U256) { + change_field(&mut self.hash, &mut self.difficulty, a); + } + /// Set the seal field of the header. - pub fn set_seal(&mut self, a: Vec) { self.seal = a; self.note_dirty(); } + pub fn set_seal(&mut self, a: Vec) { + change_field(&mut self.hash, &mut self.seal, a) + } + + /// Get & memoize the hash of this header (keccak of the RLP with seal). + pub fn compute_hash(&mut self) -> H256 { + let hash = self.hash(); + self.hash = Some(hash); + hash + } - /// Get the hash of this header (keccak of the RLP). + /// Get the hash of this header (keccak of the RLP with seal). pub fn hash(&self) -> H256 { - let mut hash = self.hash.borrow_mut(); - match &mut *hash { - &mut Some(ref h) => h.clone(), - hash @ &mut None => { - let h = self.rlp_keccak(Seal::With); - *hash = Some(h.clone()); - h - } - } + self.hash.unwrap_or_else(|| keccak(self.rlp(Seal::With))) } /// Get the hash of the header excluding the seal pub fn bare_hash(&self) -> H256 { - let mut hash = self.bare_hash.borrow_mut(); - match &mut *hash { - &mut Some(ref h) => h.clone(), - hash @ &mut None => { - let h = self.rlp_keccak(Seal::Without); - *hash = Some(h.clone()); - h - } - } + keccak(self.rlp(Seal::Without)) } - /// Note that some fields have changed. Resets the memoised hash. - pub fn note_dirty(&self) { - *self.hash.borrow_mut() = None; - *self.bare_hash.borrow_mut() = None; + /// Encode the header, getting a type-safe wrapper around the RLP. + pub fn encoded(&self) -> ::encoded::Header { + ::encoded::Header::new(self.rlp(Seal::With)) + } + + /// Get the RLP representation of this Header. + fn rlp(&self, with_seal: Seal) -> Bytes { + let mut s = RlpStream::new(); + self.stream_rlp(&mut s, with_seal); + s.out() } - // TODO: make these functions traity /// Place this header into an RLP stream `s`, optionally `with_seal`. - pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) { - s.begin_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 }); + fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) { + if let Seal::With = with_seal { + s.begin_list(13 + self.seal.len()); + } else { + s.begin_list(13); + } + s.append(&self.parent_hash); s.append(&self.uncles_hash); s.append(&self.author); @@ -257,29 +315,24 @@ impl Header { s.append(&self.gas_used); s.append(&self.timestamp); s.append(&self.extra_data); + if let Seal::With = with_seal { for b in &self.seal { s.append_raw(b, 1); } } } +} - /// Get the RLP of this header, optionally `with_seal`. - pub fn rlp(&self, with_seal: Seal) -> Bytes { - let mut s = RlpStream::new(); - self.stream_rlp(&mut s, with_seal); - s.out() - } - - /// Get the SHA3 (Keccak) of this header, optionally `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)) +/// Alter value of given field, reset memoised hash if changed. +fn change_field(hash: &mut Option, field: &mut T, value: T) where T: PartialEq { + if field != &value { + *field = value; + *hash = None; } } + impl Decodable for Header { fn decode(r: &UntrustedRlp) -> Result { let mut blockheader = Header { @@ -297,8 +350,7 @@ impl Decodable for Header { timestamp: cmp::min(r.val_at::(11)?, u64::max_value().into()).as_u64(), extra_data: r.val_at(12)?, seal: vec![], - hash: RefCell::new(Some(keccak(r.as_raw()))), - bare_hash: RefCell::new(None), + hash: keccak(r.as_raw()).into(), }; for i in 13..r.item_count()? { @@ -376,3 +428,4 @@ mod tests { assert_eq!(header_rlp, encoded_header); } } + diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 58111cd741..b0628b3e0b 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -653,7 +653,7 @@ impl Miner { } fn update_gas_limit(&self, client: &C) { - let gas_limit = client.best_block_header().gas_limit(); + let gas_limit = *client.best_block_header().gas_limit(); let mut queue = self.transaction_queue.write(); queue.set_gas_limit(gas_limit); if let GasLimit::Auto = self.options.tx_queue_gas_limit { @@ -703,7 +703,7 @@ impl Miner { condition: Option, transaction_queue: &mut BanningTransactionQueue, ) -> Vec> { - let best_block_header = client.best_block_header().decode(); + let best_block_header = client.best_block_header(); let insertion_time = client.chain_info().best_block_number; let mut inserted = Vec::with_capacity(transactions.len()); diff --git a/ethcore/src/snapshot/block.rs b/ethcore/src/snapshot/block.rs index 98215b3244..aa946fd703 100644 --- a/ethcore/src/snapshot/block.rs +++ b/ethcore/src/snapshot/block.rs @@ -135,7 +135,6 @@ impl AbridgedBlock { mod tests { use views::BlockView; use block::Block; - use header::Seal; use super::AbridgedBlock; use transaction::{Action, Transaction}; @@ -143,7 +142,7 @@ mod tests { use bytes::Bytes; fn encode_block(b: &Block) -> Bytes { - b.rlp_bytes(Seal::With) + b.rlp_bytes() } #[test] diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index 46f433c005..d3184a0810 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -28,7 +28,7 @@ use blockchain::{BlockChain, BlockProvider}; use engines::{EthEngine, EpochVerifier, EpochTransition}; use machine::EthereumMachine; use ids::BlockId; -use header::{Header, Seal}; +use header::Header; use receipt::Receipt; use snapshot::{Error, ManifestData}; @@ -324,7 +324,7 @@ impl Rebuilder for ChunkRebuilder { transactions: last_rlp.list_at(1)?, uncles: last_rlp.list_at(2)?, }; - let block_data = block.rlp_bytes(Seal::With); + let block_data = block.rlp_bytes(); let receipts: Vec = last_rlp.list_at(3)?; { diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index 5b4ff48889..7f90e327c0 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -153,19 +153,19 @@ impl<'a> PowWorker<'a> { fn write_chunk(&mut self, last: H256) -> Result<(), Error> { trace!(target: "snapshot", "prepared block chunk with {} blocks", self.rlps.len()); - let (last_header, last_details) = self.chain.block_header(&last) + let (last_header, last_details) = self.chain.block_header_data(&last) .and_then(|n| self.chain.block_details(&last).map(|d| (n, d))) .ok_or(Error::BlockNotFound(last))?; let parent_number = last_header.number() - 1; let parent_hash = last_header.parent_hash(); - let parent_total_difficulty = last_details.total_difficulty - *last_header.difficulty(); + let parent_total_difficulty = last_details.total_difficulty - last_header.difficulty(); trace!(target: "snapshot", "parent last written block: {}", parent_hash); let num_entries = self.rlps.len(); let mut rlp_stream = RlpStream::new_list(3 + num_entries); - rlp_stream.append(&parent_number).append(parent_hash).append(&parent_total_difficulty); + rlp_stream.append(&parent_number).append(&parent_hash).append(&parent_total_difficulty); for pair in self.rlps.drain(..) { rlp_stream.append_raw(&pair, 1); @@ -220,7 +220,6 @@ impl Rebuilder for PowRebuilder { /// Feed the rebuilder an uncompressed block chunk. /// Returns the number of blocks fed or any errors. fn feed(&mut self, chunk: &[u8], engine: &EthEngine, abort_flag: &AtomicBool) -> Result<(), ::error::Error> { - use header::Seal; use views::BlockView; use snapshot::verify_old_block; use ethereum_types::U256; @@ -251,7 +250,7 @@ impl Rebuilder for PowRebuilder { let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw())); let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?; - let block_bytes = block.rlp_bytes(Seal::With); + let block_bytes = block.rlp_bytes(); let is_best = cur_number == self.best_number; if is_best { diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index f9a513dd17..6b751bf2c4 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -130,7 +130,7 @@ pub fn take_snapshot( writer: W, p: &Progress ) -> Result<(), Error> { - let start_header = chain.block_header(&block_at) + let start_header = chain.block_header_data(&block_at) .ok_or(Error::InvalidStartingBlock(BlockId::Hash(block_at)))?; let state_root = start_header.state_root(); let number = start_header.number(); @@ -143,7 +143,7 @@ pub fn take_snapshot( let (state_hashes, block_hashes) = scope(|scope| { let writer = &writer; let block_guard = scope.spawn(move || chunk_secondary(chunker, chain, block_at, writer, p)); - let state_res = chunk_state(state_db, state_root, writer, p); + let state_res = chunk_state(state_db, &state_root, writer, p); state_res.and_then(|state_hashes| { block_guard.join().map(|block_hashes| (state_hashes, block_hashes)) @@ -156,7 +156,7 @@ pub fn take_snapshot( version: snapshot_version, state_hashes: state_hashes, block_hashes: block_hashes, - state_root: *state_root, + state_root: state_root, block_number: number, block_hash: block_at, }; @@ -486,8 +486,8 @@ pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &EthEngine, ch if always || rng.gen::() <= POW_VERIFY_RATE { engine.verify_block_unordered(header)?; - match chain.block_header(header.parent_hash()) { - Some(parent) => engine.verify_block_family(header, &parent), + match chain.block_header_data(header.parent_hash()) { + Some(parent) => engine.verify_block_family(header, &parent.decode()), None => Ok(()), } } else { diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 2fee61412f..8091ae73e1 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -362,7 +362,7 @@ fn transaction_proof() { let mut factories = ::factory::Factories::default(); factories.accountdb = ::account_db::Factory::Plain; // raw state values, no mangled keys. - let root = client.best_block_header().state_root(); + let root = *client.best_block_header().state_root(); let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap(); Executive::new(&mut state, &client.latest_env_info(), test_spec.engine.machine()) diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index f78059ac8d..87ed04afd8 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -211,7 +211,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth // cB.p^7 -------------/ // cB.p^8 let mut expected_uncle_parent = header.parent_hash().clone(); - let uncle_parent = bc.block_header(&uncle.parent_hash()).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash().clone())))?; + let uncle_parent = bc.block_header_data(&uncle.parent_hash()).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash().clone())))?; for _ in 0..depth { match bc.block_details(&expected_uncle_parent) { Some(details) => { @@ -224,6 +224,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth return Err(From::from(BlockError::UncleParentNotInChain(uncle_parent.hash()))); } + let uncle_parent = uncle_parent.decode(); verify_parent(&uncle, &uncle_parent, engine.params().gas_limit_bound_divisor)?; engine.verify_block_family(&uncle, &uncle_parent)?; verified.insert(uncle.hash()); @@ -496,8 +497,9 @@ mod tests { // is fine. let client = ::client::TestBlockChainClient::default(); - let parent = bc.block_header(header.parent_hash()) - .ok_or(BlockError::UnknownParent(header.parent_hash().clone()))?; + let parent = bc.block_header_data(header.parent_hash()) + .ok_or(BlockError::UnknownParent(header.parent_hash().clone()))? + .decode(); let full_params = FullFamilyParams { block_bytes: bytes, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index bcfa59c7ee..4c48ccb616 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -30,7 +30,7 @@ use ethcore::block::IsBlock; use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo}; use ethcore::ethereum::Ethash; use ethcore::filter::Filter as EthcoreFilter; -use ethcore::header::{BlockNumber as EthBlockNumber, Seal}; +use ethcore::header::{BlockNumber as EthBlockNumber}; use ethcore::log_entry::LogEntry; use ethcore::miner::MinerService; use ethcore::snapshot::SnapshotService; @@ -199,7 +199,7 @@ impl EthClient { diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 305922d5af..9780245912 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1974,7 +1974,7 @@ impl ChainSync { fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize { trace!(target: "sync", "Sending NewHashes to {:?}", peers); let mut sent = 0; - let last_parent = &io.chain().best_block_header().parent_hash(); + let last_parent = *io.chain().best_block_header().parent_hash(); for peer_id in peers { sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) { Some(rlp) => { -- GitLab From 060205ab27aaea031b30160dde8968b5f5035c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 3 Apr 2018 12:43:34 +0200 Subject: [PATCH 022/263] Allow unsafe js eval on Parity Wallet. (#8204) --- dapps/src/apps/mod.rs | 40 ++++++++++++++++++++------------------- dapps/src/page/builtin.rs | 5 +++++ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/dapps/src/apps/mod.rs b/dapps/src/apps/mod.rs index c065a08474..0b8865e76f 100644 --- a/dapps/src/apps/mod.rs +++ b/dapps/src/apps/mod.rs @@ -23,7 +23,6 @@ use page; use proxypac::ProxyPac; use web::Web; use fetch::Fetch; -use parity_dapps::WebApp; use parity_ui; use {WebProxyTokens, ParentFrameSettings}; @@ -76,25 +75,28 @@ pub fn all_endpoints( } // NOTE [ToDr] Dapps will be currently embeded on 8180 - insert::(&mut pages, "ui", Embeddable::Yes(embeddable.clone()), pool.clone()); + pages.insert( + "ui".into(), + Box::new(page::builtin::Dapp::new_safe_to_embed(pool.clone(), parity_ui::App::default(), embeddable.clone())) + ); // old version - insert::(&mut pages, "v1", Embeddable::Yes(embeddable.clone()), pool.clone()); - - pages.insert("proxy".into(), ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned())); - pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), fetch.clone(), pool.clone())); + pages.insert( + "v1".into(), + Box::new({ + let mut page = page::builtin::Dapp::new_safe_to_embed(pool.clone(), parity_ui::old::App::default(), embeddable.clone()); + // allow JS eval on old Wallet + page.allow_js_eval(); + page + }) + ); + pages.insert( + "proxy".into(), + ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()) + ); + pages.insert( + WEB_PATH.into(), + Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), fetch.clone(), pool.clone()) + ); (local_endpoints, pages) } - -fn insert(pages: &mut Endpoints, id: &str, embed_at: Embeddable, pool: CpuPool) { - pages.insert(id.to_owned(), Box::new(match embed_at { - Embeddable::Yes(address) => page::builtin::Dapp::new_safe_to_embed(pool, T::default(), address), - Embeddable::No => page::builtin::Dapp::new(pool, T::default()), - })); -} - -enum Embeddable { - Yes(Option), - #[allow(dead_code)] - No, -} diff --git a/dapps/src/page/builtin.rs b/dapps/src/page/builtin.rs index 827fe27a3b..150cfe8642 100644 --- a/dapps/src/page/builtin.rs +++ b/dapps/src/page/builtin.rs @@ -75,6 +75,11 @@ impl Dapp { fallback_to_index_html: false, } } + + /// Allow the dapp to use `unsafe-eval` to run JS. + pub fn allow_js_eval(&mut self) { + self.info.allow_js_eval = Some(true); + } } impl Endpoint for Dapp { -- GitLab From 99a13c4e660ac0eb2afb3dbc6aa6f0e96d38f2b3 Mon Sep 17 00:00:00 2001 From: ellaismer <31844524+ellaismer@users.noreply.github.com> Date: Tue, 3 Apr 2018 08:58:24 -0400 Subject: [PATCH 023/263] Cleanup Ellaism bootnodes (#8276) Removed several bootnodes known not to be running anymore. Added two new ones. --- ethcore/res/ethereum/ellaism.json | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ethcore/res/ethereum/ellaism.json b/ethcore/res/ethereum/ellaism.json index 3036992eb7..3650e68df5 100644 --- a/ethcore/res/ethereum/ellaism.json +++ b/ethcore/res/ethereum/ellaism.json @@ -46,21 +46,14 @@ "gasLimit": "0x1388" }, "nodes": [ - "enode://98b48cc7149326d00a57994ad55014a095a3e5cd4f0144cd7b034fb667d8e8017082bd90047d72c4403798b8ece11a33bd2e344d6500faba30889ebcfa5316fa@172.104.163.204:30303", + "enode://0d88e242aa0b01ee306ca43e956174677c96ec8eba4197f4d8be6fd7d4f2e57731e95d533b88229b66eb1a44399d870e99b7a4fe6547c8c80cdf00407a986e14@94.130.237.158:30303", + "enode://4be9e419d3efb0214faf3ef1794a0c33ebbd7633ece734a0a956faa166fefc496b2692a2a485adc66af805e461ba3e12f8d3941ec207e56bb9f3d3626787a705@94.130.237.158:60606", "enode://834246cc2a7584df29ccdcf3b5366f118a0e291264980376769e809665a02c4caf0d68c43eecf8390dbeaf861823b05583807af0a62542a1f3f717046b958a76@45.77.106.33:30303", - "enode://d1373d7187a20d695220fafb5746a289786bad92469d6bbe800f07572f8f444479f507cfcb8fcd8f5bee5dd44efb6185df4a1e4f1a7170408ada9876ef5b3fe4@178.79.189.58:30303", "enode://d8059dcb137cb52b8960ca82613eeba1d121105572decd8f1d3ea22b09070645eeab548d2a3cd2914f206e1331c7870bd2bd5a231ebac6b3d4886ec3b8e627e5@173.212.216.105:30303", - "enode://5a89c8664d29a321fd4cb1b55b0f0be832ce376b5e7feb14a2073fdbd9bd7b7394169ed289dd991112b42ecfb74ea36e436bc72a1c99dcdb50d96eaf3b0ed254@213.136.91.42:30303", "enode://9215ad77bd081e35013cb42a8ceadff9d8e94a78fcc680dff1752a54e7484badff0904e331c4b40a68be593782e55acfd800f076d22f9d2832e8483733ade149@213.14.82.125:30303", - "enode://07913818dafbadf44d4fc796fa414ec1d720ecfb087eff37efbe7134556658e92351559de788fa319c291e40b915cc26d902069d03bd935553d4efa688bdbbf8@45.32.19.37:30303", - "enode://645a59b6e6e20ed8864767a1d0c731f89ae276ed4e04c4f10becce655532d95cbe1bc9e2da3f13a6564f9ca8fe46fab2781a380b3a89148bccac883d6068f684@45.77.159.123:30303", - "enode://7c2f43b2e7fded9469917311574d267427e62cd12e1864effd15f31c1246e4e955463d843acaa37309693a515df7986cb6d160b7e85a4ca2779a798a72d90850@108.61.194.191:30303", "enode://5dd35866da95aea15211fb1f98684f6e8c4e355e6aa3cc17585680ed53fa164477b8c52cb6ca4b24ec4d80f3d48ff9212b53feb131d825c7945a3abaaf02d24d@178.79.189.58:60606", "enode://6c585c18024eb902ca093278af73b04863ac904caabc39ac2920c23532307c572ad92afd828a990c980d272b1f26307f2409cc97aec3ff9fe866732cae49a8c2@144.217.163.224:31337", "enode://edd90c4cc64528802ad52fd127d80b641ff80fd43fa5292fb111c8bd2914482dffee288fd1b0d26440c6b2c669b10a53cbcd37c895ba0d6194110e100a965b2d@188.166.179.159:30303", - "enode://d19783546438e8bfc11a35457ff1f47871a2ce4801b9b2dbe7606321a9ce29007305497eb8c98d7ae9dc5a913ee5533c3691b1080f7066697c4276e6140d2eac@45.77.47.184:30303", - "enode://13ed57615447bc9bf1da4e28249369babc00d2530d6c103c12350453e469a5e90cbcdb787c436977467f5864be6e64f2520180fc60b841c8c3daf84df9450190@104.207.152.17:30303", - "enode://59c228a6a0939a0b53edf6924bc7bd1384652dc1da0777495acd0707975f485f54a77c7b2dcbeece9340a43ccd9c7ea70f0cdfe48936537d238b50e5cb5dc0b2@45.77.233.0:30303", "enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303" ], "accounts": { -- GitLab From 5e7d42e4a4fbd59f18fd6988b388e1f465060ddc Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 3 Apr 2018 20:58:55 +0800 Subject: [PATCH 024/263] dapps-fetcher: calculate keccak in-flight while reading the response (#8294) * dapps-fetcher: calculate keccak in-flight while reading the response * Rename keccak_buffer_and_write -> keccak_pipe * Fix file read bug by creating another file handle as the return value --- dapps/src/apps/fetcher/installers.rs | 18 ++++++++++++------ util/hash/src/lib.rs | 7 ++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/dapps/src/apps/fetcher/installers.rs b/dapps/src/apps/fetcher/installers.rs index 2c067d493c..5bde5cf999 100644 --- a/dapps/src/apps/fetcher/installers.rs +++ b/dapps/src/apps/fetcher/installers.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; use ethereum_types::H256; use fetch; use futures_cpupool::CpuPool; -use hash::keccak_buffer; +use hash::keccak_pipe; use mime_guess::Mime; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; @@ -55,15 +55,15 @@ fn write_response_and_check_hash( // Now write the response let mut file = io::BufWriter::new(fs::File::create(&content_path)?); let mut reader = io::BufReader::new(fetch::BodyReader::new(response)); - io::copy(&mut reader, &mut file)?; + let hash = keccak_pipe(&mut reader, &mut file)?; + let mut file = file.into_inner()?; file.flush()?; // Validate hash - // TODO [ToDr] calculate keccak in-flight while reading the response - let mut file = io::BufReader::new(fs::File::open(&content_path)?); - let hash = keccak_buffer(&mut file)?; if id == hash { - Ok((file.into_inner(), content_path)) + // The writing above changed the file Read position, which we need later. So we just create a new file handle + // here. + Ok((fs::File::open(&content_path)?, content_path)) } else { Err(ValidationError::HashMismatch { expected: id, @@ -266,3 +266,9 @@ impl From for ValidationError { ValidationError::Zip(err) } } + +impl From>> for ValidationError { + fn from(err: io::IntoInnerError>) -> Self { + ValidationError::Io(err.into()) + } +} diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs index d00396501e..526d22aeda 100644 --- a/util/hash/src/lib.rs +++ b/util/hash/src/lib.rs @@ -52,7 +52,7 @@ pub fn write_keccak>(s: T, dest: &mut [u8]) { } } -pub fn keccak_buffer(r: &mut io::BufRead) -> Result { +pub fn keccak_pipe(r: &mut io::BufRead, w: &mut io::Write) -> Result { let mut output = [0u8; 32]; let mut input = [0u8; 1024]; let mut keccak = Keccak::new_keccak256(); @@ -64,12 +64,17 @@ pub fn keccak_buffer(r: &mut io::BufRead) -> Result { break; } keccak.update(&input[0..some]); + w.write_all(&input[0..some])?; } keccak.finalize(&mut output); Ok(output.into()) } +pub fn keccak_buffer(r: &mut io::BufRead) -> Result { + keccak_pipe(r, &mut io::sink()) +} + #[cfg(test)] mod tests { extern crate tempdir; -- GitLab From dcaff6f4c81238ae6744dd5fe6938288a1179172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 3 Apr 2018 15:49:23 +0100 Subject: [PATCH 025/263] Auto-updater improvements (#8078) * updater: refactor updater flow into state machine * updater: delay update randomly within max range * updater: configurable update delay * updater: split polling and updater state machine step * updater: drop state to avoid deadlocking * updater: fix fetch backoff * updater: fix overflow in update delay calculation * updater: configurable update check frequency * updater: fix update policy frequency comparison * updater: use lazy_static for platform and platform_id_hash * updater: refactor operations contract calls into OperationsClient * updater: make updater generic over operations and fetch client * updater: fix compilation * updater: add testing infrastructure and minimal test * updater: fix minor grumbles * updater: add test for successful updater flow * updater: add test for update delay * updater: add test for update check frequency * updater: mock time and rng for deterministic tests * updater: test backoff on failure * updater: add test for backoff short-circuit on new release * updater: refactor to increase readability * updater: cap maximum backoff to one month * updater: add test for detecting already downloaded update * updater: add test for updater disable on fatal errors * updater: add test for pending outdated fetch * updater: test auto install of updates * updater: add test for capability updates * updater: fix capability update * updater: use ethabi to create event topic filter * updater: decrease maximum backoff to 1 day * updater: cap maximum update delay with upcoming fork block number * updater: receive state mutex guard in updater_step * updater: overload execute_upgrade to take state mutex guard * updater: remove unnecessary clone of latest operations info * updater: remove latest operations info clone when triggering fetch --- Cargo.lock | 5 + ethcore/src/client/test_client.rs | 22 +- parity/cli/mod.rs | 14 + parity/cli/tests/config.full.toml | 2 + parity/configuration.rs | 14 +- updater/Cargo.toml | 7 + updater/res/operations.json | 37 + updater/src/lib.rs | 11 + updater/src/updater.rs | 1240 ++++++++++++++++++++++++----- util/dir/src/lib.rs | 4 +- 10 files changed, 1130 insertions(+), 226 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 278f4b673f..47b19ae11b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2229,13 +2229,18 @@ dependencies = [ "ethcore-bytes 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethsync 1.11.0", + "keccak-hash 0.1.0", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-hash-fetch 1.11.0", "parity-version 1.11.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "path 0.1.0", + "rand 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index eed6c5e5b5..31d9357668 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -16,7 +16,7 @@ //! Test client. -use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrder}; use std::sync::Arc; use std::collections::{HashMap, BTreeMap}; use std::mem; @@ -114,6 +114,8 @@ pub struct TestBlockChainClient { pub traces: RwLock>>, /// Pruning history size to report. pub history: RwLock>, + /// Is disabled + pub disabled: AtomicBool, } /// Used for generating test client blocks. @@ -180,6 +182,7 @@ impl TestBlockChainClient { first_block: RwLock::new(None), traces: RwLock::new(None), history: RwLock::new(None), + disabled: AtomicBool::new(false), }; // insert genesis hash. @@ -356,6 +359,11 @@ impl TestBlockChainClient { pub fn set_history(&self, h: Option) { *self.history.write() = h; } + + /// Returns true if the client has been disabled. + pub fn is_disabled(&self) -> bool { + self.disabled.load(AtomicOrder::Relaxed) + } } pub fn get_temp_state_db() -> StateDB { @@ -679,8 +687,14 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn block_number(&self, _id: BlockId) -> Option { - unimplemented!() + fn block_number(&self, id: BlockId) -> Option { + match id { + BlockId::Number(number) => Some(number), + BlockId::Earliest => Some(0), + BlockId::Latest => Some(self.chain_info().best_block_number), + BlockId::Hash(ref h) => + self.numbers.read().iter().find(|&(_, hash)| hash == h).map(|e| *e.0 as u64) + } } fn block_body(&self, id: BlockId) -> Option { @@ -827,7 +841,7 @@ impl BlockChainClient for TestBlockChainClient { fn set_spec_name(&self, _: String) { unimplemented!(); } - fn disable(&self) { unimplemented!(); } + fn disable(&self) { self.disabled.store(true, AtomicOrder::Relaxed); } fn pruning_info(&self) -> PruningInfo { let best_num = self.chain_info().best_block_number; diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 04a4a21e1a..22be9a0c47 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -280,6 +280,14 @@ usage! { "--auto-update=[SET]", "Set a releases set to automatically update and install. SET can be one of: all - All updates in the our release track; critical - Only consensus/security updates; none - No updates will be auto-installed.", + ARG arg_auto_update_delay: (u16) = 100u16, or |c: &Config| c.parity.as_ref()?.auto_update_delay.clone(), + "--auto-update-delay=[NUM]", + "Specify the maximum number of blocks used for randomly delaying updates.", + + ARG arg_auto_update_check_frequency: (u16) = 20u16, or |c: &Config| c.parity.as_ref()?.auto_update_check_frequency.clone(), + "--auto-update-check-frequency=[NUM]", + "Specify the number of blocks between each auto-update check.", + ARG arg_release_track: (String) = "current", or |c: &Config| c.parity.as_ref()?.release_track.clone(), "--release-track=[TRACK]", "Set which release track we should use for updates. TRACK can be one of: stable - Stable releases; beta - Beta releases; nightly - Nightly releases (unstable); testing - Testing releases (do not use); current - Whatever track this executable was released on.", @@ -1012,6 +1020,8 @@ struct Operating { mode_timeout: Option, mode_alarm: Option, auto_update: Option, + auto_update_delay: Option, + auto_update_check_frequency: Option, release_track: Option, public_node: Option, no_download: Option, @@ -1454,6 +1464,8 @@ mod tests { arg_mode_timeout: 300u64, arg_mode_alarm: 3600u64, arg_auto_update: "none".into(), + arg_auto_update_delay: 200u16, + arg_auto_update_check_frequency: 50u16, arg_release_track: "current".into(), flag_public_node: false, flag_no_download: false, @@ -1711,6 +1723,8 @@ mod tests { mode_timeout: Some(15u64), mode_alarm: Some(10u64), auto_update: None, + auto_update_delay: None, + auto_update_check_frequency: None, release_track: None, public_node: None, no_download: None, diff --git a/parity/cli/tests/config.full.toml b/parity/cli/tests/config.full.toml index 88a91e263b..749ffd8514 100644 --- a/parity/cli/tests/config.full.toml +++ b/parity/cli/tests/config.full.toml @@ -3,6 +3,8 @@ mode = "last" mode_timeout = 300 mode_alarm = 3600 auto_update = "none" +auto_update_delay = 200 +auto_update_check_frequency = 50 release_track = "current" public_node = false no_download = false diff --git a/parity/configuration.rs b/parity/configuration.rs index 2661e90f6a..07245dbbea 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -961,6 +961,8 @@ impl Configuration { }, path: default_hypervisor_path(), max_size: 128 * 1024 * 1024, + max_delay: self.args.arg_auto_update_delay as u64, + frequency: self.args.arg_auto_update_check_frequency as u64, }) } @@ -1426,6 +1428,8 @@ mod tests { track: ReleaseTrack::Unknown, path: default_hypervisor_path(), max_size: 128 * 1024 * 1024, + max_delay: 100, + frequency: 20, }, mode: Default::default(), tracing: Default::default(), @@ -1491,8 +1495,8 @@ mod tests { fn should_parse_updater_options() { // when let conf0 = parse(&["parity", "--release-track=testing"]); - let conf1 = parse(&["parity", "--auto-update", "all", "--no-consensus"]); - let conf2 = parse(&["parity", "--no-download", "--auto-update=all", "--release-track=beta"]); + let conf1 = parse(&["parity", "--auto-update", "all", "--no-consensus", "--auto-update-delay", "300"]); + let conf2 = parse(&["parity", "--no-download", "--auto-update=all", "--release-track=beta", "--auto-update-delay=300", "--auto-update-check-frequency=100"]); let conf3 = parse(&["parity", "--auto-update=xxx"]); // then @@ -1503,6 +1507,8 @@ mod tests { track: ReleaseTrack::Testing, path: default_hypervisor_path(), max_size: 128 * 1024 * 1024, + max_delay: 100, + frequency: 20, }); assert_eq!(conf1.update_policy().unwrap(), UpdatePolicy { enable_downloading: true, @@ -1511,6 +1517,8 @@ mod tests { track: ReleaseTrack::Unknown, path: default_hypervisor_path(), max_size: 128 * 1024 * 1024, + max_delay: 300, + frequency: 20, }); assert_eq!(conf2.update_policy().unwrap(), UpdatePolicy { enable_downloading: false, @@ -1519,6 +1527,8 @@ mod tests { track: ReleaseTrack::Beta, path: default_hypervisor_path(), max_size: 128 * 1024 * 1024, + max_delay: 300, + frequency: 100, }); assert!(conf3.update_policy().is_err()); } diff --git a/updater/Cargo.toml b/updater/Cargo.toml index 29fba27ffd..25f046a206 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -6,6 +6,8 @@ license = "GPL-3.0" authors = ["Parity Technologies "] [dependencies] +keccak-hash = { path = "../util/hash" } +lazy_static = "1.0" log = "0.3" ethabi = "5.1" ethabi-derive = "5.0" @@ -20,3 +22,8 @@ parking_lot = "0.5" parity-hash-fetch = { path = "../hash-fetch" } parity-version = { path = "../util/version" } path = { path = "../util/path" } +rand = "0.4" + +[dev-dependencies] +tempdir = "0.3" +matches = "0.1" diff --git a/updater/res/operations.json b/updater/res/operations.json index 2a14e0f0a0..b675269f1c 100644 --- a/updater/res/operations.json +++ b/updater/res/operations.json @@ -556,5 +556,42 @@ ], "payable": false, "type": "function" + }, + { + "name": "ReleaseAdded", + "type": "event", + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "client", + "type": "bytes32" + }, + { + "indexed": true, + "name": "forkBlock", + "type": "uint32" + }, + { + "indexed": false, + "name": "release", + "type": "bytes32" + }, + { + "indexed": false, + "name": "track", + "type": "uint8" + }, + { + "indexed": false, + "name": "semver", + "type": "uint24" + }, + { + "indexed": true, + "name": "critical", + "type": "bool" + } + ] } ] diff --git a/updater/src/lib.rs b/updater/src/lib.rs index c1e19cf1d5..91c66d7680 100644 --- a/updater/src/lib.rs +++ b/updater/src/lib.rs @@ -21,10 +21,12 @@ extern crate ethcore; extern crate ethcore_bytes as bytes; extern crate ethereum_types; extern crate ethsync; +extern crate keccak_hash as hash; extern crate parity_hash_fetch as hash_fetch; extern crate parity_version as version; extern crate parking_lot; extern crate path; +extern crate rand; extern crate semver; extern crate target_info; @@ -33,8 +35,17 @@ extern crate ethabi_contract; #[macro_use] extern crate ethabi_derive; #[macro_use] +extern crate lazy_static; +#[macro_use] extern crate log; +#[cfg(test)] +extern crate tempdir; + +#[cfg(test)] +#[macro_use] +extern crate matches; + mod updater; mod types; mod service; diff --git a/updater/src/updater.rs b/updater/src/updater.rs index 914516bb47..60984e10f1 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -14,22 +14,27 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::cmp; use std::fs; use std::io::Write; -use std::path::{PathBuf}; +use std::path::{Path, PathBuf}; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; +use parking_lot::{Mutex, MutexGuard}; +use rand::{self, Rng}; +use target_info::Target; + +use bytes::Bytes; +use ethcore::BlockNumber; +use ethcore::filter::Filter; use ethcore::client::{BlockId, BlockChainClient, ChainNotify}; +use ethereum_types::H256; use ethsync::{SyncProvider}; use hash_fetch::{self as fetch, HashFetch}; use path::restrict_permissions_owner; -use service::{Service}; -use target_info::Target; +use service::Service; use types::{ReleaseInfo, OperationsInfo, CapState, VersionInfo, ReleaseTrack}; -use ethereum_types::H256; -use bytes::Bytes; -use parking_lot::Mutex; use version; use_contract!(operations_contract, "Operations", "res/operations.json"); @@ -57,9 +62,13 @@ pub struct UpdatePolicy { /// Which track we should be following. pub track: ReleaseTrack, /// Path for the updates to go. - pub path: String, + pub path: PathBuf, /// Maximum download size. pub max_size: usize, + /// Random update delay range in blocks. + pub max_delay: u64, + /// Number of blocks between each check for updates. + pub frequency: u64, } impl Default for UpdatePolicy { @@ -71,36 +80,74 @@ impl Default for UpdatePolicy { track: ReleaseTrack::Unknown, path: Default::default(), max_size: 128 * 1024 * 1024, + max_delay: 100, + frequency: 20, } } } +/// The current updater status +#[derive(Clone, Debug, PartialEq)] +enum UpdaterStatus { + /// Updater is currently disabled. + Disabled, + /// Updater is currently idle. + Idle, + /// Updater is waiting for block number to fetch a new release. + Waiting { + release: ReleaseInfo, + binary: H256, + block_number: BlockNumber, + }, + /// Updater is fetching a new release. + Fetching { + release: ReleaseInfo, + binary: H256, + retries: u32, + }, + /// Updater failed fetching a new release and it is now backing off until the next retry. + FetchBackoff { + release: ReleaseInfo, + binary: H256, + backoff: (u32, Instant), + }, + /// Updater is ready to update to a new release. + Ready { + release: ReleaseInfo, + }, + /// Updater has installed a new release and can be manually restarted. + Installed { + release: ReleaseInfo, + }, +} + +impl Default for UpdaterStatus { + fn default() -> Self { + UpdaterStatus::Idle + } +} + #[derive(Debug, Default)] struct UpdaterState { latest: Option, - - fetching: Option, - ready: Option, - installed: Option, - capability: CapState, - - disabled: bool, - - backoff: Option<(u32, Instant)>, + status: UpdaterStatus, } /// Service for checking for updates and determining whether we can achieve consensus. -pub struct Updater { +pub struct Updater { // Useful environmental stuff. update_policy: UpdatePolicy, - weak_self: Mutex>, + weak_self: Mutex>>, client: Weak, - sync: Weak, - fetcher: fetch::Client, - operations_contract: operations_contract::Operations, + sync: Option>, + fetcher: F, + operations_client: O, exit_handler: Mutex>>, + time_provider: T, + rng: R, + // Our version info (static) this: VersionInfo, @@ -110,60 +157,74 @@ pub struct Updater { const CLIENT_ID: &'static str = "parity"; -fn client_id_hash() -> H256 { - CLIENT_ID.as_bytes().into() +lazy_static! { + static ref CLIENT_ID_HASH: H256 = CLIENT_ID.as_bytes().into(); } -fn platform() -> String { - if cfg!(target_os = "macos") { - "x86_64-apple-darwin".into() - } else if cfg!(windows) { - "x86_64-pc-windows-msvc".into() - } else if cfg!(target_os = "linux") { - format!("{}-unknown-linux-gnu", Target::arch()) - } else { - version::platform() - } +lazy_static! { + static ref PLATFORM: String = { + if cfg!(target_os = "macos") { + "x86_64-apple-darwin".into() + } else if cfg!(windows) { + "x86_64-pc-windows-msvc".into() + } else if cfg!(target_os = "linux") { + format!("{}-unknown-linux-gnu", Target::arch()) + } else { + version::platform() + } + }; } -fn platform_id_hash() -> H256 { - platform().as_bytes().into() +lazy_static! { + static ref PLATFORM_ID_HASH: H256 = PLATFORM.as_bytes().into(); } -impl Updater { - pub fn new(client: Weak, sync: Weak, update_policy: UpdatePolicy, fetcher: fetch::Client) -> Arc { - let r = Arc::new(Updater { - update_policy: update_policy, - weak_self: Mutex::new(Default::default()), - client: client.clone(), - sync: sync.clone(), - fetcher, - operations_contract: operations_contract::Operations::default(), - exit_handler: Mutex::new(None), - this: VersionInfo::this(), - state: Mutex::new(Default::default()), - }); - *r.weak_self.lock() = Arc::downgrade(&r); - r.poll(); - r +/// Client trait for getting latest release information from operations contract. +/// Useful for mocking in tests. +pub trait OperationsClient: Send + Sync + 'static { + /// Get the latest release operations info for the given track. + fn latest(&self, this: &VersionInfo, track: ReleaseTrack) -> Result; + + /// Fetches the block number when the given release was added, checking the interval [from; latest_block]. + fn release_block_number(&self, from: BlockNumber, release: &ReleaseInfo) -> Option; +} + +/// OperationsClient that delegates calls to the operations contract. +pub struct OperationsContractClient { + operations_contract: operations_contract::Operations, + client: Weak, +} + +impl OperationsContractClient { + fn new( + operations_contract: operations_contract::Operations, + client: Weak, + ) -> OperationsContractClient { + OperationsContractClient { operations_contract, client } } - /// Set a closure to call when we want to restart the client - pub fn set_exit_handler(&self, f: F) where F: Fn() + 'static + Send { - *self.exit_handler.lock() = Some(Box::new(f)); + /// Get the hash of the latest release for the given track + fn latest_hash(&self, track: ReleaseTrack, do_call: &F) -> Result + where F: Fn(Vec) -> Result, String> { + self.operations_contract.functions() + .latest_in_track() + .call(*CLIENT_ID_HASH, u8::from(track), do_call) + .map_err(|e| format!("{:?}", e)) } - fn collect_release_info) -> Result, String>>(&self, release_id: H256, do_call: &T) -> Result { + /// Get release info for the given release + fn release_info(&self, release_id: H256, do_call: &F) -> Result + where F: Fn(Vec) -> Result, String> { let (fork, track, semver, is_critical) = self.operations_contract.functions() .release() - .call(client_id_hash(), release_id, &do_call) + .call(*CLIENT_ID_HASH, release_id, &do_call) .map_err(|e| format!("{:?}", e))?; let (fork, track, semver) = (fork.low_u64(), track.low_u32(), semver.low_u32()); let latest_binary = self.operations_contract.functions() .checksum() - .call(client_id_hash(), release_id, platform_id_hash(), &do_call) + .call(*CLIENT_ID_HASH, release_id, *PLATFORM_ID_HASH, &do_call) .map_err(|e| format!("{:?}", e))?; Ok(ReleaseInfo { @@ -173,39 +234,24 @@ impl Updater { binary: if latest_binary.is_zero() { None } else { Some(latest_binary) }, }) } +} - /// Returns release track of the parity node. - /// `update_policy.track` is the track specified from the command line, whereas `this.track` - /// is the track of the software which is currently run - fn track(&self) -> ReleaseTrack { - match self.update_policy.track { - ReleaseTrack::Unknown => self.this.track, - x => x, - } - } - - fn latest_in_track) -> Result, String>>(&self, track: ReleaseTrack, do_call: &T) -> Result { - self.operations_contract.functions() - .latest_in_track() - .call(client_id_hash(), u8::from(track), do_call) - .map_err(|e| format!("{:?}", e)) - } - - fn collect_latest(&self) -> Result { - if self.track() == ReleaseTrack::Unknown { - return Err(format!("Current executable ({}) is unreleased.", self.this.hash)); +impl OperationsClient for OperationsContractClient { + fn latest(&self, this: &VersionInfo, track: ReleaseTrack) -> Result { + if track == ReleaseTrack::Unknown { + return Err(format!("Current executable ({}) is unreleased.", this.hash)); } let client = self.client.upgrade().ok_or_else(|| "Cannot obtain client")?; let address = client.registry_address("operations".into(), BlockId::Latest).ok_or_else(|| "Cannot get operations contract address")?; let do_call = |data| client.call_contract(BlockId::Latest, address, data).map_err(|e| format!("{:?}", e)); - trace!(target: "updater", "Looking up this_fork for our release: {}/{:?}", CLIENT_ID, self.this.hash); + trace!(target: "updater", "Looking up this_fork for our release: {}/{:?}", CLIENT_ID, this.hash); // get the fork number of this release let this_fork = self.operations_contract.functions() .release() - .call(client_id_hash(), self.this.hash, &do_call) + .call(*CLIENT_ID_HASH, this.hash, &do_call) .ok() .and_then(|(fork, track, _, _)| { let this_track: ReleaseTrack = (track.low_u64() as u8).into(); @@ -216,23 +262,23 @@ impl Updater { }); // get the hash of the latest release in our track - let latest_in_track = self.latest_in_track(self.track(), &do_call)?; + let latest_in_track = self.latest_hash(track, &do_call)?; // get the release info for the latest version in track - let in_track = self.collect_release_info(latest_in_track, &do_call)?; + let in_track = self.release_info(latest_in_track, &do_call)?; let mut in_minor = Some(in_track.clone()); const PROOF: &'static str = "in_minor initialised and assigned with Some; loop breaks if None assigned; qed"; // if the minor version has changed, let's check the minor version on a different track - while in_minor.as_ref().expect(PROOF).version.version.minor != self.this.version.minor { + while in_minor.as_ref().expect(PROOF).version.version.minor != this.version.minor { let track = match in_minor.as_ref().expect(PROOF).version.track { ReleaseTrack::Beta => ReleaseTrack::Stable, ReleaseTrack::Nightly => ReleaseTrack::Beta, _ => { in_minor = None; break; } }; - let latest_in_track = self.latest_in_track(track, &do_call)?; - in_minor = Some(self.collect_release_info(latest_in_track, &do_call)?); + let latest_in_track = self.latest_hash(track, &do_call)?; + in_minor = Some(self.release_info(latest_in_track, &do_call)?); } let fork = self.operations_contract.functions() @@ -248,196 +294,954 @@ impl Updater { }) } + fn release_block_number(&self, from: BlockNumber, release: &ReleaseInfo) -> Option { + let client = self.client.upgrade()?; + let address = client.registry_address("operations".into(), BlockId::Latest)?; + + let event = self.operations_contract.events().release_added(); + + let topics = event.create_filter(Some(*CLIENT_ID_HASH), Some(release.fork.into()), Some(release.is_critical)); + let topics = vec![topics.topic0, topics.topic1, topics.topic2, topics.topic3]; + let topics = topics.into_iter().map(Into::into).map(Some).collect(); + + let filter = Filter { + from_block: BlockId::Number(from), + to_block: BlockId::Latest, + address: Some(vec![address]), + topics: topics, + limit: None, + }; + + client.logs(filter) + .iter() + .filter_map(|log| { + let event = event.parse_log((log.topics.clone(), log.data.clone()).into()).ok()?; + let version_info = VersionInfo::from_raw(event.semver.low_u32(), event.track.low_u32() as u8, event.release.into()); + if version_info == release.version { + Some(log.block_number) + } else { + None + } + }) + .last() + } +} + +/// Trait to provide current time. Useful for mocking in tests. +pub trait TimeProvider: Send + Sync + 'static { + /// Returns an instant corresponding to "now". + fn now(&self) -> Instant; +} + +/// TimeProvider implementation that delegates calls to std::time. +pub struct StdTimeProvider; + +impl TimeProvider for StdTimeProvider { + fn now(&self) -> Instant { + Instant::now() + } +} + +/// Trait to generate a random number within a given range. +/// Useful for mocking in tests. +pub trait GenRange: Send + Sync + 'static { + /// Generate a random value in the range [low, high), i.e. inclusive of low and exclusive of high. + fn gen_range(&self, low: u64, high: u64) -> u64; +} + +/// GenRange implementation that uses a rand::thread_rng for randomness. +pub struct ThreadRngGenRange; + +impl GenRange for ThreadRngGenRange { + fn gen_range(&self, low: u64, high: u64) -> u64 { + rand::thread_rng().gen_range(low, high) + } +} + +impl Updater { + pub fn new( + client: Weak, + sync: Weak, + update_policy: UpdatePolicy, + fetcher: fetch::Client, + ) -> Arc { + let r = Arc::new(Updater { + update_policy: update_policy, + weak_self: Mutex::new(Default::default()), + client: client.clone(), + sync: Some(sync.clone()), + fetcher, + operations_client: OperationsContractClient::new( + operations_contract::Operations::default(), + client.clone()), + exit_handler: Mutex::new(None), + this: VersionInfo::this(), + time_provider: StdTimeProvider, + rng: ThreadRngGenRange, + state: Mutex::new(Default::default()), + }); + *r.weak_self.lock() = Arc::downgrade(&r); + r.poll(); + r + } + fn update_file_name(v: &VersionInfo) -> String { format!("parity-{}.{}.{}-{:x}", v.version.major, v.version.minor, v.version.patch, v.hash) } +} + +impl Updater { + /// Set a closure to call when we want to restart the client + pub fn set_exit_handler(&self, g: G) where G: Fn() + 'static + Send { + *self.exit_handler.lock() = Some(Box::new(g)); + } + + /// Returns release track of the parity node. + /// `update_policy.track` is the track specified from the command line, whereas `this.track` + /// is the track of the software which is currently run + fn track(&self) -> ReleaseTrack { + match self.update_policy.track { + ReleaseTrack::Unknown => self.this.track, + x => x, + } + } fn updates_path(&self, name: &str) -> PathBuf { - let mut dest = PathBuf::from(self.update_policy.path.clone()); - dest.push(name); - dest - } - - fn fetch_done(&self, result: Result) { - // old below - (|| -> Result<(), (String, bool)> { - let auto = { - let mut s = self.state.lock(); - let fetched = s.fetching.take().unwrap(); - let dest = self.updates_path(&Self::update_file_name(&fetched.version)); - if !dest.exists() { - let b = match result { - Ok(b) => { - s.backoff = None; - b - }, - Err(e) => { - let mut n = s.backoff.map(|b| b.0 + 1).unwrap_or(1); - s.backoff = Some((n, Instant::now() + Duration::from_secs(2usize.pow(n) as u64))); - - return Err((format!("Unable to fetch update ({}): {:?}", fetched.version, e), false)); - }, + self.update_policy.path.join(name) + } + + fn on_fetch(&self, latest: &OperationsInfo, res: Result) { + let mut state = self.state.lock(); + + // Bail out if the latest release has changed in the meantime + if state.latest.as_ref() != Some(&latest) { + return; + } + + // The updated status should be set to fetching + if let UpdaterStatus::Fetching { ref release, binary, retries } = state.status.clone() { + match res { + // We've successfully fetched the binary + Ok(path) => { + let setup = |path: &Path| -> Result<(), String> { + let dest = self.updates_path(&Updater::update_file_name(&release.version)); + if !dest.exists() { + info!(target: "updater", "Fetched latest version ({}) OK to {}", release.version, path.display()); + fs::create_dir_all(dest.parent().expect("at least one thing pushed; qed")).map_err(|e| format!("Unable to create updates path: {:?}", e))?; + fs::copy(path, &dest).map_err(|e| format!("Unable to copy update: {:?}", e))?; + restrict_permissions_owner(&dest, false, true).map_err(|e| format!("Unable to update permissions: {}", e))?; + info!(target: "updater", "Copied updated binary to {}", dest.display()); + } + + Ok(()) }; - info!(target: "updater", "Fetched latest version ({}) OK to {}", fetched.version, b.display()); - fs::create_dir_all(dest.parent().expect("at least one thing pushed; qed")).map_err(|e| (format!("Unable to create updates path: {:?}", e), true))?; - fs::copy(&b, &dest).map_err(|e| (format!("Unable to copy update: {:?}", e), true))?; - restrict_permissions_owner(&dest, false, true).map_err(|e| (format!("Unable to update permissions: {}", e), true))?; - info!(target: "updater", "Installed updated binary to {}", dest.display()); - } - let auto = match self.update_policy.filter { - UpdateFilter::All => true, - UpdateFilter::Critical if fetched.is_critical /* TODO: or is on a bad fork */ => true, - _ => false, + // There was a fatal error setting up the update, disable the updater + if let Err(err) = setup(&path) { + state.status = UpdaterStatus::Disabled; + warn!("{}", err); + } else { + state.status = UpdaterStatus::Ready { release: release.clone() }; + self.updater_step(state); + } + }, + // There was an error fetching the update, apply a backoff delay before retrying + Err(err) => { + let delay = 2usize.pow(retries) as u64; + // cap maximum backoff to 1 day + let delay = cmp::min(delay, 24 * 60 * 60); + let backoff = (retries, self.time_provider.now() + Duration::from_secs(delay)); + + state.status = UpdaterStatus::FetchBackoff { release: release.clone(), backoff, binary }; + + warn!("Unable to fetch update ({}): {:?}, retrying in {} seconds.", release.version, err, delay); + }, + } + } + } + + fn execute_upgrade(&self, mut state: MutexGuard) -> bool { + if let UpdaterStatus::Ready { ref release } = state.status.clone() { + let file = Updater::update_file_name(&release.version); + let path = self.updates_path("latest"); + + // TODO: creating then writing is a bit fragile. would be nice to make it atomic. + if let Err(err) = fs::File::create(&path).and_then(|mut f| f.write_all(file.as_bytes())) { + state.status = UpdaterStatus::Disabled; + + warn!(target: "updater", "Unable to create soft-link for update {:?}", err); + return false; + } + + info!(target: "updater", "Completed upgrade to {}", &release.version); + state.status = UpdaterStatus::Installed { release: release.clone() }; + + match *self.exit_handler.lock() { + Some(ref h) => (*h)(), + None => info!(target: "updater", "Update installed, ready for restart."), + } + + return true; + }; + + warn!(target: "updater", "Execute upgrade called when no upgrade ready."); + false + } + + fn updater_step(&self, mut state: MutexGuard) { + let current_block_number = self.client.upgrade().map_or(0, |c| c.block_number(BlockId::Latest).unwrap_or(0)); + + if let Some(latest) = state.latest.clone() { + let fetch = |latest, binary| { + info!(target: "updater", "Attempting to get parity binary {}", binary); + let weak_self = self.weak_self.lock().clone(); + let f = move |res: Result| { + if let Some(this) = weak_self.upgrade() { + this.on_fetch(&latest, res) + } }; - s.ready = Some(fetched); - auto + + self.fetcher.fetch( + binary, + fetch::Abort::default().with_max_size(self.update_policy.max_size), + Box::new(f)); }; - if auto { - // will lock self.state, so ensure it's outside of previous block. - self.execute_upgrade(); + + match state.status.clone() { + // updater is disabled + UpdaterStatus::Disabled => {}, + // the update has already been installed + UpdaterStatus::Installed { ref release, .. } if *release == latest.track => {}, + // we're currently fetching this update + UpdaterStatus::Fetching { ref release, .. } if *release == latest.track => {}, + // the fetch has failed and we're backing off the next retry + UpdaterStatus::FetchBackoff { ref release, backoff, .. } if *release == latest.track && self.time_provider.now() < backoff.1 => {}, + // we're delaying the update until the given block number + UpdaterStatus::Waiting { ref release, block_number, .. } if *release == latest.track && current_block_number < block_number => {}, + // we're at (or past) the block that triggers the update, let's fetch the binary + UpdaterStatus::Waiting { ref release, block_number, binary } if *release == latest.track && current_block_number >= block_number => { + info!(target: "updater", "Update for binary {} triggered", binary); + + state.status = UpdaterStatus::Fetching { release: release.clone(), binary, retries: 1 }; + fetch(latest, binary); + }, + // we're ready to retry the fetch after we applied a backoff for the previous failure + UpdaterStatus::FetchBackoff { ref release, backoff, binary } if *release == latest.track && self.time_provider.now() >= backoff.1 => { + state.status = UpdaterStatus::Fetching { release: release.clone(), binary, retries: backoff.0 + 1 }; + fetch(latest, binary); + }, + // the update is ready to be installed + UpdaterStatus::Ready { ref release } if *release == latest.track => { + let auto = match self.update_policy.filter { + UpdateFilter::All => true, + UpdateFilter::Critical if release.is_critical /* TODO: or is on a bad fork */ => true, + _ => false, + }; + + if auto { + self.execute_upgrade(state); + } + }, + // this is the default case that does the initial triggering to update. we can reach this case by being + // `Idle` but also if the latest release is updated, regardless of the state we're in (except if the + // updater is in the `Disabled` state). if we push a bad update (e.g. wrong hashes or download url) + // clients might eventually be on a really long backoff state for that release, but as soon a new + // release is pushed we'll fall through to the default case. + _ => { + if let Some(binary) = latest.track.binary { + let running_later = latest.track.version.version < self.version_info().version; + let running_latest = latest.track.version.hash == self.version_info().hash; + + // Bail out if we're already running the latest version or a later one + if running_later || running_latest { + return; + } + + let path = self.updates_path(&Updater::update_file_name(&latest.track.version)); + if path.exists() { + info!(target: "updater", "Already fetched binary."); + state.status = UpdaterStatus::Ready { release: latest.track.clone() }; + self.updater_step(state); + + } else if self.update_policy.enable_downloading { + let update_block_number = { + let max_delay = if latest.fork >= current_block_number { + cmp::min(latest.fork - current_block_number, self.update_policy.max_delay) + } else { + self.update_policy.max_delay + }; + + let from = current_block_number.saturating_sub(max_delay); + match self.operations_client.release_block_number(from, &latest.track) { + Some(block_number) => { + let delay = self.rng.gen_range(0, max_delay); + block_number.saturating_add(delay) + }, + None => current_block_number, + } + }; + + state.status = UpdaterStatus::Waiting { release: latest.track.clone(), binary, block_number: update_block_number }; + + if update_block_number > current_block_number { + info!(target: "updater", "Update for binary {} will be triggered at block {}", binary, update_block_number); + } else { + self.updater_step(state); + } + } + } + }, } - Ok(()) - })().unwrap_or_else(|(e, fatal)| { self.state.lock().disabled = fatal; warn!("{}", e); }); + } } fn poll(&self) { trace!(target: "updater", "Current release is {} ({:?})", self.this, self.this.hash); // We rely on a secure state. Bail if we're unsure about it. - if self.client.upgrade().map_or(true, |s| !s.chain_info().security_level().is_full()) { + if self.client.upgrade().map_or(true, |c| !c.chain_info().security_level().is_full()) { return; } - let current_number = self.client.upgrade().map_or(0, |c| c.block_number(BlockId::Latest).unwrap_or(0)); - - let mut capability = CapState::Unknown; - let latest = self.collect_latest().ok(); - if let Some(ref latest) = latest { - trace!(target: "updater", "Latest release in our track is v{} it is {}critical ({} binary is {})", - latest.track.version, - if latest.track.is_critical {""} else {"non-"}, - &platform(), - if let Some(ref b) = latest.track.binary { - format!("{}", b) - } else { - "unreleased".into() - } - ); - let mut s = self.state.lock(); - let running_later = latest.track.version.version < self.version_info().version; - let running_latest = latest.track.version.hash == self.version_info().hash; - let already_have_latest = s.installed.as_ref().or(s.ready.as_ref()).map_or(false, |t| *t == latest.track); - - if !s.disabled && self.update_policy.enable_downloading && !running_later && !running_latest && !already_have_latest { - if let Some(b) = latest.track.binary { - if s.fetching.is_none() { - if self.updates_path(&Self::update_file_name(&latest.track.version)).exists() { - info!(target: "updater", "Already fetched binary."); - s.fetching = Some(latest.track.clone()); - drop(s); - self.fetch_done(Ok(PathBuf::new())); - } else { - if s.backoff.iter().all(|&(_, instant)| Instant::now() >= instant) { - info!(target: "updater", "Attempting to get parity binary {}", b); - s.fetching = Some(latest.track.clone()); - drop(s); - let weak_self = self.weak_self.lock().clone(); - let f = move |r: Result| if let Some(this) = weak_self.upgrade() { this.fetch_done(r) }; - let a = fetch::Abort::default().with_max_size(self.update_policy.max_size); - self.fetcher.fetch(b, a, Box::new(f)); - } - } - } - } - } - trace!(target: "updater", "Fork: this/current/latest/latest-known: {}/#{}/#{}/#{}", match latest.this_fork { Some(f) => format!("#{}", f), None => "unknown".into(), }, current_number, latest.track.fork, latest.fork); - - if let Some(this_fork) = latest.this_fork { - if this_fork < latest.fork { - // We're behind the latest fork. Now is the time to be upgrading; perhaps we're too late... - if let Some(c) = self.client.upgrade() { - let current_number = c.block_number(BlockId::Latest).unwrap_or(0); - if current_number >= latest.fork - 1 { - // We're at (or past) the last block we can import. Disable the client. - if self.update_policy.require_consensus { + // Only check for updates every n blocks + let current_block_number = self.client.upgrade().map_or(0, |c| c.block_number(BlockId::Latest).unwrap_or(0)); + if current_block_number % cmp::max(self.update_policy.frequency, 1) != 0 { + return; + } + + let mut state = self.state.lock(); + + // Get the latest available release + let latest = self.operations_client.latest(&self.this, self.track()).ok(); + + if let Some(latest) = latest { + // Update current capability + state.capability = match latest.this_fork { + // We're behind the latest fork. Now is the time to be upgrading, perhaps we're too late... + Some(this_fork) if this_fork < latest.fork => { + if current_block_number >= latest.fork - 1 { + // We're at (or past) the last block we can import. Disable the client. + if self.update_policy.require_consensus { + if let Some(c) = self.client.upgrade() { c.disable(); } - capability = CapState::IncapableSince(latest.fork); - } else { - capability = CapState::CapableUntil(latest.fork); } + + CapState::IncapableSince(latest.fork) + } else { + CapState::CapableUntil(latest.fork) } - } else { - capability = CapState::Capable; - } - } - } + }, + Some(_) => CapState::Capable, + None => CapState::Unknown, + }; + + // There's a new release available + if state.latest.as_ref() != Some(&latest) { + trace!(target: "updater", "Latest release in our track is v{} it is {}critical ({} binary is {})", + latest.track.version, + if latest.track.is_critical {""} else {"non-"}, + *PLATFORM, + latest.track.binary.map(|b| format!("{}", b)).unwrap_or("unreleased".into())); - let mut s = self.state.lock(); + trace!(target: "updater", "Fork: this/current/latest/latest-known: {}/#{}/#{}/#{}", + latest.this_fork.map(|f| format!("#{}", f)).unwrap_or("unknown".into()), + current_block_number, + latest.track.fork, + latest.fork); - if s.latest != latest { - s.backoff = None; + // Update latest release + state.latest = Some(latest); + } } - s.latest = latest; - s.capability = capability; + self.updater_step(state); } } impl ChainNotify for Updater { fn new_blocks(&self, _imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { - match (self.client.upgrade(), self.sync.upgrade()) { + match (self.client.upgrade(), self.sync.as_ref().and_then(Weak::upgrade)) { (Some(ref c), Some(ref s)) if !s.status().is_syncing(c.queue_info()) => self.poll(), _ => {}, } } } -impl Service for Updater { +impl Service for Updater { fn capability(&self) -> CapState { self.state.lock().capability } fn upgrade_ready(&self) -> Option { - self.state.lock().ready.clone() + match self.state.lock().status { + UpdaterStatus::Ready { ref release, .. } => Some(release.clone()), + _ => None, + } } fn execute_upgrade(&self) -> bool { - let mut s = self.state.lock(); - let ready = match s.ready.take() { - Some(ready) => ready, - None => { - warn!(target: "updater", "Execute upgrade called when no upgrade ready."); - return false; + let state = self.state.lock(); + self.execute_upgrade(state) + } + + fn version_info(&self) -> VersionInfo { + self.this.clone() + } + + fn info(&self) -> Option { + self.state.lock().latest.clone() + } +} + +#[cfg(test)] +pub mod tests { + use std::fs::File; + use std::io::Read; + use std::sync::Arc; + use semver::Version; + use tempdir::TempDir; + use ethcore::client::{TestBlockChainClient, EachBlockWith}; + use self::fetch::Error; + use super::*; + + #[derive(Clone)] + struct FakeOperationsClient { + result: Arc, Option)>>, + } + + impl FakeOperationsClient { + fn new() -> FakeOperationsClient { + FakeOperationsClient { result: Arc::new(Mutex::new((None, None))) } + } + + fn set_result(&self, operations_info: Option, release_block_number: Option) { + let mut result = self.result.lock(); + result.0 = operations_info; + result.1 = release_block_number; + } + } + + impl OperationsClient for FakeOperationsClient { + fn latest(&self, _this: &VersionInfo, _track: ReleaseTrack) -> Result { + self.result.lock().0.clone().ok_or("unavailable".into()) + } + + fn release_block_number(&self, _from: BlockNumber, _release: &ReleaseInfo) -> Option { + self.result.lock().1.clone() + } + } + + #[derive(Clone)] + struct FakeFetch { + on_done: Arc) + Send>>>>, + } + + impl FakeFetch { + fn new() -> FakeFetch { + FakeFetch { on_done: Arc::new(Mutex::new(None)) } + } + + fn trigger(&self, result: Option) { + if let Some(ref on_done) = *self.on_done.lock() { + on_done(result.ok_or(Error::NoResolution)) } - }; + } + } - let p = Self::update_file_name(&ready.version); - let n = self.updates_path("latest"); + impl HashFetch for FakeFetch { + fn fetch(&self, _hash: H256, _abort: fetch::Abort, on_done: Box) + Send>) { + *self.on_done.lock() = Some(on_done); + } + } - // TODO: creating then writing is a bit fragile. would be nice to make it atomic. - if let Err(e) = fs::File::create(&n).and_then(|mut f| f.write_all(p.as_bytes())) { - s.ready = Some(ready); - warn!(target: "updater", "Unable to create soft-link for update {:?}", e); - return false; + #[derive(Clone)] + struct FakeTimeProvider { + result: Arc>, + } + + impl FakeTimeProvider { + fn new() -> FakeTimeProvider { + FakeTimeProvider { result: Arc::new(Mutex::new(Instant::now())) } } - info!(target: "updater", "Completed upgrade to {}", &ready.version); - s.installed = Some(ready); - match *self.exit_handler.lock() { - Some(ref h) => (*h)(), - None => info!(target: "updater", "Update installed; ready for restart."), + fn set_result(&self, result: Instant) { + *self.result.lock() = result; } + } - true + impl TimeProvider for FakeTimeProvider { + fn now(&self) -> Instant { + *self.result.lock() + } } - fn version_info(&self) -> VersionInfo { - self.this.clone() + #[derive(Clone)] + struct FakeGenRange { + result: Arc>, } - fn info(&self) -> Option { - self.state.lock().latest.clone() + impl FakeGenRange { + fn new() -> FakeGenRange { + FakeGenRange { result: Arc::new(Mutex::new(0)) } + } + + fn set_result(&self, result: u64) { + *self.result.lock() = result; + } + } + + impl GenRange for FakeGenRange { + fn gen_range(&self, _low: u64, _high: u64) -> u64 { + *self.result.lock() + } + } + + type TestUpdater = Updater; + + fn setup(update_policy: UpdatePolicy) -> ( + Arc, + Arc, + FakeOperationsClient, + FakeFetch, + FakeTimeProvider, + FakeGenRange) { + + let client = Arc::new(TestBlockChainClient::new()); + let weak_client = Arc::downgrade(&client); + + let operations_client = FakeOperationsClient::new(); + let fetcher = FakeFetch::new(); + let time_provider = FakeTimeProvider::new(); + let rng = FakeGenRange::new(); + + let this = VersionInfo { + track: ReleaseTrack::Beta, + version: Version::parse("1.0.0").unwrap(), + hash: 0.into(), + }; + + let updater = Arc::new(Updater { + update_policy: update_policy, + weak_self: Mutex::new(Default::default()), + client: weak_client, + sync: None, + fetcher: fetcher.clone(), + operations_client: operations_client.clone(), + exit_handler: Mutex::new(None), + this: this, + time_provider: time_provider.clone(), + rng: rng.clone(), + state: Mutex::new(Default::default()), + }); + + *updater.weak_self.lock() = Arc::downgrade(&updater); + + (client, updater, operations_client, fetcher, time_provider, rng) + } + + fn update_policy() -> (UpdatePolicy, TempDir) { + let tempdir = TempDir::new("").unwrap(); + + let update_policy = UpdatePolicy { + path: tempdir.path().into(), + enable_downloading: true, + max_delay: 10, + frequency: 1, + ..Default::default() + }; + + (update_policy, tempdir) + } + + fn new_upgrade(version: &str) -> (VersionInfo, ReleaseInfo, OperationsInfo) { + let latest_version = VersionInfo { + track: ReleaseTrack::Beta, + version: Version::parse(version).unwrap(), + hash: 1.into(), + }; + + let latest_release = ReleaseInfo { + version: latest_version.clone(), + is_critical: false, + fork: 0, + binary: Some(0.into()), + }; + + let latest = OperationsInfo { + fork: 0, + this_fork: Some(0), + track: latest_release.clone(), + minor: None, + }; + + (latest_version, latest_release, latest) + } + + #[test] + fn should_stay_idle_when_no_release() { + let (update_policy, _) = update_policy(); + let (_client, updater, _, _, ..) = setup(update_policy); + + assert_eq!(updater.state.lock().status, UpdaterStatus::Idle); + updater.poll(); + assert_eq!(updater.state.lock().status, UpdaterStatus::Idle); + } + + #[test] + fn should_update_on_new_release() { + let (update_policy, tempdir) = update_policy(); + let (_client, updater, operations_client, fetcher, ..) = setup(update_policy); + let (latest_version, latest_release, latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + // we start in idle state and with no information regarding the latest release + assert_eq!(updater.state.lock().latest, None); + assert_eq!(updater.state.lock().status, UpdaterStatus::Idle); + + updater.poll(); + + // after the first poll the latest release should be set to the one we're mocking and the updater should be + // fetching it + assert_eq!(updater.state.lock().latest, Some(latest)); + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Fetching { ref release, retries, .. } if *release == latest_release && retries == 1); + + // mock fetcher with update binary and trigger the fetch + let update_file = tempdir.path().join("parity"); + File::create(update_file.clone()).unwrap(); + fetcher.trigger(Some(update_file)); + + // after the fetch finishes the upgrade should be ready to install + assert_eq!(updater.state.lock().status, UpdaterStatus::Ready { release: latest_release.clone() }); + assert_eq!(updater.upgrade_ready(), Some(latest_release.clone())); + + // the current update_policy doesn't allow updating automatically, but we can trigger the update manually + ::execute_upgrade(&*updater); + + assert_eq!(updater.state.lock().status, UpdaterStatus::Installed { release: latest_release }); + + // the final binary should exist in the updates folder and the 'latest' file should be updated to point to it + let updated_binary = tempdir.path().join(Updater::update_file_name(&latest_version)); + let latest_file = tempdir.path().join("latest"); + + assert!(updated_binary.exists()); + assert!(latest_file.exists()); + + let mut latest_file_content = String::new(); + File::open(latest_file).unwrap().read_to_string(&mut latest_file_content).unwrap(); + + assert_eq!(latest_file_content, updated_binary.file_name().and_then(|n| n.to_str()).unwrap()); + } + + #[test] + fn should_randomly_delay_new_updates() { + let (update_policy, _) = update_policy(); + let (client, updater, operations_client, _, _, rng) = setup(update_policy); + + let (_, latest_release, latest) = new_upgrade("1.0.1"); + operations_client.set_result(Some(latest.clone()), Some(0)); + + rng.set_result(5); + + updater.poll(); + + // the update should be delayed for 5 blocks + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Waiting { ref release, block_number, .. } if *release == latest_release && block_number == 5); + + client.add_blocks(1, EachBlockWith::Nothing); + updater.poll(); + + // we should still be in the waiting state after we push one block + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Waiting { ref release, block_number, .. } if *release == latest_release && block_number == 5); + + client.add_blocks(5, EachBlockWith::Nothing); + updater.poll(); + + // after we're past the delay the status should switch to fetching + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Fetching { ref release, .. } if *release == latest_release); + } + + #[test] + fn should_not_delay_old_updates() { + let (update_policy, _) = update_policy(); + let (client, updater, operations_client, ..) = setup(update_policy); + client.add_blocks(100, EachBlockWith::Nothing); + + let (_, latest_release, latest) = new_upgrade("1.0.1"); + operations_client.set_result(Some(latest.clone()), Some(0)); + + updater.poll(); + + // the update should not be delayed since it's older than the maximum delay + // the update was at block 0 (100 blocks ago), and the maximum delay is 10 blocks + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Fetching { ref release, .. } if *release == latest_release); + } + + #[test] + fn should_check_for_updates_with_configured_frequency() { + let (mut update_policy, _) = update_policy(); + update_policy.frequency = 2; + + let (client, updater, operations_client, _, _, rng) = setup(update_policy); + let (_, latest_release, latest) = new_upgrade("1.0.1"); + operations_client.set_result(Some(latest.clone()), Some(0)); + rng.set_result(5); + + client.add_blocks(1, EachBlockWith::Nothing); + updater.poll(); + + // the updater should stay idle since we only check for updates every other block (odd blocks in this case) + assert_eq!(updater.state.lock().status, UpdaterStatus::Idle); + + client.add_blocks(1, EachBlockWith::Nothing); + updater.poll(); + + // after adding a block we check for a new update and trigger the random delay (of 5 blocks) + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Waiting { ref release, block_number, .. } if *release == latest_release && block_number == 5); + } + + #[test] + fn should_backoff_retry_when_update_fails() { + let (update_policy, tempdir) = update_policy(); + let (_client, updater, operations_client, fetcher, time_provider, ..) = setup(update_policy); + let (_, latest_release, latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + let mut now = Instant::now(); + time_provider.set_result(now); + + updater.poll(); + fetcher.trigger(None); + + // we triggered the fetcher with an error result so the updater should backoff any retry + assert_matches!( + updater.state.lock().status, + UpdaterStatus::FetchBackoff { ref release, ref backoff, .. } if *release == latest_release && backoff.0 == 1); + + now += Duration::from_secs(1); + time_provider.set_result(now); + updater.poll(); + + // if we don't wait for the elapsed time the updater status should stay the same + assert_matches!( + updater.state.lock().status, + UpdaterStatus::FetchBackoff { ref release, ref backoff, .. } if *release == latest_release && backoff.0 == 1); + + now += Duration::from_secs(1); + time_provider.set_result(now); + updater.poll(); + fetcher.trigger(None); + + // the backoff time has elapsed so we retried again (and failed) + assert_matches!( + updater.state.lock().status, + UpdaterStatus::FetchBackoff { ref release, ref backoff, .. } if *release == latest_release && backoff.0 == 2); + + now += Duration::from_secs(4); + time_provider.set_result(now); + updater.poll(); + + let update_file = tempdir.path().join("parity"); + File::create(update_file.clone()).unwrap(); + fetcher.trigger(Some(update_file)); + + // after setting up the mocked fetch and waiting for the backoff period the update should succeed + assert_eq!(updater.state.lock().status, UpdaterStatus::Ready { release: latest_release }); + } + + #[test] + fn should_quit_backoff_on_new_release() { + let (update_policy, tempdir) = update_policy(); + let (_client, updater, operations_client, fetcher, ..) = setup(update_policy); + let (_, latest_release, latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + updater.poll(); + fetcher.trigger(None); + + // we triggered the fetcher with an error result so the updater should backoff any retry + assert_matches!( + updater.state.lock().status, + UpdaterStatus::FetchBackoff { ref release, ref backoff, .. } if *release == latest_release && backoff.0 == 1); + + // mock new working release and trigger the fetch afterwards + let (_, latest_release, latest) = new_upgrade("1.0.2"); + operations_client.set_result(Some(latest.clone()), None); + let update_file = tempdir.path().join("parity"); + File::create(update_file.clone()).unwrap(); + + updater.poll(); + fetcher.trigger(Some(update_file)); + + // a new release should short-circuit the backoff + assert_eq!(updater.state.lock().status, UpdaterStatus::Ready { release: latest_release }); + } + + #[test] + fn should_detect_already_downloaded_releases() { + let (update_policy, tempdir) = update_policy(); + let (_client, updater, operations_client, ..) = setup(update_policy); + let (latest_version, latest_release, latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + // mock final update file + let update_file = tempdir.path().join(Updater::update_file_name(&latest_version)); + File::create(update_file.clone()).unwrap(); + + updater.poll(); + + // after checking for a new update we immediately declare it as ready since it already exists on disk + // there was no need to trigger the fetch + assert_eq!(updater.state.lock().status, UpdaterStatus::Ready { release: latest_release }); + } + + #[test] + fn should_stay_disabled_after_fatal_error() { + let (update_policy, tempdir) = update_policy(); + let (client, updater, operations_client, fetcher, ..) = setup(update_policy); + let (_, _, latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + updater.poll(); + // trigger the fetch but don't create the file on-disk. this should lead to a fatal error that disables the updater + let update_file = tempdir.path().join("parity"); + fetcher.trigger(Some(update_file)); + + assert_eq!(updater.state.lock().status, UpdaterStatus::Disabled); + + client.add_blocks(100, EachBlockWith::Nothing); + updater.poll(); + + // the updater should stay disabled after new blocks are pushed + assert_eq!(updater.state.lock().status, UpdaterStatus::Disabled); + + let (_, _, latest) = new_upgrade("1.0.2"); + operations_client.set_result(Some(latest.clone()), None); + + updater.poll(); + + // the updater should stay disabled after a new release is pushed + assert_eq!(updater.state.lock().status, UpdaterStatus::Disabled); + } + + #[test] + fn should_ignore_current_fetch_on_new_release() { + let (update_policy, _) = update_policy(); + let (_client, updater, operations_client, fetcher, ..) = setup(update_policy); + let (_, latest_release, latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + updater.poll(); + + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Fetching { ref release, .. } if *release == latest_release); + + let (_, latest_release, latest) = new_upgrade("1.0.2"); + operations_client.set_result(Some(latest.clone()), None); + fetcher.trigger(None); + updater.poll(); + + // even though we triggered the previous fetch with an error, the current state was updated to fetch the new + // release, and the previous fetch is ignored + assert_matches!( + updater.state.lock().status, + UpdaterStatus::Fetching { ref release, .. } if *release == latest_release); + } + + #[test] + fn should_auto_install_updates_if_update_policy_allows() { + let (mut update_policy, tempdir) = update_policy(); + update_policy.filter = UpdateFilter::All; + let (_client, updater, operations_client, fetcher, ..) = setup(update_policy); + let (latest_version, latest_release, latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + // we start in idle state and with no information regarding the latest release + assert_eq!(updater.state.lock().latest, None); + assert_eq!(updater.state.lock().status, UpdaterStatus::Idle); + + updater.poll(); + + // mock fetcher with update binary and trigger the fetch + let update_file = tempdir.path().join("parity"); + File::create(update_file.clone()).unwrap(); + fetcher.trigger(Some(update_file)); + + // the update is auto installed since the update policy allows it + assert_eq!(updater.state.lock().status, UpdaterStatus::Installed { release: latest_release }); + + // the final binary should exist in the updates folder and the 'latest' file should be updated to point to it + let updated_binary = tempdir.path().join(Updater::update_file_name(&latest_version)); + let latest_file = tempdir.path().join("latest"); + + assert!(updated_binary.exists()); + assert!(latest_file.exists()); + + let mut latest_file_content = String::new(); + File::open(latest_file).unwrap().read_to_string(&mut latest_file_content).unwrap(); + + assert_eq!(latest_file_content, updated_binary.file_name().and_then(|n| n.to_str()).unwrap()); + } + + #[test] + fn should_update_capability() { + let (update_policy, _tempdir) = update_policy(); + let (client, updater, operations_client, _, ..) = setup(update_policy); + let (_, _, mut latest) = new_upgrade("1.0.1"); + + // mock operations contract with a new version + operations_client.set_result(Some(latest.clone()), None); + + // we start with no information regarding our node's capabilities + assert_eq!(updater.state.lock().capability, CapState::Unknown); + + updater.poll(); + + // our node supports the current fork + assert_eq!(updater.state.lock().capability, CapState::Capable); + + // lets announce a new fork which our node doesn't support + latest.fork = 2; + operations_client.set_result(Some(latest.clone()), None); + updater.poll(); + + // our node is only capable of operating until block #2 when the fork triggers + assert_eq!(updater.state.lock().capability, CapState::CapableUntil(2)); + + client.add_blocks(3, EachBlockWith::Nothing); + updater.poll(); + + // after we move past the fork the capability should be updated to incapable + assert_eq!(updater.state.lock().capability, CapState::IncapableSince(2)); + + // and since our update policy requires consensus, the client should be disabled + assert!(client.is_disabled()); } } diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index 765572b42c..b2ffed329c 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -232,9 +232,9 @@ pub fn default_local_path() -> String { } /// Default hypervisor path -pub fn default_hypervisor_path() -> String { +pub fn default_hypervisor_path() -> PathBuf { let app_info = AppInfo { name: PRODUCT_HYPERVISOR, author: AUTHOR }; - get_app_root(AppDataType::UserData, &app_info).map(|p| p.to_string_lossy().into_owned()).unwrap_or_else(|_| "$HOME/.parity-hypervisor".to_owned()) + get_app_root(AppDataType::UserData, &app_info).unwrap_or_else(|_| "$HOME/.parity-hypervisor".into()) } /// Get home directory. -- GitLab From 0a535bf4854cad64d00c156818a794c99c7ec7c0 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 3 Apr 2018 16:51:57 +0200 Subject: [PATCH 026/263] Honor --max-peers if --min-peers is not specified (#8087) * Change interpretation min and max peers * Only min specified -> Set min to that value and max to default * Only max specified -> Set min and max to that value * Both specified -> Set min the smallest value and max to the largest value * simplify logic, new ParseError & add tests * simplify code according to the review comments * address review comments * more fine-grained tests --- parity/cli/mod.rs | 22 +++++++++++--- parity/cli/usage.rs | 12 ++++++++ parity/configuration.rs | 66 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 22be9a0c47..7b26aa6bd1 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -409,11 +409,11 @@ usage! { "--port=[PORT]", "Override the port on which the node should listen.", - ARG arg_min_peers: (u16) = 25u16, or |c: &Config| c.network.as_ref()?.min_peers.clone(), + ARG arg_min_peers: (Option) = None, or |c: &Config| c.network.as_ref()?.min_peers.clone(), "--min-peers=[NUM]", "Try to maintain at least NUM peers.", - ARG arg_max_peers: (u16) = 50u16, or |c: &Config| c.network.as_ref()?.max_peers.clone(), + ARG arg_max_peers: (Option) = None, or |c: &Config| c.network.as_ref()?.max_peers.clone(), "--max-peers=[NUM]", "Allow up to NUM peers.", @@ -1504,8 +1504,8 @@ mod tests { // -- Networking Options flag_no_warp: false, arg_port: 30303u16, - arg_min_peers: 25u16, - arg_max_peers: 50u16, + arg_min_peers: Some(25u16), + arg_max_peers: Some(50u16), arg_max_pending_peers: 64u16, arg_snapshot_peers: 0u16, arg_allow_ips: "all".into(), @@ -1896,4 +1896,18 @@ mod tests { stratum: None, }); } + + #[test] + fn should_not_accept_min_peers_bigger_than_max_peers() { + match Args::parse(&["parity", "--max-peers=39", "--min-peers=40"]) { + Err(ArgsError::PeerConfiguration) => (), + _ => assert_eq!(false, true), + } + } + + #[test] + fn should_accept_max_peers_equal_or_bigger_than_min_peers() { + Args::parse(&["parity", "--max-peers=40", "--min-peers=40"]).unwrap(); + Args::parse(&["parity", "--max-peers=100", "--min-peers=40"]).unwrap(); + } } diff --git a/parity/cli/usage.rs b/parity/cli/usage.rs index 2dabc8378c..2bdeaaed1a 100644 --- a/parity/cli/usage.rs +++ b/parity/cli/usage.rs @@ -161,6 +161,7 @@ macro_rules! usage { Clap(ClapError), Decode(toml::de::Error), Config(String, io::Error), + PeerConfiguration, } impl ArgsError { @@ -177,6 +178,10 @@ macro_rules! usage { println_stderr!("{}", e); process::exit(2) }, + ArgsError::PeerConfiguration => { + println_stderr!("You have supplied `min_peers` > `max_peers`"); + process::exit(2) + } } } } @@ -312,6 +317,13 @@ macro_rules! usage { pub fn parse>(command: &[S]) -> Result { let raw_args = RawArgs::parse(command)?; + if let (Some(max_peers), Some(min_peers)) = (raw_args.arg_max_peers, raw_args.arg_min_peers) { + // Invalid configuration pattern `mix_peers` > `max_peers` + if min_peers > max_peers { + return Err(ArgsError::PeerConfiguration); + } + } + // Skip loading config file if no_config flag is specified if raw_args.flag_no_config { return Ok(raw_args.into_args(Config::default())); diff --git a/parity/configuration.rs b/parity/configuration.rs index 07245dbbea..db8759a71f 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::cmp::{max, min}; use std::time::Duration; use std::io::Read; use std::net::SocketAddr; use std::path::{Path, PathBuf}; use std::collections::BTreeMap; -use std::cmp::max; use std::str::FromStr; use cli::{Args, ArgsError}; use hash::keccak; @@ -55,6 +55,9 @@ use account::{AccountCmd, NewAccount, ListAccounts, ImportAccounts, ImportFromGe use snapshot::{self, SnapshotCommand}; use network::{IpFilter}; +const DEFAULT_MAX_PEERS: u16 = 50; +const DEFAULT_MIN_PEERS: u16 = 25; + #[derive(Debug, PartialEq)] pub enum Cmd { Run(RunCmd), @@ -469,8 +472,9 @@ impl Configuration { } fn max_peers(&self) -> u32 { - let peers = self.args.arg_max_peers as u32; - max(self.min_peers(), peers) + self.args.arg_max_peers + .or(max(self.args.arg_min_peers, Some(DEFAULT_MAX_PEERS))) + .unwrap_or(DEFAULT_MAX_PEERS) as u32 } fn ip_filter(&self) -> Result { @@ -481,7 +485,9 @@ impl Configuration { } fn min_peers(&self) -> u32 { - self.args.arg_peers.unwrap_or(self.args.arg_min_peers) as u32 + self.args.arg_min_peers + .or(min(self.args.arg_max_peers, Some(DEFAULT_MIN_PEERS))) + .unwrap_or(DEFAULT_MIN_PEERS) as u32 } fn max_pending_peers(&self) -> u32 { @@ -1970,4 +1976,56 @@ mod tests { assert_eq!(std.directories().cache, dir::helpers::replace_home_and_local(&base_path, &local_path, ::dir::CACHE_PATH)); assert_eq!(base.directories().cache, "/test/cache"); } + + #[test] + fn should_respect_only_max_peers_and_default() { + let args = vec!["parity", "--max-peers=50"]; + let conf = Configuration::parse(&args, None).unwrap(); + match conf.into_command().unwrap().cmd { + Cmd::Run(c) => { + assert_eq!(c.net_conf.min_peers, 25); + assert_eq!(c.net_conf.max_peers, 50); + }, + _ => panic!("Should be Cmd::Run"), + } + } + + #[test] + fn should_respect_only_max_peers_less_than_default() { + let args = vec!["parity", "--max-peers=5"]; + let conf = Configuration::parse(&args, None).unwrap(); + match conf.into_command().unwrap().cmd { + Cmd::Run(c) => { + assert_eq!(c.net_conf.min_peers, 5); + assert_eq!(c.net_conf.max_peers, 5); + }, + _ => panic!("Should be Cmd::Run"), + } + } + + #[test] + fn should_respect_only_min_peers_and_default() { + let args = vec!["parity", "--min-peers=5"]; + let conf = Configuration::parse(&args, None).unwrap(); + match conf.into_command().unwrap().cmd { + Cmd::Run(c) => { + assert_eq!(c.net_conf.min_peers, 5); + assert_eq!(c.net_conf.max_peers, 50); + }, + _ => panic!("Should be Cmd::Run"), + } + } + + #[test] + fn should_respect_only_min_peers_and_greater_than_default() { + let args = vec!["parity", "--min-peers=500"]; + let conf = Configuration::parse(&args, None).unwrap(); + match conf.into_command().unwrap().cmd { + Cmd::Run(c) => { + assert_eq!(c.net_conf.min_peers, 500); + assert_eq!(c.net_conf.max_peers, 500); + }, + _ => panic!("Should be Cmd::Run"), + } + } } -- GitLab From ec96091369dc254df3c3762134136aa4ab6d2577 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 3 Apr 2018 17:54:34 +0300 Subject: [PATCH 027/263] SecretStore: generating and retrieving decryption keys via service contract (#8029) * SecretStore: started document keys generation via contract * fixed Cargo.lock * SecretStore: doc key contract gen tests * SecretStore: fixed log parsing * SecretStore: flush * SecretStore: secretstore_generateDocumentKey RPC * SecretStore: return encrypted_key from secretstore_generateDocumentKey * prepare to GenerateDocKey -> StoreDocKey * SecretStore: ability to identify requester via Public/Address * SecretStore: store author address instead of public in db * flush * SecretStore: flush * SecretStore: fixed test * SecretStore: flush * SecretStore: flush * SecretStore: flush * SecretStore: flush * SecretStore: start async generation session * SecretStore: process StoreDocumentKey service tasks * SecretStore: flush * SecretStore: update service contact ABI * SecretStore: flush * SecretStore: flush * SecretStore: fixed event * SecretStore: flush * SecretStore: fixed tests * SecretStore: fix broadcast shadows decryption * SecretStore: finally decryption via service contract works * SecretStore: fix for updated contract * SecretStore: restored pending requests reqding * SecretStore: fixed some TODOs * SecretStore: OnChainServiceContractAggregate * SecretStore: different names for different contracts types * SecretStore: updated contracts interfaces * SecretStore: utilize aggregate service contract * fixed compilation * SecretStore: fixes for updated contract * SecretStore: service fixes after testing * fixed cli test compilation * SecretStore: decryption_session_origin_is_known_to_all_initialized_nodes * SecretStore: added new contract listener tests * SecretStore: session_listener_works * removed optional TODO * SecretStore: fixed KeyServer shutdown * fixed warn + grumble * const durations --- parity/cli/mod.rs | 30 +- parity/cli/tests/config.full.toml | 4 + parity/configuration.rs | 34 +- parity/secretstore.rs | 28 +- secret_store/res/key_server_set.json | 25 +- secret_store/res/service.json | 35 +- secret_store/src/acl_storage.rs | 26 +- secret_store/src/key_server.rs | 152 ++-- .../key_version_negotiation_session.rs | 7 +- .../servers_set_change_session.rs | 5 +- .../client_sessions/decryption_session.rs | 237 ++++-- .../client_sessions/encryption_session.rs | 59 +- .../client_sessions/generation_session.rs | 39 +- .../client_sessions/signing_session_ecdsa.rs | 19 +- .../signing_session_schnorr.rs | 25 +- .../src/key_server_cluster/cluster.rs | 70 +- .../key_server_cluster/cluster_sessions.rs | 40 +- .../jobs/consensus_session.rs | 30 +- .../key_server_cluster/jobs/decryption_job.rs | 4 +- .../key_server_cluster/jobs/job_session.rs | 75 +- .../key_server_cluster/jobs/key_access_job.rs | 2 +- .../src/key_server_cluster/message.rs | 6 + secret_store/src/key_server_cluster/mod.rs | 4 +- secret_store/src/key_storage.rs | 4 + secret_store/src/lib.rs | 81 +- secret_store/src/listener/http_listener.rs | 45 +- secret_store/src/listener/mod.rs | 60 +- secret_store/src/listener/service_contract.rs | 789 +++++++++++++++--- .../listener/service_contract_aggregate.rs | 100 +++ .../src/listener/service_contract_listener.rs | 692 +++++++++++---- secret_store/src/traits.rs | 28 +- secret_store/src/types/all.rs | 44 +- 32 files changed, 2117 insertions(+), 682 deletions(-) create mode 100644 secret_store/src/listener/service_contract_aggregate.rs diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 7b26aa6bd1..6e21238e60 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -573,7 +573,23 @@ usage! { ARG arg_secretstore_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract.clone(), "--secretstore-contract=[SOURCE]", - "Secret Store Service contract address source: none, registry (contract address is read from registry) or address.", + "Secret Store Service contract address source: none, registry (contract address is read from secretstore_service entry in registry) or address.", + + ARG arg_secretstore_srv_gen_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_srv_gen.clone(), + "--secretstore-srv-gen-contract=[SOURCE]", + "Secret Store Service server key generation contract address source: none, registry (contract address is read from secretstore_service_srv_gen entry in registry) or address.", + + ARG arg_secretstore_srv_retr_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_srv_retr.clone(), + "--secretstore-srv-retr-contract=[SOURCE]", + "Secret Store Service server key retrieval contract address source: none, registry (contract address is read from secretstore_service_srv_retr entry in registry) or address.", + + ARG arg_secretstore_doc_store_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_doc_store.clone(), + "--secretstore-doc-store-contract=[SOURCE]", + "Secret Store Service document key store contract address source: none, registry (contract address is read from secretstore_service_doc_store entry in registry) or address.", + + ARG arg_secretstore_doc_sretr_contract: (String) = "none", or |c: &Config| c.secretstore.as_ref()?.service_contract_doc_sretr.clone(), + "--secretstore-doc-sretr-contract=[SOURCE]", + "Secret Store Service document key shadow retrieval contract address source: none, registry (contract address is read from secretstore_service_doc_sretr entry in registry) or address.", ARG arg_secretstore_nodes: (String) = "", or |c: &Config| c.secretstore.as_ref()?.nodes.as_ref().map(|vec| vec.join(",")), "--secretstore-nodes=[NODES]", @@ -1133,6 +1149,10 @@ struct SecretStore { disable_acl_check: Option, disable_auto_migrate: Option, service_contract: Option, + service_contract_srv_gen: Option, + service_contract_srv_retr: Option, + service_contract_doc_store: Option, + service_contract_doc_sretr: Option, self_secret: Option, admin_public: Option, nodes: Option>, @@ -1554,6 +1574,10 @@ mod tests { flag_no_secretstore_acl_check: false, flag_no_secretstore_auto_migrate: false, arg_secretstore_contract: "none".into(), + arg_secretstore_srv_gen_contract: "none".into(), + arg_secretstore_srv_retr_contract: "none".into(), + arg_secretstore_doc_store_contract: "none".into(), + arg_secretstore_doc_sretr_contract: "none".into(), arg_secretstore_secret: None, arg_secretstore_admin_public: None, arg_secretstore_nodes: "".into(), @@ -1812,6 +1836,10 @@ mod tests { disable_acl_check: None, disable_auto_migrate: None, service_contract: None, + service_contract_srv_gen: None, + service_contract_srv_retr: None, + service_contract_doc_store: None, + service_contract_doc_sretr: None, self_secret: None, admin_public: None, nodes: None, diff --git a/parity/cli/tests/config.full.toml b/parity/cli/tests/config.full.toml index 749ffd8514..702a186319 100644 --- a/parity/cli/tests/config.full.toml +++ b/parity/cli/tests/config.full.toml @@ -83,6 +83,10 @@ disable = false disable_http = false disable_acl_check = false service_contract = "none" +service_contract_srv_gen = "none" +service_contract_srv_retr = "none" +service_contract_doc_store = "none" +service_contract_doc_sretr = "none" nodes = [] http_interface = "local" http_port = 8082 diff --git a/parity/configuration.rs b/parity/configuration.rs index db8759a71f..f242edb0f6 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -635,6 +635,10 @@ impl Configuration { acl_check_enabled: self.secretstore_acl_check_enabled(), auto_migrate_enabled: self.secretstore_auto_migrate_enabled(), service_contract_address: self.secretstore_service_contract_address()?, + service_contract_srv_gen_address: self.secretstore_service_contract_srv_gen_address()?, + service_contract_srv_retr_address: self.secretstore_service_contract_srv_retr_address()?, + service_contract_doc_store_address: self.secretstore_service_contract_doc_store_address()?, + service_contract_doc_sretr_address: self.secretstore_service_contract_doc_sretr_address()?, self_secret: self.secretstore_self_secret()?, nodes: self.secretstore_nodes()?, interface: self.secretstore_interface(), @@ -1127,11 +1131,23 @@ impl Configuration { } fn secretstore_service_contract_address(&self) -> Result, String> { - Ok(match self.args.arg_secretstore_contract.as_ref() { - "none" => None, - "registry" => Some(SecretStoreContractAddress::Registry), - a => Some(SecretStoreContractAddress::Address(a.parse().map_err(|e| format!("{}", e))?)), - }) + into_secretstore_service_contract_address(self.args.arg_secretstore_contract.as_ref()) + } + + fn secretstore_service_contract_srv_gen_address(&self) -> Result, String> { + into_secretstore_service_contract_address(self.args.arg_secretstore_srv_gen_contract.as_ref()) + } + + fn secretstore_service_contract_srv_retr_address(&self) -> Result, String> { + into_secretstore_service_contract_address(self.args.arg_secretstore_srv_retr_contract.as_ref()) + } + + fn secretstore_service_contract_doc_store_address(&self) -> Result, String> { + into_secretstore_service_contract_address(self.args.arg_secretstore_doc_store_contract.as_ref()) + } + + fn secretstore_service_contract_doc_sretr_address(&self) -> Result, String> { + into_secretstore_service_contract_address(self.args.arg_secretstore_doc_sretr_contract.as_ref()) } fn ui_enabled(&self) -> bool { @@ -1164,6 +1180,14 @@ impl Configuration { } } +fn into_secretstore_service_contract_address(s: &str) -> Result, String> { + match s { + "none" => Ok(None), + "registry" => Ok(Some(SecretStoreContractAddress::Registry)), + a => Ok(Some(SecretStoreContractAddress::Address(a.parse().map_err(|e| format!("{}", e))?))), + } +} + #[cfg(test)] mod tests { use std::io::Write; diff --git a/parity/secretstore.rs b/parity/secretstore.rs index c71f2c14da..797f8673b1 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -55,6 +55,14 @@ pub struct Configuration { pub auto_migrate_enabled: bool, /// Service contract address. pub service_contract_address: Option, + /// Server key generation service contract address. + pub service_contract_srv_gen_address: Option, + /// Server key retrieval service contract address. + pub service_contract_srv_retr_address: Option, + /// Document key store service contract address. + pub service_contract_doc_store_address: Option, + /// Document key shadow retrieval service contract address. + pub service_contract_doc_sretr_address: Option, /// This node secret. pub self_secret: Option, /// Other nodes IDs + addresses. @@ -108,6 +116,13 @@ mod server { use ansi_term::Colour::Red; use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress}; + fn into_service_contract_address(address: ContractAddress) -> ethcore_secretstore::ContractAddress { + match address { + ContractAddress::Registry => ethcore_secretstore::ContractAddress::Registry, + ContractAddress::Address(address) => ethcore_secretstore::ContractAddress::Address(address), + } + } + /// Key server pub struct KeyServer { _key_server: Box, @@ -150,10 +165,11 @@ mod server { address: conf.http_interface.clone(), port: conf.http_port, }) } else { None }, - service_contract_address: conf.service_contract_address.map(|c| match c { - ContractAddress::Registry => ethcore_secretstore::ContractAddress::Registry, - ContractAddress::Address(address) => ethcore_secretstore::ContractAddress::Address(address), - }), + service_contract_address: conf.service_contract_address.map(into_service_contract_address), + service_contract_srv_gen_address: conf.service_contract_srv_gen_address.map(into_service_contract_address), + service_contract_srv_retr_address: conf.service_contract_srv_retr_address.map(into_service_contract_address), + service_contract_doc_store_address: conf.service_contract_doc_store_address.map(into_service_contract_address), + service_contract_doc_sretr_address: conf.service_contract_doc_sretr_address.map(into_service_contract_address), data_path: conf.data_path.clone(), acl_check_enabled: conf.acl_check_enabled, cluster_config: ethcore_secretstore::ClusterConfiguration { @@ -195,6 +211,10 @@ impl Default for Configuration { acl_check_enabled: true, auto_migrate_enabled: true, service_contract_address: None, + service_contract_srv_gen_address: None, + service_contract_srv_retr_address: None, + service_contract_doc_store_address: None, + service_contract_doc_sretr_address: None, self_secret: None, admin_public: None, nodes: BTreeMap::new(), diff --git a/secret_store/res/key_server_set.json b/secret_store/res/key_server_set.json index 0fb9502b11..28530e3532 100644 --- a/secret_store/res/key_server_set.json +++ b/secret_store/res/key_server_set.json @@ -1 +1,24 @@ -[{"constant":true,"inputs":[],"name":"getMigrationMaster","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getMigrationKeyServerPublic","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"bytes32"}],"name":"startMigration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getMigrationKeyServerAddress","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMigrationId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNewKeyServers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"bytes32"}],"name":"confirmMigration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getMigrationKeyServers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"isMigrationConfirmed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentKeyServers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getCurrentKeyServerPublic","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getNewKeyServerAddress","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getCurrentKeyServerAddress","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getNewKeyServerPublic","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keyServer","type":"address"}],"name":"KeyServerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keyServer","type":"address"}],"name":"KeyServerRemoved","type":"event"},{"anonymous":false,"inputs":[],"name":"MigrationStarted","type":"event"},{"anonymous":false,"inputs":[],"name":"MigrationCompleted","type":"event"}] \ No newline at end of file +[ + {"constant":true,"inputs":[],"name":"getMigrationMaster","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getMigrationKeyServerPublic","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":false,"inputs":[{"name":"id","type":"bytes32"}],"name":"startMigration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getCurrentKeyServerIndex","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getMigrationKeyServerAddress","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[],"name":"getMigrationId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[],"name":"getNewKeyServers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":false,"inputs":[{"name":"id","type":"bytes32"}],"name":"confirmMigration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[],"name":"getMigrationKeyServers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"isMigrationConfirmed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[],"name":"getCurrentKeyServersCount","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[],"name":"getCurrentKeyServers","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[],"name":"getCurrentLastChange","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getCurrentKeyServerPublic","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getNewKeyServerAddress","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getCurrentKeyServerAddress","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getNewKeyServerPublic","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"index","type":"uint8"}],"name":"getCurrentKeyServer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}, + {"anonymous":false,"inputs":[{"indexed":false,"name":"keyServer","type":"address"}],"name":"KeyServerAdded","type":"event"}, + {"anonymous":false,"inputs":[{"indexed":false,"name":"keyServer","type":"address"}],"name":"KeyServerRemoved","type":"event"}, + {"anonymous":false,"inputs":[],"name":"MigrationStarted","type":"event"}, + {"anonymous":false,"inputs":[],"name":"MigrationCompleted","type":"event"} +] \ No newline at end of file diff --git a/secret_store/res/service.json b/secret_store/res/service.json index 37d45350b2..d79c38e7aa 100644 --- a/secret_store/res/service.json +++ b/secret_store/res/service.json @@ -1,8 +1,33 @@ [ + {"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"requireKeyServer","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[],"name":"serverKeyGenerationRequestsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}, - {"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getServerKeyId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"}, - {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"serverKeyPublic","type":"bytes"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"serverKeyGenerated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, - {"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"}],"name":"getServerKeyThreshold","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}, - {"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"authority","type":"address"}],"name":"getServerKeyConfirmationStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}, - {"anonymous":false,"inputs":[{"indexed":true,"name":"serverKeyId","type":"bytes32"},{"indexed":true,"name":"threshold","type":"uint256"}],"name":"ServerKeyRequested","type":"event"} + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"}],"name":"serverKeyGenerationError","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getServerKeyGenerationRequest","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"serverKeyPublic","type":"bytes"}],"name":"serverKeyGenerated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"keyServer","type":"address"}],"name":"isServerKeyGenerationResponseRequired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}, + {"anonymous":false,"inputs":[{"indexed":false,"name":"serverKeyId","type":"bytes32"},{"indexed":false,"name":"author","type":"address"},{"indexed":false,"name":"threshold","type":"uint8"}],"name":"ServerKeyGenerationRequested","type":"event"}, + + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"}],"name":"serverKeyRetrievalError","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[],"name":"serverKeyRetrievalRequestsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"keyServer","type":"address"}],"name":"isServerKeyRetrievalResponseRequired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getServerKeyRetrievalRequest","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"serverKeyPublic","type":"bytes"},{"name":"threshold","type":"uint8"}],"name":"serverKeyRetrieved","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"anonymous":false,"inputs":[{"indexed":false,"name":"serverKeyId","type":"bytes32"}],"name":"ServerKeyRetrievalRequested","type":"event"}, + + {"constant":true,"inputs":[],"name":"documentKeyStoreRequestsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"}],"name":"documentKeyStoreError","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"}],"name":"documentKeyStored","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"keyServer","type":"address"}],"name":"isDocumentKeyStoreResponseRequired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getDocumentKeyStoreRequest","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"address"},{"name":"","type":"bytes"},{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"}, + {"anonymous":false,"inputs":[{"indexed":false,"name":"serverKeyId","type":"bytes32"},{"indexed":false,"name":"author","type":"address"},{"indexed":false,"name":"commonPoint","type":"bytes"},{"indexed":false,"name":"encryptedPoint","type":"bytes"}],"name":"DocumentKeyStoreRequested","type":"event"}, + + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"requester","type":"address"},{"name":"commonPoint","type":"bytes"},{"name":"threshold","type":"uint8"}],"name":"documentKeyCommonRetrieved","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"keyServer","type":"address"},{"name":"requester","type":"address"}],"name":"isDocumentKeyShadowRetrievalResponseRequired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"requester","type":"address"},{"name":"participants","type":"uint256"},{"name":"decryptedSecret","type":"bytes"},{"name":"shadow","type":"bytes"}],"name":"documentKeyPersonalRetrieved","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":false,"inputs":[{"name":"serverKeyId","type":"bytes32"},{"name":"requester","type":"address"}],"name":"documentKeyShadowRetrievalError","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}, + {"constant":true,"inputs":[],"name":"documentKeyShadowRetrievalRequestsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}, + {"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getDocumentKeyShadowRetrievalRequest","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"bytes"},{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}, + {"anonymous":false,"inputs":[{"indexed":false,"name":"serverKeyId","type":"bytes32"},{"indexed":false,"name":"requester","type":"address"}],"name":"DocumentKeyCommonRetrievalRequested","type":"event"}, + {"anonymous":false,"inputs":[{"indexed":false,"name":"serverKeyId","type":"bytes32"},{"indexed":false,"name":"requesterPublic","type":"bytes"}],"name":"DocumentKeyPersonalRetrievalRequested","type":"event"} ] \ No newline at end of file diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index f3d116145f..0ff8a2f307 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -17,12 +17,11 @@ use std::sync::Arc; use std::collections::{HashMap, HashSet}; use parking_lot::{Mutex, RwLock}; -use ethkey::public_to_address; use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; use ethereum_types::{H256, Address}; use bytes::Bytes; use trusted_client::TrustedClient; -use types::all::{Error, ServerKeyId, Public}; +use types::all::{Error, ServerKeyId}; use_contract!(acl_storage, "AclStorage", "res/acl_storage.json"); @@ -30,8 +29,8 @@ const ACL_CHECKER_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_acl_checke /// ACL storage of Secret Store pub trait AclStorage: Send + Sync { - /// Check if requestor with `public` key can access document with hash `document` - fn check(&self, public: &Public, document: &ServerKeyId) -> Result; + /// Check if requestor can access document with hash `document` + fn check(&self, requester: Address, document: &ServerKeyId) -> Result; } /// On-chain ACL storage implementation. @@ -53,7 +52,7 @@ struct CachedContract { /// Dummy ACL storage implementation (check always passed). #[derive(Default, Debug)] pub struct DummyAclStorage { - prohibited: RwLock>>, + prohibited: RwLock>>, } impl OnChainAclStorage { @@ -70,8 +69,8 @@ impl OnChainAclStorage { } impl AclStorage for OnChainAclStorage { - fn check(&self, public: &Public, document: &ServerKeyId) -> Result { - self.contract.lock().check(public, document) + fn check(&self, requester: Address, document: &ServerKeyId) -> Result { + self.contract.lock().check(requester, document) } } @@ -104,16 +103,15 @@ impl CachedContract { } } - pub fn check(&mut self, public: &Public, document: &ServerKeyId) -> Result { + pub fn check(&mut self, requester: Address, document: &ServerKeyId) -> Result { if let Some(client) = self.client.get() { // call contract to check accesss match self.contract_addr { Some(contract_address) => { - let address = public_to_address(&public); let do_call = |data| client.call_contract(BlockId::Latest, contract_address, data); self.contract.functions() .check_permissions() - .call(address, document.clone(), &do_call) + .call(requester, document.clone(), &do_call) .map_err(|e| Error::Internal(e.to_string())) }, None => Err(Error::Internal("ACL checker contract is not configured".to_owned())), @@ -127,18 +125,18 @@ impl CachedContract { impl DummyAclStorage { /// Prohibit given requestor access to given documents #[cfg(test)] - pub fn prohibit(&self, public: Public, document: ServerKeyId) { + pub fn prohibit(&self, requester: Address, document: ServerKeyId) { self.prohibited.write() - .entry(public) + .entry(requester) .or_insert_with(Default::default) .insert(document); } } impl AclStorage for DummyAclStorage { - fn check(&self, public: &Public, document: &ServerKeyId) -> Result { + fn check(&self, requester: Address, document: &ServerKeyId) -> Result { Ok(self.prohibited.read() - .get(public) + .get(&requester) .map(|docs| !docs.contains(document)) .unwrap_or(true)) } diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs index 181df0caaf..02d19eede1 100644 --- a/secret_store/src/key_server.rs +++ b/secret_store/src/key_server.rs @@ -22,13 +22,12 @@ use futures::{self, Future}; use parking_lot::Mutex; use tokio_core::reactor::Core; use ethcrypto; -use ethkey; use super::acl_storage::AclStorage; use super::key_storage::KeyStorage; use super::key_server_set::KeyServerSet; use key_server_cluster::{math, ClusterCore}; use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer, NodeKeyPair}; -use types::all::{Error, Public, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, +use types::all::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, ClusterConfiguration, MessageHash, EncryptedMessageSignature, NodeId}; use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration}; @@ -71,39 +70,39 @@ impl AdminSessionsServer for KeyServerImpl { } impl ServerKeyGenerator for KeyServerImpl { - fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result { + fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result { // recover requestor' public key from signature - let public = ethkey::recover(signature, key_id) - .map_err(|_| Error::BadSignature)?; + let address = author.address(key_id).map_err(Error::InsufficientRequesterData)?; // generate server key - let generation_session = self.data.lock().cluster.new_generation_session(key_id.clone(), public, threshold)?; - generation_session.wait(None).map_err(Into::into) + let generation_session = self.data.lock().cluster.new_generation_session(key_id.clone(), None, address, threshold)?; + generation_session.wait(None) + .expect("when wait is called without timeout it always returns Some; qed") + .map_err(Into::into) } } impl DocumentKeyServer for KeyServerImpl { - fn store_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, common_point: Public, encrypted_document_key: Public) -> Result<(), Error> { + fn store_document_key(&self, key_id: &ServerKeyId, author: &Requester, common_point: Public, encrypted_document_key: Public) -> Result<(), Error> { // store encrypted key let encryption_session = self.data.lock().cluster.new_encryption_session(key_id.clone(), - signature.clone().into(), common_point, encrypted_document_key)?; + author.clone(), common_point, encrypted_document_key)?; encryption_session.wait(None).map_err(Into::into) } - fn generate_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result { + fn generate_document_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result { // recover requestor' public key from signature - let public = ethkey::recover(signature, key_id) - .map_err(|_| Error::BadSignature)?; + let public = author.public(key_id).map_err(Error::InsufficientRequesterData)?; // generate server key - let server_key = self.generate_key(key_id, signature, threshold)?; + let server_key = self.generate_key(key_id, author, threshold)?; // generate random document key let document_key = math::generate_random_point()?; let encrypted_document_key = math::encrypt_secret(&document_key, &server_key)?; // store document key in the storage - self.store_document_key(key_id, signature, encrypted_document_key.common_point, encrypted_document_key.encrypted_point)?; + self.store_document_key(key_id, author, encrypted_document_key.common_point, encrypted_document_key.encrypted_point)?; // encrypt document key with requestor public key let document_key = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &document_key) @@ -111,15 +110,16 @@ impl DocumentKeyServer for KeyServerImpl { Ok(document_key) } - fn restore_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result { + fn restore_document_key(&self, key_id: &ServerKeyId, requester: &Requester) -> Result { // recover requestor' public key from signature - let public = ethkey::recover(signature, key_id) - .map_err(|_| Error::BadSignature)?; + let public = requester.public(key_id).map_err(Error::InsufficientRequesterData)?; // decrypt document key let decryption_session = self.data.lock().cluster.new_decryption_session(key_id.clone(), - signature.clone().into(), None, false)?; - let document_key = decryption_session.wait()?.decrypted_secret; + None, requester.clone(), None, false, false)?; + let document_key = decryption_session.wait(None) + .expect("when wait is called without timeout it always returns Some; qed")? + .decrypted_secret; // encrypt document key with requestor public key let document_key = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &document_key) @@ -127,22 +127,23 @@ impl DocumentKeyServer for KeyServerImpl { Ok(document_key) } - fn restore_document_key_shadow(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result { + fn restore_document_key_shadow(&self, key_id: &ServerKeyId, requester: &Requester) -> Result { let decryption_session = self.data.lock().cluster.new_decryption_session(key_id.clone(), - signature.clone().into(), None, true)?; - decryption_session.wait().map_err(Into::into) + None, requester.clone(), None, true, false)?; + decryption_session.wait(None) + .expect("when wait is called without timeout it always returns Some; qed") + .map_err(Into::into) } } impl MessageSigner for KeyServerImpl { - fn sign_message_schnorr(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result { + fn sign_message_schnorr(&self, key_id: &ServerKeyId, requester: &Requester, message: MessageHash) -> Result { // recover requestor' public key from signature - let public = ethkey::recover(signature, key_id) - .map_err(|_| Error::BadSignature)?; + let public = requester.public(key_id).map_err(Error::InsufficientRequesterData)?; // sign message let signing_session = self.data.lock().cluster.new_schnorr_signing_session(key_id.clone(), - signature.clone().into(), None, message)?; + requester.clone().into(), None, message)?; let message_signature = signing_session.wait()?; // compose two message signature components into single one @@ -156,14 +157,13 @@ impl MessageSigner for KeyServerImpl { Ok(message_signature) } - fn sign_message_ecdsa(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result { + fn sign_message_ecdsa(&self, key_id: &ServerKeyId, requester: &Requester, message: MessageHash) -> Result { // recover requestor' public key from signature - let public = ethkey::recover(signature, key_id) - .map_err(|_| Error::BadSignature)?; + let public = requester.public(key_id).map_err(Error::InsufficientRequesterData)?; // sign message let signing_session = self.data.lock().cluster.new_ecdsa_signing_session(key_id.clone(), - signature.clone().into(), None, message)?; + requester.clone().into(), None, message)?; let message_signature = signing_session.wait()?; // encrypt combined signature with requestor public key @@ -177,7 +177,7 @@ impl KeyServerCore { pub fn new(config: &ClusterConfiguration, key_server_set: Arc, self_key_pair: Arc, acl_storage: Arc, key_storage: Arc) -> Result { let config = NetClusterConfiguration { threads: config.threads, - self_key_pair: self_key_pair, + self_key_pair: self_key_pair.clone(), listen_address: (config.listener_address.address.clone(), config.listener_address.port), key_server_set: key_server_set, allow_connecting_to_higher_nodes: config.allow_connecting_to_higher_nodes, @@ -189,7 +189,7 @@ impl KeyServerCore { let (stop, stopped) = futures::oneshot(); let (tx, rx) = mpsc::channel(); - let handle = thread::spawn(move || { + let handle = thread::Builder::new().name("KeyServerLoop".into()).spawn(move || { let mut el = match Core::new() { Ok(el) => el, Err(e) => { @@ -202,7 +202,9 @@ impl KeyServerCore { let cluster_client = cluster.and_then(|c| c.run().map(|_| c.client())); tx.send(cluster_client.map_err(Into::into)).expect("Rx is blocking upper thread."); let _ = el.run(futures::empty().select(stopped)); - }); + + trace!(target: "secretstore_net", "{}: KeyServerLoop thread stopped", self_key_pair.public()); + }).map_err(|e| Error::Internal(format!("{}", e)))?; let cluster = rx.recv().map_err(|e| Error::Internal(format!("error initializing event loop: {}", e)))??; Ok(KeyServerCore { @@ -225,26 +227,25 @@ pub mod tests { use std::collections::BTreeSet; use std::time; use std::sync::Arc; - use std::sync::atomic::{AtomicUsize, Ordering}; use std::net::SocketAddr; use std::collections::BTreeMap; use ethcrypto; use ethkey::{self, Secret, Random, Generator, verify_public}; use acl_storage::DummyAclStorage; + use key_storage::KeyStorage; use key_storage::tests::DummyKeyStorage; use node_key_pair::PlainNodeKeyPair; use key_server_set::tests::MapKeyServerSet; use key_server_cluster::math; use ethereum_types::{H256, H520}; use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId, - EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature, NodeId}; + EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature, + Requester, NodeId}; use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer}; use super::KeyServerImpl; #[derive(Default)] - pub struct DummyKeyServer { - pub generation_requests_count: AtomicUsize, - } + pub struct DummyKeyServer; impl KeyServer for DummyKeyServer {} @@ -255,41 +256,40 @@ pub mod tests { } impl ServerKeyGenerator for DummyKeyServer { - fn generate_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _threshold: usize) -> Result { - self.generation_requests_count.fetch_add(1, Ordering::Relaxed); - Err(Error::Internal("test error".into())) + fn generate_key(&self, _key_id: &ServerKeyId, _author: &Requester, _threshold: usize) -> Result { + unimplemented!("test-only") } } impl DocumentKeyServer for DummyKeyServer { - fn store_document_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _common_point: Public, _encrypted_document_key: Public) -> Result<(), Error> { + fn store_document_key(&self, _key_id: &ServerKeyId, _author: &Requester, _common_point: Public, _encrypted_document_key: Public) -> Result<(), Error> { unimplemented!("test-only") } - fn generate_document_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _threshold: usize) -> Result { + fn generate_document_key(&self, _key_id: &ServerKeyId, _author: &Requester, _threshold: usize) -> Result { unimplemented!("test-only") } - fn restore_document_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature) -> Result { + fn restore_document_key(&self, _key_id: &ServerKeyId, _requester: &Requester) -> Result { unimplemented!("test-only") } - fn restore_document_key_shadow(&self, _key_id: &ServerKeyId, _signature: &RequestSignature) -> Result { + fn restore_document_key_shadow(&self, _key_id: &ServerKeyId, _requester: &Requester) -> Result { unimplemented!("test-only") } } impl MessageSigner for DummyKeyServer { - fn sign_message_schnorr(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _message: MessageHash) -> Result { + fn sign_message_schnorr(&self, _key_id: &ServerKeyId, _requester: &Requester, _message: MessageHash) -> Result { unimplemented!("test-only") } - fn sign_message_ecdsa(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _message: MessageHash) -> Result { + fn sign_message_ecdsa(&self, _key_id: &ServerKeyId, _requester: &Requester, _message: MessageHash) -> Result { unimplemented!("test-only") } } - fn make_key_servers(start_port: u16, num_nodes: usize) -> Vec { + fn make_key_servers(start_port: u16, num_nodes: usize) -> (Vec, Vec>) { let key_pairs: Vec<_> = (0..num_nodes).map(|_| Random.generate().unwrap()).collect(); let configs: Vec<_> = (0..num_nodes).map(|i| ClusterConfiguration { threads: 1, @@ -309,11 +309,12 @@ pub mod tests { let key_servers_set: BTreeMap = configs[0].nodes.iter() .map(|(k, a)| (k.clone(), format!("{}:{}", a.address, a.port).parse().unwrap())) .collect(); + let key_storages = (0..num_nodes).map(|_| Arc::new(DummyKeyStorage::default())).collect::>(); let key_servers: Vec<_> = configs.into_iter().enumerate().map(|(i, cfg)| KeyServerImpl::new(&cfg, Arc::new(MapKeyServerSet::new(key_servers_set.clone())), Arc::new(PlainNodeKeyPair::new(key_pairs[i].clone())), Arc::new(DummyAclStorage::default()), - Arc::new(DummyKeyStorage::default())).unwrap() + key_storages[i].clone()).unwrap() ).collect(); // wait until connections are established. It is fast => do not bother with events here @@ -343,25 +344,25 @@ pub mod tests { } } - key_servers + (key_servers, key_storages) } #[test] fn document_key_generation_and_retrievement_works_over_network_with_single_node() { //::logger::init_log(); - let key_servers = make_key_servers(6070, 1); + let (key_servers, _) = make_key_servers(6070, 1); // generate document key let threshold = 0; let document = Random.generate().unwrap().secret().clone(); let secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&secret, &document).unwrap(); - let generated_key = key_servers[0].generate_document_key(&document, &signature, threshold).unwrap(); + let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap(); let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap(); // now let's try to retrieve key back for key_server in key_servers.iter() { - let retrieved_key = key_server.restore_document_key(&document, &signature).unwrap(); + let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap(); let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); assert_eq!(retrieved_key, generated_key); } @@ -370,7 +371,7 @@ pub mod tests { #[test] fn document_key_generation_and_retrievement_works_over_network_with_3_nodes() { //::logger::init_log(); - let key_servers = make_key_servers(6080, 3); + let (key_servers, key_storages) = make_key_servers(6080, 3); let test_cases = [0, 1, 2]; for threshold in &test_cases { @@ -378,14 +379,18 @@ pub mod tests { let document = Random.generate().unwrap().secret().clone(); let secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&secret, &document).unwrap(); - let generated_key = key_servers[0].generate_document_key(&document, &signature, *threshold).unwrap(); + let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), *threshold).unwrap(); let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap(); // now let's try to retrieve key back - for key_server in key_servers.iter() { - let retrieved_key = key_server.restore_document_key(&document, &signature).unwrap(); + for (i, key_server) in key_servers.iter().enumerate() { + let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap(); let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); assert_eq!(retrieved_key, generated_key); + + let key_share = key_storages[i].get(&document).unwrap().unwrap(); + assert!(key_share.common_point.is_some()); + assert!(key_share.encrypted_point.is_some()); } } } @@ -393,7 +398,7 @@ pub mod tests { #[test] fn server_key_generation_and_storing_document_key_works_over_network_with_3_nodes() { //::logger::init_log(); - let key_servers = make_key_servers(6090, 3); + let (key_servers, _) = make_key_servers(6090, 3); let test_cases = [0, 1, 2]; for threshold in &test_cases { @@ -401,18 +406,19 @@ pub mod tests { let server_key_id = Random.generate().unwrap().secret().clone(); let requestor_secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap(); - let server_public = key_servers[0].generate_key(&server_key_id, &signature, *threshold).unwrap(); + let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), *threshold).unwrap(); // generate document key (this is done by KS client so that document key is unknown to any KS) let generated_key = Random.generate().unwrap().public().clone(); let encrypted_document_key = math::encrypt_secret(&generated_key, &server_public).unwrap(); // store document key - key_servers[0].store_document_key(&server_key_id, &signature, encrypted_document_key.common_point, encrypted_document_key.encrypted_point).unwrap(); + key_servers[0].store_document_key(&server_key_id, &signature.clone().into(), + encrypted_document_key.common_point, encrypted_document_key.encrypted_point).unwrap(); // now let's try to retrieve key back for key_server in key_servers.iter() { - let retrieved_key = key_server.restore_document_key(&server_key_id, &signature).unwrap(); + let retrieved_key = key_server.restore_document_key(&server_key_id, &signature.clone().into()).unwrap(); let retrieved_key = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); let retrieved_key = Public::from_slice(&retrieved_key); assert_eq!(retrieved_key, generated_key); @@ -423,7 +429,7 @@ pub mod tests { #[test] fn server_key_generation_and_message_signing_works_over_network_with_3_nodes() { //::logger::init_log(); - let key_servers = make_key_servers(6100, 3); + let (key_servers, _) = make_key_servers(6100, 3); let test_cases = [0, 1, 2]; for threshold in &test_cases { @@ -431,11 +437,11 @@ pub mod tests { let server_key_id = Random.generate().unwrap().secret().clone(); let requestor_secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap(); - let server_public = key_servers[0].generate_key(&server_key_id, &signature, *threshold).unwrap(); + let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), *threshold).unwrap(); // sign message let message_hash = H256::from(42); - let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature, message_hash.clone()).unwrap(); + let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); let combined_signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &combined_signature).unwrap(); let signature_c = Secret::from_slice(&combined_signature[..32]); let signature_s = Secret::from_slice(&combined_signature[32..]); @@ -448,21 +454,21 @@ pub mod tests { #[test] fn decryption_session_is_delegated_when_node_does_not_have_key_share() { //::logger::init_log(); - let key_servers = make_key_servers(6110, 3); + let (key_servers, _) = make_key_servers(6110, 3); // generate document key let threshold = 0; let document = Random.generate().unwrap().secret().clone(); let secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&secret, &document).unwrap(); - let generated_key = key_servers[0].generate_document_key(&document, &signature, threshold).unwrap(); + let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap(); let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap(); // remove key from node0 key_servers[0].cluster().key_storage().remove(&document).unwrap(); // now let's try to retrieve key back by requesting it from node0, so that session must be delegated - let retrieved_key = key_servers[0].restore_document_key(&document, &signature).unwrap(); + let retrieved_key = key_servers[0].restore_document_key(&document, &signature.into()).unwrap(); let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); assert_eq!(retrieved_key, generated_key); } @@ -470,21 +476,21 @@ pub mod tests { #[test] fn schnorr_signing_session_is_delegated_when_node_does_not_have_key_share() { //::logger::init_log(); - let key_servers = make_key_servers(6114, 3); + let (key_servers, _) = make_key_servers(6114, 3); let threshold = 1; // generate server key let server_key_id = Random.generate().unwrap().secret().clone(); let requestor_secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap(); - let server_public = key_servers[0].generate_key(&server_key_id, &signature, threshold).unwrap(); + let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), threshold).unwrap(); // remove key from node0 key_servers[0].cluster().key_storage().remove(&server_key_id).unwrap(); // sign message let message_hash = H256::from(42); - let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature, message_hash.clone()).unwrap(); + let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); let combined_signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &combined_signature).unwrap(); let signature_c = Secret::from_slice(&combined_signature[..32]); let signature_s = Secret::from_slice(&combined_signature[32..]); @@ -496,21 +502,21 @@ pub mod tests { #[test] fn ecdsa_signing_session_is_delegated_when_node_does_not_have_key_share() { //::logger::init_log(); - let key_servers = make_key_servers(6117, 4); + let (key_servers, _) = make_key_servers(6117, 4); let threshold = 1; // generate server key let server_key_id = Random.generate().unwrap().secret().clone(); let requestor_secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap(); - let server_public = key_servers[0].generate_key(&server_key_id, &signature, threshold).unwrap(); + let server_public = key_servers[0].generate_key(&server_key_id, &signature.clone().into(), threshold).unwrap(); // remove key from node0 key_servers[0].cluster().key_storage().remove(&server_key_id).unwrap(); // sign message let message_hash = H256::random(); - let signature = key_servers[0].sign_message_ecdsa(&server_key_id, &signature, message_hash.clone()).unwrap(); + let signature = key_servers[0].sign_message_ecdsa(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); let signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &signature).unwrap(); let signature: H520 = signature[0..65].into(); diff --git a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs index b7291c25c8..15abdce89d 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use std::collections::{BTreeSet, BTreeMap}; -use ethereum_types::H256; +use ethereum_types::{Address, H256}; use ethkey::Secret; use parking_lot::{Mutex, Condvar}; use key_server_cluster::{Error, SessionId, NodeId, DocumentKeyShare}; @@ -55,8 +55,8 @@ pub struct SessionImpl { /// Action after key version is negotiated. #[derive(Clone)] pub enum ContinueAction { - /// Decryption session + is_shadow_decryption. - Decrypt(Arc, bool), + /// Decryption session + origin + is_shadow_decryption + is_broadcast_decryption. + Decrypt(Arc, Option
, bool, bool), /// Schnorr signing session + message hash. SchnorrSign(Arc, H256), /// ECDSA signing session + message hash. @@ -202,6 +202,7 @@ impl SessionImpl where T: SessionTransport { /// Wait for session completion. pub fn wait(&self) -> Result<(H256, NodeId), Error> { Self::wait_session(&self.core.completed, &self.data, None, |data| data.result.clone()) + .expect("wait_session returns Some if called without timeout; qed") } /// Initialize session. diff --git a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs index 01f3392375..d701a57da0 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs @@ -221,6 +221,7 @@ impl SessionImpl { /// Wait for session completion. pub fn wait(&self) -> Result<(), Error> { Self::wait_session(&self.core.completed, &self.data, None, |data| data.result.clone()) + .expect("wait_session returns Some if called without timeout; qed") } /// Initialize servers set change session on master node. @@ -337,7 +338,7 @@ impl SessionImpl { } let unknown_sessions_job = UnknownSessionsJob::new_on_master(self.core.key_storage.clone(), self.core.meta.self_node_id.clone()); - consensus_session.disseminate_jobs(unknown_sessions_job, self.unknown_sessions_transport(), false) + consensus_session.disseminate_jobs(unknown_sessions_job, self.unknown_sessions_transport(), false).map(|_| ()) } /// When unknown sessions are requested. @@ -1166,7 +1167,7 @@ pub mod tests { pub fn generate_key(threshold: usize, nodes_ids: BTreeSet) -> GenerationMessageLoop { let mut gml = GenerationMessageLoop::with_nodes_ids(nodes_ids); - gml.master().initialize(Default::default(), false, threshold, gml.nodes.keys().cloned().collect::>().into()).unwrap(); + gml.master().initialize(Default::default(), Default::default(), false, threshold, gml.nodes.keys().cloned().collect::>().into()).unwrap(); while let Some((from, to, message)) = gml.take_message() { gml.process_message((from, to, message)).unwrap(); } diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs index c3946f7469..49c4e26d61 100644 --- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs @@ -14,10 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::BTreeSet; +use std::collections::{BTreeSet, BTreeMap}; use std::sync::Arc; +use std::time; use parking_lot::{Mutex, Condvar}; -use ethereum_types::H256; +use ethereum_types::{Address, H256}; use ethkey::Secret; use key_server_cluster::{Error, AclStorage, DocumentKeyShare, NodeId, SessionId, Requester, EncryptedDocumentKeyShadow, SessionMeta}; @@ -26,7 +27,7 @@ use key_server_cluster::cluster_sessions::{SessionIdWithSubSession, ClusterSessi use key_server_cluster::message::{Message, DecryptionMessage, DecryptionConsensusMessage, RequestPartialDecryption, PartialDecryption, DecryptionSessionError, DecryptionSessionCompleted, ConsensusMessage, InitializeConsensusSession, ConfirmConsensusInitialization, DecryptionSessionDelegation, DecryptionSessionDelegationCompleted}; -use key_server_cluster::jobs::job_session::{JobSession, JobTransport}; +use key_server_cluster::jobs::job_session::{JobSession, JobSessionState, JobTransport}; use key_server_cluster::jobs::key_access_job::KeyAccessJob; use key_server_cluster::jobs::decryption_job::{PartialDecryptionRequest, PartialDecryptionResponse, DecryptionJob}; use key_server_cluster::jobs::consensus_session::{ConsensusSessionParams, ConsensusSessionState, ConsensusSession}; @@ -71,6 +72,8 @@ type BroadcastDecryptionJobSession = JobSession, + /// Session origin (if any). + pub origin: Option
, /// Consensus-based decryption session. pub consensus_session: DecryptionConsensusSession, /// Broadcast decryption job. @@ -110,6 +113,8 @@ struct DecryptionConsensusTransport { access_key: Secret, /// Session-level nonce. nonce: u64, + /// Session origin (if any). + origin: Option
, /// Selected key version (on master node). version: Option, /// Cluster. @@ -157,6 +162,7 @@ impl SessionImpl { id: params.meta.id.clone(), access_key: params.access_key.clone(), nonce: params.nonce, + origin: None, version: None, cluster: params.cluster.clone(), }; @@ -180,6 +186,7 @@ impl SessionImpl { }, data: Mutex::new(SessionData { version: None, + origin: None, consensus_session: consensus_session, broadcast_job_session: None, is_shadow_decryption: None, @@ -214,13 +221,42 @@ impl SessionImpl { self.data.lock().result.clone() } + /// Get key requester. + pub fn requester(&self) -> Option { + self.data.lock().consensus_session.consensus_job().executor().requester().cloned() + } + + /// Get session origin. + pub fn origin(&self) -> Option
{ + self.data.lock().origin.clone() + } + /// Wait for session completion. - pub fn wait(&self) -> Result { - Self::wait_session(&self.core.completed, &self.data, None, |data| data.result.clone()) + pub fn wait(&self, timeout: Option) -> Option> { + Self::wait_session(&self.core.completed, &self.data, timeout, |data| data.result.clone()) + } + + /// Get broadcasted shadows. + pub fn broadcast_shadows(&self) -> Option>> { + let data = self.data.lock(); + + if data.result.is_none() || (data.is_broadcast_session, data.is_shadow_decryption) != (Some(true), Some(true)) { + return None; + } + + let proof = "data.is_shadow_decryption is true; decrypt_shadow.is_some() is checked in DecryptionJob::check_partial_response; qed"; + Some(match self.core.meta.master_node_id == self.core.meta.self_node_id { + true => data.consensus_session.computation_job().responses().iter() + .map(|(n, r)| (n.clone(), r.decrypt_shadow.clone().expect(proof))) + .collect(), + false => data.broadcast_job_session.as_ref().expect("session completed; is_shadow_decryption == true; we're on non-master node; qed").responses().iter() + .map(|(n, r)| (n.clone(), r.decrypt_shadow.clone().expect(proof))) + .collect(), + }) } /// Delegate session to other node. - pub fn delegate(&self, master: NodeId, version: H256, is_shadow_decryption: bool, is_broadcast_session: bool) -> Result<(), Error> { + pub fn delegate(&self, master: NodeId, origin: Option
, version: H256, is_shadow_decryption: bool, is_broadcast_session: bool) -> Result<(), Error> { if self.core.meta.master_node_id != self.core.meta.self_node_id { return Err(Error::InvalidStateForRequest); } @@ -235,6 +271,7 @@ impl SessionImpl { session: self.core.meta.id.clone().into(), sub_session: self.core.access_key.clone().into(), session_nonce: self.core.nonce, + origin: origin.map(Into::into), requester: data.consensus_session.consensus_job().executor().requester() .expect("signature is passed to master node on creation; session can be delegated from master node only; qed") .clone().into(), @@ -247,7 +284,7 @@ impl SessionImpl { } /// Initialize decryption session on master node. - pub fn initialize(&self, version: H256, is_shadow_decryption: bool, is_broadcast_session: bool) -> Result<(), Error> { + pub fn initialize(&self, origin: Option
, version: H256, is_shadow_decryption: bool, is_broadcast_session: bool) -> Result<(), Error> { debug_assert_eq!(self.core.meta.self_node_id, self.core.meta.master_node_id); // check if version exists @@ -268,6 +305,8 @@ impl SessionImpl { } data.consensus_session.consensus_job_mut().transport_mut().version = Some(version.clone()); + data.consensus_session.consensus_job_mut().transport_mut().origin = origin.clone(); + data.origin = origin; data.version = Some(version.clone()); data.is_shadow_decryption = Some(is_shadow_decryption); data.is_broadcast_session = Some(is_broadcast_session); @@ -323,7 +362,7 @@ impl SessionImpl { data.delegation_status = Some(DelegationStatus::DelegatedFrom(sender.clone(), message.session_nonce)); } - self.initialize(message.version.clone().into(), message.is_shadow_decryption, message.is_broadcast_session) + self.initialize(message.origin.clone().map(Into::into), message.version.clone().into(), message.is_shadow_decryption, message.is_broadcast_session) } /// When delegated session is completed on other node. @@ -364,6 +403,7 @@ impl SessionImpl { .unwrap_or(false); data.consensus_session.consensus_job_mut().executor_mut().set_has_key_share(has_key_share); data.version = Some(version); + data.origin = message.origin.clone().map(Into::into); } data.consensus_session.on_consensus_message(&sender, &message.message)?; @@ -397,13 +437,19 @@ impl SessionImpl { let requester_public = data.consensus_session.consensus_job().executor().requester() .ok_or(Error::InvalidStateForRequest)? .public(&self.core.meta.id) - .ok_or(Error::InsufficientRequesterData)?; + .map_err(Error::InsufficientRequesterData)?; let decryption_job = DecryptionJob::new_on_slave(self.core.meta.self_node_id.clone(), self.core.access_key.clone(), requester_public.clone(), key_share.clone(), key_version)?; let decryption_transport = self.core.decryption_transport(false); + // update flags if not on master + if self.core.meta.self_node_id != self.core.meta.master_node_id { + data.is_shadow_decryption = Some(message.is_shadow_decryption); + data.is_broadcast_session = Some(message.is_broadcast_session); + } + // respond to request - data.consensus_session.on_job_request(sender, PartialDecryptionRequest { + let partial_decryption = data.consensus_session.on_job_request(sender, PartialDecryptionRequest { id: message.request_id.clone().into(), is_shadow_decryption: message.is_shadow_decryption, is_broadcast_session: message.is_broadcast_session, @@ -417,7 +463,7 @@ impl SessionImpl { self.core.access_key.clone(), requester_public, key_share.clone(), key_version, message.is_shadow_decryption, message.is_broadcast_session)?; Self::create_broadcast_decryption_job(&self.core, &mut *data, consensus_group, broadcast_decryption_job, - message.request_id.clone().into())?; + message.request_id.clone().into(), Some(partial_decryption.take_response()))?; } Ok(()) @@ -430,38 +476,52 @@ impl SessionImpl { debug_assert!(sender != &self.core.meta.self_node_id); let mut data = self.data.lock(); - if self.core.meta.self_node_id == self.core.meta.master_node_id { + let is_master_node = self.core.meta.self_node_id == self.core.meta.master_node_id; + let result = if is_master_node { data.consensus_session.on_job_response(sender, PartialDecryptionResponse { request_id: message.request_id.clone().into(), shadow_point: message.shadow_point.clone().into(), decrypt_shadow: message.decrypt_shadow.clone(), })?; - } else { - match data.broadcast_job_session.as_mut() { - Some(broadcast_job_session) => broadcast_job_session.on_partial_response(sender, PartialDecryptionResponse { - request_id: message.request_id.clone().into(), - shadow_point: message.shadow_point.clone().into(), - decrypt_shadow: message.decrypt_shadow.clone(), - })?, - None => return Err(Error::TooEarlyForRequest), + + if data.consensus_session.state() != ConsensusSessionState::Finished && + data.consensus_session.state() != ConsensusSessionState::Failed { + return Ok(()); } - } - if data.consensus_session.state() != ConsensusSessionState::Finished { - return Ok(()); - } + // send completion signal to all nodes, except for rejected nodes + if is_master_node { + for node in data.consensus_session.consensus_non_rejected_nodes() { + self.core.cluster.send(&node, Message::Decryption(DecryptionMessage::DecryptionSessionCompleted(DecryptionSessionCompleted { + session: self.core.meta.id.clone().into(), + sub_session: self.core.access_key.clone().into(), + session_nonce: self.core.nonce, + })))?; + } + } - // send compeltion signal to all nodes, except for rejected nodes - for node in data.consensus_session.consensus_non_rejected_nodes() { - self.core.cluster.send(&node, Message::Decryption(DecryptionMessage::DecryptionSessionCompleted(DecryptionSessionCompleted { - session: self.core.meta.id.clone().into(), - sub_session: self.core.access_key.clone().into(), - session_nonce: self.core.nonce, - })))?; - } + data.consensus_session.result() + } else { + match data.broadcast_job_session.as_mut() { + Some(broadcast_job_session) => { + broadcast_job_session.on_partial_response(sender, PartialDecryptionResponse { + request_id: message.request_id.clone().into(), + shadow_point: message.shadow_point.clone().into(), + decrypt_shadow: message.decrypt_shadow.clone(), + })?; + + if broadcast_job_session.state() != JobSessionState::Finished && + broadcast_job_session.state() != JobSessionState::Failed { + return Ok(()); + } + + broadcast_job_session.result() + }, + None => return Err(Error::InvalidMessage), + } + }; - let result = data.consensus_session.result()?; - Self::set_decryption_result(&self.core, &mut *data, Ok(result)); + Self::set_decryption_result(&self.core, &mut *data, result); Ok(()) } @@ -543,28 +603,31 @@ impl SessionImpl { let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); let requester = data.consensus_session.consensus_job().executor().requester().ok_or(Error::InvalidStateForRequest)?.clone(); - let requester_public = requester.public(&core.meta.id).ok_or(Error::InsufficientRequesterData)?; + let requester_public = requester.public(&core.meta.id).map_err(Error::InsufficientRequesterData)?; let consensus_group = data.consensus_session.select_consensus_group()?.clone(); let decryption_job = DecryptionJob::new_on_master(core.meta.self_node_id.clone(), core.access_key.clone(), requester_public.clone(), key_share.clone(), key_version, is_shadow_decryption, is_broadcast_session)?; - let decryption_request_id = decryption_job.request_id().clone().expect("TODO"); + let decryption_request_id = decryption_job.request_id().clone() + .expect("DecryptionJob always have request_id when created on master; it is created using new_on_master above; qed"); let decryption_transport = core.decryption_transport(false); - data.consensus_session.disseminate_jobs(decryption_job, decryption_transport, data.is_broadcast_session.expect("TODO"))?; + let is_broadcast_session = data.is_broadcast_session + .expect("disseminate_jobs is called on master node only; on master node is_broadcast_session is filled during initialization; qed"); + let self_response = data.consensus_session.disseminate_jobs(decryption_job, decryption_transport, is_broadcast_session)?; // ...and prepare decryption job session if we need to broadcast result - if data.is_broadcast_session.expect("TODO") { + if is_broadcast_session { let broadcast_decryption_job = DecryptionJob::new_on_master(core.meta.self_node_id.clone(), core.access_key.clone(), requester_public, key_share.clone(), key_version, is_shadow_decryption, is_broadcast_session)?; Self::create_broadcast_decryption_job(&core, data, consensus_group, broadcast_decryption_job, - decryption_request_id)?; + decryption_request_id, self_response)?; } Ok(()) } /// Create broadcast decryption job. - fn create_broadcast_decryption_job(core: &SessionCore, data: &mut SessionData, mut consensus_group: BTreeSet, mut job: DecryptionJob, request_id: Secret) -> Result<(), Error> { + fn create_broadcast_decryption_job(core: &SessionCore, data: &mut SessionData, mut consensus_group: BTreeSet, mut job: DecryptionJob, request_id: Secret, self_response: Option) -> Result<(), Error> { consensus_group.insert(core.meta.self_node_id.clone()); job.set_request_id(request_id.clone().into()); @@ -575,7 +638,7 @@ impl SessionImpl { self_node_id: core.meta.self_node_id.clone(), threshold: core.meta.threshold, }, job, transport); - job_session.initialize(consensus_group, core.meta.self_node_id != core.meta.master_node_id)?; + job_session.initialize(consensus_group, self_response, core.meta.self_node_id != core.meta.master_node_id)?; data.broadcast_job_session = Some(job_session); Ok(()) @@ -691,6 +754,7 @@ impl JobTransport for DecryptionConsensusTransport { session: self.id.clone().into(), sub_session: self.access_key.clone().into(), session_nonce: self.nonce, + origin: self.origin.clone().map(Into::into), message: ConsensusMessage::InitializeConsensusSession(InitializeConsensusSession { requester: request.into(), version: version.clone().into(), @@ -703,6 +767,7 @@ impl JobTransport for DecryptionConsensusTransport { session: self.id.clone().into(), sub_session: self.access_key.clone().into(), session_nonce: self.nonce, + origin: None, message: ConsensusMessage::ConfirmConsensusInitialization(ConfirmConsensusInitialization { is_confirmed: response, }) @@ -751,7 +816,7 @@ mod tests { use std::sync::Arc; use std::collections::{BTreeMap, VecDeque}; use acl_storage::DummyAclStorage; - use ethkey::{self, KeyPair, Random, Generator, Public, Secret}; + use ethkey::{self, KeyPair, Random, Generator, Public, Secret, public_to_address}; use key_server_cluster::{NodeId, DocumentKeyShare, DocumentKeyShareVersion, SessionId, Requester, Error, EncryptedDocumentKeyShadow, SessionMeta}; use key_server_cluster::cluster::tests::DummyCluster; @@ -918,7 +983,7 @@ mod tests { cluster: Arc::new(DummyCluster::new(self_node_id.clone())), nonce: 0, }, Some(Requester::Signature(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()))).unwrap(); - assert_eq!(session.initialize(Default::default(), false, false), Err(Error::InvalidMessage)); + assert_eq!(session.initialize(Default::default(), Default::default(), false, false), Err(Error::InvalidMessage)); } #[test] @@ -951,24 +1016,25 @@ mod tests { cluster: Arc::new(DummyCluster::new(self_node_id.clone())), nonce: 0, }, Some(Requester::Signature(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()))).unwrap(); - assert_eq!(session.initialize(Default::default(), false, false), Err(Error::ConsensusUnreachable)); + assert_eq!(session.initialize(Default::default(), Default::default(), false, false), Err(Error::ConsensusUnreachable)); } #[test] fn fails_to_initialize_when_already_initialized() { let (_, _, _, sessions) = prepare_decryption_sessions(); - assert_eq!(sessions[0].initialize(Default::default(), false, false).unwrap(), ()); - assert_eq!(sessions[0].initialize(Default::default(), false, false).unwrap_err(), Error::InvalidStateForRequest); + assert_eq!(sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(), ()); + assert_eq!(sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap_err(), Error::InvalidStateForRequest); } #[test] fn fails_to_accept_initialization_when_already_initialized() { let (_, _, _, sessions) = prepare_decryption_sessions(); - assert_eq!(sessions[0].initialize(Default::default(), false, false).unwrap(), ()); + assert_eq!(sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(), ()); assert_eq!(sessions[0].on_consensus_message(sessions[1].node(), &message::DecryptionConsensusMessage { session: SessionId::default().into(), sub_session: sessions[0].access_key().clone().into(), session_nonce: 0, + origin: None, message: message::ConsensusMessage::InitializeConsensusSession(message::InitializeConsensusSession { requester: Requester::Signature(ethkey::sign( Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).into(), @@ -984,6 +1050,7 @@ mod tests { session: SessionId::default().into(), sub_session: sessions[0].access_key().clone().into(), session_nonce: 0, + origin: None, message: message::ConsensusMessage::InitializeConsensusSession(message::InitializeConsensusSession { requester: Requester::Signature(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).into(), @@ -1008,6 +1075,7 @@ mod tests { session: SessionId::default().into(), sub_session: sessions[0].access_key().clone().into(), session_nonce: 0, + origin: None, message: message::ConsensusMessage::InitializeConsensusSession(message::InitializeConsensusSession { requester: Requester::Signature(ethkey::sign(Random.generate().unwrap().secret(), &SessionId::default()).unwrap()).into(), @@ -1041,7 +1109,7 @@ mod tests { #[test] fn fails_to_accept_partial_decrypt_twice() { let (_, clusters, _, sessions) = prepare_decryption_sessions(); - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); let mut pd_from = None; let mut pd_msg = None; @@ -1069,7 +1137,7 @@ mod tests { #[test] fn node_is_marked_rejected_when_timed_out_during_initialization_confirmation() { let (_, _, _, sessions) = prepare_decryption_sessions(); - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); // 1 node disconnects => we still can recover secret sessions[0].on_node_timeout(sessions[1].node()); @@ -1086,8 +1154,8 @@ mod tests { let (_, clusters, acl_storages, sessions) = prepare_decryption_sessions(); let key_pair = Random.generate().unwrap(); - acl_storages[1].prohibit(key_pair.public().clone(), SessionId::default()); - sessions[0].initialize(Default::default(), false, false).unwrap(); + acl_storages[1].prohibit(public_to_address(key_pair.public()), SessionId::default()); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange_until(&clusters, &sessions, |_, _, _| sessions[0].state() == ConsensusSessionState::WaitingForPartialResults).unwrap(); @@ -1099,7 +1167,7 @@ mod tests { #[test] fn session_does_not_fail_if_requested_node_disconnects() { let (_, clusters, _, sessions) = prepare_decryption_sessions(); - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange_until(&clusters, &sessions, |_, _, _| sessions[0].state() == ConsensusSessionState::WaitingForPartialResults).unwrap(); @@ -1115,7 +1183,7 @@ mod tests { #[test] fn session_does_not_fail_if_node_with_shadow_point_disconnects() { let (_, clusters, _, sessions) = prepare_decryption_sessions(); - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange_until(&clusters, &sessions, |_, _, _| sessions[0].state() == ConsensusSessionState::WaitingForPartialResults && sessions[0].data.lock().consensus_session.computation_job().responses().len() == 2).unwrap(); @@ -1132,7 +1200,7 @@ mod tests { #[test] fn session_restarts_if_confirmed_node_disconnects() { let (_, clusters, _, sessions) = prepare_decryption_sessions(); - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange_until(&clusters, &sessions, |_, _, _| sessions[0].state() == ConsensusSessionState::WaitingForPartialResults).unwrap(); @@ -1147,7 +1215,7 @@ mod tests { #[test] fn session_does_not_fail_if_non_master_node_disconnects_from_non_master_node() { let (_, clusters, _, sessions) = prepare_decryption_sessions(); - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange_until(&clusters, &sessions, |_, _, _| sessions[0].state() == ConsensusSessionState::WaitingForPartialResults).unwrap(); @@ -1162,7 +1230,7 @@ mod tests { let (_, clusters, _, sessions) = prepare_decryption_sessions(); // now let's try to do a decryption - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange(&clusters, &sessions).unwrap(); @@ -1184,7 +1252,7 @@ mod tests { let (key_pair, clusters, _, sessions) = prepare_decryption_sessions(); // now let's try to do a decryption - sessions[0].initialize(Default::default(), true, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), true, false).unwrap(); do_messages_exchange(&clusters, &sessions).unwrap(); @@ -1215,12 +1283,12 @@ mod tests { let (key_pair, clusters, acl_storages, sessions) = prepare_decryption_sessions(); // now let's try to do a decryption - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); // we need 4 out of 5 nodes to agree to do a decryption // let's say that 2 of these nodes are disagree - acl_storages[1].prohibit(key_pair.public().clone(), SessionId::default()); - acl_storages[2].prohibit(key_pair.public().clone(), SessionId::default()); + acl_storages[1].prohibit(public_to_address(key_pair.public()), SessionId::default()); + acl_storages[2].prohibit(public_to_address(key_pair.public()), SessionId::default()); assert_eq!(do_messages_exchange(&clusters, &sessions).unwrap_err(), Error::ConsensusUnreachable); @@ -1235,10 +1303,10 @@ mod tests { // we need 4 out of 5 nodes to agree to do a decryption // let's say that 1 of these nodes (master) is disagree - acl_storages[0].prohibit(key_pair.public().clone(), SessionId::default()); + acl_storages[0].prohibit(public_to_address(key_pair.public()), SessionId::default()); // now let's try to do a decryption - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange(&clusters, &sessions).unwrap(); @@ -1278,7 +1346,7 @@ mod tests { ); // now let's try to do a decryption - sessions[1].delegate(sessions[0].core.meta.self_node_id.clone(), Default::default(), false, false).unwrap(); + sessions[1].delegate(sessions[0].core.meta.self_node_id.clone(), Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange(&clusters, &sessions).unwrap(); // now check that: @@ -1304,7 +1372,7 @@ mod tests { } // now let's try to do a decryption - sessions[0].initialize(Default::default(), false, false).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, false).unwrap(); do_messages_exchange(&clusters, &sessions).unwrap(); assert_eq!(sessions[0].decrypted_secret().unwrap().unwrap(), EncryptedDocumentKeyShadow { @@ -1317,13 +1385,52 @@ mod tests { #[test] fn decryption_result_restored_on_all_nodes_if_broadcast_session_is_completed() { let (_, clusters, _, sessions) = prepare_decryption_sessions(); - sessions[0].initialize(Default::default(), false, true).unwrap(); + sessions[0].initialize(Default::default(), Default::default(), false, true).unwrap(); do_messages_exchange(&clusters, &sessions).unwrap(); // decryption result must be the same and available on 4 nodes let result = sessions[0].decrypted_secret(); assert!(result.clone().unwrap().is_ok()); + assert_eq!(result.clone().unwrap().unwrap(), EncryptedDocumentKeyShadow { + decrypted_secret: SECRET_PLAIN.into(), + common_point: None, + decrypt_shadows: None, + }); assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == result).count()); assert_eq!(1, sessions.iter().skip(1).filter(|s| s.decrypted_secret().is_none()).count()); } + + #[test] + fn decryption_shadows_restored_on_all_nodes_if_shadow_broadcast_session_is_completed() { + let (key_pair, clusters, _, sessions) = prepare_decryption_sessions(); + sessions[0].initialize(Default::default(), Default::default(), true, true).unwrap(); + do_messages_exchange(&clusters, &sessions).unwrap(); + + // decryption shadows must be the same and available on 4 nodes + let broadcast_shadows = sessions[0].broadcast_shadows(); + assert!(broadcast_shadows.is_some()); + assert_eq!(3, sessions.iter().skip(1).filter(|s| s.broadcast_shadows() == broadcast_shadows).count()); + assert_eq!(1, sessions.iter().skip(1).filter(|s| s.broadcast_shadows().is_none()).count()); + + // 4 nodes must be able to recover original secret + use ethcrypto::DEFAULT_MAC; + use ethcrypto::ecies::decrypt; + let result = sessions[0].decrypted_secret().unwrap().unwrap(); + assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == Some(Ok(result.clone()))).count()); + let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter() + .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap())) + .collect(); + let decrypted_secret = math::decrypt_with_shadow_coefficients(result.decrypted_secret, result.common_point.unwrap(), decrypt_shadows).unwrap(); + assert_eq!(decrypted_secret, SECRET_PLAIN.into()); + } + + #[test] + fn decryption_session_origin_is_known_to_all_initialized_nodes() { + let (_, clusters, _, sessions) = prepare_decryption_sessions(); + sessions[0].initialize(Some(1.into()), Default::default(), true, true).unwrap(); + do_messages_exchange(&clusters, &sessions).unwrap(); + + // all session must have origin set + assert_eq!(5, sessions.iter().filter(|s| s.origin() == Some(1.into())).count()); + } } diff --git a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs index eafac6fd25..ca8bac3815 100644 --- a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs @@ -19,8 +19,10 @@ use std::fmt::{Debug, Formatter, Error as FmtError}; use std::time; use std::sync::Arc; use parking_lot::{Condvar, Mutex}; +use ethereum_types::Address; use ethkey::Public; -use key_server_cluster::{Error, NodeId, SessionId, Requester, KeyStorage, DocumentKeyShare}; +use key_server_cluster::{Error, NodeId, SessionId, Requester, KeyStorage, + DocumentKeyShare, ServerKeyId}; use key_server_cluster::cluster::Cluster; use key_server_cluster::cluster_sessions::ClusterSession; use key_server_cluster::message::{Message, EncryptionMessage, InitializeEncryptionSession, @@ -107,7 +109,7 @@ pub enum SessionState { impl SessionImpl { /// Create new encryption session. pub fn new(params: SessionParams) -> Result { - check_encrypted_data(¶ms.encrypted_data)?; + check_encrypted_data(params.encrypted_data.as_ref())?; Ok(SessionImpl { id: params.id, @@ -133,9 +135,9 @@ impl SessionImpl { /// Wait for session completion. pub fn wait(&self, timeout: Option) -> Result<(), Error> { Self::wait_session(&self.completed, &self.data, timeout, |data| data.result.clone()) + .expect("wait_session returns Some if called without timeout; qed") } - /// Start new session initialization. This must be called on master node. pub fn initialize(&self, requester: Requester, common_point: Public, encrypted_point: Public) -> Result<(), Error> { let mut data = self.data.lock(); @@ -155,17 +157,10 @@ impl SessionImpl { // TODO [Reliability]: there could be situation when some nodes have failed to store encrypted data // => potential problems during restore. some confirmation step is needed (2pc)? // save encryption data - if let Some(mut encrypted_data) = self.encrypted_data.clone() { - // check that the requester is the author of the encrypted data - let requester_address = requester.address(&self.id).ok_or(Error::InsufficientRequesterData)?; - if encrypted_data.author != requester_address { - return Err(Error::AccessDenied); - } - - encrypted_data.common_point = Some(common_point.clone()); - encrypted_data.encrypted_point = Some(encrypted_point.clone()); - self.key_storage.update(self.id.clone(), encrypted_data) - .map_err(|e| Error::KeyStorage(e.into()))?; + if let Some(encrypted_data) = self.encrypted_data.clone() { + let requester_address = requester.address(&self.id).map_err(Error::InsufficientRequesterData)?; + update_encrypted_data(&self.key_storage, self.id.clone(), + encrypted_data, requester_address, common_point.clone(), encrypted_point.clone())?; } // start initialization @@ -199,18 +194,11 @@ impl SessionImpl { } // check that the requester is the author of the encrypted data - if let Some(mut encrypted_data) = self.encrypted_data.clone() { + if let Some(encrypted_data) = self.encrypted_data.clone() { let requester: Requester = message.requester.clone().into(); - let requestor_address = requester.address(&self.id).ok_or(Error::InsufficientRequesterData)?; - if encrypted_data.author != requestor_address { - return Err(Error::AccessDenied); - } - - // save encryption data - encrypted_data.common_point = Some(message.common_point.clone().into()); - encrypted_data.encrypted_point = Some(message.encrypted_point.clone().into()); - self.key_storage.update(self.id.clone(), encrypted_data) - .map_err(|e| Error::KeyStorage(e.into()))?; + let requester_address = requester.address(&self.id).map_err(Error::InsufficientRequesterData)?; + update_encrypted_data(&self.key_storage, self.id.clone(), + encrypted_data, requester_address, message.common_point.clone().into(), message.encrypted_point.clone().into())?; } // update state @@ -333,13 +321,28 @@ impl Debug for SessionImpl { } } -fn check_encrypted_data(encrypted_data: &Option) -> Result<(), Error> { - if let &Some(ref encrypted_data) = encrypted_data { +/// Check that common_point and encrypted point are not yet set in key share. +pub fn check_encrypted_data(key_share: Option<&DocumentKeyShare>) -> Result<(), Error> { + if let Some(key_share) = key_share { // check that common_point and encrypted_point are still not set yet - if encrypted_data.common_point.is_some() || encrypted_data.encrypted_point.is_some() { + if key_share.common_point.is_some() || key_share.encrypted_point.is_some() { return Err(Error::CompletedSessionId); } } Ok(()) } + +/// Update key share with encrypted document key. +pub fn update_encrypted_data(key_storage: &Arc, key_id: ServerKeyId, mut key_share: DocumentKeyShare, author: Address, common_point: Public, encrypted_point: Public) -> Result<(), Error> { + // author must be the same + if key_share.author != author { + return Err(Error::AccessDenied); + } + + // save encryption data + key_share.common_point = Some(common_point); + key_share.encrypted_point = Some(encrypted_point); + key_storage.update(key_id, key_share) + .map_err(|e| Error::KeyStorage(e.into())) +} diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs index 30a35cbf6b..2c0cbe2b1e 100644 --- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs @@ -82,6 +82,8 @@ struct SessionData { author: Option
, // === Values, filled when session initialization is completed === + /// Session origin (if any). + origin: Option
, /// Is zero secret generation session? is_zero: Option, /// Threshold value for this DKG. Only `threshold + 1` will be able to collectively recreate joint secret, @@ -217,6 +219,7 @@ impl SessionImpl { simulate_faulty_behaviour: false, master: None, author: None, + origin: None, is_zero: None, threshold: None, derived_point: None, @@ -251,8 +254,13 @@ impl SessionImpl { self.data.lock().state.clone() } + /// Get session origin. + pub fn origin(&self) -> Option
{ + self.data.lock().origin.clone() + } + /// Wait for session completion. - pub fn wait(&self, timeout: Option) -> Result { + pub fn wait(&self, timeout: Option) -> Option> { Self::wait_session(&self.completed, &self.data, timeout, |data| data.joint_public_and_secret.clone() .map(|r| r.map(|r| r.0.clone()))) } @@ -263,7 +271,7 @@ impl SessionImpl { } /// Start new session initialization. This must be called on master node. - pub fn initialize(&self, author: Address, is_zero: bool, threshold: usize, nodes: InitializationNodes) -> Result<(), Error> { + pub fn initialize(&self, origin: Option
, author: Address, is_zero: bool, threshold: usize, nodes: InitializationNodes) -> Result<(), Error> { check_cluster_nodes(self.node(), &nodes.set())?; check_threshold(threshold, &nodes.set())?; @@ -277,6 +285,7 @@ impl SessionImpl { // update state data.master = Some(self.node().clone()); data.author = Some(author.clone()); + data.origin = origin.clone(); data.is_zero = Some(is_zero); data.threshold = Some(threshold); match nodes { @@ -304,6 +313,7 @@ impl SessionImpl { self.cluster.send(&next_node, Message::Generation(GenerationMessage::InitializeSession(InitializeSession { session: self.id.clone().into(), session_nonce: self.nonce, + origin: origin.map(Into::into), author: author.into(), nodes: data.nodes.iter().map(|(k, v)| (k.clone().into(), v.id_number.clone().into())).collect(), is_zero: data.is_zero.expect("is_zero is filled in initialization phase; KD phase follows initialization phase; qed"), @@ -380,6 +390,7 @@ impl SessionImpl { data.author = Some(message.author.clone().into()); data.state = SessionState::WaitingForInitializationComplete; data.nodes = message.nodes.iter().map(|(id, number)| (id.clone().into(), NodeData::with_id_number(number.clone().into()))).collect(); + data.origin = message.origin.clone().map(Into::into); data.is_zero = Some(message.is_zero); data.threshold = Some(message.threshold); @@ -411,6 +422,7 @@ impl SessionImpl { return self.cluster.send(&next_receiver, Message::Generation(GenerationMessage::InitializeSession(InitializeSession { session: self.id.clone().into(), session_nonce: self.nonce, + origin: data.origin.clone().map(Into::into), author: data.author.as_ref().expect("author is filled on initialization step; confrm initialization follows initialization; qed").clone().into(), nodes: data.nodes.iter().map(|(k, v)| (k.clone().into(), v.id_number.clone().into())).collect(), is_zero: data.is_zero.expect("is_zero is filled in initialization phase; KD phase follows initialization phase; qed"), @@ -937,7 +949,7 @@ pub mod tests { use std::time::Duration; use tokio_core::reactor::Core; use ethereum_types::Address; - use ethkey::{Random, Generator, Public, KeyPair}; + use ethkey::{Random, Generator, KeyPair}; use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage}; use key_server_cluster::message::{self, Message, GenerationMessage}; use key_server_cluster::cluster::tests::{DummyCluster, make_clusters, run_clusters, loop_until, all_connections_established}; @@ -1065,7 +1077,7 @@ pub mod tests { fn make_simple_cluster(threshold: usize, num_nodes: usize) -> Result<(SessionId, NodeId, NodeId, MessageLoop), Error> { let l = MessageLoop::new(num_nodes); - l.master().initialize(Default::default(), false, threshold, l.nodes.keys().cloned().collect::>().into())?; + l.master().initialize(Default::default(), Default::default(), false, threshold, l.nodes.keys().cloned().collect::>().into())?; let session_id = l.session_id.clone(); let master_id = l.master().node().clone(); @@ -1076,7 +1088,7 @@ pub mod tests { #[test] fn initializes_in_cluster_of_single_node() { let l = MessageLoop::new(1); - assert!(l.master().initialize(Default::default(), false, 0, l.nodes.keys().cloned().collect::>().into()).is_ok()); + assert!(l.master().initialize(Default::default(), Default::default(), false, 0, l.nodes.keys().cloned().collect::>().into()).is_ok()); } #[test] @@ -1091,7 +1103,7 @@ pub mod tests { nonce: Some(0), }); let cluster_nodes: BTreeSet<_> = (0..2).map(|_| math::generate_random_point().unwrap()).collect(); - assert_eq!(session.initialize(Default::default(), false, 0, cluster_nodes.into()).unwrap_err(), Error::InvalidNodesConfiguration); + assert_eq!(session.initialize(Default::default(), Default::default(), false, 0, cluster_nodes.into()).unwrap_err(), Error::InvalidNodesConfiguration); } #[test] @@ -1105,7 +1117,7 @@ pub mod tests { #[test] fn fails_to_initialize_when_already_initialized() { let (_, _, _, l) = make_simple_cluster(0, 2).unwrap(); - assert_eq!(l.master().initialize(Default::default(), false, 0, l.nodes.keys().cloned().collect::>().into()).unwrap_err(), + assert_eq!(l.master().initialize(Default::default(), Default::default(), false, 0, l.nodes.keys().cloned().collect::>().into()).unwrap_err(), Error::InvalidStateForRequest); } @@ -1185,6 +1197,7 @@ pub mod tests { assert_eq!(l.first_slave().on_initialize_session(m, &message::InitializeSession { session: sid.into(), session_nonce: 0, + origin: None, author: Address::default().into(), nodes: nodes.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), is_zero: false, @@ -1202,6 +1215,7 @@ pub mod tests { assert_eq!(l.first_slave().on_initialize_session(m, &message::InitializeSession { session: sid.into(), session_nonce: 0, + origin: None, author: Address::default().into(), nodes: nodes.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), is_zero: false, @@ -1345,7 +1359,7 @@ pub mod tests { let test_cases = [(0, 5), (2, 5), (3, 5)]; for &(threshold, num_nodes) in &test_cases { let mut l = MessageLoop::new(num_nodes); - l.master().initialize(Default::default(), false, threshold, l.nodes.keys().cloned().collect::>().into()).unwrap(); + l.master().initialize(Default::default(), Default::default(), false, threshold, l.nodes.keys().cloned().collect::>().into()).unwrap(); assert_eq!(l.nodes.len(), num_nodes); // let nodes do initialization + keys dissemination @@ -1377,6 +1391,9 @@ pub mod tests { #[test] fn encryption_session_works_over_network() { + const CONN_TIMEOUT: Duration = Duration::from_millis(300); + const SESSION_TIMEOUT: Duration = Duration::from_millis(1000); + let test_cases = [(1, 3)]; for &(threshold, num_nodes) in &test_cases { let mut core = Core::new().unwrap(); @@ -1386,12 +1403,12 @@ pub mod tests { run_clusters(&clusters); // establish connections - loop_until(&mut core, Duration::from_millis(300), || clusters.iter().all(all_connections_established)); + loop_until(&mut core, CONN_TIMEOUT, || clusters.iter().all(all_connections_established)); // run session to completion let session_id = SessionId::default(); - let session = clusters[0].client().new_generation_session(session_id, Public::default(), threshold).unwrap(); - loop_until(&mut core, Duration::from_millis(1000), || session.joint_public_and_secret().is_some()); + let session = clusters[0].client().new_generation_session(session_id, Default::default(), Default::default(), threshold).unwrap(); + loop_until(&mut core, SESSION_TIMEOUT, || session.joint_public_and_secret().is_some()); } } diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs index ddd4944129..02c20bc20e 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs @@ -222,6 +222,7 @@ impl SessionImpl { /// Wait for session completion. pub fn wait(&self) -> Result { Self::wait_session(&self.core.completed, &self.data, None, |data| data.result.clone()) + .expect("wait_session returns Some if called without timeout; qed") } /// Delegate session to other node. @@ -402,7 +403,7 @@ impl SessionImpl { session_nonce: n, message: m, })); - sig_nonce_generation_session.initialize(Default::default(), false, key_share.threshold, consensus_group_map.clone().into())?; + sig_nonce_generation_session.initialize(Default::default(), Default::default(), false, key_share.threshold, consensus_group_map.clone().into())?; data.sig_nonce_generation_session = Some(sig_nonce_generation_session); // start generation of inversed nonce computation session @@ -414,7 +415,7 @@ impl SessionImpl { session_nonce: n, message: m, })); - inv_nonce_generation_session.initialize(Default::default(), false, key_share.threshold, consensus_group_map.clone().into())?; + inv_nonce_generation_session.initialize(Default::default(), Default::default(), false, key_share.threshold, consensus_group_map.clone().into())?; data.inv_nonce_generation_session = Some(inv_nonce_generation_session); // start generation of zero-secret shares for inversed nonce computation session @@ -426,7 +427,7 @@ impl SessionImpl { session_nonce: n, message: m, })); - inv_zero_generation_session.initialize(Default::default(), true, key_share.threshold * 2, consensus_group_map.clone().into())?; + inv_zero_generation_session.initialize(Default::default(), Default::default(), true, key_share.threshold * 2, consensus_group_map.clone().into())?; data.inv_zero_generation_session = Some(inv_zero_generation_session); data.state = SessionState::NoncesGenerating; @@ -688,7 +689,7 @@ impl SessionImpl { id: message.request_id.clone().into(), inversed_nonce_coeff: message.inversed_nonce_coeff.clone().into(), message_hash: message.message_hash.clone().into(), - }, signing_job, signing_transport) + }, signing_job, signing_transport).map(|_| ()) } /// When partial signature is received. @@ -989,7 +990,7 @@ impl SessionCore { let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); let signing_job = EcdsaSigningJob::new_on_master(key_share.clone(), key_version, nonce_public, inv_nonce_share, inversed_nonce_coeff, message_hash)?; - consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false) + consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false).map(|_| ()) } } @@ -1054,7 +1055,7 @@ mod tests { use std::sync::Arc; use std::collections::{BTreeSet, BTreeMap, VecDeque}; use ethereum_types::H256; - use ethkey::{self, Random, Generator, KeyPair, verify_public}; + use ethkey::{self, Random, Generator, KeyPair, verify_public, public_to_address}; use acl_storage::DummyAclStorage; use key_server_cluster::{NodeId, DummyKeyStorage, SessionId, SessionMeta, Error, KeyStorage}; use key_server_cluster::cluster_sessions::ClusterSession; @@ -1165,7 +1166,7 @@ mod tests { fn prepare_signing_sessions(threshold: usize, num_nodes: usize) -> (KeyGenerationMessageLoop, MessageLoop) { // run key generation sessions let mut gl = KeyGenerationMessageLoop::new(num_nodes); - gl.master().initialize(Default::default(), false, threshold, gl.nodes.keys().cloned().collect::>().into()).unwrap(); + gl.master().initialize(Default::default(), Default::default(), false, threshold, gl.nodes.keys().cloned().collect::>().into()).unwrap(); while let Some((from, to, message)) = gl.take_message() { gl.process_message((from, to, message)).unwrap(); } @@ -1214,7 +1215,7 @@ mod tests { // we need at least 3-of-4 nodes to agree to reach consensus // let's say 1 of 4 nodes disagee - sl.acl_storages[1].prohibit(sl.requester.public().clone(), SessionId::default()); + sl.acl_storages[1].prohibit(public_to_address(sl.requester.public()), SessionId::default()); // then consensus reachable, but single node will disagree while let Some((from, to, message)) = sl.take_message() { @@ -1235,7 +1236,7 @@ mod tests { // we need at least 3-of-4 nodes to agree to reach consensus // let's say 1 of 4 nodes disagee - sl.acl_storages[0].prohibit(sl.requester.public().clone(), SessionId::default()); + sl.acl_storages[0].prohibit(public_to_address(sl.requester.public()), SessionId::default()); // then consensus reachable, but single node will disagree while let Some((from, to, message)) = sl.take_message() { diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs index 4eaf072373..b4041da53f 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs @@ -209,6 +209,7 @@ impl SessionImpl { /// Wait for session completion. pub fn wait(&self) -> Result<(Secret, Secret), Error> { Self::wait_session(&self.core.completed, &self.data, None, |data| data.result.clone()) + .expect("wait_session returns Some if called without timeout; qed") } /// Delegate session to other node. @@ -277,7 +278,7 @@ impl SessionImpl { }), nonce: None, }); - generation_session.initialize(Default::default(), false, 0, vec![self.core.meta.self_node_id.clone()].into_iter().collect::>().into())?; + generation_session.initialize(Default::default(), Default::default(), false, 0, vec![self.core.meta.self_node_id.clone()].into_iter().collect::>().into())?; debug_assert_eq!(generation_session.state(), GenerationSessionState::WaitingForGenerationConfirmation); let joint_public_and_secret = generation_session @@ -406,7 +407,7 @@ impl SessionImpl { nonce: None, }); - generation_session.initialize(Default::default(), false, key_share.threshold, consensus_group.into())?; + generation_session.initialize(Default::default(), Default::default(), false, key_share.threshold, consensus_group.into())?; data.generation_session = Some(generation_session); data.state = SessionState::SessionKeyGeneration; @@ -508,7 +509,7 @@ impl SessionImpl { id: message.request_id.clone().into(), message_hash: message.message_hash.clone().into(), other_nodes_ids: message.nodes.iter().cloned().map(Into::into).collect(), - }, signing_job, signing_transport) + }, signing_job, signing_transport).map(|_| ()) } /// When partial signature is received. @@ -735,8 +736,9 @@ impl SessionCore { }; let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); - let signing_job = SchnorrSigningJob::new_on_master(self.meta.self_node_id.clone(), key_share.clone(), key_version, session_public, session_secret_share, message_hash)?; - consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false) + let signing_job = SchnorrSigningJob::new_on_master(self.meta.self_node_id.clone(), key_share.clone(), key_version, + session_public, session_secret_share, message_hash)?; + consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false).map(|_| ()) } } @@ -802,7 +804,7 @@ mod tests { use std::str::FromStr; use std::collections::{BTreeSet, BTreeMap, VecDeque}; use ethereum_types::{Address, H256}; - use ethkey::{self, Random, Generator, Public, Secret, KeyPair}; + use ethkey::{self, Random, Generator, Public, Secret, KeyPair, public_to_address}; use acl_storage::DummyAclStorage; use key_server_cluster::{NodeId, DummyKeyStorage, DocumentKeyShare, DocumentKeyShareVersion, SessionId, Requester, SessionMeta, Error, KeyStorage}; @@ -928,7 +930,7 @@ mod tests { fn prepare_signing_sessions(threshold: usize, num_nodes: usize) -> (KeyGenerationMessageLoop, MessageLoop) { // run key generation sessions let mut gl = KeyGenerationMessageLoop::new(num_nodes); - gl.master().initialize(Default::default(), false, threshold, gl.nodes.keys().cloned().collect::>().into()).unwrap(); + gl.master().initialize(Default::default(), Default::default(), false, threshold, gl.nodes.keys().cloned().collect::>().into()).unwrap(); while let Some((from, to, message)) = gl.take_message() { gl.process_message((from, to, message)).unwrap(); } @@ -1114,6 +1116,7 @@ mod tests { message: GenerationMessage::InitializeSession(InitializeSession { session: SessionId::default().into(), session_nonce: 0, + origin: None, author: Address::default().into(), nodes: BTreeMap::new(), is_zero: false, @@ -1157,8 +1160,8 @@ mod tests { // we need at least 2-of-3 nodes to agree to reach consensus // let's say 2 of 3 nodes disagee - sl.acl_storages[1].prohibit(sl.requester.public().clone(), SessionId::default()); - sl.acl_storages[2].prohibit(sl.requester.public().clone(), SessionId::default()); + sl.acl_storages[1].prohibit(public_to_address(sl.requester.public()), SessionId::default()); + sl.acl_storages[2].prohibit(public_to_address(sl.requester.public()), SessionId::default()); // then consensus is unreachable assert_eq!(sl.run_until(|_| false), Err(Error::ConsensusUnreachable)); @@ -1171,7 +1174,7 @@ mod tests { // we need at least 2-of-3 nodes to agree to reach consensus // let's say 1 of 3 nodes disagee - sl.acl_storages[1].prohibit(sl.requester.public().clone(), SessionId::default()); + sl.acl_storages[1].prohibit(public_to_address(sl.requester.public()), SessionId::default()); // then consensus reachable, but single node will disagree while let Some((from, to, message)) = sl.take_message() { @@ -1192,7 +1195,7 @@ mod tests { // we need at least 2-of-3 nodes to agree to reach consensus // let's say 1 of 3 nodes disagee - sl.acl_storages[0].prohibit(sl.requester.public().clone(), SessionId::default()); + sl.acl_storages[0].prohibit(public_to_address(sl.requester.public()), SessionId::default()); // then consensus reachable, but single node will disagree while let Some((from, to, message)) = sl.take_message() { diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs index 22590f1a7e..c90474fa63 100644 --- a/secret_store/src/key_server_cluster/cluster.rs +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -26,8 +26,8 @@ use parking_lot::{RwLock, Mutex}; use tokio_io::IoFuture; use tokio_core::reactor::{Handle, Remote, Interval}; use tokio_core::net::{TcpListener, TcpStream}; -use ethkey::{Public, KeyPair, Signature, Random, Generator, public_to_address}; -use ethereum_types::H256; +use ethkey::{Public, KeyPair, Signature, Random, Generator}; +use ethereum_types::{Address, H256}; use key_server_cluster::{Error, NodeId, SessionId, Requester, AclStorage, KeyStorage, KeyServerSet, NodeKeyPair}; use key_server_cluster::cluster_sessions::{ClusterSession, AdminSession, ClusterSessions, SessionIdWithSubSession, ClusterSessionsContainer, SERVERS_SET_CHANGE_SESSION_ID, create_cluster_view, AdminSessionCreationData, ClusterSessionsListener}; @@ -66,11 +66,11 @@ pub trait ClusterClient: Send + Sync { /// Get cluster state. fn cluster_state(&self) -> ClusterState; /// Start new generation session. - fn new_generation_session(&self, session_id: SessionId, author: Public, threshold: usize) -> Result, Error>; + fn new_generation_session(&self, session_id: SessionId, origin: Option
, author: Address, threshold: usize) -> Result, Error>; /// Start new encryption session. - fn new_encryption_session(&self, session_id: SessionId, requester: Requester, common_point: Public, encrypted_point: Public) -> Result, Error>; + fn new_encryption_session(&self, session_id: SessionId, author: Requester, common_point: Public, encrypted_point: Public) -> Result, Error>; /// Start new decryption session. - fn new_decryption_session(&self, session_id: SessionId, requester: Requester, version: Option, is_shadow_decryption: bool) -> Result, Error>; + fn new_decryption_session(&self, session_id: SessionId, origin: Option
, requester: Requester, version: Option, is_shadow_decryption: bool, is_broadcast_decryption: bool) -> Result, Error>; /// Start new Schnorr signing session. fn new_schnorr_signing_session(&self, session_id: SessionId, requester: Requester, version: Option, message_hash: H256) -> Result, Error>; /// Start new ECDSA session. @@ -82,6 +82,8 @@ pub trait ClusterClient: Send + Sync { /// Listen for new generation sessions. fn add_generation_listener(&self, listener: Arc>); + /// Listen for new decryption sessions. + fn add_decryption_listener(&self, listener: Arc>); /// Ask node to make 'faulty' generation sessions. #[cfg(test)] @@ -477,11 +479,11 @@ impl ClusterCore { data.sessions.negotiation_sessions.remove(&session.id()); match session.wait() { Ok((version, master)) => match session.take_continue_action() { - Some(ContinueAction::Decrypt(session, is_shadow_decryption)) => { + Some(ContinueAction::Decrypt(session, origin, is_shadow_decryption, is_broadcast_decryption)) => { let initialization_error = if data.self_key_pair.public() == &master { - session.initialize(version, is_shadow_decryption, false) + session.initialize(origin, version, is_shadow_decryption, is_broadcast_decryption) } else { - session.delegate(master, version, is_shadow_decryption, false) + session.delegate(master, origin, version, is_shadow_decryption, is_broadcast_decryption) }; if let Err(error) = initialization_error { @@ -516,7 +518,7 @@ impl ClusterCore { None => (), }, Err(error) => match session.take_continue_action() { - Some(ContinueAction::Decrypt(session, _)) => { + Some(ContinueAction::Decrypt(session, _, _, _)) => { data.sessions.decryption_sessions.remove(&session.id()); session.on_session_error(&meta.self_node_id, error); }, @@ -901,13 +903,13 @@ impl ClusterClient for ClusterClientImpl { self.data.connections.cluster_state() } - fn new_generation_session(&self, session_id: SessionId, author: Public, threshold: usize) -> Result, Error> { + fn new_generation_session(&self, session_id: SessionId, origin: Option
, author: Address, threshold: usize) -> Result, Error> { let mut connected_nodes = self.data.connections.connected_nodes(); connected_nodes.insert(self.data.self_key_pair.public().clone()); let cluster = create_cluster_view(&self.data, true)?; let session = self.data.sessions.generation_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id, None, false, None)?; - match session.initialize(public_to_address(&author), false, threshold, connected_nodes.into()) { + match session.initialize(origin, author, false, threshold, connected_nodes.into()) { Ok(()) => Ok(session), Err(error) => { self.data.sessions.generation_sessions.remove(&session.id()); @@ -931,7 +933,7 @@ impl ClusterClient for ClusterClientImpl { } } - fn new_decryption_session(&self, session_id: SessionId, requester: Requester, version: Option, is_shadow_decryption: bool) -> Result, Error> { + fn new_decryption_session(&self, session_id: SessionId, origin: Option
, requester: Requester, version: Option, is_shadow_decryption: bool, is_broadcast_decryption: bool) -> Result, Error> { let mut connected_nodes = self.data.connections.connected_nodes(); connected_nodes.insert(self.data.self_key_pair.public().clone()); @@ -942,11 +944,11 @@ impl ClusterClient for ClusterClientImpl { session_id.clone(), None, false, Some(requester))?; let initialization_result = match version { - Some(version) => session.initialize(version, is_shadow_decryption, false), + Some(version) => session.initialize(origin, version, is_shadow_decryption, is_broadcast_decryption), None => { self.create_key_version_negotiation_session(session_id.id.clone()) .map(|version_session| { - version_session.set_continue_action(ContinueAction::Decrypt(session.clone(), is_shadow_decryption)); + version_session.set_continue_action(ContinueAction::Decrypt(session.clone(), origin, is_shadow_decryption, is_broadcast_decryption)); ClusterCore::try_continue_session(&self.data, Some(version_session)); }) }, @@ -1056,6 +1058,10 @@ impl ClusterClient for ClusterClientImpl { self.data.sessions.generation_sessions.add_listener(listener); } + fn add_decryption_listener(&self, listener: Arc>) { + self.data.sessions.decryption_sessions.add_listener(listener); + } + #[cfg(test)] fn connect(&self) { ClusterCore::connect_disconnected_nodes(self.data.clone()); @@ -1085,11 +1091,12 @@ fn make_socket_address(address: &str, port: u16) -> Result { #[cfg(test)] pub mod tests { use std::sync::Arc; + use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{Duration, Instant}; use std::collections::{BTreeSet, VecDeque}; use parking_lot::Mutex; use tokio_core::reactor::Core; - use ethereum_types::H256; + use ethereum_types::{Address, H256}; use ethkey::{Random, Generator, Public, Signature, sign}; use key_server_cluster::{NodeId, SessionId, Requester, Error, DummyAclStorage, DummyKeyStorage, MapKeyServerSet, PlainNodeKeyPair, KeyStorage}; @@ -1107,7 +1114,9 @@ pub mod tests { const TIMEOUT: Duration = Duration::from_millis(300); #[derive(Default)] - pub struct DummyClusterClient; + pub struct DummyClusterClient { + pub generation_requests_count: AtomicUsize, + } #[derive(Debug)] pub struct DummyCluster { @@ -1123,15 +1132,20 @@ pub mod tests { impl ClusterClient for DummyClusterClient { fn cluster_state(&self) -> ClusterState { unimplemented!("test-only") } - fn new_generation_session(&self, _session_id: SessionId, _author: Public, _threshold: usize) -> Result, Error> { unimplemented!("test-only") } + fn new_generation_session(&self, _session_id: SessionId, _origin: Option
, _author: Address, _threshold: usize) -> Result, Error> { + self.generation_requests_count.fetch_add(1, Ordering::Relaxed); + Err(Error::Io("test-errror".into())) + } fn new_encryption_session(&self, _session_id: SessionId, _requester: Requester, _common_point: Public, _encrypted_point: Public) -> Result, Error> { unimplemented!("test-only") } - fn new_decryption_session(&self, _session_id: SessionId, _requester: Requester, _version: Option, _is_shadow_decryption: bool) -> Result, Error> { unimplemented!("test-only") } + fn new_decryption_session(&self, _session_id: SessionId, _origin: Option
, _requester: Requester, _version: Option, _is_shadow_decryption: bool, _is_broadcast_session: bool) -> Result, Error> { unimplemented!("test-only") } fn new_schnorr_signing_session(&self, _session_id: SessionId, _requester: Requester, _version: Option, _message_hash: H256) -> Result, Error> { unimplemented!("test-only") } fn new_ecdsa_signing_session(&self, _session_id: SessionId, _requester: Requester, _version: Option, _message_hash: H256) -> Result, Error> { unimplemented!("test-only") } + fn new_key_version_negotiation_session(&self, _session_id: SessionId) -> Result>, Error> { unimplemented!("test-only") } fn new_servers_set_change_session(&self, _session_id: Option, _migration_id: Option, _new_nodes_set: BTreeSet, _old_set_signature: Signature, _new_set_signature: Signature) -> Result, Error> { unimplemented!("test-only") } fn add_generation_listener(&self, _listener: Arc>) {} + fn add_decryption_listener(&self, _listener: Arc>) {} fn make_faulty_generation_sessions(&self) { unimplemented!("test-only") } fn generation_session(&self, _session_id: &SessionId) -> Option> { unimplemented!("test-only") } @@ -1258,7 +1272,7 @@ pub mod tests { let core = Core::new().unwrap(); let clusters = make_clusters(&core, 6013, 3); clusters[0].run().unwrap(); - match clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1) { + match clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 1) { Err(Error::NodeDisconnected) => (), Err(e) => panic!("unexpected error {:?}", e), _ => panic!("unexpected success"), @@ -1277,7 +1291,7 @@ pub mod tests { clusters[1].client().make_faulty_generation_sessions(); // start && wait for generation session to fail - let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); + let session = clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 1).unwrap(); loop_until(&mut core, TIMEOUT, || session.joint_public_and_secret().is_some() && clusters[0].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_err()); @@ -1306,7 +1320,7 @@ pub mod tests { clusters[0].client().make_faulty_generation_sessions(); // start && wait for generation session to fail - let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); + let session = clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 1).unwrap(); loop_until(&mut core, TIMEOUT, || session.joint_public_and_secret().is_some() && clusters[0].client().generation_session(&SessionId::default()).is_none()); assert!(session.joint_public_and_secret().unwrap().is_err()); @@ -1332,7 +1346,7 @@ pub mod tests { loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // start && wait for generation session to complete - let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); + let session = clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 1).unwrap(); loop_until(&mut core, TIMEOUT, || (session.state() == GenerationSessionState::Finished || session.state() == GenerationSessionState::Failed) && clusters[0].client().generation_session(&SessionId::default()).is_none()); @@ -1359,11 +1373,11 @@ pub mod tests { // generation session { // try to start generation session => fail in initialization - assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 100).map(|_| ()), + assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 100).map(|_| ()), Err(Error::InvalidThreshold)); // try to start generation session => fails in initialization - assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 100).map(|_| ()), + assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 100).map(|_| ()), Err(Error::InvalidThreshold)); assert!(clusters[0].data.sessions.generation_sessions.is_empty()); @@ -1372,11 +1386,11 @@ pub mod tests { // decryption session { // try to start decryption session => fails in initialization - assert_eq!(clusters[0].client().new_decryption_session(Default::default(), Default::default(), Some(Default::default()), false).map(|_| ()), + assert_eq!(clusters[0].client().new_decryption_session(Default::default(), Default::default(), Default::default(), Some(Default::default()), false, false).map(|_| ()), Err(Error::InvalidMessage)); // try to start generation session => fails in initialization - assert_eq!(clusters[0].client().new_decryption_session(Default::default(), Default::default(), Some(Default::default()), false).map(|_| ()), + assert_eq!(clusters[0].client().new_decryption_session(Default::default(), Default::default(), Default::default(), Some(Default::default()), false, false).map(|_| ()), Err(Error::InvalidMessage)); assert!(clusters[0].data.sessions.decryption_sessions.is_empty()); @@ -1393,7 +1407,7 @@ pub mod tests { loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // start && wait for generation session to complete - let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); + let session = clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 1).unwrap(); loop_until(&mut core, TIMEOUT, || (session.state() == GenerationSessionState::Finished || session.state() == GenerationSessionState::Failed) && clusters[0].client().generation_session(&SessionId::default()).is_none()); @@ -1442,7 +1456,7 @@ pub mod tests { loop_until(&mut core, TIMEOUT, || clusters.iter().all(all_connections_established)); // start && wait for generation session to complete - let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap(); + let session = clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 1).unwrap(); loop_until(&mut core, TIMEOUT, || (session.state() == GenerationSessionState::Finished || session.state() == GenerationSessionState::Failed) && clusters[0].client().generation_session(&SessionId::default()).is_none()); diff --git a/secret_store/src/key_server_cluster/cluster_sessions.rs b/secret_store/src/key_server_cluster/cluster_sessions.rs index cdd0c19585..e67458f766 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions.rs @@ -84,10 +84,10 @@ pub trait ClusterSession { fn on_message(&self, sender: &NodeId, message: &Message) -> Result<(), Error>; /// 'Wait for session completion' helper. - fn wait_session Option>>(completion_event: &Condvar, session_data: &Mutex, timeout: Option, result_reader: F) -> Result { + fn wait_session Option>>(completion_event: &Condvar, session_data: &Mutex, timeout: Option, result_reader: F) -> Option> { let mut locked_data = session_data.lock(); match result_reader(&locked_data) { - Some(result) => result, + Some(result) => Some(result), None => { match timeout { None => completion_event.wait(&mut locked_data), @@ -97,7 +97,6 @@ pub trait ClusterSession { } result_reader(&locked_data) - .expect("waited for completion; completion is only signaled when result.is_some(); qed") }, } } @@ -563,12 +562,14 @@ pub fn create_cluster_view(data: &Arc, requires_all_connections: bo #[cfg(test)] mod tests { use std::sync::Arc; + use std::sync::atomic::{AtomicUsize, Ordering}; use ethkey::{Random, Generator}; use key_server_cluster::{Error, DummyAclStorage, DummyKeyStorage, MapKeyServerSet, PlainNodeKeyPair}; use key_server_cluster::cluster::ClusterConfiguration; use key_server_cluster::connection_trigger::SimpleServersSetChangeSessionCreatorConnector; use key_server_cluster::cluster::tests::DummyCluster; - use super::{ClusterSessions, AdminSessionCreationData}; + use key_server_cluster::generation_session::{SessionImpl as GenerationSession}; + use super::{ClusterSessions, AdminSessionCreationData, ClusterSessionsListener}; pub fn make_cluster_sessions() -> ClusterSessions { let key_pair = Random.generate().unwrap(); @@ -610,4 +611,35 @@ mod tests { Ok(_) => unreachable!("OK"), } } + + #[test] + fn session_listener_works() { + #[derive(Default)] + struct GenerationSessionListener { + inserted: AtomicUsize, + removed: AtomicUsize, + } + + impl ClusterSessionsListener for GenerationSessionListener { + fn on_session_inserted(&self, _session: Arc) { + self.inserted.fetch_add(1, Ordering::Relaxed); + } + + fn on_session_removed(&self, _session: Arc) { + self.removed.fetch_add(1, Ordering::Relaxed); + } + } + + let listener = Arc::new(GenerationSessionListener::default()); + let sessions = make_cluster_sessions(); + sessions.generation_sessions.add_listener(listener.clone()); + + sessions.generation_sessions.insert(Arc::new(DummyCluster::new(Default::default())), Default::default(), Default::default(), None, false, None).unwrap(); + assert_eq!(listener.inserted.load(Ordering::Relaxed), 1); + assert_eq!(listener.removed.load(Ordering::Relaxed), 0); + + sessions.generation_sessions.remove(&Default::default()); + assert_eq!(listener.inserted.load(Ordering::Relaxed), 1); + assert_eq!(listener.removed.load(Ordering::Relaxed), 1); + } } diff --git a/secret_store/src/key_server_cluster/jobs/consensus_session.rs b/secret_store/src/key_server_cluster/jobs/consensus_session.rs index 42de71b544..cc4ebc6d9f 100644 --- a/secret_store/src/key_server_cluster/jobs/consensus_session.rs +++ b/secret_store/src/key_server_cluster/jobs/consensus_session.rs @@ -17,7 +17,7 @@ use std::collections::BTreeSet; use key_server_cluster::{Error, NodeId, SessionMeta, Requester}; use key_server_cluster::message::ConsensusMessage; -use key_server_cluster::jobs::job_session::{JobSession, JobSessionState, JobTransport, JobExecutor}; +use key_server_cluster::jobs::job_session::{JobSession, JobSessionState, JobTransport, JobExecutor, JobPartialRequestAction}; /// Consensus session state. #[derive(Debug, Clone, Copy, PartialEq)] @@ -114,7 +114,6 @@ impl &JobSession { self.computation_job.as_ref() .expect("computation_job must only be called on master nodes") @@ -140,15 +139,15 @@ impl) -> Result<(), Error> { debug_assert!(self.meta.self_node_id == self.meta.master_node_id); - let initialization_result = self.consensus_job.initialize(nodes, false); + let initialization_result = self.consensus_job.initialize(nodes, None, false); self.state = ConsensusSessionState::EstablishingConsensus; - self.process_result(initialization_result) + self.process_result(initialization_result.map(|_| ())) } /// Process consensus request message. pub fn on_consensus_partial_request(&mut self, sender: &NodeId, request: ConsensusExecutor::PartialJobRequest) -> Result<(), Error> { let consensus_result = self.consensus_job.on_partial_request(sender, request); - self.process_result(consensus_result) + self.process_result(consensus_result.map(|_| ())) } /// Process consensus message response. @@ -179,19 +178,22 @@ impl Result<(), Error> { + pub fn disseminate_jobs(&mut self, executor: ComputationExecutor, transport: ComputationTransport, broadcast_self_response: bool) -> Result, Error> { let consensus_group = self.select_consensus_group()?.clone(); self.consensus_group.clear(); let mut computation_job = JobSession::new(self.meta.clone(), executor, transport); - let computation_result = computation_job.initialize(consensus_group, broadcast_self_response); + let computation_result = computation_job.initialize(consensus_group, None, broadcast_self_response); self.computation_job = Some(computation_job); self.state = ConsensusSessionState::WaitingForPartialResults; - self.process_result(computation_result) + match computation_result { + Ok(computation_result) => self.process_result(Ok(())).map(|_| computation_result), + Err(error) => Err(self.process_result(Err(error)).unwrap_err()), + } } /// Process job request on slave node. - pub fn on_job_request(&mut self, node: &NodeId, request: ComputationExecutor::PartialJobRequest, executor: ComputationExecutor, transport: ComputationTransport) -> Result<(), Error> { + pub fn on_job_request(&mut self, node: &NodeId, request: ComputationExecutor::PartialJobRequest, executor: ComputationExecutor, transport: ComputationTransport) -> Result, Error> { if &self.meta.master_node_id != node { return Err(Error::InvalidMessage); } @@ -350,7 +352,7 @@ impl - self.consensus_job.on_partial_request(sender, message.requester.clone().into()), + self.consensus_job.on_partial_request(sender, message.requester.clone().into()).map(|_| ()), &ConsensusMessage::ConfirmConsensusInitialization(ref message) => self.consensus_job.on_partial_response(sender, message.is_confirmed), }; @@ -361,7 +363,7 @@ impl None, Some(decrypt_shadow) => Some(encrypt(&self.requester, &DEFAULT_MAC, &**decrypt_shadow)?), }, diff --git a/secret_store/src/key_server_cluster/jobs/job_session.rs b/secret_store/src/key_server_cluster/jobs/job_session.rs index 0299fdb141..82f387d7b9 100644 --- a/secret_store/src/key_server_cluster/jobs/job_session.rs +++ b/secret_store/src/key_server_cluster/jobs/job_session.rs @@ -197,7 +197,7 @@ impl JobSession where Executor: JobExe } /// Initialize. - pub fn initialize(&mut self, nodes: BTreeSet, broadcast_self_response: bool) -> Result<(), Error> { + pub fn initialize(&mut self, nodes: BTreeSet, self_response: Option, broadcast_self_response: bool) -> Result, Error> { debug_assert!(self.meta.self_node_id == self.meta.master_node_id); if nodes.len() < self.meta.threshold + 1 { @@ -215,15 +215,13 @@ impl JobSession where Executor: JobExe responses: BTreeMap::new(), }; let waits_for_self = active_data.requests.contains(&self.meta.self_node_id); - let self_response = if waits_for_self { - let partial_request = self.executor.prepare_partial_request(&self.meta.self_node_id, &active_data.requests)?; - Some(self.executor.process_partial_request(partial_request)?) - } else { - None - }; let self_response = match self_response { - Some(JobPartialRequestAction::Respond(self_response)) => Some(self_response), - Some(JobPartialRequestAction::Reject(self_response)) => Some(self_response), + Some(self_response) => Some(self_response), + None if waits_for_self => { + let partial_request = self.executor.prepare_partial_request(&self.meta.self_node_id, &active_data.requests)?; + let self_response = self.executor.process_partial_request(partial_request)?; + Some(self_response.take_response()) + }, None => None, }; @@ -249,11 +247,11 @@ impl JobSession where Executor: JobExe } } - Ok(()) + Ok(self_response) } /// When partial request is received by slave node. - pub fn on_partial_request(&mut self, node: &NodeId, request: Executor::PartialJobRequest) -> Result<(), Error> { + pub fn on_partial_request(&mut self, node: &NodeId, request: Executor::PartialJobRequest) -> Result, Error> { if node != &self.meta.master_node_id { return Err(Error::InvalidMessage); } @@ -264,17 +262,19 @@ impl JobSession where Executor: JobExe return Err(Error::InvalidStateForRequest); } - let partial_response = match self.executor.process_partial_request(request)? { - JobPartialRequestAction::Respond(partial_response) => { + let partial_request_action = self.executor.process_partial_request(request)?; + let partial_response = match partial_request_action { + JobPartialRequestAction::Respond(ref partial_response) => { self.data.state = JobSessionState::Finished; - partial_response + partial_response.clone() }, - JobPartialRequestAction::Reject(partial_response) => { + JobPartialRequestAction::Reject(ref partial_response) => { self.data.state = JobSessionState::Failed; - partial_response + partial_response.clone() }, }; - self.transport.send_partial_response(node, partial_response) + self.transport.send_partial_response(node, partial_response)?; + Ok(partial_request_action) } /// When partial request is received by master node. @@ -291,7 +291,7 @@ impl JobSession where Executor: JobExe if !active_data.requests.remove(node) { return Err(Error::InvalidNodeForRequest); } - + match self.executor.check_partial_response(node, &response)? { JobPartialResponseAction::Ignore => Ok(()), JobPartialResponseAction::Reject => { @@ -358,6 +358,15 @@ impl JobSession where Executor: JobExe } } +impl JobPartialRequestAction { + /// Take actual response. + pub fn take_response(self) -> PartialJobResponse { + match self { + JobPartialRequestAction::Respond(response) => response, + JobPartialRequestAction::Reject(response) => response, + } + } +} #[cfg(test)] pub mod tests { @@ -415,14 +424,14 @@ pub mod tests { #[test] fn job_initialize_fails_if_not_inactive() { let mut job = JobSession::new(make_master_session_meta(0), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1)].into_iter().collect(), false).unwrap(); - assert_eq!(job.initialize(vec![Public::from(1)].into_iter().collect(), false).unwrap_err(), Error::InvalidStateForRequest); + job.initialize(vec![Public::from(1)].into_iter().collect(), None, false).unwrap(); + assert_eq!(job.initialize(vec![Public::from(1)].into_iter().collect(), None, false).unwrap_err(), Error::InvalidStateForRequest); } #[test] fn job_initialization_leads_to_finish_if_single_node_is_required() { let mut job = JobSession::new(make_master_session_meta(0), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Finished); assert!(job.is_result_ready()); assert_eq!(job.result(), Ok(4)); @@ -431,7 +440,7 @@ pub mod tests { #[test] fn job_initialization_does_not_leads_to_finish_if_single_other_node_is_required() { let mut job = JobSession::new(make_master_session_meta(0), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); } @@ -474,7 +483,7 @@ pub mod tests { #[test] fn job_response_fails_if_comes_to_failed_state() { let mut job = JobSession::new(make_master_session_meta(0), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(2)].into_iter().collect(), None, false).unwrap(); job.on_session_timeout().unwrap_err(); assert_eq!(job.on_partial_response(&NodeId::from(2), 2).unwrap_err(), Error::InvalidStateForRequest); } @@ -482,14 +491,14 @@ pub mod tests { #[test] fn job_response_fails_if_comes_from_unknown_node() { let mut job = JobSession::new(make_master_session_meta(0), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.on_partial_response(&NodeId::from(3), 2).unwrap_err(), Error::InvalidNodeForRequest); } #[test] fn job_response_leads_to_failure_if_too_few_nodes_left() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); assert_eq!(job.on_partial_response(&NodeId::from(2), 3).unwrap_err(), Error::ConsensusUnreachable); assert_eq!(job.state(), JobSessionState::Failed); @@ -498,7 +507,7 @@ pub mod tests { #[test] fn job_response_succeeds() { let mut job = JobSession::new(make_master_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); assert!(!job.is_result_ready()); job.on_partial_response(&NodeId::from(2), 2).unwrap(); @@ -509,7 +518,7 @@ pub mod tests { #[test] fn job_response_leads_to_finish() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); job.on_partial_response(&NodeId::from(2), 2).unwrap(); assert_eq!(job.state(), JobSessionState::Finished); @@ -534,7 +543,7 @@ pub mod tests { #[test] fn job_node_error_ignored_when_disconnects_from_rejected() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); job.on_partial_response(&NodeId::from(2), 3).unwrap(); job.on_node_error(&NodeId::from(2)).unwrap(); @@ -544,7 +553,7 @@ pub mod tests { #[test] fn job_node_error_ignored_when_disconnects_from_unknown() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); job.on_node_error(&NodeId::from(3)).unwrap(); assert_eq!(job.state(), JobSessionState::Active); @@ -553,7 +562,7 @@ pub mod tests { #[test] fn job_node_error_ignored_when_disconnects_from_requested_and_enough_nodes_left() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); job.on_node_error(&NodeId::from(3)).unwrap(); assert_eq!(job.state(), JobSessionState::Active); @@ -562,7 +571,7 @@ pub mod tests { #[test] fn job_node_error_leads_to_fail_when_disconnects_from_requested_and_not_enough_nodes_left() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); assert_eq!(job.on_node_error(&NodeId::from(2)).unwrap_err(), Error::ConsensusUnreachable); assert_eq!(job.state(), JobSessionState::Failed); @@ -571,7 +580,7 @@ pub mod tests { #[test] fn job_broadcasts_self_response() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), true).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, true).unwrap(); assert_eq!(job.state(), JobSessionState::Active); assert_eq!(job.transport().response(), (NodeId::from(2), 4)); } @@ -579,7 +588,7 @@ pub mod tests { #[test] fn job_does_not_broadcasts_self_response() { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); - job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), false).unwrap(); + job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); assert!(job.transport().is_empty_response()); } diff --git a/secret_store/src/key_server_cluster/jobs/key_access_job.rs b/secret_store/src/key_server_cluster/jobs/key_access_job.rs index 2cb686e6c2..a47385b5ae 100644 --- a/secret_store/src/key_server_cluster/jobs/key_access_job.rs +++ b/secret_store/src/key_server_cluster/jobs/key_access_job.rs @@ -78,7 +78,7 @@ impl JobExecutor for KeyAccessJob { } self.requester = Some(partial_request.clone()); - self.acl_storage.check(&partial_request.public(&self.id).ok_or(Error::InsufficientRequesterData)?, &self.id) + self.acl_storage.check(partial_request.address(&self.id).map_err(Error::InsufficientRequesterData)?, &self.id) .map_err(|_| Error::AccessDenied) .map(|is_confirmed| if is_confirmed { JobPartialRequestAction::Respond(true) } else { JobPartialRequestAction::Reject(false) }) } diff --git a/secret_store/src/key_server_cluster/message.rs b/secret_store/src/key_server_cluster/message.rs index 9a93efb03a..e08d6761a6 100644 --- a/secret_store/src/key_server_cluster/message.rs +++ b/secret_store/src/key_server_cluster/message.rs @@ -272,6 +272,8 @@ pub struct InitializeSession { pub session: MessageSessionId, /// Session-level nonce. pub session_nonce: u64, + /// Session origin address (if any). + pub origin: Option, /// Session author. pub author: SerializableAddress, /// All session participants along with their identification numbers. @@ -713,6 +715,8 @@ pub struct DecryptionConsensusMessage { pub sub_session: SerializableSecret, /// Session-level nonce. pub session_nonce: u64, + /// Session origin (in consensus initialization message). + pub origin: Option, /// Consensus message. pub message: ConsensusMessage, } @@ -788,6 +792,8 @@ pub struct DecryptionSessionDelegation { pub sub_session: SerializableSecret, /// Session-level nonce. pub session_nonce: u64, + /// Session origin. + pub origin: Option, /// Requester. pub requester: SerializableRequester, /// Key version. diff --git a/secret_store/src/key_server_cluster/mod.rs b/secret_store/src/key_server_cluster/mod.rs index 17334e838a..804c85e311 100644 --- a/secret_store/src/key_server_cluster/mod.rs +++ b/secret_store/src/key_server_cluster/mod.rs @@ -115,7 +115,7 @@ pub enum Error { /// Can't start exclusive session, because there are other active sessions. HasActiveSessions, /// Insufficient requester data. - InsufficientRequesterData, + InsufficientRequesterData(String), } impl From for Error { @@ -164,7 +164,7 @@ impl fmt::Display for Error { Error::AccessDenied => write!(f, "Access denied"), Error::ExclusiveSessionActive => write!(f, "Exclusive session active"), Error::HasActiveSessions => write!(f, "Unable to start exclusive session"), - Error::InsufficientRequesterData => write!(f, "Insufficient requester data"), + Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), } } } diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index 4429500db1..1d4b968c07 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -475,6 +475,10 @@ pub mod tests { let config = ServiceConfiguration { listener_address: None, service_contract_address: None, + service_contract_srv_gen_address: None, + service_contract_srv_retr_address: None, + service_contract_doc_store_address: None, + service_contract_doc_sretr_address: None, acl_check_enabled: true, data_path: tempdir.path().display().to_string(), cluster_config: ClusterConfiguration { diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 9d89ba0c63..e796ff4bc5 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -86,26 +86,75 @@ pub fn start(client: Arc, sync: Arc, self_key_pair: Arc = key_server; - // prepare listeners + // prepare HTTP listener let http_listener = match config.listener_address { - Some(listener_address) => Some(listener::http_listener::KeyServerHttpListener::start(listener_address, key_server.clone())?), + Some(listener_address) => Some(listener::http_listener::KeyServerHttpListener::start(listener_address, Arc::downgrade(&key_server))?), None => None, }; - let contract_listener = config.service_contract_address.map(|service_contract_address| { - let service_contract = Arc::new(listener::service_contract::OnChainServiceContract::new(trusted_client, service_contract_address, self_key_pair.clone())); - let contract_listener = listener::service_contract_listener::ServiceContractListener::new(listener::service_contract_listener::ServiceContractListenerParams { - contract: service_contract, - key_server: key_server.clone(), - self_key_pair: self_key_pair, - key_server_set: key_server_set, - cluster: cluster, - key_storage: key_storage, - }); - client.add_notify(contract_listener.clone()); - contract_listener - }); + + // prepare service contract listeners + let create_service_contract = |address, name, api_mask| + Arc::new(listener::service_contract::OnChainServiceContract::new( + api_mask, + trusted_client.clone(), + name, + address, + self_key_pair.clone())); + + let mut contracts: Vec> = Vec::new(); + config.service_contract_address.map(|address| + create_service_contract(address, + listener::service_contract::SERVICE_CONTRACT_REGISTRY_NAME.to_owned(), + listener::ApiMask::all())) + .map(|l| contracts.push(l)); + config.service_contract_srv_gen_address.map(|address| + create_service_contract(address, + listener::service_contract::SRV_KEY_GEN_SERVICE_CONTRACT_REGISTRY_NAME.to_owned(), + listener::ApiMask { server_key_generation_requests: true, ..Default::default() })) + .map(|l| contracts.push(l)); + config.service_contract_srv_retr_address.map(|address| + create_service_contract(address, + listener::service_contract::SRV_KEY_RETR_SERVICE_CONTRACT_REGISTRY_NAME.to_owned(), + listener::ApiMask { server_key_retrieval_requests: true, ..Default::default() })) + .map(|l| contracts.push(l)); + config.service_contract_doc_store_address.map(|address| + create_service_contract(address, + listener::service_contract::DOC_KEY_STORE_SERVICE_CONTRACT_REGISTRY_NAME.to_owned(), + listener::ApiMask { document_key_store_requests: true, ..Default::default() })) + .map(|l| contracts.push(l)); + config.service_contract_doc_sretr_address.map(|address| + create_service_contract(address, + listener::service_contract::DOC_KEY_SRETR_SERVICE_CONTRACT_REGISTRY_NAME.to_owned(), + listener::ApiMask { document_key_shadow_retrieval_requests: true, ..Default::default() })) + .map(|l| contracts.push(l)); + + let contract: Option> = match contracts.len() { + 0 => None, + 1 => Some(contracts.pop().expect("contract.len() is 1; qed")), + _ => Some(Arc::new(listener::service_contract_aggregate::OnChainServiceContractAggregate::new(contracts))), + }; + + let contract_listener = match contract { + Some(contract) => Some({ + let listener = listener::service_contract_listener::ServiceContractListener::new( + listener::service_contract_listener::ServiceContractListenerParams { + contract: contract, + self_key_pair: self_key_pair.clone(), + key_server_set: key_server_set, + acl_storage: acl_storage, + cluster: cluster, + key_storage: key_storage, + } + )?; + client.add_notify(listener.clone()); + listener + }), + None => None, + }; + Ok(Box::new(listener::Listener::new(key_server, http_listener, contract_listener))) } diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index 4d34f984bf..1680201e19 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -16,7 +16,7 @@ use std::collections::BTreeSet; use std::io::Read; -use std::sync::Arc; +use std::sync::{Arc, Weak}; use hyper::header; use hyper::uri::RequestUri; use hyper::method::Method as HttpMethod; @@ -77,12 +77,12 @@ struct KeyServerHttpHandler { /// Shared http handler struct KeyServerSharedHttpHandler { - key_server: Arc, + key_server: Weak, } impl KeyServerHttpListener { /// Start KeyServer http listener - pub fn start(listener_address: NodeAddress, key_server: Arc) -> Result { + pub fn start(listener_address: NodeAddress, key_server: Weak) -> Result { let shared_handler = Arc::new(KeyServerSharedHttpHandler { key_server: key_server, }); @@ -128,56 +128,72 @@ impl HttpHandler for KeyServerHttpHandler { match &req_uri { &RequestUri::AbsolutePath(ref path) => match parse_request(&req_method, &path, &req_body) { Request::GenerateServerKey(document, signature, threshold) => { - return_server_public_key(req, res, self.handler.key_server.generate_key(&document, &signature, threshold) + return_server_public_key(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.generate_key(&document, &signature.into(), threshold)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "GenerateServerKey request {} has failed with: {}", req_uri, err); err })); }, Request::StoreDocumentKey(document, signature, common_point, encrypted_document_key) => { - return_empty(req, res, self.handler.key_server.store_document_key(&document, &signature, common_point, encrypted_document_key) + return_empty(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.store_document_key(&document, &signature.into(), common_point, encrypted_document_key)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "StoreDocumentKey request {} has failed with: {}", req_uri, err); err })); }, Request::GenerateDocumentKey(document, signature, threshold) => { - return_document_key(req, res, self.handler.key_server.generate_document_key(&document, &signature, threshold) + return_document_key(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.generate_document_key(&document, &signature.into(), threshold)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "GenerateDocumentKey request {} has failed with: {}", req_uri, err); err })); }, Request::GetDocumentKey(document, signature) => { - return_document_key(req, res, self.handler.key_server.restore_document_key(&document, &signature) + return_document_key(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.restore_document_key(&document, &signature.into())) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "GetDocumentKey request {} has failed with: {}", req_uri, err); err })); }, Request::GetDocumentKeyShadow(document, signature) => { - return_document_key_shadow(req, res, self.handler.key_server.restore_document_key_shadow(&document, &signature) + return_document_key_shadow(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.restore_document_key_shadow(&document, &signature.into())) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "GetDocumentKeyShadow request {} has failed with: {}", req_uri, err); err })); }, Request::SchnorrSignMessage(document, signature, message_hash) => { - return_message_signature(req, res, self.handler.key_server.sign_message_schnorr(&document, &signature, message_hash) + return_message_signature(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.sign_message_schnorr(&document, &signature.into(), message_hash)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "SchnorrSignMessage request {} has failed with: {}", req_uri, err); err })); }, Request::EcdsaSignMessage(document, signature, message_hash) => { - return_message_signature(req, res, self.handler.key_server.sign_message_ecdsa(&document, &signature, message_hash) + return_message_signature(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.sign_message_ecdsa(&document, &signature.into(), message_hash)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "EcdsaSignMessage request {} has failed with: {}", req_uri, err); err })); }, Request::ChangeServersSet(old_set_signature, new_set_signature, new_servers_set) => { - return_empty(req, res, self.handler.key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set) + return_empty(req, res, self.handler.key_server.upgrade() + .map(|key_server| key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) .map_err(|err| { warn!(target: "secretstore", "ChangeServersSet request {} has failed with: {}", req_uri, err); err @@ -241,7 +257,7 @@ fn return_bytes(req: HttpRequest, mut res: HttpResponse, result: R fn return_error(mut res: HttpResponse, err: Error) { match err { - Error::BadSignature => *res.status_mut() = HttpStatusCode::BadRequest, + Error::InsufficientRequesterData(_) => *res.status_mut() = HttpStatusCode::BadRequest, Error::AccessDenied => *res.status_mut() = HttpStatusCode::Forbidden, Error::DocumentNotFound => *res.status_mut() = HttpStatusCode::NotFound, Error::Hyper(_) => *res.status_mut() = HttpStatusCode::BadRequest, @@ -342,15 +358,16 @@ mod tests { use std::sync::Arc; use hyper::method::Method as HttpMethod; use ethkey::Public; + use traits::KeyServer; use key_server::tests::DummyKeyServer; use types::all::NodeAddress; use super::{parse_request, Request, KeyServerHttpListener}; #[test] fn http_listener_successfully_drops() { - let key_server = Arc::new(DummyKeyServer::default()); + let key_server: Arc = Arc::new(DummyKeyServer::default()); let address = NodeAddress { address: "127.0.0.1".into(), port: 9000 }; - let listener = KeyServerHttpListener::start(address, key_server).unwrap(); + let listener = KeyServerHttpListener::start(address, Arc::downgrade(&key_server)).unwrap(); drop(listener); } diff --git a/secret_store/src/listener/mod.rs b/secret_store/src/listener/mod.rs index df96c583d4..2c4fbaf4cb 100644 --- a/secret_store/src/listener/mod.rs +++ b/secret_store/src/listener/mod.rs @@ -16,6 +16,7 @@ pub mod http_listener; pub mod service_contract; +pub mod service_contract_aggregate; pub mod service_contract_listener; mod tasks_queue; @@ -23,15 +24,42 @@ use std::collections::BTreeSet; use std::sync::Arc; use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, AdminSessionsServer, KeyServer}; use types::all::{Error, Public, MessageHash, EncryptedMessageSignature, RequestSignature, ServerKeyId, - EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId}; + EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId, Requester}; + +/// Available API mask. +#[derive(Debug, Default)] +pub struct ApiMask { + /// Accept server key generation requests. + pub server_key_generation_requests: bool, + /// Accept server key retrieval requests. + pub server_key_retrieval_requests: bool, + /// Accept document key store requests. + pub document_key_store_requests: bool, + /// Accept document key shadow retrieval requests. + pub document_key_shadow_retrieval_requests: bool, +} +/// Combined HTTP + service contract listener. pub struct Listener { key_server: Arc, _http: Option, _contract: Option>, } +impl ApiMask { + /// Create mask that accepts all requests. + pub fn all() -> Self { + ApiMask { + server_key_generation_requests: true, + server_key_retrieval_requests: true, + document_key_store_requests: true, + document_key_shadow_retrieval_requests: true, + } + } +} + impl Listener { + /// Create new listener. pub fn new(key_server: Arc, http: Option, contract: Option>) -> Self { Self { key_server: key_server, @@ -44,36 +72,36 @@ impl Listener { impl KeyServer for Listener {} impl ServerKeyGenerator for Listener { - fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result { - self.key_server.generate_key(key_id, signature, threshold) + fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result { + self.key_server.generate_key(key_id, author, threshold) } } impl DocumentKeyServer for Listener { - fn store_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, common_point: Public, encrypted_document_key: Public) -> Result<(), Error> { - self.key_server.store_document_key(key_id, signature, common_point, encrypted_document_key) + fn store_document_key(&self, key_id: &ServerKeyId, author: &Requester, common_point: Public, encrypted_document_key: Public) -> Result<(), Error> { + self.key_server.store_document_key(key_id, author, common_point, encrypted_document_key) } - fn generate_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result { - self.key_server.generate_document_key(key_id, signature, threshold) + fn generate_document_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result { + self.key_server.generate_document_key(key_id, author, threshold) } - fn restore_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result { - self.key_server.restore_document_key(key_id, signature) + fn restore_document_key(&self, key_id: &ServerKeyId, requester: &Requester) -> Result { + self.key_server.restore_document_key(key_id, requester) } - fn restore_document_key_shadow(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result { - self.key_server.restore_document_key_shadow(key_id, signature) + fn restore_document_key_shadow(&self, key_id: &ServerKeyId, requester: &Requester) -> Result { + self.key_server.restore_document_key_shadow(key_id, requester) } } impl MessageSigner for Listener { - fn sign_message_schnorr(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result { - self.key_server.sign_message_schnorr(key_id, signature, message) + fn sign_message_schnorr(&self, key_id: &ServerKeyId, requester: &Requester, message: MessageHash) -> Result { + self.key_server.sign_message_schnorr(key_id, requester, message) } - fn sign_message_ecdsa(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result { - self.key_server.sign_message_ecdsa(key_id, signature, message) + fn sign_message_ecdsa(&self, key_id: &ServerKeyId, requester: &Requester, message: MessageHash) -> Result { + self.key_server.sign_message_ecdsa(key_id, requester, message) } } @@ -81,4 +109,4 @@ impl AdminSessionsServer for Listener { fn change_servers_set(&self, old_set_signature: RequestSignature, new_set_signature: RequestSignature, new_servers_set: BTreeSet) -> Result<(), Error> { self.key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set) } -} \ No newline at end of file +} diff --git a/secret_store/src/listener/service_contract.rs b/secret_store/src/listener/service_contract.rs index f2d13f192f..7bb28ae053 100644 --- a/secret_store/src/listener/service_contract.rs +++ b/secret_store/src/listener/service_contract.rs @@ -16,28 +16,51 @@ use std::sync::Arc; use parking_lot::RwLock; +use ethabi::RawLog; use ethcore::filter::Filter; use ethcore::client::{Client, BlockChainClient, BlockId, RegistryInfo, CallContract}; -use ethkey::{Public, Signature, public_to_address}; +use ethkey::{Public, public_to_address}; use hash::keccak; +use bytes::Bytes; use ethereum_types::{H256, U256, Address}; +use listener::ApiMask; use listener::service_contract_listener::ServiceTask; use trusted_client::TrustedClient; use {ServerKeyId, NodeKeyPair, ContractAddress}; use_contract!(service, "Service", "res/service.json"); -/// Name of the SecretStore contract in the registry. -const SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service"; - -/// Key server has been added to the set. -const SERVER_KEY_REQUESTED_EVENT_NAME: &'static [u8] = &*b"ServerKeyRequested(bytes32,uint256)"; +/// Name of the general SecretStore contract in the registry. +pub const SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service"; +/// Name of the server key generation SecretStore contract in the registry. +pub const SRV_KEY_GEN_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_srv_gen"; +/// Name of the server key retrieval SecretStore contract in the registry. +pub const SRV_KEY_RETR_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_srv_retr"; +/// Name of the document key store SecretStore contract in the registry. +pub const DOC_KEY_STORE_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_doc_store"; +/// Name of the document key retrieval SecretStore contract in the registry. +pub const DOC_KEY_SRETR_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_doc_sretr"; + +/// Server key generation has been requested. +const SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME: &'static [u8] = &*b"ServerKeyGenerationRequested(bytes32,address,uint8)"; +/// Server key retrieval has been requested. +const SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = &*b"ServerKeyRetrievalRequested(bytes32)"; +/// Document key store has been requested. +const DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME: &'static [u8] = &*b"DocumentKeyStoreRequested(bytes32,address,bytes,bytes)"; +/// Document key common part retrieval has been requested. +const DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = &*b"DocumentKeyCommonRetrievalRequested(bytes32,address)"; +/// Document key personal part retrieval has been requested. +const DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = &*b"DocumentKeyPersonalRetrievalRequested(bytes32,bytes)"; /// Number of confirmations required before request can be processed. const REQUEST_CONFIRMATIONS_REQUIRED: u64 = 3; lazy_static! { - static ref SERVER_KEY_REQUESTED_EVENT_NAME_HASH: H256 = keccak(SERVER_KEY_REQUESTED_EVENT_NAME); + pub static ref SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH: H256 = keccak(SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME); + pub static ref SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH: H256 = keccak(SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME); + pub static ref DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH: H256 = keccak(DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME); + pub static ref DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH: H256 = keccak(DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME); + pub static ref DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH: H256 = keccak(DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME); } /// Service contract trait. @@ -45,61 +68,82 @@ pub trait ServiceContract: Send + Sync { /// Update contract when new blocks are enacted. Returns true if contract is installed && up-to-date (i.e. chain is synced). fn update(&self) -> bool; /// Read recent contract logs. Returns topics of every entry. - fn read_logs(&self) -> Box>>; + fn read_logs(&self) -> Box>; /// Publish generated key. fn read_pending_requests(&self) -> Box>; - /// Publish server key. - fn publish_server_key(&self, server_key_id: &ServerKeyId, server_key: &Public) -> Result<(), String>; + /// Publish generated server key. + fn publish_generated_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String>; + /// Publish server key generation error. + fn publish_server_key_generation_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; + /// Publish retrieved server key. + fn publish_retrieved_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String>; + /// Publish server key retrieval error. + fn publish_server_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; + /// Publish stored document key. + fn publish_stored_document_key(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; + /// Publish document key store error. + fn publish_document_key_store_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; + /// Publish retrieved document key common. + fn publish_retrieved_document_key_common(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String>; + /// Publish retrieved document key personal. + fn publish_retrieved_document_key_personal(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String>; + /// Publish document key store error. + fn publish_document_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String>; } /// On-chain service contract. pub struct OnChainServiceContract { + /// Requests mask. + mask: ApiMask, /// Blockchain client. client: TrustedClient, /// This node key pair. self_key_pair: Arc, - /// Contract addresss. + /// Contract registry name (if any). + name: String, + /// Contract address. address: ContractAddress, /// Contract. + contract: service::Service, + /// Contract. data: RwLock, } /// On-chain service contract data. struct ServiceData { - /// Contract. - pub contract: service::Service, - /// Contract address. + /// Actual contract address. pub contract_address: Address, /// Last block we have read logs from. pub last_log_block: Option, } /// Pending requests iterator. -struct PendingRequestsIterator { - /// Blockchain client. - client: Arc, - /// Contract. - contract: service::Service, - /// Contract address. - contract_address: Address, - /// This node key pair. - self_key_pair: Arc, - /// Block, this iterator is created for. - block: H256, +struct PendingRequestsIterator Option<(bool, ServiceTask)>> { + /// Pending request read function. + read_request: F, /// Current request index. index: U256, /// Requests length. length: U256, } +/// Server key generation related functions. +struct ServerKeyGenerationService; +/// Server key retrieval related functions. +struct ServerKeyRetrievalService; +/// Document key store related functions. +struct DocumentKeyStoreService; +/// Document key shadow retrievalrelated functions. +struct DocumentKeyShadowRetrievalService; + impl OnChainServiceContract { /// Create new on-chain service contract. - pub fn new(client: TrustedClient, address: ContractAddress, self_key_pair: Arc) -> Self { + pub fn new(mask: ApiMask, client: TrustedClient, name: String, address: ContractAddress, self_key_pair: Arc) -> Self { let contract_addr = match address { - ContractAddress::Registry => client.get().and_then(|c| c.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) + ContractAddress::Registry => client.get().and_then(|c| c.registry_address(name.clone(), BlockId::Latest) .map(|address| { - trace!(target: "secretstore", "{}: installing service contract from address {}", - self_key_pair.public(), address); + trace!(target: "secretstore", "{}: installing {} service contract from address {}", + self_key_pair.public(), name, address); address })) .unwrap_or_default(), @@ -111,16 +155,81 @@ impl OnChainServiceContract { }; OnChainServiceContract { + mask: mask, client: client, self_key_pair: self_key_pair, + name: name, address: address, + contract: service::Service::default(), data: RwLock::new(ServiceData { - contract: service::Service::default(), contract_address: contract_addr, last_log_block: None, }), } } + + /// Send transaction to the service contract. + fn send_contract_transaction(&self, origin: &Address, server_key_id: &ServerKeyId, is_response_required: C, prepare_tx: P) -> Result<(), String> + where C: FnOnce(&Client, &Address, &service::Service, &ServerKeyId, &Address) -> bool, + P: FnOnce(&Client, &Address, &service::Service) -> Result { + // only publish if contract address is set && client is online + let client = match self.client.get() { + Some(client) => client, + None => return Err("trusted client is required to publish key".into()), + }; + + // only publish key if contract waits for publication + // failing is ok here - it could be that enough confirmations have been recevied + // or key has been requested using HTTP API + let self_address = public_to_address(self.self_key_pair.public()); + if !is_response_required(&*client, origin, &self.contract, server_key_id, &self_address) { + return Ok(()); + } + + // prepare transaction data + let transaction_data = prepare_tx(&*client, origin, &self.contract)?; + + // send transaction + client.transact_contract( + origin.clone(), + transaction_data + ).map_err(|e| format!("{}", e))?; + + Ok(()) + } + + /// Create task-specific pending requests iterator. + fn create_pending_requests_iterator< + C: 'static + Fn(&Client, &Address, &service::Service, &BlockId) -> Result, + R: 'static + Fn(&NodeKeyPair, &Client, &Address, &service::Service, &BlockId, U256) -> Result<(bool, ServiceTask), String> + >(&self, client: Arc, contract_address: &Address, block: &BlockId, get_count: C, read_item: R) -> Box> { + let contract = service::Service::default(); + get_count(&*client, contract_address, &contract, block) + .map(|count| { + let client = client.clone(); + let self_key_pair = self.self_key_pair.clone(); + let contract_address = contract_address.clone(); + let block = block.clone(); + Box::new(PendingRequestsIterator { + read_request: move |index| read_item(&*self_key_pair, &*client, &contract_address, &contract, &block, index) + .map_err(|error| { + warn!(target: "secretstore", "{}: reading pending request failed: {}", + self_key_pair.public(), error); + error + }) + .ok(), + index: 0.into(), + length: count, + }) as Box> + }) + .map_err(|error| { + warn!(target: "secretstore", "{}: creating pending requests iterator failed: {}", + self.self_key_pair.public(), error); + error + }) + .ok() + .unwrap_or_else(|| Box::new(::std::iter::empty())) + } } impl ServiceContract for OnChainServiceContract { @@ -130,10 +239,10 @@ impl ServiceContract for OnChainServiceContract { if let &ContractAddress::Registry = &self.address { if let Some(client) = self.client.get() { // update contract address from registry - let service_contract_addr = client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest).unwrap_or_default(); + let service_contract_addr = client.registry_address(self.name.clone(), BlockId::Latest).unwrap_or_default(); if self.data.read().contract_address != service_contract_addr { - trace!(target: "secretstore", "{}: installing service contract from address {}", - self.self_key_pair.public(), service_contract_addr); + trace!(target: "secretstore", "{}: installing {} service contract from address {}", + self.self_key_pair.public(), self.name, service_contract_addr); self.data.write().contract_address = service_contract_addr; } } @@ -143,7 +252,7 @@ impl ServiceContract for OnChainServiceContract { && self.client.get().is_some() } - fn read_logs(&self) -> Box>> { + fn read_logs(&self) -> Box> { let client = match self.client.get() { Some(client) => client, None => { @@ -181,16 +290,33 @@ impl ServiceContract for OnChainServiceContract { from_block: BlockId::Hash(first_block), to_block: BlockId::Hash(last_block), address: Some(vec![address]), - topics: vec![ - Some(vec![*SERVER_KEY_REQUESTED_EVENT_NAME_HASH]), - None, - None, - None, - ], + topics: vec![Some(mask_topics(&self.mask))], limit: None, }); - Box::new(request_logs.into_iter().map(|log| log.entry.topics)) + Box::new(request_logs.into_iter() + .filter_map(|log| { + let raw_log: RawLog = (log.entry.topics.into_iter().map(|t| t.0.into()).collect(), log.entry.data).into(); + if raw_log.topics[0] == *SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH { + ServerKeyGenerationService::parse_log(&address, &self.contract, raw_log) + } else if raw_log.topics[0] == *SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH { + ServerKeyRetrievalService::parse_log(&address, &self.contract, raw_log) + } else if raw_log.topics[0] == *DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH { + DocumentKeyStoreService::parse_log(&address, &self.contract, raw_log) + } else if raw_log.topics[0] == *DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH { + DocumentKeyShadowRetrievalService::parse_common_request_log(&address, &self.contract, raw_log) + } else if raw_log.topics[0] == *DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH { + DocumentKeyShadowRetrievalService::parse_personal_request_log(&address, &self.contract, raw_log) + } else { + Err("unknown type of log entry".into()) + } + .map_err(|error| { + warn!(target: "secretstore", "{}: error parsing log entry from service contract: {}", + self.self_key_pair.public(), error); + error + }) + .ok() + }).collect::>().into_iter()) } fn read_pending_requests(&self) -> Box> { @@ -205,81 +331,102 @@ impl ServiceContract for OnChainServiceContract { match data.contract_address == Default::default() { true => Box::new(::std::iter::empty()), false => get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED + 1) - .and_then(|b| { - let contract_address = data.contract_address; - let do_call = |data| client.call_contract(BlockId::Hash(b), contract_address, data); - data.contract.functions().server_key_generation_requests_count().call(&do_call) - .map_err(|error| { - warn!(target: "secretstore", "{}: call to server_key_generation_requests_count failed: {}", - self.self_key_pair.public(), error); - error - }) - .map(|l| (b, l)) - .ok() + .map(|b| { + let block = BlockId::Hash(b); + let iter = match self.mask.server_key_generation_requests { + true => Box::new(self.create_pending_requests_iterator(client.clone(), &data.contract_address, &block, + &ServerKeyGenerationService::read_pending_requests_count, + &ServerKeyGenerationService::read_pending_request)) as Box>, + false => Box::new(::std::iter::empty()), + }; + let iter = match self.mask.server_key_retrieval_requests { + true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &data.contract_address, &block, + &ServerKeyRetrievalService::read_pending_requests_count, + &ServerKeyRetrievalService::read_pending_request))), + false => iter, + }; + let iter = match self.mask.document_key_store_requests { + true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &data.contract_address, &block, + &DocumentKeyStoreService::read_pending_requests_count, + &DocumentKeyStoreService::read_pending_request))), + false => iter, + }; + let iter = match self.mask.document_key_shadow_retrieval_requests { + true => Box::new(iter.chain(self.create_pending_requests_iterator(client, &data.contract_address, &block, + &DocumentKeyShadowRetrievalService::read_pending_requests_count, + &DocumentKeyShadowRetrievalService::read_pending_request))), + false => iter + }; + + iter }) - .map(|(b, l)| Box::new(PendingRequestsIterator { - client: client, - contract: service::Service::default(), - contract_address: data.contract_address, - self_key_pair: self.self_key_pair.clone(), - block: b, - index: 0.into(), - length: l, - }) as Box>) .unwrap_or_else(|| Box::new(::std::iter::empty())) } } - fn publish_server_key(&self, server_key_id: &ServerKeyId, server_key: &Public) -> Result<(), String> { - // only publish if contract address is set && client is online - let data = self.data.read(); - if data.contract_address == Default::default() { - // it is not an error, because key could be generated even without contract - return Ok(()); - } + fn publish_generated_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String> { + self.send_contract_transaction(origin, server_key_id, ServerKeyGenerationService::is_response_required, |_, _, service| + Ok(ServerKeyGenerationService::prepare_pubish_tx_data(service, server_key_id, &server_key)) + ) + } - let client = match self.client.get() { - Some(client) => client, - None => return Err("trusted client is required to publish key".into()), - }; + fn publish_server_key_generation_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.send_contract_transaction(origin, server_key_id, ServerKeyGenerationService::is_response_required, |_, _, service| + Ok(ServerKeyGenerationService::prepare_error_tx_data(service, server_key_id)) + ) + } - // only publish key if contract waits for publication - // failing is ok here - it could be that enough confirmations have been recevied - // or key has been requested using HTTP API - let contract_address = data.contract_address; - let do_call = |data| client.call_contract(BlockId::Latest, contract_address, data); - let self_address = public_to_address(self.self_key_pair.public()); - if data.contract.functions() - .get_server_key_confirmation_status() - .call(*server_key_id, self_address, &do_call) - .unwrap_or(false) { - return Ok(()); - } + fn publish_retrieved_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String> { + let threshold = serialize_threshold(threshold)?; + self.send_contract_transaction(origin, server_key_id, ServerKeyRetrievalService::is_response_required, |_, _, service| + Ok(ServerKeyRetrievalService::prepare_pubish_tx_data(service, server_key_id, server_key, threshold)) + ) + } - // prepare transaction data - let server_key_hash = keccak(server_key); - let signed_server_key = self.self_key_pair.sign(&server_key_hash).map_err(|e| format!("{}", e))?; - let signed_server_key: Signature = signed_server_key.into_electrum().into(); - let transaction_data = data.contract.functions() - .server_key_generated() - .input(*server_key_id, - server_key.to_vec(), - signed_server_key.v(), - signed_server_key.r(), - signed_server_key.s(), - ); + fn publish_server_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.send_contract_transaction(origin, server_key_id, ServerKeyRetrievalService::is_response_required, |_, _, service| + Ok(ServerKeyRetrievalService::prepare_error_tx_data(service, server_key_id)) + ) + } - // send transaction - client.transact_contract( - data.contract_address, - transaction_data - ).map_err(|e| format!("{}", e))?; + fn publish_stored_document_key(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.send_contract_transaction(origin, server_key_id, DocumentKeyStoreService::is_response_required, |_, _, service| + Ok(DocumentKeyStoreService::prepare_pubish_tx_data(service, server_key_id)) + ) + } - Ok(()) + fn publish_document_key_store_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.send_contract_transaction(origin, server_key_id, DocumentKeyStoreService::is_response_required, |_, _, service| + Ok(DocumentKeyStoreService::prepare_error_tx_data(service, server_key_id)) + ) + } + + fn publish_retrieved_document_key_common(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String> { + let threshold = serialize_threshold(threshold)?; + self.send_contract_transaction(origin, server_key_id, |client, contract_address, contract, server_key_id, key_server| + DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, contract, server_key_id, requester, key_server), + |_, _, service| + Ok(DocumentKeyShadowRetrievalService::prepare_pubish_common_tx_data(service, server_key_id, requester, common_point, threshold)) + ) + } + + fn publish_retrieved_document_key_personal(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String> { + self.send_contract_transaction(origin, server_key_id, |_, _, _, _, _| true, + move |client, address, service| + DocumentKeyShadowRetrievalService::prepare_pubish_personal_tx_data(client, address, service, server_key_id, requester, participants, decrypted_secret, shadow) + ) + } + + fn publish_document_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { + self.send_contract_transaction(origin, server_key_id, |client, contract_address, contract, server_key_id, key_server| + DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, contract, server_key_id, requester, key_server), + |_, _, service| + Ok(DocumentKeyShadowRetrievalService::prepare_error_tx_data(service, server_key_id, requester)) + ) } } -impl Iterator for PendingRequestsIterator { +impl Iterator for PendingRequestsIterator where F: Fn(U256) -> Option<(bool, ServiceTask)> { type Item = (bool, ServiceTask); fn next(&mut self) -> Option<(bool, ServiceTask)> { @@ -290,25 +437,27 @@ impl Iterator for PendingRequestsIterator { let index = self.index.clone(); self.index = self.index + 1.into(); - let self_address = public_to_address(self.self_key_pair.public()); - let contract_address = self.contract_address; - let do_call = |data| self.client.call_contract(BlockId::Hash(self.block.clone()), contract_address, data); - self.contract.functions().get_server_key_id().call(index, &do_call) - .and_then(|server_key_id| - self.contract.functions().get_server_key_threshold().call(server_key_id, &do_call) - .map(|threshold| (server_key_id, threshold))) - .and_then(|(server_key_id, threshold)| - self.contract.functions().get_server_key_confirmation_status().call(server_key_id, self_address, &do_call) - .map(|is_confirmed| (server_key_id, threshold, is_confirmed))) - .map(|(server_key_id, threshold, is_confirmed)| - Some((is_confirmed, ServiceTask::GenerateServerKey(server_key_id, threshold.into())))) - .map_err(|error| { - warn!(target: "secretstore", "{}: reading service contract request failed: {}", - self.self_key_pair.public(), error); - () - }) - .unwrap_or(None) + (self.read_request)(index) + } +} + +/// Returns vector of logs topics to listen to. +pub fn mask_topics(mask: &ApiMask) -> Vec { + let mut topics = Vec::new(); + if mask.server_key_generation_requests { + topics.push(*SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH); + } + if mask.server_key_retrieval_requests { + topics.push(*SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH); + } + if mask.document_key_store_requests { + topics.push(*DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH); } + if mask.document_key_shadow_retrieval_requests { + topics.push(*DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH); + topics.push(*DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH); + } + topics } /// Get hash of the last block with at least n confirmations. @@ -318,21 +467,365 @@ fn get_confirmed_block_hash(client: &Client, confirmations: u64) -> Option .and_then(|b| client.block_hash(BlockId::Number(b))) } +impl ServerKeyGenerationService { + /// Parse request log entry. + pub fn parse_log(origin: &Address, contract: &service::Service, raw_log: RawLog) -> Result { + let event = contract.events().server_key_generation_requested(); + match event.parse_log(raw_log) { + Ok(l) => Ok(ServiceTask::GenerateServerKey(origin.clone(), l.server_key_id, l.author, parse_threshold(l.threshold)?)), + Err(e) => Err(format!("{}", e)), + } + } + + /// Check if response from key server is required. + pub fn is_response_required(client: &Client, contract_address: &Address, contract: &service::Service, server_key_id: &ServerKeyId, key_server: &Address) -> bool { + // we're checking confirmation in Latest block, because we're interested in latest contract state here + let do_call = |data| client.call_contract(BlockId::Latest, *contract_address, data); + contract.functions() + .is_server_key_generation_response_required() + .call(*server_key_id, key_server.clone(), &do_call) + .unwrap_or(true) + } + + /// Prepare publish key transaction data. + pub fn prepare_pubish_tx_data(contract: &service::Service, server_key_id: &ServerKeyId, server_key_public: &Public) -> Bytes { + contract.functions() + .server_key_generated() + .input(*server_key_id, server_key_public.to_vec()) + } + + /// Prepare error transaction data. + pub fn prepare_error_tx_data(contract: &service::Service, server_key_id: &ServerKeyId) -> Bytes { + contract.functions() + .server_key_generation_error() + .input(*server_key_id) + } + + /// Read pending requests count. + fn read_pending_requests_count(client: &Client, contract_address: &Address, _contract: &service::Service, block: &BlockId) -> Result { + let do_call = |data| client.call_contract(block.clone(), contract_address.clone(), data); + let contract = service::Service::default(); + contract.functions() + .server_key_generation_requests_count() + .call(&do_call) + .map_err(|error| format!("{}", error)) + } + + /// Read pending request. + fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, contract: &service::Service, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { + let self_address = public_to_address(self_key_pair.public()); + let do_call = |d| client.call_contract(block.clone(), contract_address.clone(), d); + contract.functions() + .get_server_key_generation_request() + .call(index, &do_call) + .map_err(|error| format!("{}", error)) + .and_then(|(server_key_id, author, threshold)| parse_threshold(threshold) + .map(|threshold| (server_key_id, author, threshold))) + .and_then(|(server_key_id, author, threshold)| contract.functions() + .is_server_key_generation_response_required() + .call(server_key_id.clone(), self_address, &do_call) + .map(|not_confirmed| ( + not_confirmed, + ServiceTask::GenerateServerKey( + contract_address.clone(), + server_key_id, + author, + threshold, + ))) + .map_err(|error| format!("{}", error))) + } +} + +impl ServerKeyRetrievalService { + /// Parse request log entry. + pub fn parse_log(origin: &Address, contract: &service::Service, raw_log: RawLog) -> Result { + let event = contract.events().server_key_retrieval_requested(); + match event.parse_log(raw_log) { + Ok(l) => Ok(ServiceTask::RetrieveServerKey(origin.clone(), l.server_key_id)), + Err(e) => Err(format!("{}", e)), + } + } + + /// Check if response from key server is required. + pub fn is_response_required(client: &Client, contract_address: &Address, contract: &service::Service, server_key_id: &ServerKeyId, key_server: &Address) -> bool { + // we're checking confirmation in Latest block, because we're interested in latest contract state here + let do_call = |data| client.call_contract(BlockId::Latest, *contract_address, data); + contract.functions() + .is_server_key_retrieval_response_required() + .call(*server_key_id, key_server.clone(), &do_call) + .unwrap_or(true) + } + + /// Prepare publish key transaction data. + pub fn prepare_pubish_tx_data(contract: &service::Service, server_key_id: &ServerKeyId, server_key_public: Public, threshold: U256) -> Bytes { + contract.functions() + .server_key_retrieved() + .input(*server_key_id, server_key_public.to_vec(), threshold) + } + + /// Prepare error transaction data. + pub fn prepare_error_tx_data(contract: &service::Service, server_key_id: &ServerKeyId) -> Bytes { + contract.functions() + .server_key_retrieval_error() + .input(*server_key_id) + } + + /// Read pending requests count. + fn read_pending_requests_count(client: &Client, contract_address: &Address, _contract: &service::Service, block: &BlockId) -> Result { + let do_call = |data| client.call_contract(block.clone(), contract_address.clone(), data); + let contract = service::Service::default(); + contract.functions() + .server_key_retrieval_requests_count() + .call(&do_call) + .map_err(|error| format!("{}", error)) + } + + /// Read pending request. + fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, contract: &service::Service, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { + let self_address = public_to_address(self_key_pair.public()); + let do_call = |d| client.call_contract(block.clone(), contract_address.clone(), d); + contract.functions() + .get_server_key_retrieval_request() + .call(index, &do_call) + .map_err(|error| format!("{}", error)) + .and_then(|server_key_id| contract.functions() + .is_server_key_retrieval_response_required() + .call(server_key_id.clone(), self_address, &do_call) + .map(|not_confirmed| ( + not_confirmed, + ServiceTask::RetrieveServerKey( + contract_address.clone(), + server_key_id, + ))) + .map_err(|error| format!("{}", error))) + } +} + +impl DocumentKeyStoreService { + /// Parse request log entry. + pub fn parse_log(origin: &Address, contract: &service::Service, raw_log: RawLog) -> Result { + let event = contract.events().document_key_store_requested(); + match event.parse_log(raw_log) { + Ok(l) => Ok(ServiceTask::StoreDocumentKey(origin.clone(), l.server_key_id, l.author, (*l.common_point).into(), (*l.encrypted_point).into())), + Err(e) => Err(format!("{}", e)), + } + } + + /// Check if response from key server is required. + pub fn is_response_required(client: &Client, contract_address: &Address, contract: &service::Service, server_key_id: &ServerKeyId, key_server: &Address) -> bool { + // we're checking confirmation in Latest block, because we're interested in latest contract state here + let do_call = |data| client.call_contract(BlockId::Latest, *contract_address, data); + contract.functions() + .is_document_key_store_response_required() + .call(*server_key_id, key_server.clone(), &do_call) + .unwrap_or(true) + } + + /// Prepare publish key transaction data. + pub fn prepare_pubish_tx_data(contract: &service::Service, server_key_id: &ServerKeyId) -> Bytes { + contract.functions() + .document_key_stored() + .input(*server_key_id) + } + + /// Prepare error transaction data. + pub fn prepare_error_tx_data(contract: &service::Service, server_key_id: &ServerKeyId) -> Bytes { + contract.functions() + .document_key_store_error() + .input(*server_key_id) + } + + /// Read pending requests count. + fn read_pending_requests_count(client: &Client, contract_address: &Address, _contract: &service::Service, block: &BlockId) -> Result { + let do_call = |data| client.call_contract(block.clone(), contract_address.clone(), data); + let contract = service::Service::default(); + contract.functions() + .document_key_store_requests_count() + .call(&do_call) + .map_err(|error| format!("{}", error)) + } + + /// Read pending request. + fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, contract: &service::Service, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { + let self_address = public_to_address(self_key_pair.public()); + let do_call = |d| client.call_contract(block.clone(), contract_address.clone(), d); + contract.functions() + .get_document_key_store_request() + .call(index, &do_call) + .map_err(|error| format!("{}", error)) + .and_then(|(server_key_id, author, common_point, encrypted_point)| contract.functions() + .is_document_key_store_response_required() + .call(server_key_id.clone(), self_address, &do_call) + .map(|not_confirmed| ( + not_confirmed, + ServiceTask::StoreDocumentKey( + contract_address.clone(), + server_key_id, + author, + Public::from_slice(&common_point), + Public::from_slice(&encrypted_point), + ))) + .map_err(|error| format!("{}", error))) + } +} + +impl DocumentKeyShadowRetrievalService { + /// Parse common request log entry. + pub fn parse_common_request_log(origin: &Address, contract: &service::Service, raw_log: RawLog) -> Result { + let event = contract.events().document_key_common_retrieval_requested(); + match event.parse_log(raw_log) { + Ok(l) => Ok(ServiceTask::RetrieveShadowDocumentKeyCommon(origin.clone(), l.server_key_id, l.requester)), + Err(e) => Err(format!("{}", e)), + } + } + + /// Parse personal request log entry. + pub fn parse_personal_request_log(origin: &Address, contract: &service::Service, raw_log: RawLog) -> Result { + let event = contract.events().document_key_personal_retrieval_requested(); + match event.parse_log(raw_log) { + Ok(l) => Ok(ServiceTask::RetrieveShadowDocumentKeyPersonal(origin.clone(), l.server_key_id, (*l.requester_public).into())), + Err(e) => Err(format!("{}", e)), + } + } + + /// Check if response from key server is required. + pub fn is_response_required(client: &Client, contract_address: &Address, contract: &service::Service, server_key_id: &ServerKeyId, requester: &Address, key_server: &Address) -> bool { + // we're checking confirmation in Latest block, because we're interested in latest contract state here + let do_call = |data| client.call_contract(BlockId::Latest, *contract_address, data); + contract.functions() + .is_document_key_shadow_retrieval_response_required() + .call(*server_key_id, *requester, key_server.clone(), &do_call) + .unwrap_or(true) + } + + /// Prepare publish common key transaction data. + pub fn prepare_pubish_common_tx_data(contract: &service::Service, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: U256) -> Bytes { + contract.functions() + .document_key_common_retrieved() + .input(*server_key_id, *requester, common_point.to_vec(), threshold) + } + + /// Prepare publish personal key transaction data. + pub fn prepare_pubish_personal_tx_data(client: &Client, contract_address: &Address, contract: &service::Service, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result { + let mut participants_mask = U256::default(); + for participant in participants { + let participant_index = Self::map_key_server_address(client, contract_address, contract, participant.clone()) + .map_err(|e| format!("Error searching for {} participant: {}", participant, e))?; + participants_mask = participants_mask | (U256::one() << participant_index.into()); + } + Ok(contract.functions() + .document_key_personal_retrieved() + .input(*server_key_id, *requester, participants_mask, decrypted_secret.to_vec(), shadow)) + } + + /// Prepare error transaction data. + pub fn prepare_error_tx_data(contract: &service::Service, server_key_id: &ServerKeyId, requester: &Address) -> Bytes { + contract.functions() + .document_key_shadow_retrieval_error() + .input(*server_key_id, *requester) + } + + /// Read pending requests count. + fn read_pending_requests_count(client: &Client, contract_address: &Address, _contract: &service::Service, block: &BlockId) -> Result { + let do_call = |data| client.call_contract(block.clone(), contract_address.clone(), data); + let contract = service::Service::default(); + contract.functions() + .document_key_shadow_retrieval_requests_count() + .call(&do_call) + .map_err(|error| format!("{}", error)) + } + + /// Read pending request. + fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, contract: &service::Service, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { + let self_address = public_to_address(self_key_pair.public()); + let do_call = |d| client.call_contract(block.clone(), contract_address.clone(), d); + contract.functions() + .get_document_key_shadow_retrieval_request() + .call(index, &do_call) + .map_err(|error| format!("{}", error)) + .and_then(|(server_key_id, requester, is_common_retrieval_completed)| { + let requester = Public::from_slice(&requester); + contract.functions() + .is_document_key_shadow_retrieval_response_required() + .call(server_key_id.clone(), public_to_address(&requester), self_address, &do_call) + .map(|not_confirmed| ( + not_confirmed, + match is_common_retrieval_completed { + true => ServiceTask::RetrieveShadowDocumentKeyCommon( + contract_address.clone(), + server_key_id, + public_to_address(&requester), + ), + false => ServiceTask::RetrieveShadowDocumentKeyPersonal( + contract_address.clone(), + server_key_id, + requester, + ) + }, + )) + .map_err(|error| format!("{}", error)) + }) + } + + /// Map from key server address to key server index. + fn map_key_server_address(client: &Client, contract_address: &Address, contract: &service::Service, key_server: Address) -> Result { + // we're checking confirmation in Latest block, because tx ,ust be appended to the latest state + let do_call = |data| client.call_contract(BlockId::Latest, *contract_address, data); + contract.functions() + .require_key_server() + .call(key_server, &do_call) + .map_err(|e| format!("{}", e)) + .and_then(|index| if index > ::std::u8::MAX.into() { + Err(format!("key server index is too big: {}", index)) + } else { + let index: u32 = index.into(); + Ok(index as u8) + }) + } +} + +/// Parse threshold (we only supposrt 256 KS at max). +fn parse_threshold(threshold: U256) -> Result { + let threshold_num = threshold.low_u64(); + if threshold != threshold_num.into() || threshold_num >= ::std::u8::MAX as u64 { + return Err(format!("invalid threshold to use in service contract: {}", threshold)); + } + + Ok(threshold_num as usize) +} + +/// Serialize threshold (we only support 256 KS at max). +fn serialize_threshold(threshold: usize) -> Result { + if threshold > ::std::u8::MAX as usize { + return Err(format!("invalid threshold to use in service contract: {}", threshold)); + } + Ok(threshold.into()) +} + #[cfg(test)] pub mod tests { use parking_lot::Mutex; + use bytes::Bytes; use ethkey::Public; - use ethereum_types::H256; + use ethereum_types::Address; use listener::service_contract_listener::ServiceTask; - use ServerKeyId; + use {ServerKeyId}; use super::ServiceContract; #[derive(Default)] pub struct DummyServiceContract { pub is_actual: bool, - pub logs: Vec>, + pub logs: Vec, pub pending_requests: Vec<(bool, ServiceTask)>, - pub published_keys: Mutex>, + pub generated_server_keys: Mutex>, + pub server_keys_generation_failures: Mutex>, + pub retrieved_server_keys: Mutex>, + pub server_keys_retrieval_failures: Mutex>, + pub stored_document_keys: Mutex>, + pub document_keys_store_failures: Mutex>, + pub common_shadow_retrieved_document_keys: Mutex>, + pub personal_shadow_retrieved_document_keys: Mutex, Public, Bytes)>>, + pub document_keys_shadow_retrieval_failures: Mutex>, } impl ServiceContract for DummyServiceContract { @@ -340,7 +833,7 @@ pub mod tests { true } - fn read_logs(&self) -> Box>> { + fn read_logs(&self) -> Box> { Box::new(self.logs.clone().into_iter()) } @@ -348,8 +841,48 @@ pub mod tests { Box::new(self.pending_requests.clone().into_iter()) } - fn publish_server_key(&self, server_key_id: &ServerKeyId, server_key: &Public) -> Result<(), String> { - self.published_keys.lock().push((server_key_id.clone(), server_key.clone())); + fn publish_generated_server_key(&self, _origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String> { + self.generated_server_keys.lock().push((server_key_id.clone(), server_key.clone())); + Ok(()) + } + + fn publish_server_key_generation_error(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.server_keys_generation_failures.lock().push(server_key_id.clone()); + Ok(()) + } + + fn publish_retrieved_server_key(&self, _origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String> { + self.retrieved_server_keys.lock().push((server_key_id.clone(), server_key.clone(), threshold)); + Ok(()) + } + + fn publish_server_key_retrieval_error(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.server_keys_retrieval_failures.lock().push(server_key_id.clone()); + Ok(()) + } + + fn publish_stored_document_key(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.stored_document_keys.lock().push(server_key_id.clone()); + Ok(()) + } + + fn publish_document_key_store_error(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.document_keys_store_failures.lock().push(server_key_id.clone()); + Ok(()) + } + + fn publish_retrieved_document_key_common(&self, _origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String> { + self.common_shadow_retrieved_document_keys.lock().push((server_key_id.clone(), requester.clone(), common_point.clone(), threshold)); + Ok(()) + } + + fn publish_retrieved_document_key_personal(&self, _origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String> { + self.personal_shadow_retrieved_document_keys.lock().push((server_key_id.clone(), requester.clone(), participants.iter().cloned().collect(), decrypted_secret, shadow)); + Ok(()) + } + + fn publish_document_key_retrieval_error(&self, _origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { + self.document_keys_shadow_retrieval_failures.lock().push((server_key_id.clone(), requester.clone())); Ok(()) } } diff --git a/secret_store/src/listener/service_contract_aggregate.rs b/secret_store/src/listener/service_contract_aggregate.rs new file mode 100644 index 0000000000..9ec467fea4 --- /dev/null +++ b/secret_store/src/listener/service_contract_aggregate.rs @@ -0,0 +1,100 @@ +// 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 . + +use std::sync::Arc; +use bytes::Bytes; +use ethereum_types::Address; +use ethkey::Public; +use listener::service_contract::ServiceContract; +use listener::service_contract_listener::ServiceTask; +use {ServerKeyId}; + +/// Aggregated on-chain service contract. +pub struct OnChainServiceContractAggregate { + /// All hosted service contracts. + contracts: Vec>, +} + +impl OnChainServiceContractAggregate { + /// Create new aggregated service contract listener. + pub fn new(contracts: Vec>) -> Self { + debug_assert!(contracts.len() > 1); + OnChainServiceContractAggregate { + contracts: contracts, + } + } +} + +impl ServiceContract for OnChainServiceContractAggregate { + fn update(&self) -> bool { + let mut result = false; + for contract in &self.contracts { + result = contract.update() || result; + } + result + } + + fn read_logs(&self) -> Box> { + self.contracts.iter() + .fold(Box::new(::std::iter::empty()) as Box>, |i, c| + Box::new(i.chain(c.read_logs()))) + } + + fn read_pending_requests(&self) -> Box> { + self.contracts.iter() + .fold(Box::new(::std::iter::empty()) as Box>, |i, c| + Box::new(i.chain(c.read_pending_requests()))) + } + + // in current implementation all publish methods are independent of actual contract adddress + // (tx is sent to origin) => we do not care which contract to use for publish data in methods below + + fn publish_generated_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String> { + self.contracts[0].publish_generated_server_key(origin, server_key_id, server_key) + } + + fn publish_server_key_generation_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.contracts[0].publish_server_key_generation_error(origin, server_key_id) + } + + fn publish_retrieved_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String> { + self.contracts[0].publish_retrieved_server_key(origin, server_key_id, server_key, threshold) + } + + fn publish_server_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.contracts[0].publish_server_key_retrieval_error(origin, server_key_id) + } + + fn publish_stored_document_key(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.contracts[0].publish_stored_document_key(origin, server_key_id) + } + + fn publish_document_key_store_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { + self.contracts[0].publish_document_key_store_error(origin, server_key_id) + } + + fn publish_retrieved_document_key_common(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String> { + self.contracts[0].publish_retrieved_document_key_common(origin, server_key_id, requester, common_point, threshold) + } + + fn publish_retrieved_document_key_personal(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String> { + self.contracts[0].publish_retrieved_document_key_personal(origin, server_key_id, requester, participants, decrypted_secret, shadow) + } + + fn publish_document_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { + self.contracts[0].publish_document_key_retrieval_error(origin, server_key_id, requester) + } +} diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 0d04a7daed..8776dc218e 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -20,16 +20,20 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; use parking_lot::Mutex; use ethcore::client::ChainNotify; -use ethkey::{Random, Generator, Public, sign}; +use ethkey::{Public, public_to_address}; use bytes::Bytes; -use ethereum_types::{H256, U256}; +use ethereum_types::{H256, U256, Address}; use key_server_set::KeyServerSet; use key_server_cluster::{ClusterClient, ClusterSessionsListener, ClusterSession}; +use key_server_cluster::math; use key_server_cluster::generation_session::SessionImpl as GenerationSession; +use key_server_cluster::encryption_session::{check_encrypted_data, update_encrypted_data}; +use key_server_cluster::decryption_session::SessionImpl as DecryptionSession; use key_storage::KeyStorage; +use acl_storage::AclStorage; use listener::service_contract::ServiceContract; use listener::tasks_queue::TasksQueue; -use {ServerKeyId, NodeKeyPair, KeyServer}; +use {ServerKeyId, NodeKeyPair, Error}; /// Retry interval (in blocks). Every RETRY_INTERVAL_BLOCKS blocks each KeyServer reads pending requests from /// service contract && tries to re-execute. The reason to have this mechanism is primarily because keys @@ -56,12 +60,12 @@ pub struct ServiceContractListener { pub struct ServiceContractListenerParams { /// Service contract. pub contract: Arc, - /// Key server reference. - pub key_server: Arc, /// This node key pair. pub self_key_pair: Arc, /// Key servers set. pub key_server_set: Arc, + /// ACL storage reference. + pub acl_storage: Arc, /// Cluster reference. pub cluster: Arc, /// Key storage reference. @@ -78,8 +82,10 @@ struct ServiceContractListenerData { pub tasks_queue: Arc>, /// Service contract. pub contract: Arc, - /// Key server reference. - pub key_server: Arc, + /// ACL storage reference. + pub acl_storage: Arc, + /// Cluster client reference. + pub cluster: Arc, /// This node key pair. pub self_key_pair: Arc, /// Key servers set. @@ -92,8 +98,10 @@ struct ServiceContractListenerData { /// Retry-related data. #[derive(Default)] struct ServiceContractRetryData { - /// Server keys, which we have generated (or tried to generate) since last retry moment. - pub generated_keys: HashSet, + /// Server keys, which we have 'touched' since last retry. + pub affected_server_keys: HashSet, + /// Document keys + requesters, which we have 'touched' since last retry. + pub affected_document_keys: HashSet<(ServerKeyId, Address)>, } /// Service task. @@ -101,23 +109,30 @@ struct ServiceContractRetryData { pub enum ServiceTask { /// Retry all 'stalled' tasks. Retry, - /// Generate server key (server_key_id, threshold). - GenerateServerKey(H256, H256), - /// Confirm server key (server_key_id). - RestoreServerKey(H256), + /// Generate server key (origin, server_key_id, author, threshold). + GenerateServerKey(Address, ServerKeyId, Address, usize), + /// Retrieve server key (origin, server_key_id). + RetrieveServerKey(Address, ServerKeyId), + /// Store document key (origin, server_key_id, author, common_point, encrypted_point). + StoreDocumentKey(Address, ServerKeyId, Address, Public, Public), + /// Retrieve common data of document key (origin, server_key_id, requester). + RetrieveShadowDocumentKeyCommon(Address, ServerKeyId, Address), + /// Retrieve personal data of document key (origin, server_key_id, requester). + RetrieveShadowDocumentKeyPersonal(Address, ServerKeyId, Public), /// Shutdown listener. Shutdown, } impl ServiceContractListener { /// Create new service contract listener. - pub fn new(params: ServiceContractListenerParams) -> Arc { + pub fn new(params: ServiceContractListenerParams) -> Result, Error> { let data = Arc::new(ServiceContractListenerData { last_retry: AtomicUsize::new(0), retry_data: Default::default(), tasks_queue: Arc::new(TasksQueue::new()), contract: params.contract, - key_server: params.key_server, + acl_storage: params.acl_storage, + cluster: params.cluster, self_key_pair: params.self_key_pair, key_server_set: params.key_server_set, key_storage: params.key_storage, @@ -129,39 +144,55 @@ impl ServiceContractListener { None } else { let service_thread_data = data.clone(); - Some(thread::spawn(move || Self::run_service_thread(service_thread_data))) + Some(thread::Builder::new().name("ServiceContractListener".into()).spawn(move || + Self::run_service_thread(service_thread_data)).map_err(|e| Error::Internal(format!("{}", e)))?) }; let contract = Arc::new(ServiceContractListener { data: data, service_handle: service_handle, }); - params.cluster.add_generation_listener(contract.clone()); - contract + contract.data.cluster.add_generation_listener(contract.clone()); + contract.data.cluster.add_decryption_listener(contract.clone()); + Ok(contract) } /// Process incoming events of service contract. fn process_service_contract_events(&self) { self.data.tasks_queue.push_many(self.data.contract.read_logs() - .filter_map(|topics| match topics.len() { - // when key is already generated && we have this key - 3 if self.data.key_storage.get(&topics[1]).map(|k| k.is_some()).unwrap_or_default() => { - Some(ServiceTask::RestoreServerKey( - topics[1], - )) - } - // when key is not yet generated && this node should be master of this key generation session - 3 if is_processed_by_this_key_server(&*self.data.key_server_set, &*self.data.self_key_pair, &topics[1]) => { - Some(ServiceTask::GenerateServerKey( - topics[1], - topics[2], - )) - }, - 3 => None, - l @ _ => { - warn!(target: "secretstore", "Ignoring ServerKeyRequested event with wrong number of params {}", l); - None - }, - })); + .filter_map(|task| Self::filter_task(&self.data, task))); + } + + /// Filter service task. Only returns Some if task must be executed by this server. + fn filter_task(data: &Arc, task: ServiceTask) -> Option { + match task { + // when this node should be master of this server key generation session + ServiceTask::GenerateServerKey(origin, server_key_id, author, threshold) if is_processed_by_this_key_server( + &*data.key_server_set, &*data.self_key_pair, &server_key_id) => + Some(ServiceTask::GenerateServerKey(origin, server_key_id, author, threshold)), + // when server key is not yet generated and generation must be initiated by other node + ServiceTask::GenerateServerKey(_, _, _, _) => None, + + // when server key retrieval is requested + ServiceTask::RetrieveServerKey(origin, server_key_id) => + Some(ServiceTask::RetrieveServerKey(origin, server_key_id)), + + // when document key store is requested + ServiceTask::StoreDocumentKey(origin, server_key_id, author, common_point, encrypted_point) => + Some(ServiceTask::StoreDocumentKey(origin, server_key_id, author, common_point, encrypted_point)), + + // when common document key data retrieval is requested + ServiceTask::RetrieveShadowDocumentKeyCommon(origin, server_key_id, requester) => + Some(ServiceTask::RetrieveShadowDocumentKeyCommon(origin, server_key_id, requester)), + + // when this node should be master of this document key decryption session + ServiceTask::RetrieveShadowDocumentKeyPersonal(origin, server_key_id, requester) if is_processed_by_this_key_server( + &*data.key_server_set, &*data.self_key_pair, &server_key_id) => + Some(ServiceTask::RetrieveShadowDocumentKeyPersonal(origin, server_key_id, requester)), + // when server key is not yet generated and generation must be initiated by other node + ServiceTask::RetrieveShadowDocumentKeyPersonal(_, _, _) => None, + + ServiceTask::Retry | ServiceTask::Shutdown => unreachable!("must be filtered outside"), + } } /// Service thread procedure. @@ -172,18 +203,45 @@ impl ServiceContractListener { match task { ServiceTask::Shutdown => break, - task @ _ => { - // the only possible reaction to an error is a trace && it is already happened + task => { + // the only possible reaction to an error is a tx+trace && it is already happened let _ = Self::process_service_task(&data, task); }, }; } + + trace!(target: "secretstore_net", "{}: ServiceContractListener thread stopped", data.self_key_pair.public()); } /// Process single service task. fn process_service_task(data: &Arc, task: ServiceTask) -> Result<(), String> { - match task { - ServiceTask::Retry => + match &task { + &ServiceTask::GenerateServerKey(origin, server_key_id, author, threshold) => { + data.retry_data.lock().affected_server_keys.insert(server_key_id.clone()); + log_service_task_result(&task, data.self_key_pair.public(), + Self::generate_server_key(&data, origin, &server_key_id, author, threshold)) + }, + &ServiceTask::RetrieveServerKey(origin, server_key_id) => { + data.retry_data.lock().affected_server_keys.insert(server_key_id.clone()); + log_service_task_result(&task, data.self_key_pair.public(), + Self::retrieve_server_key(&data, origin, &server_key_id)) + }, + &ServiceTask::StoreDocumentKey(origin, server_key_id, author, common_point, encrypted_point) => { + data.retry_data.lock().affected_document_keys.insert((server_key_id.clone(), author.clone())); + log_service_task_result(&task, data.self_key_pair.public(), + Self::store_document_key(&data, origin, &server_key_id, &author, &common_point, &encrypted_point)) + }, + &ServiceTask::RetrieveShadowDocumentKeyCommon(origin, server_key_id, requester) => { + data.retry_data.lock().affected_document_keys.insert((server_key_id.clone(), requester.clone())); + log_service_task_result(&task, data.self_key_pair.public(), + Self::retrieve_document_key_common(&data, origin, &server_key_id, &requester)) + }, + &ServiceTask::RetrieveShadowDocumentKeyPersonal(origin, server_key_id, requester) => { + data.retry_data.lock().affected_server_keys.insert(server_key_id.clone()); + log_service_task_result(&task, data.self_key_pair.public(), + Self::retrieve_document_key_personal(&data, origin, &server_key_id, requester)) + }, + &ServiceTask::Retry => { Self::retry_pending_requests(&data) .map(|processed_requests| { if processed_requests != 0 { @@ -196,38 +254,9 @@ impl ServiceContractListener { warn!(target: "secretstore", "{}: retrying pending requests has failed with: {}", data.self_key_pair.public(), error); error - }), - ServiceTask::RestoreServerKey(server_key_id) => { - data.retry_data.lock().generated_keys.insert(server_key_id.clone()); - Self::restore_server_key(&data, &server_key_id) - .and_then(|server_key| Self::publish_server_key(&data, &server_key_id, &server_key)) - .map(|_| { - trace!(target: "secretstore", "{}: processed RestoreServerKey({}) request", - data.self_key_pair.public(), server_key_id); - () - }) - .map_err(|error| { - warn!(target: "secretstore", "{}: failed to process RestoreServerKey({}) request with: {}", - data.self_key_pair.public(), server_key_id, error); - error }) }, - ServiceTask::GenerateServerKey(server_key_id, threshold) => { - data.retry_data.lock().generated_keys.insert(server_key_id.clone()); - Self::generate_server_key(&data, &server_key_id, &threshold) - .and_then(|server_key| Self::publish_server_key(&data, &server_key_id, &server_key)) - .map(|_| { - trace!(target: "secretstore", "{}: processed GenerateServerKey({}, {}) request", - data.self_key_pair.public(), server_key_id, threshold); - () - }) - .map_err(|error| { - warn!(target: "secretstore", "{}: failed to process GenerateServerKey({}, {}) request with: {}", - data.self_key_pair.public(), server_key_id, threshold, error); - error - }) - }, - ServiceTask::Shutdown => unreachable!("it must be checked outside"), + &ServiceTask::Shutdown => unreachable!("must be filtered outside"), } } @@ -236,32 +265,28 @@ impl ServiceContractListener { let mut failed_requests = 0; let mut processed_requests = 0; let retry_data = ::std::mem::replace(&mut *data.retry_data.lock(), Default::default()); - for (is_confirmed, task) in data.contract.read_pending_requests() { + let pending_tasks = data.contract.read_pending_requests() + .filter_map(|(is_confirmed, task)| Self::filter_task(data, task) + .map(|t| (is_confirmed, t))); + for (is_confirmed, task) in pending_tasks { // only process requests, which we haven't confirmed yet if is_confirmed { continue; } - let request_result = match task { - ServiceTask::GenerateServerKey(server_key_id, threshold) => { - // only process request, which haven't been processed recently - // there could be a lag when we've just generated server key && retrying on the same block - // (or before our tx is mined) - state is not updated yet - if retry_data.generated_keys.contains(&server_key_id) { - continue; - } - - // process request - let is_own_request = is_processed_by_this_key_server(&*data.key_server_set, &*data.self_key_pair, &server_key_id); - Self::process_service_task(data, match is_own_request { - true => ServiceTask::GenerateServerKey(server_key_id, threshold.into()), - false => ServiceTask::RestoreServerKey(server_key_id), - }) - }, - _ => Err("not supported".into()), - }; + match task { + ServiceTask::GenerateServerKey(_, ref key, _, _) | ServiceTask::RetrieveServerKey(_, ref key) + if retry_data.affected_server_keys.contains(key) => continue, + ServiceTask::StoreDocumentKey(_, ref key, ref author, _, _) | + ServiceTask::RetrieveShadowDocumentKeyCommon(_, ref key, ref author) + if retry_data.affected_document_keys.contains(&(key.clone(), author.clone())) => continue, + ServiceTask::RetrieveShadowDocumentKeyPersonal(_, ref key, ref requester) + if retry_data.affected_document_keys.contains(&(key.clone(), public_to_address(requester))) => continue, + _ => (), + } // process request result + let request_result = Self::process_service_task(data, task); match request_result { Ok(_) => processed_requests += 1, Err(_) => { @@ -276,33 +301,119 @@ impl ServiceContractListener { Ok(processed_requests) } - /// Generate server key. - fn generate_server_key(data: &Arc, server_key_id: &ServerKeyId, threshold: &H256) -> Result { - let threshold_num = threshold.low_u64(); - if threshold != &threshold_num.into() || threshold_num >= ::std::usize::MAX as u64 { - return Err(format!("invalid threshold {:?}", threshold)); + /// Generate server key (start generation session). + fn generate_server_key(data: &Arc, origin: Address, server_key_id: &ServerKeyId, author: Address, threshold: usize) -> Result<(), String> { + Self::process_server_key_generation_result(data, origin, server_key_id, data.cluster.new_generation_session( + server_key_id.clone(), Some(origin), author, threshold).map(|_| None).map_err(Into::into)) + } + + /// Process server key generation result. + fn process_server_key_generation_result(data: &Arc, origin: Address, server_key_id: &ServerKeyId, result: Result, Error>) -> Result<(), String> { + match result { + Ok(None) => Ok(()), + Ok(Some(server_key)) => { + data.contract.publish_generated_server_key(&origin, server_key_id, server_key) + }, + Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) => { + // ignore error as we're already processing an error + let _ = data.contract.publish_server_key_generation_error(&origin, server_key_id) + .map_err(|error| warn!(target: "secretstore", "{}: failed to publish GenerateServerKey({}) error: {}", + data.self_key_pair.public(), server_key_id, error)); + Err(format!("{}", error)) + } } + } - // key server expects signed server_key_id in server_key_generation procedure - // only signer could store document key for this server key later - // => this API (server key generation) is not suitable for usage in encryption via contract endpoint - let author_key = Random.generate().map_err(|e| format!("{}", e))?; - let server_key_id_signature = sign(author_key.secret(), server_key_id).map_err(|e| format!("{}", e))?; - data.key_server.generate_key(server_key_id, &server_key_id_signature, threshold_num as usize) - .map_err(Into::into) + /// Retrieve server key. + fn retrieve_server_key(data: &Arc, origin: Address, server_key_id: &ServerKeyId) -> Result<(), String> { + match data.key_storage.get(server_key_id) { + Ok(Some(server_key_share)) => { + data.contract.publish_retrieved_server_key(&origin, server_key_id, server_key_share.public, server_key_share.threshold) + }, + Ok(None) => { + data.contract.publish_server_key_retrieval_error(&origin, server_key_id) + } + Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) => { + // ignore error as we're already processing an error + let _ = data.contract.publish_server_key_retrieval_error(&origin, server_key_id) + .map_err(|error| warn!(target: "secretstore", "{}: failed to publish RetrieveServerKey({}) error: {}", + data.self_key_pair.public(), server_key_id, error)); + Err(format!("{}", error)) + } + } + } + + /// Store document key. + fn store_document_key(data: &Arc, origin: Address, server_key_id: &ServerKeyId, author: &Address, common_point: &Public, encrypted_point: &Public) -> Result<(), String> { + let store_result = data.key_storage.get(server_key_id) + .and_then(|key_share| key_share.ok_or(Error::DocumentNotFound)) + .and_then(|key_share| check_encrypted_data(Some(&key_share)).map(|_| key_share).map_err(Into::into)) + .and_then(|key_share| update_encrypted_data(&data.key_storage, server_key_id.clone(), key_share, + author.clone(), common_point.clone(), encrypted_point.clone()).map_err(Into::into)); + match store_result { + Ok(()) => { + data.contract.publish_stored_document_key(&origin, server_key_id) + }, + Err(ref error) if is_internal_error(&error) => Err(format!("{}", error)), + Err(ref error) => { + // ignore error as we're already processing an error + let _ = data.contract.publish_document_key_store_error(&origin, server_key_id) + .map_err(|error| warn!(target: "secretstore", "{}: failed to publish StoreDocumentKey({}) error: {}", + data.self_key_pair.public(), server_key_id, error)); + Err(format!("{}", error)) + }, + } } - /// Restore server key. - fn restore_server_key(data: &Arc, server_key_id: &ServerKeyId) -> Result { - data.key_storage.get(server_key_id) - .map_err(|e| format!("{}", e)) - .and_then(|ks| ks.ok_or("missing key".to_owned())) - .map(|ks| ks.public) + /// Retrieve common part of document key. + fn retrieve_document_key_common(data: &Arc, origin: Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { + let retrieval_result = data.acl_storage.check(requester.clone(), server_key_id) + .and_then(|is_allowed| if !is_allowed { Err(Error::AccessDenied) } else { Ok(()) }) + .and_then(|_| data.key_storage.get(server_key_id).and_then(|key_share| key_share.ok_or(Error::DocumentNotFound))) + .and_then(|key_share| key_share.common_point + .ok_or(Error::DocumentNotFound) + .and_then(|common_point| math::make_common_shadow_point(key_share.threshold, common_point) + .map_err(|e| Error::Internal(e.into()))) + .map(|common_point| (common_point, key_share.threshold))); + match retrieval_result { + Ok((common_point, threshold)) => { + data.contract.publish_retrieved_document_key_common(&origin, server_key_id, requester, common_point, threshold) + }, + Err(ref error) if is_internal_error(&error) => Err(format!("{}", error)), + Err(ref error) => { + // ignore error as we're already processing an error + let _ = data.contract.publish_document_key_retrieval_error(&origin, server_key_id, requester) + .map_err(|error| warn!(target: "secretstore", "{}: failed to publish RetrieveDocumentKey({}) error: {}", + data.self_key_pair.public(), server_key_id, error)); + Err(format!("{}", error)) + }, + } } - /// Publish server key. - fn publish_server_key(data: &Arc, server_key_id: &ServerKeyId, server_key: &Public) -> Result<(), String> { - data.contract.publish_server_key(server_key_id, server_key) + /// Retrieve personal part of document key (start decryption session). + fn retrieve_document_key_personal(data: &Arc, origin: Address, server_key_id: &ServerKeyId, requester: Public) -> Result<(), String> { + Self::process_document_key_retrieval_result(data, origin, server_key_id, &public_to_address(&requester), data.cluster.new_decryption_session( + server_key_id.clone(), Some(origin), requester.clone().into(), None, true, true).map(|_| None).map_err(Into::into)) + } + + /// Process document key retrieval result. + fn process_document_key_retrieval_result(data: &Arc, origin: Address, server_key_id: &ServerKeyId, requester: &Address, result: Result, Public, Bytes)>, Error>) -> Result<(), String> { + match result { + Ok(None) => Ok(()), + Ok(Some((participants, decrypted_secret, shadow))) => { + data.contract.publish_retrieved_document_key_personal(&origin, server_key_id, &requester, &participants, decrypted_secret, shadow) + }, + Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) => { + // ignore error as we're already processing an error + let _ = data.contract.publish_document_key_retrieval_error(&origin, server_key_id, &requester) + .map_err(|error| warn!(target: "secretstore", "{}: failed to publish RetrieveDocumentKey({}) error: {}", + data.self_key_pair.public(), server_key_id, error)); + Err(format!("{}", error)) + } + } } } @@ -340,25 +451,84 @@ impl ChainNotify for ServiceContractListener { impl ClusterSessionsListener for ServiceContractListener { fn on_session_removed(&self, session: Arc) { - // only publish when the session is started by another node - // when it is started by this node, it is published from process_service_task - if !is_processed_by_this_key_server(&*self.data.key_server_set, &*self.data.self_key_pair, &session.id()) { - // by this time sesion must already be completed - either successfully, or not - assert!(session.is_finished()); - - // ignore result - the only thing that we can do is to log the error - match session.wait(Some(Default::default())) - .map_err(|e| format!("{}", e)) - .and_then(|server_key| Self::publish_server_key(&self.data, &session.id(), &server_key)) { - Ok(_) => trace!(target: "secretstore", "{}: completed foreign GenerateServerKey({}) request", - self.data.self_key_pair.public(), session.id()), - Err(error) => warn!(target: "secretstore", "{}: failed to process GenerateServerKey({}) request with: {}", - self.data.self_key_pair.public(), session.id(), error), + // by this time sesion must already be completed - either successfully, or not + assert!(session.is_finished()); + + // ignore result - the only thing that we can do is to log the error + let server_key_id = session.id(); + if let Some(origin) = session.origin() { + if let Some(generation_result) = session.wait(Some(Default::default())) { + let generation_result = generation_result.map(Some).map_err(Into::into); + let _ = Self::process_server_key_generation_result(&self.data, origin, &server_key_id, generation_result); + } + } + } +} + +impl ClusterSessionsListener for ServiceContractListener { + fn on_session_removed(&self, session: Arc) { + // by this time sesion must already be completed - either successfully, or not + assert!(session.is_finished()); + + // ignore result - the only thing that we can do is to log the error + let session_id = session.id(); + let server_key_id = session_id.id; + if let (Some(requester), Some(origin)) = (session.requester().and_then(|r| r.address(&server_key_id).ok()), session.origin()) { + if let Some(retrieval_result) = session.wait(Some(Default::default())) { + let retrieval_result = retrieval_result.map(|key_shadow| + session.broadcast_shadows() + .and_then(|broadcast_shadows| + broadcast_shadows.get(self.data.self_key_pair.public()) + .map(|self_shadow| ( + broadcast_shadows.keys().map(public_to_address).collect(), + key_shadow.decrypted_secret, + self_shadow.clone() + ))) + ).map_err(Into::into); + let _ = Self::process_document_key_retrieval_result(&self.data, origin, &server_key_id, &requester, retrieval_result); } } } } +impl ::std::fmt::Display for ServiceTask { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match *self { + ServiceTask::Retry => write!(f, "Retry"), + ServiceTask::GenerateServerKey(_, ref server_key_id, ref author, ref threshold) => + write!(f, "GenerateServerKey({}, {}, {})", server_key_id, author, threshold), + ServiceTask::RetrieveServerKey(_, ref server_key_id) => + write!(f, "RetrieveServerKey({})", server_key_id), + ServiceTask::StoreDocumentKey(_, ref server_key_id, ref author, _, _) => + write!(f, "StoreDocumentKey({}, {})", server_key_id, author), + ServiceTask::RetrieveShadowDocumentKeyCommon(_, ref server_key_id, ref requester) => + write!(f, "RetrieveShadowDocumentKeyCommon({}, {})", server_key_id, requester), + ServiceTask::RetrieveShadowDocumentKeyPersonal(_, ref server_key_id, ref requester) => + write!(f, "RetrieveShadowDocumentKeyPersonal({}, {})", server_key_id, public_to_address(requester)), + ServiceTask::Shutdown => write!(f, "Shutdown"), + } + } +} + +/// Is internal error? Internal error means that it is SS who's responsible for it, like: connectivity, db failure, ... +/// External error is caused by SS misuse, like: trying to generate duplicated key, access denied, ... +/// When internal error occurs, we just ignore request for now and will retry later. +/// When external error occurs, we reject request. +fn is_internal_error(_error: &Error) -> bool { + // TODO [Reliability]: implement me after proper is passed through network + false +} + +/// Log service task result. +fn log_service_task_result(task: &ServiceTask, self_id: &Public, result: Result<(), String>) -> Result<(), String> { + match result { + Ok(_) => trace!(target: "secretstore", "{}: processed {} request", self_id, task), + Err(ref error) => warn!(target: "secretstore", "{}: failed to process {} request with: {}", self_id, task, error), + } + + result +} + /// Returns true when session, related to `server_key_id` must be started on this KeyServer. fn is_processed_by_this_key_server(key_server_set: &KeyServerSet, self_key_pair: &NodeKeyPair, server_key_id: &H256) -> bool { let servers = key_server_set.snapshot().current_set; @@ -390,17 +560,31 @@ mod tests { use listener::service_contract::ServiceContract; use listener::service_contract::tests::DummyServiceContract; use key_server_cluster::DummyClusterClient; - use key_server::tests::DummyKeyServer; + use acl_storage::{AclStorage, DummyAclStorage}; use key_storage::{KeyStorage, DocumentKeyShare}; use key_storage::tests::DummyKeyStorage; use key_server_set::tests::MapKeyServerSet; - use PlainNodeKeyPair; + use {PlainNodeKeyPair, ServerKeyId}; use super::{ServiceTask, ServiceContractListener, ServiceContractListenerParams, is_processed_by_this_key_server}; - fn make_service_contract_listener(contract: Option>, key_server: Option>, key_storage: Option>) -> Arc { + fn create_non_empty_key_storage(has_doc_key: bool) -> Arc { + let key_storage = Arc::new(DummyKeyStorage::default()); + let mut key_share = DocumentKeyShare::default(); + key_share.public = KeyPair::from_secret("0000000000000000000000000000000000000000000000000000000000000001" + .parse().unwrap()).unwrap().public().clone(); + if has_doc_key { + key_share.common_point = Some(Default::default()); + key_share.encrypted_point = Some(Default::default()); + } + key_storage.insert(Default::default(), key_share.clone()).unwrap(); + key_storage + } + + fn make_service_contract_listener(contract: Option>, cluster: Option>, key_storage: Option>, acl_storage: Option>) -> Arc { let contract = contract.unwrap_or_else(|| Arc::new(DummyServiceContract::default())); - let key_server = key_server.unwrap_or_else(|| Arc::new(DummyKeyServer::default())); + let cluster = cluster.unwrap_or_else(|| Arc::new(DummyClusterClient::default())); let key_storage = key_storage.unwrap_or_else(|| Arc::new(DummyKeyStorage::default())); + let acl_storage = acl_storage.unwrap_or_else(|| Arc::new(DummyAclStorage::default())); let servers_set = Arc::new(MapKeyServerSet::new(vec![ ("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8".parse().unwrap(), "127.0.0.1:8080".parse().unwrap()), @@ -412,12 +596,12 @@ mod tests { let self_key_pair = Arc::new(PlainNodeKeyPair::new(KeyPair::from_secret("0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap()).unwrap())); ServiceContractListener::new(ServiceContractListenerParams { contract: contract, - key_server: key_server, self_key_pair: self_key_pair, key_server_set: servers_set, - cluster: Arc::new(DummyClusterClient::default()), + acl_storage: acl_storage, + cluster: cluster, key_storage: key_storage, - }) + }).unwrap() } #[test] @@ -576,84 +760,254 @@ mod tests { #[test] fn no_tasks_scheduled_when_no_contract_events() { - let listener = make_service_contract_listener(None, None, None); + let listener = make_service_contract_listener(None, None, None, None); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); listener.process_service_contract_events(); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); } + // server key generation tests + #[test] - fn server_key_generation_is_scheduled_when_requested_key_is_unknown() { + fn server_key_generation_is_scheduled_when_requested() { let mut contract = DummyServiceContract::default(); - contract.logs.push(vec![Default::default(), Default::default(), Default::default()]); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None); + contract.logs.push(ServiceTask::GenerateServerKey(Default::default(), Default::default(), Default::default(), 0)); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); listener.process_service_contract_events(); assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); - assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::GenerateServerKey(Default::default(), Default::default()))); + assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::GenerateServerKey( + Default::default(), Default::default(), Default::default(), 0))); } #[test] - fn no_new_tasks_scheduled_when_requested_key_is_unknown_and_request_belongs_to_other_key_server() { + fn no_new_tasks_scheduled_when_server_key_generation_requested_and_request_belongs_to_other_key_server() { let server_key_id = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap(); let mut contract = DummyServiceContract::default(); - contract.logs.push(vec![Default::default(), server_key_id, Default::default()]); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None); + contract.logs.push(ServiceTask::GenerateServerKey(Default::default(), server_key_id, Default::default(), 0)); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); listener.process_service_contract_events(); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); } #[test] - fn server_key_restore_is_scheduled_when_requested_key_is_known() { + fn generation_session_is_created_when_processing_generate_server_key_task() { + let cluster = Arc::new(DummyClusterClient::default()); + let listener = make_service_contract_listener(None, Some(cluster.clone()), None, None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::GenerateServerKey( + Default::default(), Default::default(), Default::default(), Default::default())).unwrap_err(); + assert_eq!(cluster.generation_requests_count.load(Ordering::Relaxed), 1); + } + + #[test] + fn server_key_generation_is_not_retried_if_tried_in_the_same_cycle() { + let mut contract = DummyServiceContract::default(); + contract.pending_requests.push((false, ServiceTask::GenerateServerKey(Default::default(), + Default::default(), Default::default(), Default::default()))); + let cluster = Arc::new(DummyClusterClient::default()); + let listener = make_service_contract_listener(Some(Arc::new(contract)), Some(cluster.clone()), None, None); + listener.data.retry_data.lock().affected_server_keys.insert(Default::default()); + ServiceContractListener::retry_pending_requests(&listener.data).unwrap(); + assert_eq!(cluster.generation_requests_count.load(Ordering::Relaxed), 0); + } + + // server key retrieval tests + + #[test] + fn server_key_retrieval_is_scheduled_when_requested() { + let mut contract = DummyServiceContract::default(); + contract.logs.push(ServiceTask::RetrieveServerKey(Default::default(), Default::default())); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + listener.process_service_contract_events(); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveServerKey( + Default::default(), Default::default()))); + } + + #[test] + fn server_key_retrieval_is_scheduled_when_requested_and_request_belongs_to_other_key_server() { + let server_key_id: ServerKeyId = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap(); let mut contract = DummyServiceContract::default(); - contract.logs.push(vec![Default::default(), Default::default(), Default::default()]); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None); - listener.data.key_storage.insert(Default::default(), Default::default()).unwrap(); + contract.logs.push(ServiceTask::RetrieveServerKey(Default::default(), server_key_id.clone())); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); listener.process_service_contract_events(); assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); - assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RestoreServerKey(Default::default()))); + assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveServerKey( + Default::default(), server_key_id))); } #[test] - fn no_new_tasks_scheduled_when_wrong_number_of_topics_in_log() { + fn server_key_is_retrieved_when_processing_retrieve_server_key_task() { + let contract = Arc::new(DummyServiceContract::default()); + let key_storage = create_non_empty_key_storage(false); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveServerKey( + Default::default(), Default::default())).unwrap(); + assert_eq!(*contract.retrieved_server_keys.lock(), vec![(Default::default(), + KeyPair::from_secret("0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap()).unwrap().public().clone(), 0)]); + } + + #[test] + fn server_key_retrieval_failure_is_reported_when_processing_retrieve_server_key_task_and_key_is_unknown() { + let contract = Arc::new(DummyServiceContract::default()); + let listener = make_service_contract_listener(Some(contract.clone()), None, None, None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveServerKey( + Default::default(), Default::default())).unwrap(); + assert_eq!(*contract.server_keys_retrieval_failures.lock(), vec![Default::default()]); + } + + #[test] + fn server_key_retrieval_is_not_retried_if_tried_in_the_same_cycle() { + let mut contract = DummyServiceContract::default(); + contract.pending_requests.push((false, ServiceTask::RetrieveServerKey(Default::default(), Default::default()))); + let cluster = Arc::new(DummyClusterClient::default()); + let listener = make_service_contract_listener(Some(Arc::new(contract)), Some(cluster.clone()), None, None); + listener.data.retry_data.lock().affected_server_keys.insert(Default::default()); + ServiceContractListener::retry_pending_requests(&listener.data).unwrap(); + assert_eq!(cluster.generation_requests_count.load(Ordering::Relaxed), 0); + } + + // document key store tests + + #[test] + fn document_key_store_is_scheduled_when_requested() { let mut contract = DummyServiceContract::default(); - contract.logs.push(vec![Default::default(), Default::default()]); - let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None); + contract.logs.push(ServiceTask::StoreDocumentKey(Default::default(), Default::default(), + Default::default(), Default::default(), Default::default())); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); listener.process_service_contract_events(); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::StoreDocumentKey( + Default::default(), Default::default(), Default::default(), Default::default(), Default::default()))); + } + + #[test] + fn document_key_store_is_scheduled_when_requested_and_request_belongs_to_other_key_server() { + let server_key_id: ServerKeyId = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap(); + let mut contract = DummyServiceContract::default(); + contract.logs.push(ServiceTask::StoreDocumentKey(Default::default(), server_key_id.clone(), + Default::default(), Default::default(), Default::default())); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + listener.process_service_contract_events(); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::StoreDocumentKey( + Default::default(), server_key_id, Default::default(), Default::default(), Default::default()))); } #[test] - fn generation_session_is_created_when_processing_generate_server_key_task() { - let key_server = Arc::new(DummyKeyServer::default()); - let listener = make_service_contract_listener(None, Some(key_server.clone()), None); - ServiceContractListener::process_service_task(&listener.data, ServiceTask::GenerateServerKey(Default::default(), Default::default())).unwrap_err(); - assert_eq!(key_server.generation_requests_count.load(Ordering::Relaxed), 1); + fn document_key_is_stored_when_processing_store_document_key_task() { + let contract = Arc::new(DummyServiceContract::default()); + let key_storage = create_non_empty_key_storage(false); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( + Default::default(), Default::default(), Default::default(), Default::default(), Default::default())).unwrap(); + assert_eq!(*contract.stored_document_keys.lock(), vec![Default::default()]); + + let key_share = key_storage.get(&Default::default()).unwrap().unwrap(); + assert_eq!(key_share.common_point, Some(Default::default())); + assert_eq!(key_share.encrypted_point, Some(Default::default())); } #[test] - fn key_is_read_and_published_when_processing_restore_server_key_task() { + fn document_key_store_failure_reported_when_no_server_key() { let contract = Arc::new(DummyServiceContract::default()); - let key_storage = Arc::new(DummyKeyStorage::default()); - let mut key_share = DocumentKeyShare::default(); - key_share.public = KeyPair::from_secret("0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap()).unwrap().public().clone(); - key_storage.insert(Default::default(), key_share.clone()).unwrap(); - let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage)); - ServiceContractListener::process_service_task(&listener.data, ServiceTask::RestoreServerKey(Default::default())).unwrap(); - assert_eq!(*contract.published_keys.lock(), vec![(Default::default(), key_share.public)]); + let listener = make_service_contract_listener(Some(contract.clone()), None, None, None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( + Default::default(), Default::default(), Default::default(), Default::default(), Default::default())).unwrap_err(); + assert_eq!(*contract.document_keys_store_failures.lock(), vec![Default::default()]); + } + + #[test] + fn document_key_store_failure_reported_when_document_key_already_set() { + let contract = Arc::new(DummyServiceContract::default()); + let key_storage = create_non_empty_key_storage(true); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( + Default::default(), Default::default(), Default::default(), Default::default(), Default::default())).unwrap_err(); + assert_eq!(*contract.document_keys_store_failures.lock(), vec![Default::default()]); } #[test] - fn generation_is_not_retried_if_tried_in_the_same_cycle() { + fn document_key_store_failure_reported_when_author_differs() { + let contract = Arc::new(DummyServiceContract::default()); + let key_storage = create_non_empty_key_storage(false); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage), None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::StoreDocumentKey( + Default::default(), Default::default(), 1.into(), Default::default(), Default::default())).unwrap_err(); + assert_eq!(*contract.document_keys_store_failures.lock(), vec![Default::default()]); + } + + // document key shadow common retrieval tests + + #[test] + fn document_key_shadow_common_retrieval_is_scheduled_when_requested() { let mut contract = DummyServiceContract::default(); - contract.pending_requests.push((false, ServiceTask::GenerateServerKey(Default::default(), Default::default()))); - let key_server = Arc::new(DummyKeyServer::default()); - let listener = make_service_contract_listener(Some(Arc::new(contract)), Some(key_server.clone()), None); - listener.data.retry_data.lock().generated_keys.insert(Default::default()); - ServiceContractListener::retry_pending_requests(&listener.data).unwrap(); - assert_eq!(key_server.generation_requests_count.load(Ordering::Relaxed), 0); + contract.logs.push(ServiceTask::RetrieveShadowDocumentKeyCommon(Default::default(), Default::default(), Default::default())); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + listener.process_service_contract_events(); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveShadowDocumentKeyCommon( + Default::default(), Default::default(), Default::default()))); + } + + #[test] + fn document_key_shadow_common_retrieval_is_scheduled_when_requested_and_request_belongs_to_other_key_server() { + let server_key_id: ServerKeyId = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse().unwrap(); + let mut contract = DummyServiceContract::default(); + contract.logs.push(ServiceTask::RetrieveShadowDocumentKeyCommon(Default::default(), server_key_id.clone(), Default::default())); + let listener = make_service_contract_listener(Some(Arc::new(contract)), None, None, None); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 1); + listener.process_service_contract_events(); + assert_eq!(listener.data.tasks_queue.snapshot().len(), 2); + assert_eq!(listener.data.tasks_queue.snapshot().pop_back(), Some(ServiceTask::RetrieveShadowDocumentKeyCommon( + Default::default(), server_key_id, Default::default()))); + } + + #[test] + fn document_key_shadow_common_is_retrieved_when_processing_document_key_shadow_common_retrieval_task() { + let contract = Arc::new(DummyServiceContract::default()); + let key_storage = create_non_empty_key_storage(true); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( + Default::default(), Default::default(), Default::default())).unwrap(); + assert_eq!(*contract.common_shadow_retrieved_document_keys.lock(), vec![(Default::default(), Default::default(), + Default::default(), 0)]); + } + + #[test] + fn document_key_shadow_common_retrieval_failure_reported_when_access_denied() { + let acl_storage = DummyAclStorage::default(); + acl_storage.prohibit(Default::default(), Default::default()); + let contract = Arc::new(DummyServiceContract::default()); + let key_storage = create_non_empty_key_storage(true); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), Some(Arc::new(acl_storage))); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( + Default::default(), Default::default(), Default::default())).unwrap_err(); + assert_eq!(*contract.document_keys_shadow_retrieval_failures.lock(), vec![(Default::default(), Default::default())]); + } + + #[test] + fn document_key_shadow_common_retrieval_failure_reported_when_no_server_key() { + let contract = Arc::new(DummyServiceContract::default()); + let listener = make_service_contract_listener(Some(contract.clone()), None, None, None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( + Default::default(), Default::default(), Default::default())).unwrap_err(); + assert_eq!(*contract.document_keys_shadow_retrieval_failures.lock(), vec![(Default::default(), Default::default())]); + } + + #[test] + fn document_key_shadow_common_retrieval_failure_reported_when_no_document_key() { + let contract = Arc::new(DummyServiceContract::default()); + let key_storage = create_non_empty_key_storage(false); + let listener = make_service_contract_listener(Some(contract.clone()), None, Some(key_storage.clone()), None); + ServiceContractListener::process_service_task(&listener.data, ServiceTask::RetrieveShadowDocumentKeyCommon( + Default::default(), Default::default(), Default::default())).unwrap_err(); + assert_eq!(*contract.document_keys_shadow_retrieval_failures.lock(), vec![(Default::default(), Default::default())]); } } diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs index d486cfb10e..ea09a3d906 100644 --- a/secret_store/src/traits.rs +++ b/secret_store/src/traits.rs @@ -17,8 +17,8 @@ use std::collections::BTreeSet; use ethkey::{KeyPair, Signature, Error as EthKeyError}; use ethereum_types::{H256, Address}; -use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, EncryptedDocumentKey, - EncryptedDocumentKeyShadow, NodeId}; +use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, Requester, + EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId}; /// Node key pair. pub trait NodeKeyPair: Send + Sync { @@ -36,34 +36,34 @@ pub trait NodeKeyPair: Send + Sync { pub trait ServerKeyGenerator { /// Generate new SK. /// `key_id` is the caller-provided identifier of generated SK. - /// `signature` is `key_id`, signed with caller public key. + /// `author` is the author of key entry. /// `threshold + 1` is the minimal number of nodes, required to restore private key. /// Result is a public portion of SK. - fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result; + fn generate_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result; } /// Document key (DK) server. pub trait DocumentKeyServer: ServerKeyGenerator { /// Store externally generated DK. /// `key_id` is identifier of previously generated SK. - /// `signature` is key_id, signed with caller public key. Caller must be the same as in the `generate_key` call. + /// `author` is the same author, that has created the server key. /// `common_point` is a result of `k * T` expression, where `T` is generation point and `k` is random scalar in EC field. /// `encrypted_document_key` is a result of `M + k * y` expression, where `M` is unencrypted document key (point on EC), /// `k` is the same scalar used in `common_point` calculation and `y` is previously generated public part of SK. - fn store_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, common_point: Public, encrypted_document_key: Public) -> Result<(), Error>; + fn store_document_key(&self, key_id: &ServerKeyId, author: &Requester, common_point: Public, encrypted_document_key: Public) -> Result<(), Error>; /// Generate and store both SK and DK. This is a shortcut for consequent calls of `generate_key` and `store_document_key`. /// The only difference is that DK is generated by DocumentKeyServer (which might be considered unsafe). /// `key_id` is the caller-provided identifier of generated SK. - /// `signature` is `key_id`, signed with caller public key. + /// `author` is the author of server && document key entry. /// `threshold + 1` is the minimal number of nodes, required to restore private key. /// Result is a DK, encrypted with caller public key. - fn generate_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result; + fn generate_document_key(&self, key_id: &ServerKeyId, author: &Requester, threshold: usize) -> Result; /// Restore previously stored DK. /// DK is decrypted on the key server (which might be considered unsafe), and then encrypted with caller public key. /// `key_id` is identifier of previously generated SK. - /// `signature` is key_id, signed with caller public key. Caller must be on ACL for this function to succeed. + /// `requester` is the one who requests access to document key. Caller must be on ACL for this function to succeed. /// Result is a DK, encrypted with caller public key. - fn restore_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result; + fn restore_document_key(&self, key_id: &ServerKeyId, requester: &Requester) -> Result; /// Restore previously stored DK. /// To decrypt DK on client: /// 1) use requestor secret key to decrypt secret coefficients from result.decrypt_shadows @@ -71,24 +71,24 @@ pub trait DocumentKeyServer: ServerKeyGenerator { /// 3) calculate decrypt_shadow_point: decrypt_shadows_sum * result.common_point /// 4) calculate decrypted_secret: result.decrypted_secret + decrypt_shadow_point /// Result is a DK shadow. - fn restore_document_key_shadow(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result; + fn restore_document_key_shadow(&self, key_id: &ServerKeyId, requester: &Requester) -> Result; } /// Message signer. pub trait MessageSigner: ServerKeyGenerator { /// Generate Schnorr signature for message with previously generated SK. /// `key_id` is the caller-provided identifier of generated SK. - /// `signature` is `key_id`, signed with caller public key. + /// `requester` is the one who requests access to server key private. /// `message` is the message to be signed. /// Result is a signed message, encrypted with caller public key. - fn sign_message_schnorr(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result; + fn sign_message_schnorr(&self, key_id: &ServerKeyId, requester: &Requester, message: MessageHash) -> Result; /// Generate ECDSA signature for message with previously generated SK. /// WARNING: only possible when SK was generated using t <= 2 * N. /// `key_id` is the caller-provided identifier of generated SK. /// `signature` is `key_id`, signed with caller public key. /// `message` is the message to be signed. /// Result is a signed message, encrypted with caller public key. - fn sign_message_ecdsa(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result; + fn sign_message_ecdsa(&self, key_id: &ServerKeyId, signature: &Requester, message: MessageHash) -> Result; } /// Administrative sessions server. diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index 9c6f4d1721..356f1f1f00 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -38,8 +38,8 @@ pub use ethkey::Public; /// Secret store error #[derive(Debug, PartialEq)] pub enum Error { - /// Bad signature is passed - BadSignature, + /// Insufficient requester data + InsufficientRequesterData(String), /// Access to resource is denied AccessDenied, /// Requested document not found @@ -77,8 +77,16 @@ pub enum ContractAddress { pub struct ServiceConfiguration { /// HTTP listener address. If None, HTTP API is disabled. pub listener_address: Option, - /// Service contract address. If None, service contract API is disabled. + /// Service contract address. pub service_contract_address: Option, + /// Server key generation service contract address. + pub service_contract_srv_gen_address: Option, + /// Server key retrieval service contract address. + pub service_contract_srv_retr_address: Option, + /// Document key store service contract address. + pub service_contract_doc_store_address: Option, + /// Document key shadow retrieval service contract address. + pub service_contract_doc_sretr_address: Option, /// Is ACL check enabled. If false, everyone has access to all keys. Useful for tests only. pub acl_check_enabled: bool, /// Data directory path for secret store @@ -131,7 +139,7 @@ pub enum Requester { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { - Error::BadSignature => write!(f, "Bad signature"), + Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), Error::AccessDenied => write!(f, "Access dened"), Error::DocumentNotFound => write!(f, "Document not found"), Error::Hyper(ref msg) => write!(f, "Hyper error: {}", msg), @@ -163,6 +171,8 @@ impl From for Error { impl From for Error { fn from(err: key_server_cluster::Error) -> Self { match err { + key_server_cluster::Error::InsufficientRequesterData(err) + => Error::InsufficientRequesterData(err), key_server_cluster::Error::ConsensusUnreachable | key_server_cluster::Error::AccessDenied => Error::AccessDenied, key_server_cluster::Error::MissingKeyShare => Error::DocumentNotFound, @@ -184,16 +194,18 @@ impl Default for Requester { } impl Requester { - pub fn public(&self, server_key_id: &ServerKeyId) -> Option { + pub fn public(&self, server_key_id: &ServerKeyId) -> Result { match *self { - Requester::Signature(ref signature) => ethkey::recover(signature, server_key_id).ok(), - Requester::Public(ref public) => Some(public.clone()), - Requester::Address(_) => None, + Requester::Signature(ref signature) => ethkey::recover(signature, server_key_id) + .map_err(|e| format!("bad signature: {}", e)), + Requester::Public(ref public) => Ok(public.clone()), + Requester::Address(_) => Err("cannot recover public from address".into()), } } - pub fn address(&self, server_key_id: &ServerKeyId) -> Option { - self.public(server_key_id).map(|p| ethkey::public_to_address(&p)) + pub fn address(&self, server_key_id: &ServerKeyId) -> Result { + self.public(server_key_id) + .map(|p| ethkey::public_to_address(&p)) } } @@ -202,3 +214,15 @@ impl From for Requester { Requester::Signature(signature) } } + +impl From for Requester { + fn from(public: ethereum_types::Public) -> Requester { + Requester::Public(public) + } +} + +impl From for Requester { + fn from(address: ethereum_types::Address) -> Requester { + Requester::Address(address) + } +} -- GitLab From 679d6c6f2b54f960a3b9fda5de12c1e9861b0baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 3 Apr 2018 23:16:29 +0100 Subject: [PATCH 028/263] build: fix updater rand dependency in Cargo.lock (#8298) --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 47b19ae11b..dda4645167 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2237,7 +2237,7 @@ dependencies = [ "parity-version 1.11.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "path 0.1.0", - "rand 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -- GitLab From ea6b0ec1643a1d91750145743340331b34f2309b Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 4 Apr 2018 18:07:49 +0900 Subject: [PATCH 029/263] remove evmjit (#8229) * removed not working evmjit, closes #8192 closes #6205 * removed evmjit from build scripts * fixed parity compile error * removed evmjit cli options * fixed invalid test config files --- Cargo.lock | 8 - Cargo.toml | 1 - docker/hub/Dockerfile | 19 +- docker/ubuntu-jit/Dockerfile | 58 ---- ethcore/Cargo.toml | 1 - ethcore/evm/Cargo.toml | 2 - ethcore/evm/src/factory.rs | 55 +--- ethcore/evm/src/jit.rs | 414 ------------------------- ethcore/evm/src/lib.rs | 6 - ethcore/evm/src/tests.rs | 70 ++--- ethcore/evm/src/vmtype.rs | 30 -- ethcore/src/executive.rs | 24 +- ethcore/src/lib.rs | 3 - ethcore/src/tests/evm.rs | 2 +- evmjit/Cargo.toml | 10 - evmjit/src/lib.rs | 493 ------------------------------ parity/cli/mod.rs | 20 +- parity/cli/tests/config.full.toml | 3 - parity/cli/tests/config.toml | 3 - parity/configuration.rs | 6 +- scripts/cov.sh | 2 +- scripts/doc.sh | 2 +- scripts/hook.sh | 2 +- test.sh | 2 +- 24 files changed, 57 insertions(+), 1179 deletions(-) delete mode 100644 docker/ubuntu-jit/Dockerfile delete mode 100644 ethcore/evm/src/jit.rs delete mode 100644 evmjit/Cargo.toml delete mode 100644 evmjit/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index dda4645167..1d14bcc173 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -908,7 +908,6 @@ version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "evmjit 1.11.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -939,13 +938,6 @@ dependencies = [ "vm 0.1.0", ] -[[package]] -name = "evmjit" -version = "1.11.0" -dependencies = [ - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fdlimit" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index a89708c278..f14b64fe89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,6 @@ ui-precompiled = [ ] ui-enabled = ["dapps"] dapps = ["parity-dapps"] -jit = ["ethcore/jit"] json-tests = ["ethcore/json-tests"] test-heavy = ["ethcore/test-heavy"] evm-debug = ["ethcore/evm-debug"] diff --git a/docker/hub/Dockerfile b/docker/hub/Dockerfile index c3406a5bd3..70d7277800 100644 --- a/docker/hub/Dockerfile +++ b/docker/hub/Dockerfile @@ -27,20 +27,7 @@ RUN apt-get update && \ libudev-dev \ pkg-config \ dpkg-dev \ - # evmjit dependencies - zlib1g-dev \ - libedit-dev \ - libudev-dev &&\ -# cmake and llvm ppa's. then update ppa's - add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \ - add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \ - apt-get update && \ - apt-get install -y --force-yes cmake llvm-3.7-dev && \ -# install evmjit - git clone https://github.com/debris/evmjit && \ - cd evmjit && \ - mkdir build && cd build && \ - cmake .. && make && make install && cd && \ + libudev-dev &&\ # install rustup curl https://sh.rustup.rs -sSf | sh -s -- -y && \ # rustup directory @@ -73,10 +60,6 @@ cd /build&&git clone https://github.com/paritytech/parity && \ file \ pkg-config \ dpkg-dev \ - # evmjit dependencies - zlib1g-dev \ - libedit-dev \ - cmake llvm-3.7-dev&&\ rm -rf /var/lib/apt/lists/* # setup ENTRYPOINT EXPOSE 8080 8545 8180 diff --git a/docker/ubuntu-jit/Dockerfile b/docker/ubuntu-jit/Dockerfile deleted file mode 100644 index 610d07c7dc..0000000000 --- a/docker/ubuntu-jit/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -FROM ubuntu:14.04 -WORKDIR /build - -# install tools and dependencies -RUN apt-get update && \ - apt-get install -y \ - # make - build-essential \ - # add-apt-repository - software-properties-common \ - curl \ - wget \ - git \ - g++ \ - binutils \ - file \ - # evmjit dependencies - zlib1g-dev \ - libedit-dev - -# cmake and llvm ppas. then update ppas -RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \ - add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \ - apt-get update && \ - apt-get install -y --force-yes cmake llvm-3.7-dev - -# install evmjit -RUN git clone https://github.com/debris/evmjit && \ - cd evmjit && \ - mkdir build && cd build && \ - cmake .. && make && make install && cd - -# install rustup -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y - -# rustup directory -ENV PATH /root/.cargo/bin:$PATH - -# show backtraces -ENV RUST_BACKTRACE 1 - -# show tools -RUN rustc -vV && \ -cargo -V && \ -gcc -v &&\ -g++ -v - -# build parity -ADD . /build/parity -RUN cd parity && \ - cargo build --release --features ethcore/jit --verbose && \ - ls /build/parity/target/release/parity && \ - strip /build/parity/target/release/parity - -RUN file /build/parity/target/release/parity - -EXPOSE 8080 8545 8180 -ENTRYPOINT ["/build/parity/target/release/parity"] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 2c769fac24..e870629929 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -76,7 +76,6 @@ tempdir = "0.3" trie-standardmap = { path = "../util/trie-standardmap" } [features] -jit = ["evm/jit"] evm-debug = ["slow-blocks"] evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"] slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms diff --git a/ethcore/evm/Cargo.toml b/ethcore/evm/Cargo.toml index 898b2a70a5..fa7a99f9de 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -6,7 +6,6 @@ authors = ["Parity Technologies "] [dependencies] bit-set = "0.4" ethereum-types = "0.3" -evmjit = { path = "../../evmjit", optional = true } heapsize = "0.4" lazy_static = "1.0" log = "0.3" @@ -19,6 +18,5 @@ memory-cache = { path = "../../util/memory_cache" } rustc-hex = "1.0" [features] -jit = ["evmjit"] evm-debug = [] evm-debug-tests = ["evm-debug"] diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 140f1620a3..af38afede3 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -32,23 +32,6 @@ pub struct Factory { impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. - #[cfg(feature = "jit")] - pub fn create(&self, gas: &U256) -> Box { - match self.evm { - VMType::Jit => { - Box::new(super::jit::JitEvm::default()) - }, - VMType::Interpreter => if Self::can_fit_in_usize(gas) { - Box::new(super::interpreter::Interpreter::::new(self.evm_cache.clone())) - } else { - Box::new(super::interpreter::Interpreter::::new(self.evm_cache.clone())) - } - } - } - - /// Create fresh instance of VM - /// Might choose implementation depending on supplied gas. - #[cfg(not(feature = "jit"))] pub fn create(&self, gas: &U256) -> Box { match self.evm { VMType::Interpreter => if Self::can_fit_in_usize(gas) { @@ -74,17 +57,7 @@ impl Factory { } impl Default for Factory { - /// Returns jitvm factory - #[cfg(all(feature = "jit", not(test)))] - fn default() -> Factory { - Factory { - evm: VMType::Jit, - evm_cache: Arc::new(SharedCache::default()), - } - } - /// Returns native rust evm factory - #[cfg(any(not(feature = "jit"), test))] fn default() -> Factory { Factory { evm: VMType::Interpreter, @@ -101,24 +74,7 @@ fn test_create_vm() { /// Create tests by injecting different VM factories #[macro_export] macro_rules! evm_test( - (ignorejit => $name_test: ident: $name_jit: ident, $name_int: ident) => { - #[test] - #[ignore] - #[cfg(feature = "jit")] - fn $name_jit() { - $name_test(Factory::new(VMType::Jit, 1024 * 32)); - } - #[test] - fn $name_int() { - $name_test(Factory::new(VMType::Interpreter, 1024 * 32)); - } - }; - ($name_test: ident: $name_jit: ident, $name_int: ident) => { - #[test] - #[cfg(feature = "jit")] - fn $name_jit() { - $name_test(Factory::new(VMType::Jit, 1024 * 32)); - } + ($name_test: ident: $name_int: ident) => { #[test] fn $name_int() { $name_test(Factory::new(VMType::Interpreter, 1024 * 32)); @@ -129,14 +85,7 @@ macro_rules! evm_test( /// Create ignored tests by injecting different VM factories #[macro_export] macro_rules! evm_test_ignore( - ($name_test: ident: $name_jit: ident, $name_int: ident) => { - #[test] - #[ignore] - #[cfg(feature = "jit")] - #[cfg(feature = "ignored-tests")] - fn $name_jit() { - $name_test(Factory::new(VMType::Jit, 1024 * 32)); - } + ($name_test: ident: $name_int: ident) => { #[test] #[ignore] #[cfg(feature = "ignored-tests")] diff --git a/ethcore/evm/src/jit.rs b/ethcore/evm/src/jit.rs deleted file mode 100644 index d94bb7b8e0..0000000000 --- a/ethcore/evm/src/jit.rs +++ /dev/null @@ -1,414 +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 . - -//! Just in time compiler execution environment. -use bigint::prelude::U256; -use bigint::hash::H256; -use util::*; -use evmjit; -use evm::{self, GasLeft}; -use evm::CallType; -use vm::{self, Vm}; - -/// Should be used to convert jit types to ethcore -trait FromJit: Sized { - fn from_jit(input: T) -> Self; -} - -/// Should be used to covert ethcore types to jit -trait IntoJit { - fn into_jit(self) -> T; -} - -impl<'a> FromJit<&'a evmjit::I256> for U256 { - fn from_jit(input: &'a evmjit::I256) -> Self { - unsafe { - let mut res: U256 = mem::uninitialized(); - ptr::copy(input.words.as_ptr(), res.0.as_mut_ptr(), 4); - res - } - } -} - -impl<'a> FromJit<&'a evmjit::I256> for H256 { - fn from_jit(input: &'a evmjit::I256) -> Self { - let u = U256::from_jit(input); - H256::from(&u) - } -} - -impl<'a> FromJit<&'a evmjit::I256> for Address { - fn from_jit(input: &'a evmjit::I256) -> Self { - Address::from(H256::from_jit(input)) - } -} - -impl<'a> FromJit<&'a evmjit::H256> for H256 { - fn from_jit(input: &'a evmjit::H256) -> Self { - H256::from_jit(&evmjit::I256::from(input.clone())) - } -} - -impl<'a> FromJit<&'a evmjit::H256> for Address { - fn from_jit(input: &'a evmjit::H256) -> Self { - Address::from(H256::from_jit(input)) - } -} - -impl IntoJit for U256 { - fn into_jit(self) -> evmjit::I256 { - unsafe { - let mut res: evmjit::I256 = mem::uninitialized(); - ptr::copy(self.0.as_ptr(), res.words.as_mut_ptr(), 4); - res - } - } -} - -impl IntoJit for H256 { - fn into_jit(self) -> evmjit::I256 { - let mut ret = [0; 4]; - let len = self.len(); - for i in 0..len { - let rev = len - 1 - i; - let pos = rev / 8; - ret[pos] += (self[i] as u64) << ((rev % 8) * 8); - } - evmjit::I256 { words: ret } - } -} - -impl IntoJit for H256 { - fn into_jit(self) -> evmjit::H256 { - let i: evmjit::I256 = self.into_jit(); - From::from(i) - } -} - -impl IntoJit for Address { - fn into_jit(self) -> evmjit::I256 { - H256::from(self).into_jit() - } -} - -impl IntoJit for Address { - fn into_jit(self) -> evmjit::H256 { - H256::from(self).into_jit() - } -} - -/// Externalities adapter. Maps callbacks from evmjit to externalities trait. -/// -/// Evmjit doesn't have to know about children execution failures. -/// This adapter 'catches' them and moves upstream. -struct ExtAdapter<'a> { - ext: &'a mut evm::Ext, - address: Address -} - -impl<'a> ExtAdapter<'a> { - fn new(ext: &'a mut evm::Ext, address: Address) -> Self { - ExtAdapter { - ext: ext, - address: address - } - } -} - -impl<'a> evmjit::Ext for ExtAdapter<'a> { - fn sload(&self, key: *const evmjit::I256, out_value: *mut evmjit::I256) { - unsafe { - let i = H256::from_jit(&*key); - let o = self.ext.storage_at(&i); - *out_value = o.into_jit(); - } - } - - fn sstore(&mut self, key: *const evmjit::I256, value: *const evmjit::I256) { - let key = unsafe { H256::from_jit(&*key) }; - let value = unsafe { H256::from_jit(&*value) }; - let old_value = self.ext.storage_at(&key); - // if SSTORE nonzero -> zero, increment refund count - if !old_value.is_zero() && value.is_zero() { - self.ext.inc_sstore_clears(); - } - self.ext.set_storage(key, value); - } - - fn balance(&self, address: *const evmjit::H256, out_value: *mut evmjit::I256) { - unsafe { - let a = Address::from_jit(&*address); - let o = self.ext.balance(&a); - *out_value = o.into_jit(); - } - } - - fn blockhash(&self, number: *const evmjit::I256, out_hash: *mut evmjit::H256) { - unsafe { - let n = U256::from_jit(&*number); - let o = self.ext.blockhash(&n); - *out_hash = o.into_jit(); - } - } - - fn create(&mut self, - io_gas: *mut u64, - value: *const evmjit::I256, - init_beg: *const u8, - init_size: u64, - address: *mut evmjit::H256) { - - let gas = unsafe { U256::from(*io_gas) }; - let value = unsafe { U256::from_jit(&*value) }; - let code = unsafe { slice::from_raw_parts(init_beg, init_size as usize) }; - - // check if balance is sufficient and we are not too deep - if self.ext.balance(&self.address) >= value && self.ext.depth() < self.ext.schedule().max_depth { - match self.ext.create(&gas, &value, code) { - evm::ContractCreateResult::Created(new_address, gas_left) => unsafe { - *address = new_address.into_jit(); - *io_gas = gas_left.low_u64(); - }, - evm::ContractCreateResult::Failed => unsafe { - *address = Address::new().into_jit(); - *io_gas = 0; - } - } - } else { - unsafe { *address = Address::new().into_jit(); } - } - } - - fn call(&mut self, - io_gas: *mut u64, - call_gas: u64, - sender_address: *const evmjit::H256, - receive_address: *const evmjit::H256, - code_address: *const evmjit::H256, - transfer_value: *const evmjit::I256, - // We are ignoring apparent value - it's handled in externalities. - _apparent_value: *const evmjit::I256, - in_beg: *const u8, - in_size: u64, - out_beg: *mut u8, - out_size: u64) -> bool { - - let mut gas = unsafe { U256::from(*io_gas) }; - let mut call_gas = U256::from(call_gas); - let mut gas_cost = call_gas; - let sender_address = unsafe { Address::from_jit(&*sender_address) }; - let receive_address = unsafe { Address::from_jit(&*receive_address) }; - let code_address = unsafe { Address::from_jit(&*code_address) }; - let transfer_value = unsafe { U256::from_jit(&*transfer_value) }; - - // receive address and code address are the same in normal calls - let is_callcode = receive_address != code_address; - let is_delegatecall = is_callcode && sender_address != receive_address; - - let value = if is_delegatecall { None } else { Some(transfer_value) }; - - if !is_callcode && !self.ext.exists(&code_address) { - gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas); - } - - if transfer_value > U256::zero() { - assert!(self.ext.schedule().call_value_transfer_gas > self.ext.schedule().call_stipend, "overflow possible"); - gas_cost = gas_cost + U256::from(self.ext.schedule().call_value_transfer_gas); - call_gas = call_gas + U256::from(self.ext.schedule().call_stipend); - } - - if gas_cost > gas { - unsafe { - *io_gas = -1i64 as u64; - return false; - } - } - - gas = gas - gas_cost; - - // check if balance is sufficient and we are not too deep - if self.ext.balance(&self.address) < transfer_value || self.ext.depth() >= self.ext.schedule().max_depth { - unsafe { - *io_gas = (gas + call_gas).low_u64(); - return false; - } - } - - let call_type = match (is_callcode, is_delegatecall) { - (_, true) => CallType::DelegateCall, - (true, false) => CallType::CallCode, - (false, false) => CallType::Call, - }; - - match self.ext.call( - &call_gas, - &sender_address, - &receive_address, - value, - unsafe { slice::from_raw_parts(in_beg, in_size as usize) }, - &code_address, - unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }, - call_type, - ) { - evm::MessageCallResult::Success(gas_left) => unsafe { - *io_gas = (gas + gas_left).low_u64(); - true - }, - evm::MessageCallResult::Failed => unsafe { - *io_gas = gas.low_u64(); - false - } - } - } - - fn log(&mut self, - beg: *const u8, - size: u64, - topic1: *const evmjit::H256, - topic2: *const evmjit::H256, - topic3: *const evmjit::H256, - topic4: *const evmjit::H256) { - - unsafe { - let mut topics = vec![]; - if !topic1.is_null() { - topics.push(H256::from_jit(&*topic1)); - } - - if !topic2.is_null() { - topics.push(H256::from_jit(&*topic2)); - } - - if !topic3.is_null() { - topics.push(H256::from_jit(&*topic3)); - } - - if !topic4.is_null() { - topics.push(H256::from_jit(&*topic4)); - } - - let bytes_ref: &[u8] = slice::from_raw_parts(beg, size as usize); - self.ext.log(topics, bytes_ref); - } - } - - fn extcode(&self, address: *const evmjit::H256, size: *mut u64) -> *const u8 { - unsafe { - let code = self.ext.extcode(&Address::from_jit(&*address)); - *size = code.len() as u64; - let ptr = code.as_ptr(); - mem::forget(code); - ptr - } - } -} - -#[derive(Default)] -pub struct JitEvm { - context: Option, -} - -impl vm::Vm for JitEvm { - fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result { - // Dirty hack. This is unsafe, but we interact with ffi, so it's justified. - let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) }; - let mut ext_handle = evmjit::ExtHandle::new(ext_adapter); - assert!(params.gas <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); - assert!(params.gas_price <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); - - let call_data = params.data.unwrap_or_else(Vec::new); - let code = params.code.unwrap_or_else(Vec::new); - - let mut data = evmjit::RuntimeDataHandle::new(); - data.gas = params.gas.low_u64() as i64; - data.gas_price = params.gas_price.low_u64() as i64; - data.call_data = call_data.as_ptr(); - data.call_data_size = call_data.len() as u64; - mem::forget(call_data); - data.code = code.as_ptr(); - data.code_size = code.len() as u64; - data.code_hash = code.sha3().into_jit(); - mem::forget(code); - data.address = params.address.into_jit(); - data.caller = params.sender.into_jit(); - data.origin = params.origin.into_jit(); - data.transfer_value = match params.value { - ActionValue::Transfer(val) => val.into_jit(), - ActionValue::Apparent(val) => val.into_jit() - }; - data.apparent_value = data.transfer_value; - - let mut schedule = evmjit::ScheduleHandle::new(); - schedule.have_delegate_call = ext.schedule().have_delegate_call; - - data.author = ext.env_info().author.clone().into_jit(); - data.difficulty = ext.env_info().difficulty.into_jit(); - data.gas_limit = ext.env_info().gas_limit.into_jit(); - data.number = ext.env_info().number; - // don't really know why jit timestamp is int.. - data.timestamp = ext.env_info().timestamp as i64; - - self.context = Some(unsafe { evmjit::ContextHandle::new(data, schedule, &mut ext_handle) }); - let mut context = self.context.as_mut().expect("context handle set on the prior line; qed"); - let res = context.exec(); - - match res { - evmjit::ReturnCode::Stop => Ok(GasLeft::Known(U256::from(context.gas_left()))), - evmjit::ReturnCode::Return => - Ok(GasLeft::NeedsReturn(U256::from(context.gas_left()), context.output_data())), - evmjit::ReturnCode::Suicide => { - ext.suicide(&Address::from_jit(&context.suicide_refund_address())); - Ok(GasLeft::Known(U256::from(context.gas_left()))) - }, - evmjit::ReturnCode::OutOfGas => Err(vm::Error::OutOfGas), - _err => Err(vm::Error::Internal) - } - } -} - -#[test] -fn test_to_and_from_u256() { - let u = U256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap(); - let j = u.into_jit(); - let u2 = U256::from_jit(&j); - assert_eq!(u, u2); -} - -#[test] -fn test_to_and_from_h256() { - let h = H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap(); - let j: ::evmjit::I256 = h.clone().into_jit(); - let h2 = H256::from_jit(&j); - - assert_eq!(h, h2); - - let j: ::evmjit::H256 = h.clone().into_jit(); - let h2 = H256::from_jit(&j); - assert_eq!(h, h2); -} - -#[test] -fn test_to_and_from_address() { - let a = Address::from_str("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").unwrap(); - let j: ::evmjit::I256 = a.clone().into_jit(); - let a2 = Address::from_jit(&j); - - assert_eq!(a, a2); - - let j: ::evmjit::H256 = a.clone().into_jit(); - let a2 = Address::from_jit(&j); - assert_eq!(a, a2); -} diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index b61c8aa2a9..263a11d682 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -30,9 +30,6 @@ extern crate lazy_static; #[cfg_attr(feature = "evm-debug", macro_use)] extern crate log; -#[cfg(feature = "jit")] -extern crate evmjit; - #[cfg(test)] extern crate rustc_hex; @@ -44,9 +41,6 @@ pub mod factory; mod vmtype; mod instructions; -#[cfg(feature = "jit" )] -mod jit; - #[cfg(test)] mod tests; #[cfg(all(feature="benches", test))] diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index a219ae9880..3758156e21 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -26,9 +26,9 @@ use vm::tests::{FakeExt, FakeCall, FakeCallType, test_finalize}; use factory::Factory; use vmtype::VMType; -evm_test!{test_add: test_add_jit, test_add_int} +evm_test!{test_add: test_add_int} fn test_add(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); + let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap(); let mut params = ActionParams::default(); @@ -46,7 +46,7 @@ fn test_add(factory: super::Factory) { assert_store(&ext, 0, "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); } -evm_test!{test_sha3: test_sha3_jit, test_sha3_int} +evm_test!{test_sha3: test_sha3_int} fn test_sha3(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "6000600020600055".from_hex().unwrap(); @@ -66,7 +66,7 @@ fn test_sha3(factory: super::Factory) { assert_store(&ext, 0, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); } -evm_test!{test_address: test_address_jit, test_address_int} +evm_test!{test_address: test_address_int} fn test_address(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "30600055".from_hex().unwrap(); @@ -86,7 +86,7 @@ fn test_address(factory: super::Factory) { assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"); } -evm_test!{test_origin: test_origin_jit, test_origin_int} +evm_test!{test_origin: test_origin_int} fn test_origin(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let origin = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); @@ -108,7 +108,7 @@ fn test_origin(factory: super::Factory) { assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681"); } -evm_test!{test_sender: test_sender_jit, test_sender_int} +evm_test!{test_sender: test_sender_int} fn test_sender(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); @@ -130,7 +130,7 @@ fn test_sender(factory: super::Factory) { assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681"); } -evm_test!{test_extcodecopy: test_extcodecopy_jit, test_extcodecopy_int} +evm_test!{test_extcodecopy: test_extcodecopy_int} fn test_extcodecopy(factory: super::Factory) { // 33 - sender // 3b - extcodesize @@ -165,7 +165,7 @@ fn test_extcodecopy(factory: super::Factory) { assert_store(&ext, 0, "6005600055000000000000000000000000000000000000000000000000000000"); } -evm_test!{test_log_empty: test_log_empty_jit, test_log_empty_int} +evm_test!{test_log_empty: test_log_empty_int} fn test_log_empty(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "60006000a0".from_hex().unwrap(); @@ -187,7 +187,7 @@ fn test_log_empty(factory: super::Factory) { assert!(ext.logs[0].data.is_empty()); } -evm_test!{test_log_sender: test_log_sender_jit, test_log_sender_int} +evm_test!{test_log_sender: test_log_sender_int} fn test_log_sender(factory: super::Factory) { // 60 ff - push ff // 60 00 - push 00 @@ -220,7 +220,7 @@ fn test_log_sender(factory: super::Factory) { assert_eq!(ext.logs[0].data, "ff00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()); } -evm_test!{test_blockhash: test_blockhash_jit, test_blockhash_int} +evm_test!{test_blockhash: test_blockhash_int} fn test_blockhash(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "600040600055".from_hex().unwrap(); @@ -242,7 +242,7 @@ fn test_blockhash(factory: super::Factory) { assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash); } -evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int} +evm_test!{test_calldataload: test_calldataload_int} fn test_calldataload(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "600135600055".from_hex().unwrap(); @@ -265,7 +265,7 @@ fn test_calldataload(factory: super::Factory) { } -evm_test!{test_author: test_author_jit, test_author_int} +evm_test!{test_author: test_author_int} fn test_author(factory: super::Factory) { let author = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "41600055".from_hex().unwrap(); @@ -285,7 +285,7 @@ fn test_author(factory: super::Factory) { assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"); } -evm_test!{test_timestamp: test_timestamp_jit, test_timestamp_int} +evm_test!{test_timestamp: test_timestamp_int} fn test_timestamp(factory: super::Factory) { let timestamp = 0x1234; let code = "42600055".from_hex().unwrap(); @@ -305,7 +305,7 @@ fn test_timestamp(factory: super::Factory) { assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); } -evm_test!{test_number: test_number_jit, test_number_int} +evm_test!{test_number: test_number_int} fn test_number(factory: super::Factory) { let number = 0x1234; let code = "43600055".from_hex().unwrap(); @@ -325,7 +325,7 @@ fn test_number(factory: super::Factory) { assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); } -evm_test!{test_difficulty: test_difficulty_jit, test_difficulty_int} +evm_test!{test_difficulty: test_difficulty_int} fn test_difficulty(factory: super::Factory) { let difficulty = U256::from(0x1234); let code = "44600055".from_hex().unwrap(); @@ -345,7 +345,7 @@ fn test_difficulty(factory: super::Factory) { assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); } -evm_test!{test_gas_limit: test_gas_limit_jit, test_gas_limit_int} +evm_test!{test_gas_limit: test_gas_limit_int} fn test_gas_limit(factory: super::Factory) { let gas_limit = U256::from(0x1234); let code = "45600055".from_hex().unwrap(); @@ -365,7 +365,7 @@ fn test_gas_limit(factory: super::Factory) { assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); } -evm_test!{test_mul: test_mul_jit, test_mul_int} +evm_test!{test_mul: test_mul_int} fn test_mul(factory: super::Factory) { let code = "65012365124623626543219002600055".from_hex().unwrap(); @@ -383,7 +383,7 @@ fn test_mul(factory: super::Factory) { assert_eq!(gas_left, U256::from(79_983)); } -evm_test!{test_sub: test_sub_jit, test_sub_int} +evm_test!{test_sub: test_sub_int} fn test_sub(factory: super::Factory) { let code = "65012365124623626543219003600055".from_hex().unwrap(); @@ -401,7 +401,7 @@ fn test_sub(factory: super::Factory) { assert_eq!(gas_left, U256::from(79_985)); } -evm_test!{test_div: test_div_jit, test_div_int} +evm_test!{test_div: test_div_int} fn test_div(factory: super::Factory) { let code = "65012365124623626543219004600055".from_hex().unwrap(); @@ -419,7 +419,7 @@ fn test_div(factory: super::Factory) { assert_eq!(gas_left, U256::from(79_983)); } -evm_test!{test_div_zero: test_div_zero_jit, test_div_zero_int} +evm_test!{test_div_zero: test_div_zero_int} fn test_div_zero(factory: super::Factory) { let code = "6501236512462360009004600055".from_hex().unwrap(); @@ -437,7 +437,7 @@ fn test_div_zero(factory: super::Factory) { assert_eq!(gas_left, U256::from(94_983)); } -evm_test!{test_mod: test_mod_jit, test_mod_int} +evm_test!{test_mod: test_mod_int} fn test_mod(factory: super::Factory) { let code = "650123651246236265432290066000556501236512462360009006600155".from_hex().unwrap(); @@ -456,7 +456,7 @@ fn test_mod(factory: super::Factory) { assert_eq!(gas_left, U256::from(74_966)); } -evm_test!{test_smod: test_smod_jit, test_smod_int} +evm_test!{test_smod: test_smod_int} fn test_smod(factory: super::Factory) { let code = "650123651246236265432290076000556501236512462360009007600155".from_hex().unwrap(); @@ -475,7 +475,7 @@ fn test_smod(factory: super::Factory) { assert_eq!(gas_left, U256::from(74_966)); } -evm_test!{test_sdiv: test_sdiv_jit, test_sdiv_int} +evm_test!{test_sdiv: test_sdiv_int} fn test_sdiv(factory: super::Factory) { let code = "650123651246236265432290056000556501236512462360009005600155".from_hex().unwrap(); @@ -494,7 +494,7 @@ fn test_sdiv(factory: super::Factory) { assert_eq!(gas_left, U256::from(74_966)); } -evm_test!{test_exp: test_exp_jit, test_exp_int} +evm_test!{test_exp: test_exp_int} fn test_exp(factory: super::Factory) { let code = "6016650123651246230a6000556001650123651246230a6001556000650123651246230a600255".from_hex().unwrap(); @@ -514,7 +514,7 @@ fn test_exp(factory: super::Factory) { assert_eq!(gas_left, U256::from(39_923)); } -evm_test!{test_comparison: test_comparison_jit, test_comparison_int} +evm_test!{test_comparison: test_comparison_int} fn test_comparison(factory: super::Factory) { let code = "601665012365124623818181811060005511600155146002556415235412358014600355".from_hex().unwrap(); @@ -535,7 +535,7 @@ fn test_comparison(factory: super::Factory) { assert_eq!(gas_left, U256::from(49_952)); } -evm_test!{test_signed_comparison: test_signed_comparison_jit, test_signed_comparison_int} +evm_test!{test_signed_comparison: test_signed_comparison_int} fn test_signed_comparison(factory: super::Factory) { let code = "60106000036010818112600055136001556010601060000381811260025513600355".from_hex().unwrap(); @@ -556,7 +556,7 @@ fn test_signed_comparison(factory: super::Factory) { assert_eq!(gas_left, U256::from(49_940)); } -evm_test!{test_bitops: test_bitops_jit, test_bitops_int} +evm_test!{test_bitops: test_bitops_int} fn test_bitops(factory: super::Factory) { let code = "60ff610ff08181818116600055176001551860025560008015600355198015600455600555".from_hex().unwrap(); @@ -579,7 +579,7 @@ fn test_bitops(factory: super::Factory) { assert_eq!(gas_left, U256::from(44_937)); } -evm_test!{test_addmod_mulmod: test_addmod_mulmod_jit, test_addmod_mulmod_int} +evm_test!{test_addmod_mulmod: test_addmod_mulmod_int} fn test_addmod_mulmod(factory: super::Factory) { let code = "60ff60f060108282820860005509600155600060f0601082828208196002550919600355".from_hex().unwrap(); @@ -600,7 +600,7 @@ fn test_addmod_mulmod(factory: super::Factory) { assert_eq!(gas_left, U256::from(19_914)); } -evm_test!{test_byte: test_byte_jit, test_byte_int} +evm_test!{test_byte: test_byte_int} fn test_byte(factory: super::Factory) { let code = "60f061ffff1a600055610fff601f1a600155".from_hex().unwrap(); @@ -619,7 +619,7 @@ fn test_byte(factory: super::Factory) { assert_eq!(gas_left, U256::from(74_976)); } -evm_test!{test_signextend: test_signextend_jit, test_signextend_int} +evm_test!{test_signextend: test_signextend_int} fn test_signextend(factory: super::Factory) { let code = "610fff60020b60005560ff60200b600155".from_hex().unwrap(); @@ -659,7 +659,7 @@ fn test_badinstruction_int() { } } -evm_test!{test_pop: test_pop_jit, test_pop_int} +evm_test!{test_pop: test_pop_int} fn test_pop(factory: super::Factory) { let code = "60f060aa50600055".from_hex().unwrap(); @@ -677,7 +677,7 @@ fn test_pop(factory: super::Factory) { assert_eq!(gas_left, U256::from(79_989)); } -evm_test!{test_extops: test_extops_jit, test_extops_int} +evm_test!{test_extops: test_extops_int} fn test_extops(factory: super::Factory) { let code = "5a6001555836553a600255386003553460045560016001526016590454600555".from_hex().unwrap(); @@ -702,7 +702,7 @@ fn test_extops(factory: super::Factory) { assert_eq!(gas_left, U256::from(29_898)); } -evm_test!{test_jumps: test_jumps_jit, test_jumps_int} +evm_test!{test_jumps: test_jumps_int} fn test_jumps(factory: super::Factory) { let code = "600160015560066000555b60016000540380806000551560245760015402600155600a565b".from_hex().unwrap(); @@ -722,7 +722,7 @@ fn test_jumps(factory: super::Factory) { assert_eq!(gas_left, U256::from(54_117)); } -evm_test!{test_calls: test_calls_jit, test_calls_int} +evm_test!{test_calls: test_calls_int} fn test_calls(factory: super::Factory) { let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap(); @@ -766,7 +766,7 @@ fn test_calls(factory: super::Factory) { assert_eq!(ext.calls.len(), 2); } -evm_test!{test_create_in_staticcall: test_create_in_staticcall_jit, test_create_in_staticcall_int} +evm_test!{test_create_in_staticcall: test_create_in_staticcall_int} fn test_create_in_staticcall(factory: super::Factory) { let code = "600060006064f000".from_hex().unwrap(); diff --git a/ethcore/evm/src/vmtype.rs b/ethcore/evm/src/vmtype.rs index 608ab1e815..b3a8aaf3e9 100644 --- a/ethcore/evm/src/vmtype.rs +++ b/ethcore/evm/src/vmtype.rs @@ -19,22 +19,11 @@ use std::fmt; /// Type of EVM to use. #[derive(Debug, PartialEq, Clone)] pub enum VMType { - /// JIT EVM - #[cfg(feature = "jit")] - Jit, /// RUST EVM Interpreter } impl fmt::Display for VMType { - #[cfg(feature="jit")] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", match *self { - VMType::Jit => "JIT", - VMType::Interpreter => "INT" - }) - } - #[cfg(not(feature="jit"))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", match *self { VMType::Interpreter => "INT" @@ -49,27 +38,8 @@ impl Default for VMType { } impl VMType { - /// Return all possible VMs (JIT, Interpreter) - #[cfg(feature = "jit")] - pub fn all() -> Vec { - vec![VMType::Jit, VMType::Interpreter] - } - /// Return all possible VMs (Interpreter) - #[cfg(not(feature = "jit"))] pub fn all() -> Vec { vec![VMType::Interpreter] } - - /// Return new jit if it's possible - #[cfg(not(feature = "jit"))] - pub fn jit() -> Option { - None - } - - /// Return new jit if it's possible - #[cfg(feature = "jit")] - pub fn jit() -> Option { - Some(VMType::Jit) - } } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 8e792f9e2e..c33eb2ecd6 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -721,7 +721,7 @@ mod tests { } // TODO: replace params with transactions! - evm_test!{test_sender_balance: test_sender_balance_jit, test_sender_balance_int} + evm_test!{test_sender_balance: test_sender_balance_int} fn test_sender_balance(factory: Factory) { let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &[]).0; @@ -752,7 +752,7 @@ mod tests { // TODO: just test state root. } - evm_test!{test_create_contract_out_of_depth: test_create_contract_out_of_depth_jit, test_create_contract_out_of_depth_int} + evm_test!{test_create_contract_out_of_depth: test_create_contract_out_of_depth_int} fn test_create_contract_out_of_depth(factory: Factory) { // code: // @@ -1083,7 +1083,7 @@ mod tests { assert_eq!(vm_tracer.drain().unwrap(), expected_vm_trace); } - evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int} + evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_int} fn test_create_contract_value_too_high(factory: Factory) { // code: // @@ -1135,7 +1135,7 @@ mod tests { assert_eq!(substate.contracts_created.len(), 0); } - evm_test!{test_create_contract_without_max_depth: test_create_contract_without_max_depth_jit, test_create_contract_without_max_depth_int} + evm_test!{test_create_contract_without_max_depth: test_create_contract_without_max_depth_int} fn test_create_contract_without_max_depth(factory: Factory) { // code: // @@ -1188,7 +1188,7 @@ mod tests { // test is incorrect, mk // TODO: fix (preferred) or remove - evm_test_ignore!{test_aba_calls: test_aba_calls_jit, test_aba_calls_int} + evm_test_ignore!{test_aba_calls: test_aba_calls_int} fn test_aba_calls(factory: Factory) { // 60 00 - push 0 // 60 00 - push 0 @@ -1248,7 +1248,7 @@ mod tests { // test is incorrect, mk // TODO: fix (preferred) or remove - evm_test_ignore!{test_recursive_bomb1: test_recursive_bomb1_jit, test_recursive_bomb1_int} + evm_test_ignore!{test_recursive_bomb1: test_recursive_bomb1_int} fn test_recursive_bomb1(factory: Factory) { // 60 01 - push 1 // 60 00 - push 0 @@ -1293,7 +1293,7 @@ mod tests { // test is incorrect, mk // TODO: fix (preferred) or remove - evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int} + evm_test_ignore!{test_transact_simple: test_transact_simple_int} fn test_transact_simple(factory: Factory) { let keypair = Random.generate().unwrap(); let t = Transaction { @@ -1331,7 +1331,7 @@ mod tests { assert_eq!(state.storage_at(&contract, &H256::new()).unwrap(), H256::from(&U256::from(1))); } - evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_jit, test_transact_invalid_nonce_int} + evm_test!{test_transact_invalid_nonce: test_transact_invalid_nonce_int} fn test_transact_invalid_nonce(factory: Factory) { let keypair = Random.generate().unwrap(); let t = Transaction { @@ -1363,7 +1363,7 @@ mod tests { } } - evm_test!{test_transact_gas_limit_reached: test_transact_gas_limit_reached_jit, test_transact_gas_limit_reached_int} + evm_test!{test_transact_gas_limit_reached: test_transact_gas_limit_reached_int} fn test_transact_gas_limit_reached(factory: Factory) { let keypair = Random.generate().unwrap(); let t = Transaction { @@ -1396,7 +1396,7 @@ mod tests { } } - evm_test!{test_not_enough_cash: test_not_enough_cash_jit, test_not_enough_cash_int} + evm_test!{test_not_enough_cash: test_not_enough_cash_int} fn test_not_enough_cash(factory: Factory) { let keypair = Random.generate().unwrap(); @@ -1429,7 +1429,7 @@ mod tests { } } - evm_test!{test_keccak: test_keccak_jit, test_keccak_int} + evm_test!{test_keccak: test_keccak_int} fn test_keccak(factory: Factory) { let code = "6064640fffffffff20600055".from_hex().unwrap(); @@ -1461,7 +1461,7 @@ mod tests { } } - evm_test!{test_revert: test_revert_jit, test_revert_int} + evm_test!{test_revert: test_revert_int} fn test_revert(factory: Factory) { let contract_address = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 343cef9f41..43c3336f6f 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -130,9 +130,6 @@ extern crate trace_time; #[cfg_attr(test, macro_use)] extern crate evm; -#[cfg(feature = "jit" )] -extern crate evmjit; - pub extern crate ethstore; pub mod account_provider; diff --git a/ethcore/src/tests/evm.rs b/ethcore/src/tests/evm.rs index 39feb13644..60d5e12b06 100644 --- a/ethcore/src/tests/evm.rs +++ b/ethcore/src/tests/evm.rs @@ -31,7 +31,7 @@ use rustc_hex::FromHex; use ethereum_types::{H256, Address}; use bytes::BytesRef; -evm_test!{test_blockhash_eip210: test_blockhash_eip210_jit, test_blockhash_eip210_int} +evm_test!{test_blockhash_eip210: test_blockhash_eip210_int} fn test_blockhash_eip210(factory: Factory) { let get_prev_hash_code = Arc::new("600143034060205260206020f3".from_hex().unwrap()); // this returns previous block hash let get_prev_hash_code_hash = keccak(get_prev_hash_code.as_ref()); diff --git a/evmjit/Cargo.toml b/evmjit/Cargo.toml deleted file mode 100644 index c7bf1f8ba9..0000000000 --- a/evmjit/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "evmjit" -version = "1.11.0" -authors = ["Parity Technologies "] - -[lib] -crate-type = ["dylib"] - -[dependencies] -tiny-keccak = "1.3" diff --git a/evmjit/src/lib.rs b/evmjit/src/lib.rs deleted file mode 100644 index 06aade3c2f..0000000000 --- a/evmjit/src/lib.rs +++ /dev/null @@ -1,493 +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 . - -//! Bare rust wrapper around evmjit. -//! -//! Requires latest version of Ethereum EVM JIT. https://github.com/debris/evmjit -//! -//! ``` -//! extern crate evmjit; -//! use evmjit::*; -//! -//! fn main() { -//! let mut context = ContextHandle::new(RuntimeDataHandle::new(), ExtHandle::empty()); -//! assert_eq!(context.exec(), ReturnCode::Stop); -//! } -//! ``` -//! -//! -//! To verify that c abi is "imported" correctly, run: -//! -//! ```bash -//! nm your_executable -g | grep ext -//! ``` -//! -//! It should give the following output: -//! -//! ```bash -//! 00000001000779e0 T _ext_balance -//! 0000000100077a10 T _ext_blockhash -//! 0000000100077a90 T _ext_call -//! 0000000100077a40 T _ext_create -//! 0000000100077b50 T _ext_extcode -//! 0000000100077b80 T _ext_log -//! 0000000100077b20 T _ext_sha3 -//! 0000000100077980 T _ext_sload -//! 00000001000779b0 T _ext_sstore -//! ``` - -extern crate tiny_keccak; - -use std::ops::{Deref, DerefMut}; -use self::ffi::*; - -pub use self::ffi::JitReturnCode as ReturnCode; -pub use self::ffi::JitI256 as I256; -pub use self::ffi::JitH256 as H256; - -/// Takes care of proper initialization and destruction of `RuntimeData`. -/// -/// This handle must be used to create runtime data, -/// cause underneath it's a `C++` structure. Incompatible with rust -/// structs. -pub struct RuntimeDataHandle { - runtime_data: *mut JitRuntimeData -} - -impl RuntimeDataHandle { - /// Creates new `RuntimeData` handle. - pub fn new() -> Self { - RuntimeDataHandle { - runtime_data: unsafe { evmjit_create_runtime_data() } - } - } -} - -impl Drop for RuntimeDataHandle { - fn drop(&mut self) { - unsafe { evmjit_destroy_runtime_data(self.runtime_data) } - } -} - -impl Deref for RuntimeDataHandle { - type Target = JitRuntimeData; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.runtime_data } - } -} - -impl DerefMut for RuntimeDataHandle { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.runtime_data } - } -} - -/// Takes care of proper initilization and destruction of `JitSchedule`. -/// -/// This handle must be used to jit schedule, -/// cause underneath it's a `C++` structure. Incompatible with rust -/// structs. -pub struct ScheduleHandle { - schedule: *mut JitSchedule -} - -impl ScheduleHandle { - /// Creates new `Schedule` handle. - pub fn new() -> Self { - ScheduleHandle { - schedule: unsafe { evmjit_create_schedule() } - } - } -} - -impl Drop for ScheduleHandle { - fn drop(&mut self) { - unsafe { evmjit_destroy_schedule(self.schedule) } - } -} - -impl Deref for ScheduleHandle { - type Target = JitSchedule; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.schedule } - } -} - -impl DerefMut for ScheduleHandle { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.schedule } - } -} - -/// Takes care of proper initialization and destruction of jit context. -/// -/// This handle must be used to create context, -/// cause underneath it's a `C++` structure. Incombatible with rust -/// structs. -pub struct ContextHandle { - context: *mut JitContext, - data_handle: RuntimeDataHandle, - schedule_handle: ScheduleHandle -} - -impl ContextHandle { - /// Creates new context handle. - /// - /// This function is unsafe cause ext lifetime is not considered - /// We also can't make ExtHandle a member of `ContextHandle` structure, - /// cause this would be a move operation or it would require a template - /// lifetime to a reference. Both solutions are not possible. - pub unsafe fn new(data_handle: RuntimeDataHandle, schedule_handle: ScheduleHandle, ext: &mut ExtHandle) -> Self { - let mut handle = ContextHandle { - context: std::mem::uninitialized(), - schedule_handle: schedule_handle, - data_handle: data_handle, - }; - - handle.context = evmjit_create_context(handle.data_handle.deref_mut(), ext); - handle - } - - /// Executes context. - pub fn exec(&mut self) -> JitReturnCode { - unsafe { evmjit_exec(self.context, self.schedule_handle.deref_mut()) } - } - - /// Returns output data. - pub fn output_data(&self) -> &[u8] { - unsafe { std::slice::from_raw_parts(self.data_handle.call_data, self.data_handle.call_data_size as usize) } - } - - /// Returns address to which funds should be transfered after suicide. - pub fn suicide_refund_address(&self) -> JitI256 { - // evmjit reuses data_handle address field to store suicide address - self.data_handle.address - } - - /// Returns gas left. - pub fn gas_left(&self) -> u64 { - self.data_handle.gas as u64 - } -} - -impl Drop for ContextHandle { - fn drop(&mut self) { - unsafe { evmjit_destroy_context(self.context); } - } -} - -/// Component oriented wrapper around jit ext c interface. -pub trait Ext { - fn sload(&self, index: *const JitI256, out_value: *mut JitI256); - fn sstore(&mut self, index: *const JitI256, value: *const JitI256); - fn balance(&self, address: *const JitH256, out_value: *mut JitI256); - fn blockhash(&self, number: *const JitI256, out_hash: *mut JitH256); - - fn create(&mut self, - io_gas: *mut u64, - endowment: *const JitI256, - init_beg: *const u8, - init_size: u64, - address: *mut JitH256); - - fn call(&mut self, - io_gas: *mut u64, - call_gas: u64, - sender_address: *const JitH256, - receive_address: *const JitH256, - code_address: *const JitH256, - transfer_value: *const JitI256, - apparent_value: *const JitI256, - in_beg: *const u8, - in_size: u64, - out_beg: *mut u8, - out_size: u64) -> bool; - - fn log(&mut self, - beg: *const u8, - size: u64, - topic1: *const JitH256, - topic2: *const JitH256, - topic3: *const JitH256, - topic4: *const JitH256); - - fn extcode(&self, address: *const JitH256, size: *mut u64) -> *const u8; -} - -/// C abi compatible wrapper for jit ext implementers. -pub struct ExtHandle { - ext_impl: Option> -} - -impl ExtHandle { - /// Creates new extironment wrapper for given implementation - pub fn new(ext_impl: T) -> Self where T: Ext + 'static { - ExtHandle { ext_impl: Some(Box::new(ext_impl)) } - } - - /// Creates empty extironment. - /// It can be used to for any operations. - pub fn empty() -> Self { - ExtHandle { ext_impl: None } - } -} - -impl Deref for ExtHandle { - type Target = Box; - - fn deref(&self) -> &Self::Target { - match self.ext_impl { - Some(ref ext) => ext, - None => { panic!("Handle is empty!"); } - } - } -} - -impl DerefMut for ExtHandle { - fn deref_mut(&mut self) -> &mut Self::Target { - match self.ext_impl { - Some(ref mut ext) => ext, - None => { panic!("Handle is empty!"); } - } - } -} - -/// ffi functions -pub mod ffi { - use std::slice; - use std::mem; - use tiny_keccak::Keccak; - use super::*; - - /// Jit context struct declaration. - pub enum JitContext {} - - #[repr(C)] - #[derive(Debug, Eq, PartialEq)] - /// Jit context execution return code. - pub enum JitReturnCode { - Stop = 0, - Return = 1, - Suicide = 2, - - OutOfGas = -1, - - LLVMError = -101, - UnexpectedError = -111 - } - - #[repr(C)] - #[derive(Debug, Copy, Clone)] - /// Signed 256 bit integer. - pub struct JitI256 { - pub words: [u64; 4] - } - - #[repr(C)] - #[derive(Debug, Copy, Clone)] - /// Jit Hash - pub struct JitH256 { - pub words: [u64; 4] - } - - impl From for JitI256 { - fn from(mut hash: JitH256) -> JitI256 { - unsafe { - { - let bytes: &mut [u8] = slice::from_raw_parts_mut(hash.words.as_mut_ptr() as *mut u8, 32); - bytes.reverse(); - } - mem::transmute(hash) - } - } - } - - impl From for JitH256 { - fn from(mut i: JitI256) -> JitH256 { - unsafe { - { - let bytes: &mut [u8] = slice::from_raw_parts_mut(i.words.as_mut_ptr() as *mut u8, 32); - bytes.reverse(); - } - mem::transmute(i) - } - } - } - - #[repr(C)] - #[derive(Debug)] - /// Jit runtime data. - pub struct JitRuntimeData { - pub gas: i64, - pub gas_price: i64, - pub call_data: *const u8, - pub call_data_size: u64, - pub address: JitI256, - pub caller: JitI256, - pub origin: JitI256, - pub transfer_value: JitI256, - pub apparent_value: JitI256, - pub author: JitI256, - pub difficulty: JitI256, - pub gas_limit: JitI256, - pub number: u64, - pub timestamp: i64, - pub code: *const u8, - pub code_size: u64, - pub code_hash: JitI256 - } - - #[repr(C)] - #[derive(Debug)] - /// Configurable properties of git schedule. - pub struct JitSchedule { - pub have_delegate_call: bool - } - - #[no_mangle] - pub unsafe extern "C" fn env_sload(ext: *const ExtHandle, index: *const JitI256, out_value: *mut JitI256) { - let ext = &*ext; - ext.sload(index, out_value); - } - - #[no_mangle] - pub unsafe extern "C" fn env_sstore(ext: *mut ExtHandle, index: *mut JitI256, value: *mut JitI256) { - let ext = &mut *ext; - ext.sstore(index, value); - } - - #[no_mangle] - pub unsafe extern "C" fn env_balance(ext: *const ExtHandle, address: *const JitH256, out_value: *mut JitI256) { - let ext = &*ext; - ext.balance(address, out_value); - } - - #[no_mangle] - pub unsafe extern "C" fn env_blockhash(ext: *const ExtHandle, number: *const JitI256, out_hash: *mut JitH256) { - let ext = &*ext; - ext.blockhash(number, out_hash); - } - - #[no_mangle] - pub unsafe extern "C" fn env_create(ext: *mut ExtHandle, - io_gas: *mut u64, - endowment: *const JitI256, - init_beg: *const u8, - init_size: u64, - address: *mut JitH256) { - let ext = &mut *ext; - ext.create(io_gas, endowment, init_beg, init_size, address); - } - - #[no_mangle] - pub unsafe extern "C" fn env_call(ext: *mut ExtHandle, - io_gas: *mut u64, - call_gas: u64, - sender_address: *const JitH256, - receive_address: *const JitH256, - code_address: *const JitH256, - transfer_value: *const JitI256, - apparent_value: *const JitI256, - in_beg: *const u8, - in_size: u64, - out_beg: *mut u8, - out_size: u64) -> bool { - let ext = &mut *ext; - ext.call(io_gas, call_gas, sender_address, receive_address, code_address, transfer_value, apparent_value, in_beg, in_size, out_beg, out_size) - } - - #[no_mangle] - pub unsafe extern "C" fn env_sha3(begin: *const u8, size: u64, out_hash: *mut JitH256) { - let out_hash = &mut *out_hash; - let input = slice::from_raw_parts(begin, size as usize); - let outlen = out_hash.words.len() * 8; - let output = slice::from_raw_parts_mut(out_hash.words.as_mut_ptr() as *mut u8, outlen); - let mut sha3 = Keccak::new_keccak256(); - sha3.update(input); - sha3.finalize(output); - } - - #[no_mangle] - pub unsafe extern "C" fn env_extcode(ext: *const ExtHandle, address: *const JitH256, size: *mut u64) -> *const u8 { - let ext = &*ext; - ext.extcode(address, size) - } - - #[no_mangle] - pub unsafe extern "C" fn env_log(ext: *mut ExtHandle, - beg: *const u8, - size: u64, - topic1: *const JitH256, - topic2: *const JitH256, - topic3: *const JitH256, - topic4: *const JitH256) { - let ext = &mut *ext; - ext.log(beg, size, topic1, topic2, topic3, topic4); - } - - - #[link(name="evmjit")] - extern "C" { - pub fn evmjit_create_schedule() -> *mut JitSchedule; - pub fn evmjit_destroy_schedule(schedule: *mut JitSchedule); - pub fn evmjit_create_runtime_data() -> *mut JitRuntimeData; - pub fn evmjit_destroy_runtime_data(data: *mut JitRuntimeData); - pub fn evmjit_destroy_context(context: *mut JitContext); - pub fn evmjit_exec(context: *mut JitContext, schedule: *mut JitSchedule) -> JitReturnCode; - } - - // ExtHandle is not a C type, so we need to allow "improper_ctypes" - #[link(name="evmjit")] - #[allow(improper_ctypes)] - extern "C" { - pub fn evmjit_create_context(data: *mut JitRuntimeData, ext: *mut ExtHandle) -> *mut JitContext; - } -} - -#[test] -fn ffi_test() { - unsafe { - let data = evmjit_create_runtime_data(); - let schedule = evmjit_create_schedule(); - let context = evmjit_create_context(data, &mut ExtHandle::empty()); - - let code = evmjit_exec(context, schedule); - assert_eq!(code, JitReturnCode::Stop); - - evmjit_destroy_schedule(schedule); - evmjit_destroy_runtime_data(data); - evmjit_destroy_context(context); - } -} - -#[test] -fn handle_test() { - unsafe { - let mut ext = ExtHandle::empty(); - let mut context = ContextHandle::new(RuntimeDataHandle::new(), ScheduleHandle::new(), &mut ext); - assert_eq!(context.exec(), ReturnCode::Stop); - } -} - -#[test] -fn hash_to_int() { - let h = H256 { words:[0x0123456789abcdef, 0, 0, 0] }; - let i = I256::from(h); - assert_eq!([0u64, 0, 0, 0xefcdab8967452301], i.words); - assert_eq!(H256::from(i).words, h.words); -} diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 6e21238e60..ac8a1825d6 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -857,11 +857,6 @@ usage! { "--no-periodic-snapshot", "Disable automated snapshots which usually occur once every 10000 blocks.", - ["Virtual Machine options"] - FLAG flag_jitvm: (bool) = false, or |c: &Config| c.vm.as_ref()?.jit.clone(), - "--jitvm", - "Enable the JIT VM.", - ["Whisper options"] FLAG flag_whisper: (bool) = false, or |c: &Config| c.whisper.as_ref()?.enabled, "--whisper", @@ -1023,7 +1018,6 @@ struct Config { mining: Option, footprint: Option, snapshots: Option, - vm: Option, misc: Option, stratum: Option, whisper: Option, @@ -1240,12 +1234,6 @@ struct Snapshots { disable_periodic: Option, } -#[derive(Default, Debug, PartialEq, Deserialize)] -#[serde(deny_unknown_fields)] -struct VM { - jit: Option, -} - #[derive(Default, Debug, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] struct Misc { @@ -1269,7 +1257,7 @@ mod tests { use super::{ Args, ArgsError, Config, Operating, Account, Ui, Network, Ws, Rpc, Ipc, Dapps, Ipfs, Mining, Footprint, - Snapshots, VM, Misc, Whisper, SecretStore, + Snapshots, Misc, Whisper, SecretStore, }; use toml; use clap::{ErrorKind as ClapErrorKind}; @@ -1660,9 +1648,6 @@ mod tests { arg_snapshot_at: "latest".into(), flag_no_periodic_snapshot: false, - // -- Virtual Machine Options - flag_jitvm: false, - // -- Whisper options. flag_whisper: false, arg_whisper_pool_size: 20, @@ -1906,9 +1891,6 @@ mod tests { snapshots: Some(Snapshots { disable_periodic: Some(true), }), - vm: Some(VM { - jit: Some(false), - }), misc: Some(Misc { ntp_servers: Some(vec!["0.parity.pool.ntp.org:123".into()]), logging: Some("own_tx=trace".into()), diff --git a/parity/cli/tests/config.full.toml b/parity/cli/tests/config.full.toml index 702a186319..2e546b5f1e 100644 --- a/parity/cli/tests/config.full.toml +++ b/parity/cli/tests/config.full.toml @@ -147,9 +147,6 @@ num_verifiers = 6 [snapshots] disable_periodic = false -[vm] -jit = false - [misc] logging = "own_tx=trace" log_file = "/var/log/parity.log" diff --git a/parity/cli/tests/config.toml b/parity/cli/tests/config.toml index abdf3e0c79..245935de12 100644 --- a/parity/cli/tests/config.toml +++ b/parity/cli/tests/config.toml @@ -74,9 +74,6 @@ scale_verifiers = false [snapshots] disable_periodic = true -[vm] -jit = false - [misc] ntp_servers = ["0.parity.pool.ntp.org:123"] logging = "own_tx=trace" diff --git a/parity/configuration.rs b/parity/configuration.rs index f242edb0f6..eb6ce713db 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -403,11 +403,7 @@ impl Configuration { } fn vm_type(&self) -> Result { - if self.args.flag_jitvm { - VMType::jit().ok_or("Parity is built without the JIT EVM.".into()) - } else { - Ok(VMType::Interpreter) - } + Ok(VMType::Interpreter) } fn miner_extras(&self) -> Result { diff --git a/scripts/cov.sh b/scripts/cov.sh index bd733703ce..b199da31aa 100755 --- a/scripts/cov.sh +++ b/scripts/cov.sh @@ -12,7 +12,7 @@ ### Running coverage set -x -RUSTFLAGS="-C link-dead-code" cargo test --all --exclude evmjit --no-run || exit $? +RUSTFLAGS="-C link-dead-code" cargo test --all --no-run || exit $? KCOV_TARGET="target/cov" KCOV_FLAGS="--verify" EXCLUDE="/usr/lib,/usr/include,$HOME/.cargo,$HOME/.multirust,rocksdb,secp256k1" diff --git a/scripts/doc.sh b/scripts/doc.sh index ae209ad46f..f0022610a5 100755 --- a/scripts/doc.sh +++ b/scripts/doc.sh @@ -1,5 +1,5 @@ #!/bin/sh # generate documentation only for partiy and ethcore libraries -cargo doc --no-deps --verbose --all --exclude parity-ipfs-api --exclude evmjit && +cargo doc --no-deps --verbose --all --exclude parity-ipfs-api && echo '' > target/doc/index.html diff --git a/scripts/hook.sh b/scripts/hook.sh index cb8085a028..2d64d5782f 100755 --- a/scripts/hook.sh +++ b/scripts/hook.sh @@ -7,6 +7,6 @@ echo "set -e" >> $FILE # Run release build echo "cargo build --features dev" >> $FILE # Build tests -echo "cargo test --no-run --features dev --all --exclude parity-ipfs-api --exclude evmjit" >> $FILE +echo "cargo test --no-run --features dev --all --exclude parity-ipfs-api" >> $FILE echo "" >> $FILE chmod +x $FILE diff --git a/test.sh b/test.sh index 7e98001887..84940a6aca 100755 --- a/test.sh +++ b/test.sh @@ -43,5 +43,5 @@ fi # Running test's echo "________Running Parity Full Test Suite________" -cargo test -j 8 $OPTIONS --features "$FEATURES" --all --exclude evmjit $1 +cargo test -j 8 $OPTIONS --features "$FEATURES" --all $1 -- GitLab From 9aaedad64f13cf21a3bec064480c4c61937d8865 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 4 Apr 2018 17:49:43 +0800 Subject: [PATCH 030/263] Include suicided accounts in state diff (#8297) * Include suicided accounts in state diff * Shorten form match -> if let * Test suicide trace diff in State --- ethcore/src/state/mod.rs | 58 +++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 1fe4dd4d6d..757f545115 100755 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -855,16 +855,26 @@ impl State { })) } - fn query_pod(&mut self, query: &PodState) -> trie::Result<()> { - for (address, pod_account) in query.get() { + // Return a list of all touched addresses in cache. + fn touched_addresses(&self) -> Vec
{ + assert!(self.checkpoints.borrow().is_empty()); + self.cache.borrow().iter().map(|(add, _)| *add).collect() + } + + fn query_pod(&mut self, query: &PodState, touched_addresses: &[Address]) -> trie::Result<()> { + let pod = query.get(); + + for address in touched_addresses { if !self.ensure_cached(address, RequireCache::Code, true, |a| a.is_some())? { continue } - // needs to be split into two parts for the refcell code here - // to work. - for key in pod_account.storage.keys() { - self.storage_at(address, key)?; + if let Some(pod_account) = pod.get(address) { + // needs to be split into two parts for the refcell code here + // to work. + for key in pod_account.storage.keys() { + self.storage_at(address, key)?; + } } } @@ -874,9 +884,10 @@ impl State { /// Returns a `StateDiff` describing the difference from `orig` to `self`. /// Consumes self. pub fn diff_from(&self, orig: State) -> trie::Result { + let addresses_post = self.touched_addresses(); let pod_state_post = self.to_pod(); let mut state_pre = orig; - state_pre.query_pod(&pod_state_post)?; + state_pre.query_pod(&pod_state_post, &addresses_post)?; Ok(pod_state::diff_pod(&state_pre.to_pod(), &pod_state_post)) } @@ -2202,4 +2213,37 @@ mod tests { assert!(state.exists(&d).unwrap()); assert!(!state.exists(&e).unwrap()); } + + #[test] + fn should_trace_diff_suicided_accounts() { + use pod_account; + + let a = 10.into(); + let db = get_temp_state_db(); + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.add_balance(&a, &100.into(), CleanupMode::ForceCreate).unwrap(); + state.commit().unwrap(); + state.drop() + }; + + let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + let original = state.clone(); + state.kill_account(&a); + + assert_eq!(original.touched_addresses(), vec![]); + assert_eq!(state.touched_addresses(), vec![a]); + + let diff = state.diff_from(original).unwrap(); + let diff_map = diff.get(); + assert_eq!(diff_map.len(), 1); + assert!(diff_map.get(&a).is_some()); + assert_eq!(diff_map.get(&a), + pod_account::diff_pod(Some(&PodAccount { + balance: U256::from(100), + nonce: U256::zero(), + code: Some(Default::default()), + storage: Default::default() + }), None).as_ref()); + } } -- GitLab From 0455aa96bfbe266b746b72814a39a4e34371120f Mon Sep 17 00:00:00 2001 From: Dmitry Kashitsyn Date: Wed, 4 Apr 2018 16:50:01 +0700 Subject: [PATCH 031/263] Ethcore now uses rayon to 0.9 as a dependency (#8296) (#8302) --- Cargo.lock | 2 +- ethcore/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d14bcc173..72f2c9e250 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -491,7 +491,7 @@ dependencies = [ "patricia-trie 0.1.0", "price-info 1.11.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rlp_compress 0.1.0", "rlp_derive 0.1.0", diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index e870629929..9b943fbc1b 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -45,7 +45,7 @@ num_cpus = "1.2" parity-machine = { path = "../machine" } parking_lot = "0.5" price-info = { path = "../price-info" } -rayon = "0.8" +rayon = "0.9" rand = "0.4" rlp = { path = "../util/rlp" } rlp_compress = { path = "../util/rlp_compress" } -- GitLab From e12a5159a817c2cc261482111e3867599e7680db Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 4 Apr 2018 11:50:28 +0200 Subject: [PATCH 032/263] Cleaner binary shutdown system (#8284) * Cleaner shutdown system when executing * Simplify set_exit_handler for Client * Minor change * Fix submodule --- ethcore/src/client/client.rs | 11 ++- parity/run.rs | 166 ++++++++++++++++++++--------------- 2 files changed, 100 insertions(+), 77 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c7ad18dcbd..31f8f2f25d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -220,7 +220,7 @@ pub struct Client { registrar_address: Option
, /// A closure to call when we want to restart the client - exit_handler: Mutex) + 'static + Send>>>, + exit_handler: Mutex>>, importer: Importer, } @@ -825,8 +825,11 @@ impl Client { self.notify.write().push(Arc::downgrade(&target)); } - /// Set a closure to call when we want to restart the client - pub fn set_exit_handler(&self, f: F) where F: Fn(bool, Option) + 'static + Send { + /// Set a closure to call when the client wants to be restarted. + /// + /// The parameter passed to the callback is the name of the new chain spec to use after + /// the restart. + pub fn set_exit_handler(&self, f: F) where F: Fn(String) + 'static + Send { *self.exit_handler.lock() = Some(Box::new(f)); } @@ -1625,7 +1628,7 @@ impl BlockChainClient for Client { return; } if let Some(ref h) = *self.exit_handler.lock() { - (*h)(true, Some(new_spec_name)); + (*h)(new_spec_name); } else { warn!("Not hypervised; cannot change chain."); } diff --git a/parity/run.rs b/parity/run.rs index 9b64a40d9d..4c73fe63f6 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::any::Any; use std::fmt; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; @@ -182,7 +183,7 @@ impl ::local_store::NodeInfo for FullNodeInfo { type LightClient = ::light::client::Client<::light_helpers::EpochFetch>; // helper for light execution. -fn execute_light_impl(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<((bool, Option), Weak), String> { +fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result { use light::client as light_client; use ethsync::{LightSyncParams, LightSync, ManageNetwork}; use parking_lot::{Mutex, RwLock}; @@ -260,7 +261,7 @@ fn execute_light_impl(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<((bool, Option), Weak), String> { +fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: Cr, + on_updater_rq: Rr) -> Result + where Cr: Fn(String) + 'static + Send, + Rr: Fn() + 'static + Send +{ // load spec let spec = cmd.spec.spec(&cmd.dirs.cache)?; @@ -854,7 +856,7 @@ pub fn execute_impl(cmd: RunCmd, can_restart: bool, logger: Arc) }); // the watcher must be kept alive. - let _watcher = match cmd.no_periodic_snapshot { + let watcher = match cmd.no_periodic_snapshot { true => None, false => { let sync = sync_provider.clone(); @@ -881,23 +883,58 @@ pub fn execute_impl(cmd: RunCmd, can_restart: bool, logger: Arc) open_dapp(&cmd.dapps_conf, &cmd.http_conf, &dapp)?; } - // Create a weak reference to the client so that we can wait on shutdown until it is dropped - let weak_client = Arc::downgrade(&client); - - // Handle exit - let restart = wait_for_exit(Some(updater), Some(client), can_restart); + client.set_exit_handler(on_client_rq); + updater.set_exit_handler(on_updater_rq); - info!("Finishing work, please wait..."); - - // drop this stuff as soon as exit detected. - drop((ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)); + Ok(RunningClient::Full { + informant, + client, + keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + }) +} - // to make sure timer does not spawn requests while shutdown is in progress - informant.shutdown(); - // just Arc is dropping here, to allow other reference release in its default time - drop(informant); +enum RunningClient { + Light { + informant: Arc>, + client: Arc, + keep_alive: Box, + }, + Full { + informant: Arc>, + client: Arc, + keep_alive: Box, + }, +} - Ok((restart, weak_client)) +impl RunningClient { + fn shutdown(self) { + match self { + RunningClient::Light { informant, client, keep_alive } => { + // Create a weak reference to the client so that we can wait on shutdown + // until it is dropped + let weak_client = Arc::downgrade(&client); + drop(keep_alive); + informant.shutdown(); + drop(informant); + drop(client); + wait_for_drop(weak_client); + }, + RunningClient::Full { informant, client, keep_alive } => { + info!("Finishing work, please wait..."); + // Create a weak reference to the client so that we can wait on shutdown + // until it is dropped + let weak_client = Arc::downgrade(&client); + // drop this stuff as soon as exit detected. + drop(keep_alive); + // to make sure timer does not spawn requests while shutdown is in progress + informant.shutdown(); + // just Arc is dropping here, to allow other reference release in its default time + drop(informant); + drop(client); + wait_for_drop(weak_client); + } + } + } } pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<(bool, Option), String> { @@ -917,18 +954,34 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R // increase max number of open files raise_fd_limit(); - fn wait(res: Result<((bool, Option), Weak), String>) -> Result<(bool, Option), String> { - res.map(|(restart, weak_client)| { - wait_for_drop(weak_client); - restart - }) - } + let exit = Arc::new((Mutex::new((false, None)), Condvar::new())); - if cmd.light { - wait(execute_light_impl(cmd, can_restart, logger)) + let running_client = if cmd.light { + execute_light_impl(cmd, logger)? + } else if can_restart { + let e1 = exit.clone(); + let e2 = exit.clone(); + execute_impl(cmd, logger, + move |new_chain: String| { *e1.0.lock() = (true, Some(new_chain)); e1.1.notify_all(); }, + move || { *e2.0.lock() = (true, None); e2.1.notify_all(); })? } else { - wait(execute_impl(cmd, can_restart, logger)) - } + trace!(target: "mode", "Not hypervised: not setting exit handlers."); + execute_impl(cmd, logger, move |_| {}, move || {})? + }; + + // Handle possible exits + CtrlC::set_handler({ + let e = exit.clone(); + move || { e.1.notify_all(); } + }); + + // Wait for signal + let mut l = exit.0.lock(); + let _ = exit.1.wait(&mut l); + + running_client.shutdown(); + + Ok(l.clone()) } #[cfg(not(windows))] @@ -1029,39 +1082,6 @@ fn build_create_account_hint(spec: &SpecType, keys: &str) -> String { format!("You can create an account via RPC, UI or `parity account new --chain {} --keys-path {}`.", spec, keys) } -fn wait_for_exit( - updater: Option>, - client: Option>, - can_restart: bool -) -> (bool, Option) { - let exit = Arc::new((Mutex::new((false, None)), Condvar::new())); - - // Handle possible exits - let e = exit.clone(); - CtrlC::set_handler(move || { e.1.notify_all(); }); - - if can_restart { - if let Some(updater) = updater { - // Handle updater wanting to restart us - let e = exit.clone(); - updater.set_exit_handler(move || { *e.0.lock() = (true, None); e.1.notify_all(); }); - } - - if let Some(client) = client { - // Handle updater wanting to restart us - let e = exit.clone(); - client.set_exit_handler(move |restart, new_chain: Option| { *e.0.lock() = (restart, new_chain); e.1.notify_all(); }); - } - } else { - trace!(target: "mode", "Not hypervised: not setting exit handlers."); - } - - // Wait for signal - let mut l = exit.0.lock(); - let _ = exit.1.wait(&mut l); - l.clone() -} - fn wait_for_drop(w: Weak) { let sleep_duration = Duration::from_secs(1); let warn_timeout = Duration::from_secs(60); -- GitLab From ef80698deb54dc3e2c192b448034896a021ddbb5 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 4 Apr 2018 11:54:41 +0200 Subject: [PATCH 033/263] Upgrader `remove raw unwrap` and bump semver (#8251) * remove raw unwrap and bump semver * bump rustc_version * Semver -> SemVer --- Cargo.lock | 30 +++++++++++++++--------------- Cargo.toml | 2 +- parity/upgrade.rs | 17 ++++++++++++----- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- updater/Cargo.toml | 2 +- util/version/Cargo.toml | 2 +- 7 files changed, 32 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72f2c9e250..8d85306aa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,7 +104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -773,7 +773,7 @@ dependencies = [ "ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -897,7 +897,7 @@ dependencies = [ "plain_hasher 0.1.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "triehash 0.1.0", ] @@ -1923,8 +1923,8 @@ dependencies = [ "rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rpc-cli 1.4.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2121,7 +2121,7 @@ dependencies = [ "rlp 0.2.1", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2175,7 +2175,7 @@ dependencies = [ "parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)", "parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6)", "parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079)", - "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2230,7 +2230,7 @@ dependencies = [ "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "path 0.1.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2241,7 +2241,7 @@ version = "1.11.0" dependencies = [ "ethcore-bytes 0.1.0", "rlp 0.2.1", - "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2764,10 +2764,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc_version" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2809,7 +2809,7 @@ dependencies = [ [[package]] name = "semver" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3289,7 +3289,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3759,13 +3759,13 @@ dependencies = [ "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69" +"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a" "checksum rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc9f2e05fd6a3ce1530cd5dbcc553d2f94d7749fe3e4f5b443668eddd842889e" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" "checksum sct 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1137b767bbe1c4d30656993bdd97422ed41255d9400b105d735f8c7d9e800632" -"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4763b773978e495252615e814d2ad04773b2c1f85421c7913869a537f35cb406" "checksum serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8ab31f00ae5574bb643c196d5e302961c122da1c768604c6d16a35c5d551948a" diff --git a/Cargo.toml b/Cargo.toml index f14b64fe89..d09b8a08f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ textwrap = "0.9" num_cpus = "1.2" number_prefix = "0.2" rpassword = "1.0" -semver = "0.6" +semver = "0.9" ansi_term = "0.10" parking_lot = "0.5" regex = "0.2" diff --git a/parity/upgrade.rs b/parity/upgrade.rs index fcea2560ec..c5c2e1ed48 100644 --- a/parity/upgrade.rs +++ b/parity/upgrade.rs @@ -16,7 +16,7 @@ //! Parity upgrade logic -use semver::Version; +use semver::{Version, SemVerError}; use std::collections::*; use std::fs::{self, File, create_dir_all}; use std::env; @@ -32,6 +32,13 @@ pub enum Error { CannotCreateConfigPath, CannotWriteVersionFile, CannotUpdateVersionFile, + SemVer(SemVerError), +} + +impl From for Error { + fn from(err: SemVerError) -> Self { + Error::SemVer(err) + } } const CURRENT_VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -74,7 +81,7 @@ fn push_upgrades(upgrades: &mut UpgradeList) { // dummy upgrade (remove when the first one is in) upgrades.insert( - UpgradeKey { old_version: Version::parse("0.9.0").unwrap(), new_version: Version::parse("1.0.0").unwrap() }, + UpgradeKey { old_version: Version::new(0, 9, 0), new_version: Version::new(1, 0, 0)}, dummy_upgrade); } @@ -82,7 +89,7 @@ fn upgrade_from_version(previous_version: &Version) -> Result { let mut upgrades = HashMap::new(); push_upgrades(&mut upgrades); - let current_version = Version::parse(CURRENT_VERSION).unwrap(); + let current_version = Version::parse(CURRENT_VERSION)?; let mut count = 0; for upgrade_key in upgrades.keys() { @@ -114,12 +121,12 @@ fn with_locked_version(db_path: Option<&str>, script: F) -> Result Date: Wed, 4 Apr 2018 19:05:21 +0700 Subject: [PATCH 034/263] Ethcore now uses Rayon 1.0 as a dependency (#8296) (#8304) --- Cargo.lock | 90 ++++++++++++++++++++++++++++++---------------- ethcore/Cargo.toml | 2 +- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d85306aa0..04a48ee941 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ name = "backtrace-sys" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -184,10 +184,10 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -228,15 +228,6 @@ dependencies = [ "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "coco" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "common-types" version = "0.1.0" @@ -273,6 +264,37 @@ name = "crossbeam" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crossbeam-deque" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crunchy" version = "0.1.6" @@ -381,7 +403,7 @@ version = "0.5.7" source = "git+https://github.com/paritytech/rust-secp256k1#db81cfea59014b4d176f10f86ed52e1a130b6822" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -491,7 +513,7 @@ dependencies = [ "patricia-trie 0.1.0", "price-info 1.11.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rlp_compress 0.1.0", "rlp_derive 0.1.0", @@ -1104,7 +1126,7 @@ name = "hidapi" version = "0.3.1" source = "git+https://github.com/paritytech/hidapi-rs#e77ea09c98f29ea8855dd9cd9461125a28ca9125" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1380,7 +1402,7 @@ dependencies = [ name = "keccak-hash" version = "0.1.0" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1468,7 +1490,7 @@ name = "libusb-sys" version = "0.2.4" source = "git+https://github.com/paritytech/libusb-sys#14bdb698003731b6344a79e1d814704e44363e7c" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1542,6 +1564,11 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memoffset" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memory-cache" version = "0.1.0" @@ -1613,7 +1640,7 @@ name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2570,28 +2597,28 @@ name = "rayon" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon" -version = "0.9.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2690,7 +2717,7 @@ name = "rocksdb-sys" version = "0.3.0" source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", @@ -3597,14 +3624,16 @@ dependencies = [ "checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" -"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" +"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" -"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" +"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum ct-logs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61cd11fb222fecf889f4531855c614548e92e8bd2eb178e35296885df5ee9a7c" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" @@ -3682,6 +3711,7 @@ dependencies = [ "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" +"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e3d709ffbb330e1566dc2f2a3c9b58a5ad4a381f740b810cd305dc3f089bc160" @@ -3743,8 +3773,8 @@ dependencies = [ "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" -"checksum rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" -"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" +"checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" +"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 9b943fbc1b..ba984f315f 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -45,7 +45,7 @@ num_cpus = "1.2" parity-machine = { path = "../machine" } parking_lot = "0.5" price-info = { path = "../price-info" } -rayon = "0.9" +rayon = "1.0" rand = "0.4" rlp = { path = "../util/rlp" } rlp_compress = { path = "../util/rlp_compress" } -- GitLab From 991f0cac6ebb75b2700fc2ad34bbfa05c463e3e3 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 4 Apr 2018 15:38:04 +0200 Subject: [PATCH 035/263] Update some dependencies (#8285) --- Cargo.lock | 267 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 199 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04a48ee941..59c5cd667c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,7 +113,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -273,6 +273,15 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-epoch" version = "0.3.1" @@ -287,6 +296,19 @@ dependencies = [ "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-epoch" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.2.2" @@ -295,6 +317,14 @@ dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-utils" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crunchy" version = "0.1.6" @@ -571,7 +601,7 @@ dependencies = [ "ethcore-network 1.11.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -630,7 +660,7 @@ dependencies = [ "ethcore-transaction 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", "keccak-hash 0.1.0", @@ -706,7 +736,7 @@ dependencies = [ "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ethsync 1.11.0", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -721,8 +751,8 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -755,8 +785,8 @@ dependencies = [ "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -972,12 +1002,12 @@ dependencies = [ name = "fetch" version = "0.1.0" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1022,7 +1052,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.18" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1030,7 +1060,7 @@ name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1039,7 +1069,7 @@ name = "futures-timer" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1087,7 +1117,7 @@ dependencies = [ "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)", ] @@ -1179,7 +1209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1189,8 +1219,8 @@ dependencies = [ "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1202,11 +1232,11 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ct-logs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-rustls 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1307,7 +1337,7 @@ name = "jsonrpc-core" version = "8.0.1" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1368,8 +1398,8 @@ dependencies = [ "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1755,7 +1785,7 @@ dependencies = [ name = "node-health" version = "0.1.0" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "ntp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1825,8 +1855,11 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.1.40" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num-traits" @@ -1846,7 +1879,7 @@ name = "number_prefix" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1868,7 +1901,7 @@ name = "ordered-float" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1915,7 +1948,7 @@ dependencies = [ "ethkey 0.3.0", "ethsync 1.11.0", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1973,7 +2006,7 @@ dependencies = [ "ethcore-devtools 1.11.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2037,7 +2070,7 @@ dependencies = [ "ethcore-bytes 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -2094,8 +2127,8 @@ dependencies = [ name = "parity-reactor" version = "0.1.0" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2121,7 +2154,7 @@ dependencies = [ "ethstore 0.2.0", "ethsync 1.11.0", "fetch 0.1.0", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hardware-wallet 1.11.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2164,7 +2197,7 @@ dependencies = [ name = "parity-rpc-client" version = "1.4.0" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "keccak-hash 0.1.0", @@ -2183,13 +2216,13 @@ version = "0.1.5" source = "git+https://github.com/nikvolf/parity-tokio-ipc#d6c5b3cfcc913a1b9cf0f0562a10b083ceb9fb7c" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes)", "tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2431,7 +2464,7 @@ name = "price-info" version = "1.11.0" dependencies = [ "fetch 0.1.0", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2491,7 +2524,7 @@ dependencies = [ [[package]] name = "protobuf" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2650,7 +2683,7 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", ] @@ -2659,7 +2692,7 @@ name = "relay" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2751,7 +2784,7 @@ name = "rpc-cli" version = "1.4.0" dependencies = [ "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.11.0", "parity-rpc-client 1.4.0", "rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2887,7 +2920,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3138,29 +3171,56 @@ dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-core" -version = "0.1.12" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3169,10 +3229,10 @@ version = "0.1.0" source = "git+https://github.com/nikvolf/tokio-named-pipes#0b9b728eaeb0a6673c287ac7692be398fd651752" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3180,26 +3240,39 @@ name = "tokio-proto" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-reactor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-rustls" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3208,7 +3281,33 @@ name = "tokio-service" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3216,24 +3315,46 @@ name = "tokio-timer" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-timer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-udp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-uds" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3279,7 +3400,7 @@ name = "trezor-sys" version = "1.0.0" source = "git+https://github.com/paritytech/trezor-sys#8a401705e58c83db6c29c199d9577b78fde40709" dependencies = [ - "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3632,8 +3753,11 @@ dependencies = [ "checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4e2817eb773f770dcb294127c011e22771899c21d18fce7dd739c0b9832e81" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum ct-logs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61cd11fb222fecf889f4531855c614548e92e8bd2eb178e35296885df5ee9a7c" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" @@ -3660,7 +3784,7 @@ dependencies = [ "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0bab5b5e94f5c31fc764ba5dd9ad16568aae5d4825538c01d6bca680c9bf94a7" +"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5cedfe9b6dc756220782cc1ba5bcb1fa091cdcba155e40d3556159c3db58043" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" @@ -3731,7 +3855,7 @@ dependencies = [ "checksum num-bigint 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "81b483ea42927c463e191802e7334556b48e7875297564c0e9951bd3a0ae53e3" "checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" "checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" -"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902" @@ -3762,7 +3886,7 @@ dependencies = [ "checksum primal-estimate 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56ea4531dde757b56906493c8604641da14607bf9cdaa80fb9c9cabd2429f8d5" "checksum primal-sieve 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c0911abe7b63ddec27527ba7579c3017f645eb992be6ddbfad605e34aca01876" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" -"checksum protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "568a15e4d572d9a5e63ae3a55f84328c984842887db179b40b4cc6a608bac6a4" +"checksum protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40e2484e639dcae0985fc483ad76ce7ad78ee5aa092751d7d538f0b20d76486b" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54d440c3b56eee028aa5d4f18cbed8c6e0c9ae23563b93f344beb7e73854ea02" "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" @@ -3833,13 +3957,20 @@ dependencies = [ "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" -"checksum tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "52b4e32d8edbf29501aabb3570f027c6ceb00ccef6538f4bddba0200503e74e8" -"checksum tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ab83e7adb5677e42e405fa4ceff75659d93c4d7d7dd22f52fcec59ee9f02af" +"checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" +"checksum tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "799492ccba3d8ed5e41f2520a7cfd504cb65bbfe5fbbbd0012e335ae5f188051" +"checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" +"checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a" "checksum tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes)" = "" "checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" +"checksum tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3cedc8e5af5131dc3423ffa4f877cce78ad25259a9a62de0613735a13ebc64b" "checksum tokio-rustls 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9263e472d976e4345e50c6cce4cfe6b17c71593ea593cce1df26f1efd36debb" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" +"checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" +"checksum tokio-threadpool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3d05cdd6a78005e535d2b27c21521bdf91fbb321027a62d8e178929d18966d" "checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" +"checksum tokio-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "29a89e4ad0c8f1e4c9860e605c38c69bfdad3cccd4ea446e58ff588c1c07a397" +"checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a" "checksum tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6116c71be48f8f1656551fd16458247fdd6c03201d7893ad81189055fcde03e8" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -- GitLab From d57944ffb9306d4322b9bfeb8be0d7dc57949856 Mon Sep 17 00:00:00 2001 From: East Coin Date: Wed, 4 Apr 2018 23:00:21 +0900 Subject: [PATCH 036/263] Implement Easthub chain spec (#8295) --- ethcore/res/ethereum/easthub.json | 89 +++++++++++++++++++++++++++++++ ethcore/src/ethereum/mod.rs | 5 ++ parity/cli/mod.rs | 2 +- parity/params.rs | 4 ++ 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 ethcore/res/ethereum/easthub.json diff --git a/ethcore/res/ethereum/easthub.json b/ethcore/res/ethereum/easthub.json new file mode 100644 index 0000000000..ddc170d8a6 --- /dev/null +++ b/ethcore/res/ethereum/easthub.json @@ -0,0 +1,89 @@ +{ + "name": "Easthub", + "dataDir": "easthub", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x2B5E3AF16B1880000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "ecip1017EraRounds": 5000000, + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x0000000000000000000000000000000000000000", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x7", + "chainID": "0x7", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x0400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x323031382045617374636f696e2050726f6a656374", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://ca57e40edb95a08a81b85a91e91099a0aaab777ad329ea7f3f772bc0fd511a276a5d84944725d181ff80f8c7dc1034814bff25b9723b03363d48617fed4b15f0@13.125.109.174:30303", + "enode://57254e23a7e5fe1e081ee5d1b236e37735a120660daeb4bf1fec6943a82c915c5b6fad23eeb1a43a27c23f236e084e8051aaa28f7d4139149f844747facb62bb@18.217.39.51:30303", + "enode://ef248f327c73c0318f4d51a62270b0612f3c4a4fd04b77d04854dc355980e137708d1e48811bc91387b0d7eb85cf447d8bbc095404f39bb7064e76751bda9cd4@52.221.160.236:30303", + "enode://bf6f0e37dd733cf04f2b079c753d2dea7cc7c59d8637eff9a8e63e17d08e2bfc91229fbb2dff08fe6ee12e51c1b6f8ed969d7042b89d77029e7ea02b05e17be3@18.197.47.177:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "20c1252a8cb33a7a9a257b2a4cfeed8daf87c847": { + "balance": "100000000000000000000000000" + }, + "9dcd37c8e5aea3a0d37c5d0a2db683362d81febd": { + "balance": "100000000000000000000000000" + }, + "9eff080302333f44a60bfd8c33bd63015c6d921b": { + "balance": "100000000000000000000000000" + }, + "c1df2e5de98d5c41fec0642dc302971f5d3500bd": { + "balance": "100000000000000000000000000" + }, + "2e0fb67cd1d029cbaea4b74c361efcc06b3105fd": { + "balance": "100000000000000000000000000" + }, + "2b6425cc3cd90654f077889ef7262ac2f5846460": { + "balance": "100000000000000000000000000" + }, + "28562041230c6d575e233e4ed1b35c514884d964": { + "balance": "100000000000000000000000000" + }, + "16eb6896a5a83d39ac762d79d21f825f5f980d12": { + "balance": "100000000000000000000000000" + }, + "f09e3f1de27dd03a1ac0a021b2d9e45bde1b360c": { + "balance": "100000000000000000000000000" + }, + "2d87547819c6433f208ee3096161cdb2835a2333": { + "balance": "100000000000000000000000000" + } + } +} diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index e892cf56a4..aea53ecaea 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -71,6 +71,11 @@ pub fn new_ellaism<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/ellaism.json")) } +/// Create a new Easthub mainnet chain spec. +pub fn new_easthub<'a, T: Into>>(params: T) -> Spec { + load(params.into(), include_bytes!("../../res/ethereum/easthub.json")) +} + /// Create a new Kovan testnet chain spec. pub fn new_kovan<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/kovan.json")) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index ac8a1825d6..2cc0ef7c29 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -294,7 +294,7 @@ usage! { ARG arg_chain: (String) = "foundation", or |c: &Config| c.parity.as_ref()?.chain.clone(), "--chain=[CHAIN]", - "Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, musicoin, ellaism, testnet, kovan or dev.", + "Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, musicoin, ellaism, easthub, testnet, kovan or dev.", ARG arg_keys_path: (String) = "$BASE/keys", or |c: &Config| c.parity.as_ref()?.keys_path.clone(), "--keys-path=[PATH]", diff --git a/parity/params.rs b/parity/params.rs index 4b5cd94093..ef58bc37b6 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -38,6 +38,7 @@ pub enum SpecType { Expanse, Musicoin, Ellaism, + Easthub, Dev, Custom(String), } @@ -62,6 +63,7 @@ impl str::FromStr for SpecType { "expanse" => SpecType::Expanse, "musicoin" => SpecType::Musicoin, "ellaism" => SpecType::Ellaism, + "easthub" => SpecType::Easthub, "dev" => SpecType::Dev, other => SpecType::Custom(other.into()), }; @@ -80,6 +82,7 @@ impl fmt::Display for SpecType { SpecType::Expanse => "expanse", SpecType::Musicoin => "musicoin", SpecType::Ellaism => "ellaism", + SpecType::Easthub => "easthub", SpecType::Kovan => "kovan", SpecType::Dev => "dev", SpecType::Custom(ref custom) => custom, @@ -99,6 +102,7 @@ impl SpecType { SpecType::Expanse => Ok(ethereum::new_expanse(params)), SpecType::Musicoin => Ok(ethereum::new_musicoin(params)), SpecType::Ellaism => Ok(ethereum::new_ellaism(params)), + SpecType::Easthub => Ok(ethereum::new_easthub(params)), SpecType::Kovan => Ok(ethereum::new_kovan(params)), SpecType::Dev => Ok(Spec::new_instant()), SpecType::Custom(ref filename) => { -- GitLab From 811d165458f8e068120a19ca79337b369ef8bbae Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Wed, 4 Apr 2018 18:14:59 +0300 Subject: [PATCH 037/263] Validate if gas limit is not zero (#8307) --- ethcore/src/machine.rs | 4 ++-- json/src/spec/genesis.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index ad36aa69d7..fa6a62454e 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -203,10 +203,11 @@ impl EthereumMachine { /// The gas floor target must not be lower than the engine's minimum gas limit. pub fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, gas_ceil_target: U256) { header.set_difficulty(parent.difficulty().clone()); + let gas_limit = parent.gas_limit().clone(); + assert!(!gas_limit.is_zero(), "Gas limit should be > 0"); if let Some(ref ethash_params) = self.ethash_extensions { let gas_limit = { - let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.params().gas_limit_bound_divisor; let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into(); let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into(); @@ -238,7 +239,6 @@ impl EthereumMachine { } header.set_gas_limit({ - let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.params().gas_limit_bound_divisor; if gas_limit < gas_floor_target { cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) diff --git a/json/src/spec/genesis.rs b/json/src/spec/genesis.rs index 984053e77a..f595e7750f 100644 --- a/json/src/spec/genesis.rs +++ b/json/src/spec/genesis.rs @@ -16,7 +16,7 @@ //! Spec genesis deserialization. -use uint::Uint; +use uint::{Uint, self}; use hash::{Address, H256}; use bytes::Bytes; use spec::Seal; @@ -37,6 +37,7 @@ pub struct Genesis { pub parent_hash: Option, /// Gas limit. #[serde(rename="gasLimit")] + #[serde(deserialize_with="uint::validate_non_zero")] pub gas_limit: Uint, /// Transactions root. #[serde(rename="transactionsRoot")] -- GitLab From ff0ce70169ca556c978fbcf013528b7a3daf12e9 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Apr 2018 16:11:21 +0800 Subject: [PATCH 038/263] Decouple timestamp open-block-assignment/verification to Engine (#8305) --- ethcore/src/block.rs | 2 +- ethcore/src/client/test_client.rs | 2 +- ethcore/src/engines/instant_seal.rs | 11 +++++++++++ ethcore/src/engines/mod.rs | 13 +++++++++++++ ethcore/src/header.rs | 8 -------- ethcore/src/verification/verification.rs | 12 +++++++----- 6 files changed, 33 insertions(+), 15 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index f8ccb91964..2280b40dea 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -267,7 +267,7 @@ impl<'x> OpenBlock<'x> { r.block.header.set_parent_hash(parent.hash()); r.block.header.set_number(number); r.block.header.set_author(author); - r.block.header.set_timestamp_now(parent.timestamp()); + r.block.header.set_timestamp(engine.open_block_header_timestamp(parent.timestamp())); r.block.header.set_extra_data(extra_data); let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit); diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 31d9357668..6d61035af2 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -397,7 +397,7 @@ impl PrepareOpenBlock for TestBlockChainClient { extra_data, false, ).expect("Opening block for tests will not fail."); - // TODO [todr] Override timestamp for predictability (set_timestamp_now kind of sucks) + // TODO [todr] Override timestamp for predictability open_block.set_timestamp(*self.latest_block_timestamp.read()); open_block } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 9c2600212d..af997c022e 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -50,6 +50,17 @@ impl Engine for InstantSeal fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) } + + fn open_block_header_timestamp(&self, parent_timestamp: u64) -> u64 { + use std::{time, cmp}; + + let now = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap_or_default(); + cmp::max(now.as_secs(), parent_timestamp) + } + + fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { + header_timestamp >= parent_timestamp + } } #[cfg(test)] diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 5b2b9abb0e..41b6fe7b25 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -325,6 +325,19 @@ pub trait Engine: Sync + Send { fn supports_warp(&self) -> bool { self.snapshot_components().is_some() } + + /// Return a new open block header timestamp based on the parent timestamp. + fn open_block_header_timestamp(&self, parent_timestamp: u64) -> u64 { + use std::{time, cmp}; + + let now = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap_or_default(); + cmp::max(now.as_secs() as u64, parent_timestamp + 1) + } + + /// Check whether the parent timestamp is valid. + fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { + header_timestamp > parent_timestamp + } } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 80f1646ad8..50529c7201 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -17,7 +17,6 @@ //! Block header. use std::cmp; -use std::time::{SystemTime, UNIX_EPOCH}; use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak}; use heapsize::HeapSizeOf; use ethereum_types::{H256, U256, Address, Bloom}; @@ -224,12 +223,6 @@ impl Header { change_field(&mut self.hash, &mut self.timestamp, a); } - /// Set the timestamp field of the header to the current time. - pub fn set_timestamp_now(&mut self, but_later_than: u64) { - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default(); - self.set_timestamp(cmp::max(now.as_secs() as u64, but_later_than + 1)); - } - /// Set the number field of the header. pub fn set_number(&mut self, a: BlockNumber) { change_field(&mut self.hash, &mut self.number, a); @@ -428,4 +421,3 @@ mod tests { assert_eq!(header_rlp, encoded_header); } } - diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 87ed04afd8..b670851f00 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -25,7 +25,7 @@ use std::collections::HashSet; use std::time::{SystemTime, UNIX_EPOCH}; use bytes::Bytes; -use ethereum_types::{H256, U256}; +use ethereum_types::H256; use hash::keccak; use heapsize::HeapSizeOf; use rlp::UntrustedRlp; @@ -127,7 +127,7 @@ pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> { /// Phase 3 verification. Check block information against parent and uncles. pub fn verify_block_family(header: &Header, parent: &Header, engine: &EthEngine, do_full: Option>) -> Result<(), Error> { // TODO: verify timestamp - verify_parent(&header, &parent, engine.params().gas_limit_bound_divisor)?; + verify_parent(&header, &parent, engine)?; engine.verify_block_family(&header, &parent)?; let params = match do_full { @@ -225,7 +225,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth } let uncle_parent = uncle_parent.decode(); - verify_parent(&uncle, &uncle_parent, engine.params().gas_limit_bound_divisor)?; + verify_parent(&uncle, &uncle_parent, engine)?; engine.verify_block_family(&uncle, &uncle_parent)?; verified.insert(uncle.hash()); } @@ -303,11 +303,13 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool) } /// Check header parameters agains parent header. -fn verify_parent(header: &Header, parent: &Header, gas_limit_divisor: U256) -> Result<(), Error> { +fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result<(), Error> { + let gas_limit_divisor = engine.params().gas_limit_bound_divisor; + if !header.parent_hash().is_zero() && &parent.hash() != header.parent_hash() { return Err(From::from(BlockError::InvalidParentHash(Mismatch { expected: parent.hash(), found: header.parent_hash().clone() }))) } - if header.timestamp() <= parent.timestamp() { + if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) { return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() }))) } if header.number() != parent.number() + 1 { -- GitLab From 9d3771458d0ec11f5d47b8101af11389cd675c3c Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 5 Apr 2018 17:31:06 +0900 Subject: [PATCH 039/263] bump proc macro deps (#8310) --- Cargo.lock | 158 ++++++++++++++++++------------------- util/rlp_derive/Cargo.toml | 4 +- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59c5cd667c..bc93e34b23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,7 +114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -382,8 +382,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -445,8 +445,8 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -458,13 +458,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ethabi-derive" -version = "5.0.8" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -489,7 +489,7 @@ dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -505,7 +505,7 @@ dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-bloom-journal 0.1.0", "ethcore-bytes 0.1.0", @@ -617,8 +617,8 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rlp_derive 0.1.0", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "stats 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -655,7 +655,7 @@ dependencies = [ "common-types 0.1.0", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -712,8 +712,8 @@ dependencies = [ "rlp 0.2.1", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", @@ -728,7 +728,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", @@ -746,8 +746,8 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -826,7 +826,7 @@ dependencies = [ "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -835,7 +835,7 @@ name = "ethereum-types-serialize" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -844,8 +844,8 @@ version = "0.1.0" dependencies = [ "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -876,8 +876,8 @@ dependencies = [ "panic_hook 0.1.0", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -898,8 +898,8 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -919,8 +919,8 @@ dependencies = [ "panic_hook 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -984,8 +984,8 @@ dependencies = [ "panic_hook 0.1.0", "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -1339,8 +1339,8 @@ source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1376,7 +1376,7 @@ source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1769,7 +1769,7 @@ version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-io 1.11.0", "ethcore-network-devp2p 1.11.0", @@ -1791,8 +1791,8 @@ dependencies = [ "ntp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1985,8 +1985,8 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2025,8 +2025,8 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "registrar 0.0.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2066,7 +2066,7 @@ version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", @@ -2111,8 +2111,8 @@ dependencies = [ "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2182,8 +2182,8 @@ dependencies = [ "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "stats 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2205,7 +2205,7 @@ dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.11.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2276,7 +2276,7 @@ version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2337,8 +2337,8 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2516,7 +2516,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.2.3" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2544,8 +2544,8 @@ dependencies = [ "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", "wasm 0.1.0", @@ -2600,10 +2600,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2682,7 +2682,7 @@ version = "0.0.1" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", ] @@ -2730,9 +2730,9 @@ dependencies = [ name = "rlp_derive" version = "0.1.0" dependencies = [ - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", - "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2882,27 +2882,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.29" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.29" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2910,7 +2910,7 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2921,7 +2921,7 @@ dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3036,11 +3036,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.12.14" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3362,7 +3362,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3774,7 +3774,7 @@ dependencies = [ "checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "" "checksum ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05e33a914b94b763f0a92333e4e5c95c095563f06ef7d6b295b3d3c2cf31e21f" "checksum ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca2263c24359e827348ac99aa1f2e28ba5bab0d6c0b83941fa252de8a9e9c073" -"checksum ethabi-derive 5.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "057f76ceb314191b2e7fcd6e2129d75816e80912e73ccc8324baa3b9e259bce3" +"checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" "checksum ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53eabbad504e438e20b6559fd070d79b92cb31c02f994c7ecb05e9b2df716013" "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" @@ -3885,7 +3885,7 @@ dependencies = [ "checksum primal-check 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8e65f96c0a171f887198c274392c99a116ef65aa7f53f3b6d4902f493965c2d1" "checksum primal-estimate 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56ea4531dde757b56906493c8604641da14607bf9cdaa80fb9c9cabd2429f8d5" "checksum primal-sieve 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c0911abe7b63ddec27527ba7579c3017f645eb992be6ddbfad605e34aca01876" -"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" +"checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786" "checksum protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40e2484e639dcae0985fc483ad76ce7ad78ee5aa092751d7d538f0b20d76486b" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54d440c3b56eee028aa5d4f18cbed8c6e0c9ae23563b93f344beb7e73854ea02" @@ -3893,7 +3893,7 @@ dependencies = [ "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" -"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" +"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" @@ -3921,9 +3921,9 @@ dependencies = [ "checksum sct 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1137b767bbe1c4d30656993bdd97422ed41255d9400b105d735f8c7d9e800632" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4763b773978e495252615e814d2ad04773b2c1f85421c7913869a537f35cb406" -"checksum serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8ab31f00ae5574bb643c196d5e302961c122da1c768604c6d16a35c5d551948a" -"checksum serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc848d073be32cd982380c06587ea1d433bc1a4c4a111de07ec2286a3ddade8" +"checksum serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d3bcee660dcde8f52c3765dd9ca5ee36b4bf35470a738eb0bd5a8752b0389645" +"checksum serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "f1711ab8b208541fa8de00425f6a577d90f27bb60724d2bb5fd911314af9668f" +"checksum serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89b340a48245bc03ddba31d0ff1709c118df90edc6adabaca4aac77aea181cce" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" "checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" @@ -3942,7 +3942,7 @@ dependencies = [ "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb" -"checksum syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5bc2d6ff27891209efa5f63e9de78648d7801f085e4653701a692ce938d6fd" +"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" "checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e" "checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" "checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047" diff --git a/util/rlp_derive/Cargo.toml b/util/rlp_derive/Cargo.toml index 8a78eff41f..bb488cc29e 100644 --- a/util/rlp_derive/Cargo.toml +++ b/util/rlp_derive/Cargo.toml @@ -8,8 +8,8 @@ name = "rlp_derive" proc-macro = true [dependencies] -syn = "0.12" -quote = "0.4.2" +syn = "0.13" +quote = "0.5" [dev-dependencies] rlp = { path = "../rlp" } -- GitLab From e4168c2985437fad3e35f049ec1da6e45d34f970 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Apr 2018 17:03:25 +0800 Subject: [PATCH 040/263] Remove InvalidParentHash in favor of assert! (#8300) * Remove InvalidParentHash in favor of assert! * Typo: assert test true case --- ethcore/src/error.rs | 4 ---- ethcore/src/verification/verification.rs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index dd4cf49867..aae2241168 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -86,9 +86,6 @@ pub enum BlockError { TemporarilyInvalid(OutOfBounds), /// Log bloom header field is invalid. InvalidLogBloom(Mismatch), - /// Parent hash field of header is invalid; this is an invalid error indicating a logic flaw in the codebase. - /// TODO: remove and favour an assert!/panic!. - InvalidParentHash(Mismatch), /// Number field of header is invalid. InvalidNumber(Mismatch), /// Block number isn't sensible. @@ -131,7 +128,6 @@ impl fmt::Display for BlockError { InvalidTimestamp(ref oob) => format!("Invalid timestamp in header: {}", oob), TemporarilyInvalid(ref oob) => format!("Future timestamp in header: {}", oob), InvalidLogBloom(ref oob) => format!("Invalid log bloom in header: {}", oob), - InvalidParentHash(ref mis) => format!("Invalid parent hash: {}", mis), InvalidNumber(ref mis) => format!("Invalid number in header: {}", mis), RidiculousNumber(ref oob) => format!("Implausible block number. {}", oob), UnknownParent(ref hash) => format!("Unknown parent: {}", hash), diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index b670851f00..e6289c2b0d 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -304,11 +304,11 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool) /// Check header parameters agains parent header. fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result<(), Error> { + assert!(header.parent_hash().is_zero() || &parent.hash() == header.parent_hash(), + "Parent hash should already have been verified; qed"); + let gas_limit_divisor = engine.params().gas_limit_bound_divisor; - if !header.parent_hash().is_zero() && &parent.hash() != header.parent_hash() { - return Err(From::from(BlockError::InvalidParentHash(Mismatch { expected: parent.hash(), found: header.parent_hash().clone() }))) - } if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) { return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() }))) } -- GitLab From 0d2993e46d34027af6580c071467726baea3c9d0 Mon Sep 17 00:00:00 2001 From: Kwang Yul Seo Date: Thu, 5 Apr 2018 18:31:58 +0900 Subject: [PATCH 041/263] Use associated type M::Error instead of Error (#8308) --- ethcore/src/engines/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 41b6fe7b25..65fa13b54e 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -242,11 +242,11 @@ pub trait Engine: Sync + Send { fn verify_block_unordered(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) } /// Phase 3 verification. Check block information against parent. Returns either a null `Ok` or a general error detailing the problem with import. - fn verify_block_family(&self, _header: &M::Header, _parent: &M::Header) -> Result<(), Error> { Ok(()) } + fn verify_block_family(&self, _header: &M::Header, _parent: &M::Header) -> Result<(), M::Error> { Ok(()) } /// Phase 4 verification. Verify block header against potentially external data. /// Should only be called when `register_client` has been called previously. - fn verify_block_external(&self, _header: &M::Header) -> Result<(), Error> { Ok(()) } + fn verify_block_external(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) } /// Genesis epoch data. fn genesis_epoch_data<'a>(&self, _header: &M::Header, _state: &>::StateContext) -> Result, String> { Ok(Vec::new()) } @@ -304,7 +304,7 @@ pub trait Engine: Sync + Send { fn set_signer(&self, _account_provider: Arc, _address: Address, _password: String) {} /// Sign using the EngineSigner, to be used for consensus tx signing. - fn sign(&self, _hash: H256) -> Result { unimplemented!() } + fn sign(&self, _hash: H256) -> Result { unimplemented!() } /// Add Client which can be used for sealing, potentially querying the state and sending messages. fn register_client(&self, _client: Weak) {} -- GitLab From 27c32d3629e4b70b63ee37736147318035f48792 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 5 Apr 2018 14:38:50 +0200 Subject: [PATCH 042/263] Tweaks and add a Dockerfile for Android (#8036) --- Cargo.lock | 50 +++++-- Cargo.toml | 3 + docker/android/Dockerfile | 77 ++++++++++ docker/android/cargo-config.toml | 9 ++ docker/android/libudev.patch | 216 ++++++++++++++++++++++++++++ ethcore/wasm/Cargo.toml | 2 +- parity/url.rs | 7 + util/network-devp2p/src/ip_utils.rs | 6 +- 8 files changed, 353 insertions(+), 17 deletions(-) create mode 100644 docker/android/Dockerfile create mode 100644 docker/android/cargo-config.toml create mode 100644 docker/android/libudev.patch diff --git a/Cargo.lock b/Cargo.lock index bc93e34b23..c66c614729 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1747,7 +1747,7 @@ name = "multihash" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2335,7 +2335,7 @@ dependencies = [ "ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rlp 0.2.1", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2633,6 +2633,15 @@ dependencies = [ "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rayon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rayon" version = "1.0.1" @@ -2698,12 +2707,13 @@ dependencies = [ [[package]] name = "ring" version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/paritytech/ring#13eec16273e5e8fbbb21def81eaeb11972f4f903" dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2837,7 +2847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", "sct 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2863,7 +2873,7 @@ name = "sct" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3108,6 +3118,18 @@ dependencies = [ "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term" version = "0.4.6" @@ -3604,12 +3626,12 @@ dependencies = [ "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", "pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", - "wasmi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmi" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3622,7 +3644,7 @@ name = "webpki" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3897,13 +3919,14 @@ dependencies = [ "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" +"checksum rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" -"checksum ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f7d28b30a72c01b458428e0ae988d4149c20d902346902be881e3edc4bb325c" +"checksum ring 0.12.1 (git+https://github.com/paritytech/ring)" = "" "checksum rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)" = "" "checksum rocksdb-sys 0.3.0 (git+https://github.com/paritytech/rust-rocksdb)" = "" "checksum rotor 0.6.3 (git+https://github.com/tailhook/rotor)" = "" @@ -3950,6 +3973,7 @@ dependencies = [ "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" +"checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" @@ -3996,7 +4020,7 @@ dependencies = [ "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasmi 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dedfb4cbfba1e1921b12ed05762d9d5ae99ce40e72b98bbf271561ef487e8c7" +"checksum wasmi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26b20dbeb7caee04597a5d2c93e2b3e64872c6ea2af732d7ad49dbec44067c35" "checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2" "checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/Cargo.toml b/Cargo.toml index d09b8a08f0..87daa076c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -133,3 +133,6 @@ members = [ "transaction-pool", "whisper" ] + +[patch.crates-io] +ring = { git = "https://github.com/paritytech/ring" } diff --git a/docker/android/Dockerfile b/docker/android/Dockerfile new file mode 100644 index 0000000000..5769cd13bc --- /dev/null +++ b/docker/android/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:xenial +LABEL maintainer="Parity Technologies " + +RUN apt-get update && \ + apt-get install -yq sudo curl file build-essential wget git g++ cmake pkg-config bison flex \ + unzip lib32stdc++6 lib32z1 python autotools-dev automake autoconf libtool \ + gperf xsltproc docbook-xsl + +# Rust & Cargo +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y +ENV PATH /root/.cargo/bin:$PATH +RUN rustup toolchain install stable +RUN rustup target add --toolchain stable arm-linux-androideabi +RUN rustup target add --toolchain stable armv7-linux-androideabi + +# Android NDK and toolchain +RUN cd /usr/local && \ + wget -q https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip && \ + unzip -q android-ndk-r16b-linux-x86_64.zip && \ + rm android-ndk-r16b-linux-x86_64.zip +ENV NDK_HOME /usr/local/android-ndk-r16b +RUN /usr/local/android-ndk-r16b/build/tools/make-standalone-toolchain.sh \ + --arch=arm --install-dir=/opt/ndk-standalone --stl=libc++ --platform=android-26 +ENV PATH $PATH:/opt/ndk-standalone/bin + +# Compiling OpenSSL for Android +RUN cd /root && \ + git clone git://git.openssl.org/openssl.git && \ + cd openssl && \ + git checkout OpenSSL_1_1_0-stable +ENV CROSS_SYSROOT /opt/ndk-standalone/sysroot +RUN cd /root/openssl && \ + ./Configure android-armeabi --cross-compile-prefix=arm-linux-androideabi- \ + -static no-stdio no-ui \ + -I/usr/local/android-ndk-r16b/sysroot/usr/include \ + -I/usr/local/android-ndk-r16b/sysroot/usr/include/arm-linux-androideabi \ + -L/usr/local/android-ndk-r16b/sysroot/usr/lib \ + --prefix=/opt/ndk-standalone/sysroot/usr +RUN cd /root/openssl && \ + make build_libs && \ + make install_dev +RUN rm -rf /root/openssl + +# Compiling libudev for Android +# This is the most hacky part of the process, as we need to apply a patch and pass specific +# options that the compiler environment doesn't define. +RUN cd /root && \ + git clone https://github.com/gentoo/eudev.git +ADD libudev.patch /root +RUN cd /root/eudev && \ + git checkout 83d918449f22720d84a341a05e24b6d109e6d3ae && \ + ./autogen.sh && \ + ./configure --disable-introspection --disable-programs --disable-hwdb \ + --host=arm-linux-androideabi --prefix=/opt/ndk-standalone/sysroot/usr/ \ + --enable-shared=false CC=arm-linux-androideabi-clang \ + CFLAGS="-D LINE_MAX=2048 -D RLIMIT_NLIMITS=15 -D IPTOS_LOWCOST=2 -std=gnu99" \ + CXX=arm-linux-androideabi-clang++ && \ + git apply - < /root/libudev.patch && \ + make && \ + make install +RUN rm -rf /root/eudev +RUN rm /root/libudev.patch + +# Rust-related configuration +ADD cargo-config.toml /root/.cargo/config +ENV ARM_LINUX_ANDROIDEABI_OPENSSL_DIR /opt/ndk-standalone/sysroot/usr +ENV ARMV7_LINUX_ANDROIDEABI_OPENSSL_DIR /opt/ndk-standalone/sysroot/usr +ENV CC_arm_linux_androideabi arm-linux-androideabi-clang +ENV CC_armv7_linux_androideabi arm-linux-androideabi-clang +ENV CXX_arm_linux_androideabi arm-linux-androideabi-clang++ +ENV CXX_armv7_linux_androideabi arm-linux-androideabi-clang++ +ENV AR_arm_linux_androideabi arm-linux-androideabi-ar +ENV AR_armv7_linux_androideabi arm-linux-androideabi-ar +ENV CFLAGS_arm_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID +ENV CFLAGS_armv7_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID +ENV CXXFLAGS_arm_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID +ENV CXXFLAGS_armv7_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID diff --git a/docker/android/cargo-config.toml b/docker/android/cargo-config.toml new file mode 100644 index 0000000000..7373a7e143 --- /dev/null +++ b/docker/android/cargo-config.toml @@ -0,0 +1,9 @@ +[target.armv7-linux-androideabi] +linker = "arm-linux-androideabi-clang" +ar = "arm-linux-androideabi-ar" +rustflags = ["-C", "link-arg=-lc++_static", "-C", "link-arg=-lc++abi", "-C", "link-arg=-landroid_support"] + +[target.arm-linux-androideabi] +linker = "arm-linux-androideabi-clang" +ar = "arm-linux-androideabi-ar" +rustflags = ["-C", "link-arg=-lc++_static", "-C", "link-arg=-lc++abi", "-C", "link-arg=-landroid_support"] diff --git a/docker/android/libudev.patch b/docker/android/libudev.patch new file mode 100644 index 0000000000..ba7e849b2e --- /dev/null +++ b/docker/android/libudev.patch @@ -0,0 +1,216 @@ +diff --git a/src/collect/collect.c b/src/collect/collect.c +index 2cf1f00..b24f26b 100644 +--- a/src/collect/collect.c ++++ b/src/collect/collect.c +@@ -84,7 +84,7 @@ static void usage(void) + " invoked for each ID in ) collect returns 0, the\n" + " number of missing IDs otherwise.\n" + " On error a negative number is returned.\n\n" +- , program_invocation_short_name); ++ , "parity"); + } + + /* +diff --git a/src/scsi_id/scsi_id.c b/src/scsi_id/scsi_id.c +index 8b76d87..7bf3948 100644 +--- a/src/scsi_id/scsi_id.c ++++ b/src/scsi_id/scsi_id.c +@@ -321,7 +321,7 @@ static void help(void) { + " -u --replace-whitespace Replace all whitespace by underscores\n" + " -v --verbose Verbose logging\n" + " -x --export Print values as environment keys\n" +- , program_invocation_short_name); ++ , "parity"); + + } + +diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h +index a03ee58..a7c2005 100644 +--- a/src/shared/hashmap.h ++++ b/src/shared/hashmap.h +@@ -98,10 +98,7 @@ extern const struct hash_ops uint64_hash_ops; + #if SIZEOF_DEV_T != 8 + unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; + int devt_compare_func(const void *a, const void *b) _pure_; +-extern const struct hash_ops devt_hash_ops = { +- .hash = devt_hash_func, +- .compare = devt_compare_func +-}; ++extern const struct hash_ops devt_hash_ops; + #else + #define devt_hash_func uint64_hash_func + #define devt_compare_func uint64_compare_func +diff --git a/src/shared/log.c b/src/shared/log.c +index 4a40996..1496984 100644 +--- a/src/shared/log.c ++++ b/src/shared/log.c +@@ -335,7 +335,7 @@ static int write_to_syslog( + + IOVEC_SET_STRING(iovec[0], header_priority); + IOVEC_SET_STRING(iovec[1], header_time); +- IOVEC_SET_STRING(iovec[2], program_invocation_short_name); ++ IOVEC_SET_STRING(iovec[2], "parity"); + IOVEC_SET_STRING(iovec[3], header_pid); + IOVEC_SET_STRING(iovec[4], buffer); + +@@ -383,7 +383,7 @@ static int write_to_kmsg( + char_array_0(header_pid); + + IOVEC_SET_STRING(iovec[0], header_priority); +- IOVEC_SET_STRING(iovec[1], program_invocation_short_name); ++ IOVEC_SET_STRING(iovec[1], "parity"); + IOVEC_SET_STRING(iovec[2], header_pid); + IOVEC_SET_STRING(iovec[3], buffer); + IOVEC_SET_STRING(iovec[4], "\n"); +diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c +index 6af7163..3271e56 100644 +--- a/src/udev/udevadm-control.c ++++ b/src/udev/udevadm-control.c +@@ -41,7 +41,7 @@ static void print_help(void) { + " -p --property=KEY=VALUE Set a global property for all events\n" + " -m --children-max=N Maximum number of children\n" + " --timeout=SECONDS Maximum time to block for a reply\n" +- , program_invocation_short_name); ++ , "parity"); + } + + static int adm_control(struct udev *udev, int argc, char *argv[]) { +diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c +index 0aec976..a31ac02 100644 +--- a/src/udev/udevadm-info.c ++++ b/src/udev/udevadm-info.c +@@ -279,7 +279,7 @@ static void help(void) { + " -P --export-prefix Export the key name with a prefix\n" + " -e --export-db Export the content of the udev database\n" + " -c --cleanup-db Clean up the udev database\n" +- , program_invocation_short_name); ++ , "parity"); + } + + static int uinfo(struct udev *udev, int argc, char *argv[]) { +diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c +index 15ded09..b58dd08 100644 +--- a/src/udev/udevadm-monitor.c ++++ b/src/udev/udevadm-monitor.c +@@ -73,7 +73,7 @@ static void help(void) { + " -u --udev Print udev events\n" + " -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n" + " -t --tag-match=TAG Filter events by tag\n" +- , program_invocation_short_name); ++ , "parity"); + } + + static int adm_monitor(struct udev *udev, int argc, char *argv[]) { +diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c +index 33597bc..b36a504 100644 +--- a/src/udev/udevadm-settle.c ++++ b/src/udev/udevadm-settle.c +@@ -43,7 +43,7 @@ static void help(void) { + " --version Show package version\n" + " -t --timeout=SECONDS Maximum time to wait for events\n" + " -E --exit-if-exists=FILE Stop waiting if file exists\n" +- , program_invocation_short_name); ++ , "parity"); + } + + static int adm_settle(struct udev *udev, int argc, char *argv[]) { +diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c +index baaeca9..50ed812 100644 +--- a/src/udev/udevadm-test-builtin.c ++++ b/src/udev/udevadm-test-builtin.c +@@ -39,7 +39,7 @@ static void help(struct udev *udev) { + " -h --help Print this message\n" + " --version Print version of the program\n\n" + "Commands:\n" +- , program_invocation_short_name); ++ , "parity"); + + udev_builtin_list(udev); + } +diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c +index 47fd924..a855412 100644 +--- a/src/udev/udevadm-test.c ++++ b/src/udev/udevadm-test.c +@@ -39,7 +39,7 @@ static void help(void) { + " --version Show package version\n" + " -a --action=ACTION Set action string\n" + " -N --resolve-names=early|late|never When to resolve names\n" +- , program_invocation_short_name); ++ , "parity"); + } + + static int adm_test(struct udev *udev, int argc, char *argv[]) { +diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c +index 4dc756a..67787d3 100644 +--- a/src/udev/udevadm-trigger.c ++++ b/src/udev/udevadm-trigger.c +@@ -92,7 +92,7 @@ static void help(void) { + " -y --sysname-match=NAME Trigger devices with this /sys path\n" + " --name-match=NAME Trigger devices with this /dev name\n" + " -b --parent-match=NAME Trigger devices with that parent device\n" +- , program_invocation_short_name); ++ , "parity"); + } + + static int adm_trigger(struct udev *udev, int argc, char *argv[]) { +diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c +index 3e57cf6..b03dfaa 100644 +--- a/src/udev/udevadm.c ++++ b/src/udev/udevadm.c +@@ -62,7 +62,7 @@ static int adm_help(struct udev *udev, int argc, char *argv[]) { + printf("%s [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]\n\n" + "Send control commands or test the device manager.\n\n" + "Commands:\n" +- , program_invocation_short_name); ++ , "parity"); + + for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++) + if (udevadm_cmds[i]->help != NULL) +@@ -128,7 +128,7 @@ int main(int argc, char *argv[]) { + goto out; + } + +- fprintf(stderr, "%s: missing or unknown command\n", program_invocation_short_name); ++ fprintf(stderr, "%s: missing or unknown command\n", "parity"); + rc = 2; + out: + mac_selinux_finish(); +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index cf826c6..4eec0af 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -1041,7 +1041,7 @@ static void help(void) { + " -t --event-timeout=SECONDS Seconds to wait before terminating an event\n" + " -N --resolve-names=early|late|never\n" + " When to resolve users and groups\n" +- , program_invocation_short_name); ++ , "parity"); + } + + static int parse_argv(int argc, char *argv[]) { +diff --git a/src/v4l_id/v4l_id.c b/src/v4l_id/v4l_id.c +index 1dce0d5..f65badf 100644 +--- a/src/v4l_id/v4l_id.c ++++ b/src/v4l_id/v4l_id.c +@@ -49,7 +49,7 @@ int main(int argc, char *argv[]) { + printf("%s [-h,--help] \n\n" + "Video4Linux device identification.\n\n" + " -h Print this message\n" +- , program_invocation_short_name); ++ , "parity"); + return 0; + case '?': + return -EINVAL; +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index 0744563..7151356 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -109,7 +109,7 @@ char *path_make_absolute_cwd(const char *p) { + if (path_is_absolute(p)) + return strdup(p); + +- cwd = get_current_dir_name(); ++ cwd = getcwd(malloc(128), 128); + if (!cwd) + return NULL; + diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index 10a5134d45..2b8075f741 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -12,4 +12,4 @@ libc = "0.2" pwasm-utils = "0.1" vm = { path = "../vm" } ethcore-logger = { path = "../../logger" } -wasmi = { version = "0.1", features = ["opt-in-32bit"] } +wasmi = { version = "0.1.2", features = ["opt-in-32bit"] } diff --git a/parity/url.rs b/parity/url.rs index 052e408e60..fd64e46eca 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -57,3 +57,10 @@ pub fn open(url: &str) { use std; let _ = std::process::Command::new("xdg-open").arg(url).spawn(); } + +#[cfg(target_os="android")] +pub fn open(_url: &str) { + // TODO: While it is generally always bad to leave a function implemented, there is not much + // more we can do here. This function will eventually be removed when we compile Parity + // as a library and not as a full binary. +} diff --git a/util/network-devp2p/src/ip_utils.rs b/util/network-devp2p/src/ip_utils.rs index 3767fbb15a..7c3d5c0fd3 100644 --- a/util/network-devp2p/src/ip_utils.rs +++ b/util/network-devp2p/src/ip_utils.rs @@ -210,7 +210,7 @@ impl SocketAddrExt for IpAddr { } } -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "android")))] mod getinterfaces { use std::{mem, io, ptr}; use libc::{AF_INET, AF_INET6}; @@ -280,12 +280,12 @@ mod getinterfaces { } } -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "android")))] fn get_if_addrs() -> io::Result> { getinterfaces::get_all() } -#[cfg(windows)] +#[cfg(any(windows, target_os = "android"))] fn get_if_addrs() -> io::Result> { Ok(Vec::new()) } -- GitLab From d7a7f034db6e7d84e2182ab2cd76cfc0a438723c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 6 Apr 2018 18:03:13 +0800 Subject: [PATCH 043/263] Read registry_address from block with REQUEST_CONFIRMATIONS_REQUIRED (#8309) * Read registry_address from block with REQUEST_CONFIRMATIONS_REQUIRED * Require confirmation blocks in key_server_set * Add license preamble * TODO item for constant confirmation required number * Change license year in helpers.rs to 2015-2018 --- secret_store/src/helpers.rs | 29 +++++++++++++++++++ secret_store/src/key_server_set.rs | 3 +- secret_store/src/lib.rs | 1 + secret_store/src/listener/service_contract.rs | 27 ++++++----------- 4 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 secret_store/src/helpers.rs diff --git a/secret_store/src/helpers.rs b/secret_store/src/helpers.rs new file mode 100644 index 0000000000..3bc49116e0 --- /dev/null +++ b/secret_store/src/helpers.rs @@ -0,0 +1,29 @@ +// Copyright 2015-2018 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 . + +use ethcore::client::{Client, BlockChainClient, BlockId}; +use ethereum_types::H256; + +// TODO: Instead of a constant, make this based on consensus finality. +/// Number of confirmations required before request can be processed. +pub const REQUEST_CONFIRMATIONS_REQUIRED: u64 = 3; + +/// Get hash of the last block with at least n confirmations. +pub fn get_confirmed_block_hash(client: &Client, confirmations: u64) -> Option { + client.block_number(BlockId::Latest) + .map(|b| b.saturating_sub(confirmations)) + .and_then(|b| client.block_hash(BlockId::Number(b))) +} diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index f069368b04..899709a7d5 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -26,6 +26,7 @@ use ethereum_types::{H256, Address}; use bytes::Bytes; use types::all::{Error, Public, NodeAddress, NodeId}; use trusted_client::TrustedClient; +use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; use {NodeKeyPair}; use_contract!(key_server, "KeyServerSet", "res/key_server_set.json"); @@ -325,7 +326,7 @@ impl CachedContract { fn read_from_registry_if_required(&mut self, client: &Client, enacted: Vec, retracted: Vec) { // read new contract from registry - let new_contract_addr = client.registry_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest); + let new_contract_addr = get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED).and_then(|block_hash| client.registry_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Hash(block_hash))); // new contract installed => read nodes set from the contract if self.contract_address.as_ref() != new_contract_addr.as_ref() { diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index e796ff4bc5..f08a26a907 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -54,6 +54,7 @@ extern crate log; mod key_server_cluster; mod types; +mod helpers; mod traits; mod acl_storage; diff --git a/secret_store/src/listener/service_contract.rs b/secret_store/src/listener/service_contract.rs index 7bb28ae053..4d6ac14c81 100644 --- a/secret_store/src/listener/service_contract.rs +++ b/secret_store/src/listener/service_contract.rs @@ -26,6 +26,7 @@ use ethereum_types::{H256, U256, Address}; use listener::ApiMask; use listener::service_contract_listener::ServiceTask; use trusted_client::TrustedClient; +use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; use {ServerKeyId, NodeKeyPair, ContractAddress}; use_contract!(service, "Service", "res/service.json"); @@ -52,9 +53,6 @@ const DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = & /// Document key personal part retrieval has been requested. const DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = &*b"DocumentKeyPersonalRetrievalRequested(bytes32,bytes)"; -/// Number of confirmations required before request can be processed. -const REQUEST_CONFIRMATIONS_REQUIRED: u64 = 3; - lazy_static! { pub static ref SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH: H256 = keccak(SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME); pub static ref SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH: H256 = keccak(SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME); @@ -234,16 +232,16 @@ impl OnChainServiceContract { impl ServiceContract for OnChainServiceContract { fn update(&self) -> bool { - // TODO [Sec]: registry_address currently reads from BlockId::Latest, instead of - // from block with REQUEST_CONFIRMATIONS_REQUIRED confirmations if let &ContractAddress::Registry = &self.address { if let Some(client) = self.client.get() { - // update contract address from registry - let service_contract_addr = client.registry_address(self.name.clone(), BlockId::Latest).unwrap_or_default(); - if self.data.read().contract_address != service_contract_addr { - trace!(target: "secretstore", "{}: installing {} service contract from address {}", - self.self_key_pair.public(), self.name, service_contract_addr); - self.data.write().contract_address = service_contract_addr; + if let Some(block_hash) = get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED) { + // update contract address from registry + let service_contract_addr = client.registry_address(self.name.clone(), BlockId::Hash(block_hash)).unwrap_or_default(); + if self.data.read().contract_address != service_contract_addr { + trace!(target: "secretstore", "{}: installing {} service contract from address {}", + self.self_key_pair.public(), self.name, service_contract_addr); + self.data.write().contract_address = service_contract_addr; + } } } } @@ -460,13 +458,6 @@ pub fn mask_topics(mask: &ApiMask) -> Vec { topics } -/// Get hash of the last block with at least n confirmations. -fn get_confirmed_block_hash(client: &Client, confirmations: u64) -> Option { - client.block_number(BlockId::Latest) - .map(|b| b.saturating_sub(confirmations)) - .and_then(|b| client.block_hash(BlockId::Number(b))) -} - impl ServerKeyGenerationService { /// Parse request log entry. pub fn parse_log(origin: &Address, contract: &service::Service, raw_log: RawLog) -> Result { -- GitLab From 652f5032a2936fc554d2ecec4829e16adab1dd3a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sun, 8 Apr 2018 18:29:25 +0200 Subject: [PATCH 044/263] Fix the JSONRPC API not running with the light client (#8326) --- parity/run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/run.rs b/parity/run.rs index 4c73fe63f6..7baeaaed34 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -425,7 +425,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result Date: Mon, 9 Apr 2018 17:35:54 +0800 Subject: [PATCH 045/263] remove the clone operation of code_cache (#8334) * Some tiny modifications. 1. fix some typo in the comment. 2. sort the order of methods in 'impl state::Backend for StateDB` * Remove the clone of code_cache, as it has been done in clone_basic. --- ethcore/src/state/account.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index e08ad7b185..9d72ed158c 100755 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -424,7 +424,6 @@ impl Account { pub fn clone_dirty(&self) -> Account { let mut account = self.clone_basic(); account.storage_changes = self.storage_changes.clone(); - account.code_cache = self.code_cache.clone(); account } -- GitLab From c039ab79b59e418a210f630a5ae485c39171f0e4 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 9 Apr 2018 20:21:37 +0800 Subject: [PATCH 046/263] Decouple rocksdb dependency from ethcore (#8320) * Move client DB opening logic to CLI * Move restoration db open logic to CLI This adds KeyValueDBHandler which handles opening a new database, thus allow us to move the restoration db open logic out of ethcore. * Move rocksdb's compactionprofile conversion to CLI * Move kvdb_rocksdb as test dependency for ethcore * Fix tests due to interface change * Fix service tests * Remove unused migration dep for ethcore --- Cargo.lock | 1 - ethcore/Cargo.toml | 3 +- ethcore/service/Cargo.toml | 2 +- ethcore/service/src/lib.rs | 4 +- ethcore/service/src/service.rs | 61 +++++++++++++++++---------- ethcore/src/client/config.rs | 13 ------ ethcore/src/lib.rs | 5 ++- ethcore/src/snapshot/service.rs | 27 ++++++------ ethcore/src/snapshot/tests/service.rs | 6 +-- ethcore/src/tests/helpers.rs | 19 +++++++++ parity/blockchain.rs | 22 +++++++--- parity/export_hardcoded_sync.rs | 4 +- parity/helpers.rs | 52 ++++++++++++++++++++++- parity/run.rs | 13 ++++-- parity/snapshot.rs | 11 +++-- util/kvdb/src/lib.rs | 9 ++++ 16 files changed, 176 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c66c614729..403b468f84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -535,7 +535,6 @@ dependencies = [ "macros 0.1.0", "memory-cache 0.1.0", "memorydb 0.1.1", - "migration 0.1.0", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-machine 0.1.0", diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index ba984f315f..9c61fd8ea4 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -51,12 +51,10 @@ rlp = { path = "../util/rlp" } rlp_compress = { path = "../util/rlp_compress" } rlp_derive = { path = "../util/rlp_derive" } kvdb = { path = "../util/kvdb" } -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } util-error = { path = "../util/error" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } -migration = { path = "../util/migration" } macros = { path = "../util/macros" } rust-crypto = "0.2.34" rustc-hex = "1.0" @@ -74,6 +72,7 @@ journaldb = { path = "../util/journaldb" } [dev-dependencies] tempdir = "0.3" trie-standardmap = { path = "../util/trie-standardmap" } +kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } [features] evm-debug = ["slow-blocks"] diff --git a/ethcore/service/Cargo.toml b/ethcore/service/Cargo.toml index 634769d0b5..4b53f5d00a 100644 --- a/ethcore/service/Cargo.toml +++ b/ethcore/service/Cargo.toml @@ -8,9 +8,9 @@ ansi_term = "0.10" ethcore = { path = ".." } ethcore-io = { path = "../../util/io" } kvdb = { path = "../../util/kvdb" } -kvdb-rocksdb = { path = "../../util/kvdb-rocksdb" } log = "0.3" stop-guard = { path = "../../util/stop-guard" } [dev-dependencies] tempdir = "0.3" +kvdb-rocksdb = { path = "../../util/kvdb-rocksdb" } diff --git a/ethcore/service/src/lib.rs b/ethcore/service/src/lib.rs index 907009ba32..83d9a8fe10 100644 --- a/ethcore/service/src/lib.rs +++ b/ethcore/service/src/lib.rs @@ -18,7 +18,6 @@ extern crate ansi_term; extern crate ethcore; extern crate ethcore_io as io; extern crate kvdb; -extern crate kvdb_rocksdb; extern crate stop_guard; #[macro_use] @@ -27,6 +26,9 @@ extern crate log; #[cfg(test)] extern crate tempdir; +#[cfg(test)] +extern crate kvdb_rocksdb; + mod service; pub use service::ClientService; diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index f190d6e6ac..4337996e2b 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -21,12 +21,10 @@ use std::path::Path; use ansi_term::Colour; use io::{IoContext, TimerToken, IoHandler, IoService, IoError}; -use kvdb::KeyValueDB; -use kvdb_rocksdb::{Database, DatabaseConfig}; +use kvdb::{KeyValueDB, KeyValueDBHandler}; use stop_guard::StopGuard; -use ethcore::client::{self, Client, ClientConfig, ChainNotify, ClientIoMessage}; -use ethcore::db; +use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage}; use ethcore::error::Error; use ethcore::miner::Miner; use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams}; @@ -38,7 +36,7 @@ pub struct ClientService { io_service: Arc>, client: Arc, snapshot: Arc, - database: Arc, + database: Arc, _stop_guard: StopGuard, } @@ -47,8 +45,9 @@ impl ClientService { pub fn start( config: ClientConfig, spec: &Spec, - client_path: &Path, + client_db: Arc, snapshot_path: &Path, + restoration_db_handler: Box, _ipc_path: &Path, miner: Arc, ) -> Result @@ -57,25 +56,13 @@ impl ClientService { info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name())); - let mut db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS); - - db_config.memory_budget = config.db_cache_size; - db_config.compaction = config.db_compaction.compaction_profile(client_path); - db_config.wal = config.db_wal; - - let db = Arc::new(Database::open( - &db_config, - &client_path.to_str().expect("DB path could not be converted to string.") - ).map_err(client::Error::Database)?); - - let pruning = config.pruning; - let client = Client::new(config, &spec, db.clone(), miner, io_service.channel())?; + let client = Client::new(config, &spec, client_db.clone(), miner, io_service.channel())?; let snapshot_params = SnapServiceParams { engine: spec.engine.clone(), genesis_block: spec.genesis_block(), - db_config: db_config.clone(), + restoration_db_handler: restoration_db_handler, pruning: pruning, channel: io_service.channel(), snapshot_root: snapshot_path.into(), @@ -97,7 +84,7 @@ impl ClientService { io_service: Arc::new(io_service), client: client, snapshot: snapshot, - database: db, + database: client_db, _stop_guard: stop_guard, }) } @@ -208,6 +195,9 @@ mod tests { use ethcore::client::ClientConfig; use ethcore::miner::Miner; use ethcore::spec::Spec; + use ethcore::db::NUM_COLUMNS; + use kvdb::Error; + use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile}; use super::*; #[test] @@ -216,12 +206,39 @@ mod tests { let client_path = tempdir.path().join("client"); let snapshot_path = tempdir.path().join("snapshot"); + let client_config = ClientConfig::default(); + let mut client_db_config = DatabaseConfig::with_columns(NUM_COLUMNS); + + client_db_config.memory_budget = client_config.db_cache_size; + client_db_config.compaction = CompactionProfile::auto(&client_path); + client_db_config.wal = client_config.db_wal; + + let client_db = Arc::new(Database::open( + &client_db_config, + &client_path.to_str().expect("DB path could not be converted to string.") + ).unwrap()); + + struct RestorationDBHandler { + config: DatabaseConfig, + } + + impl KeyValueDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> Result, Error> { + Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + } + } + + let restoration_db_handler = Box::new(RestorationDBHandler { + config: client_db_config, + }); + let spec = Spec::new_test(); let service = ClientService::start( ClientConfig::default(), &spec, - &client_path, + client_db, &snapshot_path, + restoration_db_handler, tempdir.path(), Arc::new(Miner::with_spec(&spec)), ); diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index b337bf4319..9787f822a4 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -15,13 +15,11 @@ // along with Parity. If not, see . use std::str::FromStr; -use std::path::Path; use std::fmt::{Display, Formatter, Error as FmtError}; use mode::Mode as IpcMode; use verification::{VerifierType, QueueConfig}; use journaldb; -use kvdb_rocksdb::CompactionProfile; pub use std::time::Duration; pub use blockchain::Config as BlockChainConfig; @@ -45,17 +43,6 @@ impl Default for DatabaseCompactionProfile { } } -impl DatabaseCompactionProfile { - /// Returns corresponding compaction profile. - pub fn compaction_profile(&self, db_path: &Path) -> CompactionProfile { - match *self { - DatabaseCompactionProfile::Auto => CompactionProfile::auto(db_path), - DatabaseCompactionProfile::SSD => CompactionProfile::ssd(), - DatabaseCompactionProfile::HDD => CompactionProfile::hdd(), - } - } -} - impl FromStr for DatabaseCompactionProfile { type Err = String; diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 43c3336f6f..d822195d32 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -93,11 +93,9 @@ extern crate triehash; extern crate ansi_term; extern crate unexpected; extern crate kvdb; -extern crate kvdb_rocksdb; extern crate kvdb_memorydb; extern crate util_error; extern crate snappy; -extern crate migration; extern crate ethabi; #[macro_use] @@ -130,6 +128,9 @@ extern crate trace_time; #[cfg_attr(test, macro_use)] extern crate evm; +#[cfg(test)] +extern crate kvdb_rocksdb; + pub extern crate ethstore; pub mod account_provider; diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 7def518f35..fad150645d 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -39,7 +39,7 @@ use parking_lot::{Mutex, RwLock, RwLockReadGuard}; use util_error::UtilError; use bytes::Bytes; use journaldb::Algorithm; -use kvdb_rocksdb::{Database, DatabaseConfig}; +use kvdb::{KeyValueDB, KeyValueDBHandler}; use snappy; /// Helper for removing directories in case of error. @@ -79,14 +79,13 @@ struct Restoration { snappy_buffer: Bytes, final_state_root: H256, guard: Guard, - db: Arc, + db: Arc, } struct RestorationParams<'a> { manifest: ManifestData, // manifest to base restoration on. pruning: Algorithm, // pruning algorithm for the database. - db_path: PathBuf, // database path - db_config: &'a DatabaseConfig, // configuration for the database. + db: Arc, // database writer: Option, // writer for recovered snapshot. genesis: &'a [u8], // genesis block of the chain. guard: Guard, // guard for the restoration directory. @@ -101,8 +100,7 @@ impl Restoration { let state_chunks = manifest.state_hashes.iter().cloned().collect(); let block_chunks = manifest.block_hashes.iter().cloned().collect(); - let raw_db = Arc::new(Database::open(params.db_config, &*params.db_path.to_string_lossy()) - .map_err(UtilError::from)?); + let raw_db = params.db; let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone()); let components = params.engine.snapshot_components() @@ -211,10 +209,10 @@ pub struct ServiceParams { pub engine: Arc, /// The chain's genesis block. pub genesis_block: Bytes, - /// Database configuration options. - pub db_config: DatabaseConfig, /// State pruning algorithm. pub pruning: Algorithm, + /// Handler for opening a restoration DB. + pub restoration_db_handler: Box, /// Async IO channel for sending messages. pub channel: Channel, /// The directory to put snapshots in. @@ -228,8 +226,8 @@ pub struct ServiceParams { /// This controls taking snapshots and restoring from them. pub struct Service { restoration: Mutex>, + restoration_db_handler: Box, snapshot_root: PathBuf, - db_config: DatabaseConfig, io_channel: Mutex, pruning: Algorithm, status: Mutex, @@ -249,8 +247,8 @@ impl Service { pub fn new(params: ServiceParams) -> Result { let mut service = Service { restoration: Mutex::new(None), + restoration_db_handler: params.restoration_db_handler, snapshot_root: params.snapshot_root, - db_config: params.db_config, io_channel: Mutex::new(params.channel), pruning: params.pruning, status: Mutex::new(RestorationStatus::Inactive), @@ -437,8 +435,7 @@ impl Service { let params = RestorationParams { manifest: manifest, pruning: self.pruning, - db_path: self.restoration_db(), - db_config: &self.db_config, + db: self.restoration_db_handler.open(&self.restoration_db())?, writer: writer, genesis: &self.genesis_block, guard: Guard::new(rest_dir), @@ -638,6 +635,7 @@ mod tests { use snapshot::{ManifestData, RestorationStatus, SnapshotService}; use super::*; use tempdir::TempDir; + use tests::helpers::restoration_db_handler; struct NoopDBRestore; impl DatabaseRestore for NoopDBRestore { @@ -657,7 +655,7 @@ mod tests { let snapshot_params = ServiceParams { engine: spec.engine.clone(), genesis_block: spec.genesis_block(), - db_config: Default::default(), + restoration_db_handler: restoration_db_handler(Default::default()), pruning: Algorithm::Archive, channel: service.channel(), snapshot_root: dir, @@ -709,8 +707,7 @@ mod tests { block_hash: H256::default(), }, pruning: Algorithm::Archive, - db_path: tempdir.path().to_owned(), - db_config: &db_config, + db: restoration_db_handler(db_config).open(&tempdir.path().to_owned()).unwrap(), writer: None, genesis: &gb, guard: Guard::benign(), diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 52b4b3cc97..4548741f39 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -24,7 +24,7 @@ use ids::BlockId; use snapshot::service::{Service, ServiceParams}; use snapshot::{self, ManifestData, SnapshotService}; use spec::Spec; -use tests::helpers::generate_dummy_client_with_spec_and_data; +use tests::helpers::{generate_dummy_client_with_spec_and_data, restoration_db_handler}; use io::IoChannel; use kvdb_rocksdb::{Database, DatabaseConfig}; @@ -65,7 +65,7 @@ fn restored_is_equivalent() { let service_params = ServiceParams { engine: spec.engine.clone(), genesis_block: spec.genesis_block(), - db_config: db_config, + restoration_db_handler: restoration_db_handler(db_config), pruning: ::journaldb::Algorithm::Archive, channel: IoChannel::disconnected(), snapshot_root: path, @@ -107,7 +107,7 @@ fn guards_delete_folders() { let service_params = ServiceParams { engine: spec.engine.clone(), genesis_block: spec.genesis_block(), - db_config: DatabaseConfig::with_columns(::db::NUM_COLUMNS), + restoration_db_handler: restoration_db_handler(DatabaseConfig::with_columns(::db::NUM_COLUMNS)), pruning: ::journaldb::Algorithm::Archive, channel: IoChannel::disconnected(), snapshot_root: tempdir.path().to_owned(), diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index fd37164dcb..14dcf3630b 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -33,8 +33,11 @@ use spec::Spec; use state_db::StateDB; use state::*; use std::sync::Arc; +use std::path::Path; use transaction::{Action, Transaction, SignedTransaction}; use views::BlockView; +use kvdb::{KeyValueDB, KeyValueDBHandler}; +use kvdb_rocksdb::{Database, DatabaseConfig}; pub fn create_test_block(header: &Header) -> Bytes { let mut rlp = RlpStream::new_list(3); @@ -349,3 +352,19 @@ impl ChainNotify for TestNotify { self.messages.write().push(data); } } + +pub fn restoration_db_handler(config: DatabaseConfig) -> Box { + use kvdb::Error; + + struct RestorationDBHandler { + config: DatabaseConfig, + } + + impl KeyValueDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> Result, Error> { + Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + } + } + + Box::new(RestorationDBHandler { config }) +} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 9dab9069d7..26eae45976 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -35,7 +35,7 @@ use cache::CacheConfig; use informant::{Informant, FullNodeInformantData, MillisecondDuration}; use kvdb_rocksdb::{Database, DatabaseConfig}; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool}; -use helpers::{to_client_config, execute_upgrades}; +use helpers::{to_client_config, execute_upgrades, open_client_db, client_db_config, restoration_db_handler, compaction_profile}; use dir::Directories; use user_defaults::UserDefaults; use fdlimit; @@ -186,7 +186,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { let client_path = db_dirs.client_path(algorithm); // execute upgrades - let compaction = cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()); + let compaction = compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()); execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction)?; // create dirs used by parity @@ -352,7 +352,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()))?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()))?; // create dirs used by parity cmd.dirs.create_dirs(false, false, false)?; @@ -376,12 +376,17 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { client_config.queue.verifier_settings = cmd.verifier_settings; + let client_db_config = client_db_config(&client_path, &client_config); + let client_db = open_client_db(&client_path, &client_db_config)?; + let restoration_db_handler = restoration_db_handler(client_db_config); + // build client let service = ClientService::start( client_config, &spec, - &client_path, + client_db, &snapshot_path, + restoration_db_handler, &cmd.dirs.ipc_path(), Arc::new(Miner::with_spec(&spec)), ).map_err(|e| format!("Client service error: {:?}", e))?; @@ -537,7 +542,7 @@ fn start_client( let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&dirs.base, &db_dirs, algorithm, compaction.compaction_profile(db_dirs.db_root_path().as_path()))?; + execute_upgrades(&dirs.base, &db_dirs, algorithm, compaction_profile(&compaction, db_dirs.db_root_path().as_path()))?; // create dirs used by parity dirs.create_dirs(false, false, false)?; @@ -559,11 +564,16 @@ fn start_client( true, ); + let client_db_config = client_db_config(&client_path, &client_config); + let client_db = open_client_db(&client_path, &client_db_config)?; + let restoration_db_handler = restoration_db_handler(client_db_config); + let service = ClientService::start( client_config, &spec, - &client_path, + client_db, &snapshot_path, + restoration_db_handler, &dirs.ipc_path(), Arc::new(Miner::with_spec(&spec)), ).map_err(|e| format!("Client service error: {:?}", e))?; diff --git a/parity/export_hardcoded_sync.rs b/parity/export_hardcoded_sync.rs index 7a48c0592e..accb6159fa 100644 --- a/parity/export_hardcoded_sync.rs +++ b/parity/export_hardcoded_sync.rs @@ -25,7 +25,7 @@ use light::client::fetch::Unavailable as UnavailableDataFetcher; use light::Cache as LightDataCache; use params::{SpecType, Pruning}; -use helpers::execute_upgrades; +use helpers::{execute_upgrades, compaction_profile}; use dir::Directories; use cache::CacheConfig; use user_defaults::UserDefaults; @@ -66,7 +66,7 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { // select pruning algorithm let algorithm = cmd.pruning.to_algorithm(&user_defaults); - let compaction = cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()); + let compaction = compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()); // execute upgrades execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction.clone())?; diff --git a/parity/helpers.rs b/parity/helpers.rs index 959dddba92..1c6c70cdae 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -18,11 +18,13 @@ use std::io; use std::io::{Write, BufReader, BufRead}; use std::time::Duration; use std::fs::File; +use std::sync::Arc; +use std::path::Path; use ethereum_types::{U256, clean_0x, Address}; -use kvdb_rocksdb::CompactionProfile; use journaldb::Algorithm; use ethcore::client::{Mode, BlockId, VMType, DatabaseCompactionProfile, ClientConfig, VerifierType}; use ethcore::miner::{PendingSet, GasLimit}; +use ethcore::db::NUM_COLUMNS; use miner::transaction_queue::PrioritizationStrategy; use cache::CacheConfig; use dir::DatabaseDirectories; @@ -30,6 +32,8 @@ use dir::helpers::replace_home; use upgrade::{upgrade, upgrade_data_paths}; use migration::migrate; use ethsync::{validate_node_url, self}; +use kvdb::{KeyValueDB, KeyValueDBHandler}; +use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile}; use path; pub fn to_duration(s: &str) -> Result { @@ -255,6 +259,52 @@ pub fn to_client_config( client_config } +// We assume client db has similar config as restoration db. +pub fn client_db_config(client_path: &Path, client_config: &ClientConfig) -> DatabaseConfig { + let mut client_db_config = DatabaseConfig::with_columns(NUM_COLUMNS); + + client_db_config.memory_budget = client_config.db_cache_size; + client_db_config.compaction = compaction_profile(&client_config.db_compaction, &client_path); + client_db_config.wal = client_config.db_wal; + + client_db_config +} + +pub fn open_client_db(client_path: &Path, client_db_config: &DatabaseConfig) -> Result, String> { + let client_db = Arc::new(Database::open( + &client_db_config, + &client_path.to_str().expect("DB path could not be converted to string.") + ).map_err(|e| format!("Client service database error: {:?}", e))?); + + Ok(client_db) +} + +pub fn restoration_db_handler(client_db_config: DatabaseConfig) -> Box { + use kvdb::Error; + + struct RestorationDBHandler { + config: DatabaseConfig, + } + + impl KeyValueDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> Result, Error> { + Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + } + } + + Box::new(RestorationDBHandler { + config: client_db_config, + }) +} + +pub fn compaction_profile(profile: &DatabaseCompactionProfile, db_path: &Path) -> CompactionProfile { + match profile { + &DatabaseCompactionProfile::Auto => CompactionProfile::auto(db_path), + &DatabaseCompactionProfile::SSD => CompactionProfile::ssd(), + &DatabaseCompactionProfile::HDD => CompactionProfile::hdd(), + } +} + pub fn execute_upgrades( base_path: &str, dirs: &DatabaseDirectories, diff --git a/parity/run.rs b/parity/run.rs index 7baeaaed34..816ddd4dd3 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -55,7 +55,7 @@ use params::{ SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch, tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool }; -use helpers::{to_client_config, execute_upgrades, passwords_from_files}; +use helpers::{to_client_config, execute_upgrades, passwords_from_files, client_db_config, open_client_db, restoration_db_handler, compaction_profile}; use upgrade::upgrade_key_location; use dir::{Directories, DatabaseDirectories}; use cache::CacheConfig; @@ -206,7 +206,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()))?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()))?; // create dirs used by parity cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?; @@ -609,12 +609,17 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // set network path. net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); + let client_db_config = client_db_config(&client_path, &client_config); + let client_db = open_client_db(&client_path, &client_db_config)?; + let restoration_db_handler = restoration_db_handler(client_db_config); + // create client service. let service = ClientService::start( client_config, &spec, - &client_path, + client_db, &snapshot_path, + restoration_db_handler, &cmd.dirs.ipc_path(), miner.clone(), ).map_err(|e| format!("Client service error: {:?}", e))?; diff --git a/parity/snapshot.rs b/parity/snapshot.rs index bda5059f7e..ae7a0698b7 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -31,7 +31,7 @@ use ethcore_service::ClientService; use cache::CacheConfig; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool}; -use helpers::{to_client_config, execute_upgrades}; +use helpers::{to_client_config, execute_upgrades, client_db_config, open_client_db, restoration_db_handler, compaction_profile}; use dir::Directories; use user_defaults::UserDefaults; use fdlimit; @@ -162,7 +162,7 @@ impl SnapshotCommand { let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&self.dirs.base, &db_dirs, algorithm, self.compaction.compaction_profile(db_dirs.db_root_path().as_path()))?; + execute_upgrades(&self.dirs.base, &db_dirs, algorithm, compaction_profile(&self.compaction, db_dirs.db_root_path().as_path()))?; // prepare client config let client_config = to_client_config( @@ -181,11 +181,16 @@ impl SnapshotCommand { true ); + let client_db_config = client_db_config(&client_path, &client_config); + let client_db = open_client_db(&client_path, &client_db_config)?; + let restoration_db_handler = restoration_db_handler(client_db_config); + let service = ClientService::start( client_config, &spec, - &client_path, + client_db, &snapshot_path, + restoration_db_handler, &self.dirs.ipc_path(), Arc::new(Miner::with_spec(&spec)) ).map_err(|e| format!("Client service error: {:?}", e))?; diff --git a/util/kvdb/src/lib.rs b/util/kvdb/src/lib.rs index 6a8412c0e8..9ed1038bff 100644 --- a/util/kvdb/src/lib.rs +++ b/util/kvdb/src/lib.rs @@ -22,6 +22,8 @@ extern crate elastic_array; extern crate ethcore_bytes as bytes; use std::io; +use std::path::Path; +use std::sync::Arc; use elastic_array::{ElasticArray128, ElasticArray32}; use bytes::Bytes; @@ -176,3 +178,10 @@ pub trait KeyValueDB: Sync + Send { /// Attempt to replace this database with a new one located at the given path. fn restore(&self, new_db: &str) -> Result<()>; } + +/// Generic key-value database handler. This trait contains one function `open`. When called, it opens database with a +/// predefined config. +pub trait KeyValueDBHandler: Send + Sync { + /// Open the predefined key-value database. + fn open(&self, path: &Path) -> Result>; +} -- GitLab From e6f75bccfe86e3a7b56909720f8d1d0755d4f6ee Mon Sep 17 00:00:00 2001 From: Anton Gavrilov Date: Mon, 9 Apr 2018 16:14:33 +0200 Subject: [PATCH 047/263] Private transactions integration pr (#6422) * Private transaction message added * Empty line removed * Private transactions logic removed from client into the separate module * Fixed compilation after merge with head * Signed private transaction message added as well * Comments after the review fixed * Private tx execution * Test update * Renamed some methods * Fixed some tests * Reverted submodules * Fixed build * Private transaction message added * Empty line removed * Private transactions logic removed from client into the separate module * Fixed compilation after merge with head * Signed private transaction message added as well * Comments after the review fixed * Encrypted private transaction message and signed reply added * Private tx execution * Test update * Main scenario completed * Merged with the latest head * Private transactions API * Comments after review fixed * Parameters for private transactions added to parity arguments * New files added * New API methods added * Do not process packets from unconfirmed peers * Merge with ptm_ss branch * Encryption and permissioning with key server added * Fixed compilation after merge * Version of Parity protocol incremented in order to support private transactions * Doc strings for constants added * Proper format for doc string added * fixed some encryptor.rs grumbles * Private transactions functionality moved to the separate crate * Refactoring in order to remove late initialisation * Tests fixed after moving to the separate crate * Fetch method removed * Sync test helpers refactored * Interaction with encryptor refactored * Contract address retrieving via substate removed * Sensible gas limit for private transactions implemented * New private contract with nonces added * Parsing of the response from key server fixed * Build fixed after the merge, native contracts removed * Crate renamed * Tests moved to the separate directory * Handling of errors reworked in order to use error chain * Encodable macro added, new constructor replaced with default * Native ethabi usage removed * Couple conversions optimized * Interactions with client reworked * Errors omitting removed * Fix after merge * Fix after the merge * private transactions improvements in progress * private_transactions -> ethcore/private-tx * making private transactions more idiomatic * private-tx encryptor uses shared FetchClient and is more idiomatic * removed redundant tests, moved integration tests to tests/ dir * fixed failing service test * reenable add_notify on private tx provider * removed private_tx tests from sync module * removed commented out code * Use plain password instead of unlocking account manager * remove dead code * Link to the contract changed * Transaction signature chain replay protection module created * Redundant type conversion removed * Contract address returned by private provider * Test fixed * Addressing grumbles in PrivateTransactions (#8249) * Tiny fixes part 1. * A bunch of additional comments and todos. * Fix ethsync tests. * resolved merge conflicts * final private tx pr (#8318) * added cli option that enables private transactions * fixed failing test * fixed failing test * fixed failing test * fixed failing test --- Cargo.lock | 41 ++ Cargo.toml | 1 + dapps/src/handlers/fetch.rs | 6 +- dapps/src/tests/helpers/fetch.rs | 4 +- ethcore/Cargo.toml | 3 +- ethcore/private-tx/Cargo.toml | 36 + ethcore/private-tx/res/private.evm | 1 + ethcore/private-tx/res/private.json | 1 + ethcore/private-tx/src/encryptor.rs | 272 +++++++ ethcore/private-tx/src/error.rs | 208 ++++++ ethcore/private-tx/src/lib.rs | 676 ++++++++++++++++++ ethcore/private-tx/src/messages.rs | 76 ++ .../private-tx/src/private_transactions.rs | 173 +++++ ethcore/private-tx/tests/private_contract.rs | 137 ++++ ethcore/service/Cargo.toml | 3 + ethcore/service/src/error.rs | 30 + ethcore/service/src/lib.rs | 13 +- ethcore/service/src/service.rs | 57 +- ethcore/src/block.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 2 +- ethcore/src/client/chain_notify.rs | 12 +- ethcore/src/client/client.rs | 6 +- ethcore/src/client/io_message.rs | 4 +- ethcore/src/client/mod.rs | 4 +- ethcore/src/client/private_notify.rs | 23 + ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 3 +- ethcore/src/engines/validator_set/contract.rs | 2 +- ethcore/src/engines/validator_set/multi.rs | 2 +- .../engines/validator_set/safe_contract.rs | 2 +- ethcore/src/error.rs | 9 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/ethereum/mod.rs | 2 +- ethcore/src/executive.rs | 3 +- ethcore/src/externalities.rs | 2 +- ethcore/src/json_tests/executive.rs | 2 +- ethcore/src/lib.rs | 8 +- ethcore/src/miner/miner.rs | 5 +- ethcore/src/snapshot/account.rs | 2 +- ethcore/src/snapshot/service.rs | 2 +- .../src/snapshot/tests/proof_of_authority.rs | 4 +- ethcore/src/snapshot/tests/service.rs | 2 +- ethcore/src/spec/spec.rs | 2 +- ethcore/src/state/account.rs | 10 + ethcore/src/state/mod.rs | 14 +- ethcore/src/state_db.rs | 2 +- .../src/{tests/helpers.rs => test_helpers.rs} | 59 +- ethcore/src/tests/client.rs | 2 +- ethcore/src/tests/evm.rs | 2 +- ethcore/src/tests/mod.rs | 1 - ethcore/src/tests/trace.rs | 2 +- ethcore/src/verification/queue/mod.rs | 2 +- ethcore/src/verification/verification.rs | 2 +- ethcore/transaction/src/transaction.rs | 24 +- hash-fetch/src/client.rs | 6 +- parity/blockchain.rs | 8 + parity/cli/mod.rs | 58 +- parity/cli/tests/config.full.toml | 9 + parity/configuration.rs | 33 +- parity/main.rs | 7 +- parity/modules.rs | 4 +- parity/rpc_apis.rs | 35 +- parity/run.rs | 23 +- parity/snapshot.rs | 7 +- price-info/src/lib.rs | 6 +- rpc/Cargo.toml | 1 + rpc/src/lib.rs | 1 + rpc/src/v1/helpers/errors.rs | 18 + rpc/src/v1/impls/light/parity_set.rs | 2 +- rpc/src/v1/impls/mod.rs | 2 + rpc/src/v1/impls/parity_set.rs | 2 +- rpc/src/v1/impls/private.rs | 122 ++++ rpc/src/v1/mod.rs | 2 +- rpc/src/v1/tests/helpers/fetch.rs | 4 +- rpc/src/v1/traits/mod.rs | 2 + rpc/src/v1/traits/private.rs | 45 ++ rpc/src/v1/types/mod.rs | 2 + rpc/src/v1/types/private_receipt.rs | 54 ++ sync/Cargo.toml | 1 + sync/src/api.rs | 32 +- sync/src/chain.rs | 103 ++- sync/src/lib.rs | 3 + sync/src/light_sync/tests/test_net.rs | 4 + sync/src/private_tx.rs | 60 ++ sync/src/tests/consensus.rs | 31 +- sync/src/tests/helpers.rs | 221 +++++- util/fetch/src/client.rs | 57 +- util/fetch/src/lib.rs | 1 + 90 files changed, 2745 insertions(+), 192 deletions(-) create mode 100644 ethcore/private-tx/Cargo.toml create mode 100644 ethcore/private-tx/res/private.evm create mode 100644 ethcore/private-tx/res/private.json create mode 100644 ethcore/private-tx/src/encryptor.rs create mode 100644 ethcore/private-tx/src/error.rs create mode 100644 ethcore/private-tx/src/lib.rs create mode 100644 ethcore/private-tx/src/messages.rs create mode 100644 ethcore/private-tx/src/private_transactions.rs create mode 100644 ethcore/private-tx/tests/private_contract.rs create mode 100644 ethcore/service/src/error.rs create mode 100644 ethcore/src/client/private_notify.rs rename ethcore/src/{tests/helpers.rs => test_helpers.rs} (82%) create mode 100644 rpc/src/v1/impls/private.rs create mode 100644 rpc/src/v1/traits/private.rs create mode 100644 rpc/src/v1/types/private_receipt.rs create mode 100644 sync/src/private_tx.rs diff --git a/Cargo.lock b/Cargo.lock index 403b468f84..28a4b8a7af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -519,6 +519,7 @@ dependencies = [ "ethkey 0.3.0", "ethstore 0.2.0", "evm 0.1.0", + "fetch 0.1.0", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hardware-wallet 1.11.0", "hashdb 0.1.1", @@ -720,6 +721,40 @@ dependencies = [ "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-private-tx" +version = "1.0.0" +dependencies = [ + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore 1.11.0", + "ethcore-bytes 0.1.0", + "ethcore-io 1.11.0", + "ethcore-logger 1.11.0", + "ethcore-miner 1.11.0", + "ethcore-transaction 0.1.0", + "ethcrypto 0.1.0", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethjson 0.1.0", + "ethkey 0.3.0", + "fetch 0.1.0", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hash 0.1.0", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.1.0", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.1", + "rlp_derive 0.1.0", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-secretstore" version = "1.0.0" @@ -762,8 +797,11 @@ name = "ethcore-service" version = "0.1.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-io 1.11.0", + "ethcore-private-tx 1.0.0", + "ethsync 1.11.0", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -948,6 +986,7 @@ dependencies = [ "plain_hasher 0.1.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "triehash 0.1.0", @@ -1939,6 +1978,7 @@ dependencies = [ "ethcore-migrations 0.1.0", "ethcore-miner 1.11.0", "ethcore-network 1.11.0", + "ethcore-private-tx 1.0.0", "ethcore-secretstore 1.0.0", "ethcore-service 0.1.0", "ethcore-stratum 1.11.0", @@ -2145,6 +2185,7 @@ dependencies = [ "ethcore-logger 1.11.0", "ethcore-miner 1.11.0", "ethcore-network 1.11.0", + "ethcore-private-tx 1.0.0", "ethcore-transaction 0.1.0", "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 87daa076c1..202215ab34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ ethcore-logger = { path = "logger" } ethcore-migrations = { path = "ethcore/migrations" } ethcore-miner = { path = "miner" } ethcore-network = { path = "util/network" } +ethcore-private-tx = { path = "ethcore/private-tx" } ethcore-service = { path = "ethcore/service" } ethcore-stratum = { path = "stratum" } ethcore-transaction = { path = "ethcore/transaction" } diff --git a/dapps/src/handlers/fetch.rs b/dapps/src/handlers/fetch.rs index 94fe608819..1408d634db 100644 --- a/dapps/src/handlers/fetch.rs +++ b/dapps/src/handlers/fetch.rs @@ -24,7 +24,7 @@ use fetch::{self, Fetch}; use futures::sync::oneshot; use futures::{self, Future}; use futures_cpupool::CpuPool; -use hyper::{self, Method, StatusCode}; +use hyper::{self, StatusCode}; use parking_lot::Mutex; use endpoint::{self, EndpointPath}; @@ -261,7 +261,7 @@ impl ContentFetcherHandler { // Validation of method let status = match *method { // Start fetching content - Method::Get => { + hyper::Method::Get => { trace!(target: "dapps", "Fetching content from: {:?}", url); FetchState::InProgress(Self::fetch_content( pool, @@ -295,7 +295,7 @@ impl ContentFetcherHandler { ) -> Box + Send> { // Start fetching the content let pool2 = pool.clone(); - let future = fetch.fetch(url, abort.into()).then(move |result| { + let future = fetch.get(url, abort.into()).then(move |result| { trace!(target: "dapps", "Fetching content finished. Starting validation: {:?}", result); Ok(match result { Ok(response) => match installer.validate_and_install(response) { diff --git a/dapps/src/tests/helpers/fetch.rs b/dapps/src/tests/helpers/fetch.rs index dfe523200e..d65d9d09b0 100644 --- a/dapps/src/tests/helpers/fetch.rs +++ b/dapps/src/tests/helpers/fetch.rs @@ -20,7 +20,7 @@ use parking_lot::Mutex; use hyper; use futures::{self, Future}; -use fetch::{self, Fetch, Url}; +use fetch::{self, Fetch, Url, Method}; pub struct FetchControl { sender: mpsc::Sender<()>, @@ -97,7 +97,7 @@ impl FakeFetch { impl Fetch for FakeFetch { type Result = Box + Send>; - fn fetch(&self, url: &str, abort: fetch::Abort) -> Self::Result { + fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { let u = Url::parse(url).unwrap(); self.requested.lock().push(url.into()); let manual = self.manual.clone(); diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 9c61fd8ea4..c028f8e6b0 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -16,6 +16,7 @@ crossbeam = "0.3" ethash = { path = "../ethash" } ethcore-bloom-journal = { path = "../util/bloom" } ethcore-bytes = { path = "../util/bytes" } +fetch = { path = "../util/fetch" } hashdb = { path = "../util/hashdb" } memorydb = { path = "../util/memorydb" } patricia-trie = { path = "../util/patricia_trie" } @@ -52,6 +53,7 @@ rlp_compress = { path = "../util/rlp_compress" } rlp_derive = { path = "../util/rlp_derive" } kvdb = { path = "../util/kvdb" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } +kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } util-error = { path = "../util/error" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } @@ -72,7 +74,6 @@ journaldb = { path = "../util/journaldb" } [dev-dependencies] tempdir = "0.3" trie-standardmap = { path = "../util/trie-standardmap" } -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } [features] evm-debug = ["slow-blocks"] diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml new file mode 100644 index 0000000000..6ecfdb5464 --- /dev/null +++ b/ethcore/private-tx/Cargo.toml @@ -0,0 +1,36 @@ +[package] +description = "Parity Private Transactions" +name = "ethcore-private-tx" +version = "1.0.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[dependencies] +error-chain = { version = "0.11", default-features = false } +ethabi = "5.1" +ethabi-contract = "5.0" +ethabi-derive = "5.0" +ethcore = { path = ".." } +ethcore-bytes = { path = "../../util/bytes" } +ethcore-io = { path = "../../util/io" } +ethcore-logger = { path = "../../logger" } +ethcore-miner = { path = "../../miner" } +ethcore-transaction = { path = "../transaction" } +ethcrypto = { path = "../../ethcrypto" } +ethereum-types = "0.3" +ethjson = { path = "../../json" } +ethkey = { path = "../../ethkey" } +fetch = { path = "../../util/fetch" } +futures = "0.1" +keccak-hash = { path = "../../util/hash" } +log = "0.3" +parking_lot = "0.5" +patricia-trie = { path = "../../util/patricia_trie" } +rand = "0.3" +rlp = { path = "../../util/rlp" } +rlp_derive = { path = "../../util/rlp_derive" } +rustc-hex = "1.0" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" +tiny-keccak = "1.3" diff --git a/ethcore/private-tx/res/private.evm b/ethcore/private-tx/res/private.evm new file mode 100644 index 0000000000..cd19d757aa --- /dev/null +++ b/ethcore/private-tx/res/private.evm @@ -0,0 +1 @@ +6060604052341561000f57600080fd5b604051610b0d380380610b0d833981016040528080518201919060200180518201919060200180518201919050508260009080519060200190610053929190610092565b50816002908051906020019061006a92919061011c565b50806001908051906020019061008192919061011c565b506001600381905550505050610204565b82805482825590600052602060002090810192821561010b579160200282015b8281111561010a5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906100b2565b5b509050610118919061019c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061015d57805160ff191683800117855561018b565b8280016001018555821561018b579182015b8281111561018a57825182559160200191906001019061016f565b5b50905061019891906101df565b5090565b6101dc91905b808211156101d857600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016101a2565b5090565b90565b61020191905b808211156101fd5760008160009055506001016101e5565b5090565b90565b6108fa806102136000396000f300606060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806317ac53a21461007d57806324c12bf61461019a57806335aa2e4414610228578063affed0e01461028b578063b7ab4db5146102b4578063c19d93fb1461031e575b600080fd5b341561008857600080fd5b610198600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506103ac565b005b34156101a557600080fd5b6101ad610600565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ed5780820151818401526020810190506101d2565b50505050905090810190601f16801561021a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561023357600080fd5b610249600480803590602001909190505061069e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561029657600080fd5b61029e6106dd565b6040518082815260200191505060405180910390f35b34156102bf57600080fd5b6102c76106e3565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561030a5780820151818401526020810190506102ef565b505050509050019250505060405180910390f35b341561032957600080fd5b610331610777565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610371578082015181840152602081019050610356565b50505050905090810190601f16801561039e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000806040805190810160405280876040518082805190602001908083835b6020831015156103f057805182526020820191506020810190506020830392506103cb565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200160035460010260001916600019168152506040518082600260200280838360005b8381101561046657808201518184015260208101905061044b565b5050505090500191505060405180910390209150600090505b6000805490508110156105d55760008181548110151561049b57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660018387848151811015156104ee57fe5b90602001906020020151878581518110151561050657fe5b90602001906020020151878681518110151561051e57fe5b90602001906020020151604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f115156105a057600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff161415156105c857fe5b808060010191505061047f565b85600190805190602001906105eb929190610815565b50600160035401600381905550505050505050565b60028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106965780601f1061066b57610100808354040283529160200191610696565b820191906000526020600020905b81548152906001019060200180831161067957829003601f168201915b505050505081565b6000818154811015156106ad57fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b6106eb610895565b600080548060200260200160405190810160405280929190818152602001828054801561076d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610723575b5050505050905090565b60018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561080d5780601f106107e25761010080835404028352916020019161080d565b820191906000526020600020905b8154815290600101906020018083116107f057829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061085657805160ff1916838001178555610884565b82800160010185558215610884579182015b82811115610883578251825591602001919060010190610868565b5b50905061089191906108a9565b5090565b602060405190810160405280600081525090565b6108cb91905b808211156108c75760008160009055506001016108af565b5090565b905600a165627a7a723058200ae0215fae320b646a22fdd58278b328f46d915bd65ddbfeb5b4a09643d6e0220029 diff --git a/ethcore/private-tx/res/private.json b/ethcore/private-tx/res/private.json new file mode 100644 index 0000000000..82a5e86bc2 --- /dev/null +++ b/ethcore/private-tx/res/private.json @@ -0,0 +1 @@ +[{"constant": false,"inputs": [{"name": "newState","type": "bytes"},{"name": "v","type": "uint8[]"},{"name": "r","type": "bytes32[]"},{"name": "s","type": "bytes32[]"}],"name": "setState","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [],"name": "code","outputs": [{"name": "","type": "bytes"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [{"name": "","type": "uint256"}],"name": "validators","outputs": [{"name": "","type": "address"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "nonce","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "getValidators","outputs": [{"name": "","type": "address[]"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "state","outputs": [{"name": "","type": "bytes"}],"payable": false,"stateMutability": "view","type": "function"},{"inputs": [{"name": "initialValidators","type": "address[]"},{"name": "initialCode","type": "bytes"},{"name": "initialState","type": "bytes"}],"payable": false,"stateMutability": "nonpayable","type": "constructor"}] diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs new file mode 100644 index 0000000000..385356227f --- /dev/null +++ b/ethcore/private-tx/src/encryptor.rs @@ -0,0 +1,272 @@ +// 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 . + +//! Encryption providers. + +use std::io::Read; +use std::iter::repeat; +use std::time::{Instant, Duration}; +use std::collections::HashMap; +use std::collections::hash_map::Entry; +use parking_lot::Mutex; +use ethcore::account_provider::AccountProvider; +use ethereum_types::{H128, H256, Address}; +use ethjson; +use ethkey::{Signature, Public}; +use ethcrypto; +use futures::Future; +use fetch::{Fetch, Client as FetchClient, Method, BodyReader}; +use bytes::{Bytes, ToPretty}; +use error::{Error, ErrorKind}; +use super::find_account_password; + +/// Initialization vector length. +const INIT_VEC_LEN: usize = 16; + +/// Duration of storing retrieved keys (in ms) +const ENCRYPTION_SESSION_DURATION: u64 = 30 * 1000; + +/// Trait for encryption/decryption operations. +pub trait Encryptor: Send + Sync + 'static { + /// Generate unique contract key && encrypt passed data. Encryption can only be performed once. + fn encrypt( + &self, + contract_address: &Address, + accounts: &AccountProvider, + initialisation_vector: &H128, + plain_data: &[u8], + ) -> Result; + + /// Decrypt data using previously generated contract key. + fn decrypt( + &self, + contract_address: &Address, + accounts: &AccountProvider, + cypher: &[u8], + ) -> Result; +} + +/// Configurtion for key server encryptor +#[derive(Default, PartialEq, Debug, Clone)] +pub struct EncryptorConfig { + /// URL to key server + pub base_url: Option, + /// Key server's threshold + pub threshold: u32, + /// Account used for signing requests to key server + pub key_server_account: Option
, + /// Passwords used to unlock accounts + pub passwords: Vec, +} + +struct EncryptionSession { + key: Bytes, + end_time: Instant, +} + +/// SecretStore-based encryption/decryption operations. +pub struct SecretStoreEncryptor { + config: EncryptorConfig, + client: FetchClient, + sessions: Mutex>, +} + +impl SecretStoreEncryptor { + /// Create new encryptor + pub fn new(config: EncryptorConfig, client: FetchClient) -> Result { + Ok(SecretStoreEncryptor { + config, + client, + sessions: Mutex::default(), + }) + } + + /// Ask secret store for key && decrypt the key. + fn retrieve_key( + &self, + url_suffix: &str, + use_post: bool, + contract_address: &Address, + accounts: &AccountProvider, + ) -> Result { + // check if the key was already cached + if let Some(key) = self.obtained_key(contract_address) { + return Ok(key); + } + let contract_address_signature = self.sign_contract_address(contract_address, accounts)?; + let requester = self.config.key_server_account.ok_or_else(|| ErrorKind::KeyServerAccountNotSet)?; + + // key id in SS is H256 && we have H160 here => expand with assitional zeros + let contract_address_extended: H256 = contract_address.into(); + let base_url = self.config.base_url.clone().ok_or_else(|| ErrorKind::KeyServerNotSet)?; + + // prepare request url + let url = format!("{}/{}/{}{}", + base_url, + contract_address_extended.to_hex(), + contract_address_signature, + url_suffix, + ); + + // send HTTP request + let method = if use_post { + Method::Post + } else { + Method::Get + }; + + let response = self.client.fetch(&url, method, Default::default()).wait() + .map_err(|e| ErrorKind::Encrypt(e.to_string()))?; + + if response.is_not_found() { + bail!(ErrorKind::EncryptionKeyNotFound(*contract_address)); + } + + if !response.is_success() { + bail!(ErrorKind::Encrypt(response.status().canonical_reason().unwrap_or("unknown").into())); + } + + // read HTTP response + let mut result = String::new(); + BodyReader::new(response).read_to_string(&mut result)?; + + // response is JSON string (which is, in turn, hex-encoded, encrypted Public) + let encrypted_bytes: ethjson::bytes::Bytes = result.trim_matches('\"').parse().map_err(|e| ErrorKind::Encrypt(e))?; + let password = find_account_password(&self.config.passwords, &*accounts, &requester); + + // decrypt Public + let decrypted_bytes = accounts.decrypt(requester, password, ðcrypto::DEFAULT_MAC, &encrypted_bytes)?; + let decrypted_key = Public::from_slice(&decrypted_bytes); + + // and now take x coordinate of Public as a key + let key: Bytes = (*decrypted_key)[..INIT_VEC_LEN].into(); + + // cache the key in the session and clear expired sessions + self.sessions.lock().insert(*contract_address, EncryptionSession{ + key: key.clone(), + end_time: Instant::now() + Duration::from_millis(ENCRYPTION_SESSION_DURATION), + }); + self.clean_expired_sessions(); + Ok(key) + } + + fn clean_expired_sessions(&self) { + let mut sessions = self.sessions.lock(); + sessions.retain(|_, session| session.end_time < Instant::now()); + } + + fn obtained_key(&self, contract_address: &Address) -> Option { + let mut sessions = self.sessions.lock(); + let stored_session = sessions.entry(*contract_address); + match stored_session { + Entry::Occupied(session) => { + if Instant::now() > session.get().end_time { + session.remove_entry(); + None + } else { + Some(session.get().key.clone()) + } + } + Entry::Vacant(_) => None, + } + } + + fn sign_contract_address(&self, contract_address: &Address, accounts: &AccountProvider) -> Result { + // key id in SS is H256 && we have H160 here => expand with assitional zeros + let contract_address_extended: H256 = contract_address.into(); + let key_server_account = self.config.key_server_account.ok_or_else(|| ErrorKind::KeyServerAccountNotSet)?; + let password = find_account_password(&self.config.passwords, accounts, &key_server_account); + Ok(accounts.sign(key_server_account, password, H256::from_slice(&contract_address_extended))?) + } +} + +impl Encryptor for SecretStoreEncryptor { + fn encrypt( + &self, + contract_address: &Address, + accounts: &AccountProvider, + initialisation_vector: &H128, + plain_data: &[u8], + ) -> Result { + // retrieve the key, try to generate it if it doesn't exist yet + let key = match self.retrieve_key("", false, contract_address, &*accounts) { + Ok(key) => Ok(key), + Err(Error(ErrorKind::EncryptionKeyNotFound(_), _)) => { + trace!("Key for account wasnt found in sstore. Creating. Address: {:?}", contract_address); + self.retrieve_key(&format!("/{}", self.config.threshold), true, contract_address, &*accounts) + } + Err(err) => Err(err), + }?; + + // encrypt data + let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len()); + cypher.extend(repeat(0).take(plain_data.len())); + ethcrypto::aes::encrypt(&key, initialisation_vector, plain_data, &mut cypher); + cypher.extend_from_slice(&initialisation_vector); + + Ok(cypher) + } + + /// Decrypt data using previously generated contract key. + fn decrypt( + &self, + contract_address: &Address, + accounts: &AccountProvider, + cypher: &[u8], + ) -> Result { + // initialization vector takes INIT_VEC_LEN bytes + let cypher_len = cypher.len(); + if cypher_len < INIT_VEC_LEN { + bail!(ErrorKind::Decrypt("Invalid cypher".into())); + } + + // retrieve existing key + let key = self.retrieve_key("", false, contract_address, accounts)?; + + // use symmetric decryption to decrypt document + let (cypher, iv) = cypher.split_at(cypher_len - INIT_VEC_LEN); + let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN); + plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN)); + ethcrypto::aes::decrypt(&key, &iv, cypher, &mut plain_data); + + Ok(plain_data) + } +} + +/// Dummy encryptor. +#[derive(Default)] +pub struct NoopEncryptor; + +impl Encryptor for NoopEncryptor { + fn encrypt( + &self, + _contract_address: &Address, + _accounts: &AccountProvider, + _initialisation_vector: &H128, + data: &[u8], + ) -> Result { + Ok(data.to_vec()) + } + + fn decrypt( + &self, + _contract_address: &Address, + _accounts: &AccountProvider, + data: &[u8], + ) -> Result { + Ok(data.to_vec()) + } +} diff --git a/ethcore/private-tx/src/error.rs b/ethcore/private-tx/src/error.rs new file mode 100644 index 0000000000..3b3c881a94 --- /dev/null +++ b/ethcore/private-tx/src/error.rs @@ -0,0 +1,208 @@ +// 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 . + +use ethereum_types::Address; +use rlp::DecoderError; +use trie::TrieError; +use ethcore::account_provider::SignError; +use ethcore::error::{Error as EthcoreError, ExecutionError}; +use transaction::Error as TransactionError; +use ethkey::Error as KeyError; + +error_chain! { + foreign_links { + Io(::std::io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; + Decoder(DecoderError) #[doc = "RLP decoding error."]; + Trie(TrieError) #[doc = "Error concerning TrieDBs."]; + } + + errors { + #[doc = "Encryption error."] + Encrypt(err: String) { + description("Encryption error"), + display("Encryption error. ({})", err), + } + + #[doc = "Decryption error."] + Decrypt(err: String) { + description("Decryption error"), + display("Decryption error. ({})", err), + } + + #[doc = "Address not authorized."] + NotAuthorised(address: Address) { + description("Address not authorized"), + display("Private transaction execution is not authorised for {}", address), + } + + #[doc = "Transaction creates more than one contract."] + TooManyContracts { + description("Transaction creates more than one contract."), + display("Private transaction created too many contracts"), + } + + #[doc = "Contract call error."] + Call(err: String) { + description("Contract call error."), + display("Contract call error. ({})", err), + } + + #[doc = "State is not available."] + StatePruned { + description("State is not available."), + display("State is not available"), + } + + #[doc = "State is incorrect."] + StateIncorrect { + description("State is incorrect."), + display("State is incorrect"), + } + + #[doc = "Wrong private transaction type."] + BadTransactonType { + description("Wrong private transaction type."), + display("Wrong private transaction type"), + } + + #[doc = "Contract does not exist or was not created."] + ContractDoesNotExist { + description("Contract does not exist or was not created."), + display("Contract does not exist or was not created"), + } + + #[doc = "Reference to the client is corrupted."] + ClientIsMalformed { + description("Reference to the client is corrupted."), + display("Reference to the client is corrupted"), + } + + #[doc = "Queue of private transactions for verification is full."] + QueueIsFull { + description("Queue of private transactions for verification is full."), + display("Queue of private transactions for verification is full"), + } + + #[doc = "The transaction already exists in queue of private transactions."] + PrivateTransactionAlreadyImported { + description("The transaction already exists in queue of private transactions."), + display("The transaction already exists in queue of private transactions."), + } + + #[doc = "The information about private transaction is not found in the store."] + PrivateTransactionNotFound { + description("The information about private transaction is not found in the store."), + display("The information about private transaction is not found in the store."), + } + + #[doc = "Account for signing public transactions not set."] + SignerAccountNotSet { + description("Account for signing public transactions not set."), + display("Account for signing public transactions not set."), + } + + #[doc = "Account for validating private transactions not set."] + ValidatorAccountNotSet { + description("Account for validating private transactions not set."), + display("Account for validating private transactions not set."), + } + + #[doc = "Account for signing requests to key server not set."] + KeyServerAccountNotSet { + description("Account for signing requests to key server not set."), + display("Account for signing requests to key server not set."), + } + + #[doc = "Encryption key is not found on key server."] + EncryptionKeyNotFound(address: Address) { + description("Encryption key is not found on key server"), + display("Encryption key is not found on key server for {}", address), + } + + #[doc = "Key server URL is not set."] + KeyServerNotSet { + description("Key server URL is not set."), + display("Key server URL is not set."), + } + + #[doc = "VM execution error."] + Execution(err: ExecutionError) { + description("VM execution error."), + display("VM execution error {}", err), + } + + #[doc = "General signing error."] + Key(err: KeyError) { + description("General signing error."), + display("General signing error {}", err), + } + + #[doc = "Account provider signing error."] + Sign(err: SignError) { + description("Account provider signing error."), + display("Account provider signing error {}", err), + } + + #[doc = "Error of transactions processing."] + Transaction(err: TransactionError) { + description("Error of transactions processing."), + display("Error of transactions processing {}", err), + } + + #[doc = "General ethcore error."] + Ethcore(err: EthcoreError) { + description("General ethcore error."), + display("General ethcore error {}", err), + } + } +} + +impl From for Error { + fn from(err: SignError) -> Self { + ErrorKind::Sign(err).into() + } +} + +impl From for Error { + fn from(err: KeyError) -> Self { + ErrorKind::Key(err).into() + } +} + +impl From for Error { + fn from(err: ExecutionError) -> Self { + ErrorKind::Execution(err).into() + } +} + +impl From for Error { + fn from(err: TransactionError) -> Self { + ErrorKind::Transaction(err).into() + } +} + +impl From for Error { + fn from(err: EthcoreError) -> Self { + ErrorKind::Ethcore(err).into() + } +} + +impl From> for Error where Error: From { + fn from(err: Box) -> Error { + Error::from(*err) + } +} + diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs new file mode 100644 index 0000000000..4fa1f8789c --- /dev/null +++ b/ethcore/private-tx/src/lib.rs @@ -0,0 +1,676 @@ +// 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 . + +//! Private transactions module. + +// Recursion limit required because of +// error_chain foreign_links. +#![recursion_limit="256"] + +mod encryptor; +mod private_transactions; +mod messages; +mod error; + +extern crate ethcore; +extern crate ethcore_io as io; +extern crate ethcore_bytes as bytes; +extern crate ethcore_transaction as transaction; +extern crate ethcore_miner; +extern crate ethcrypto; +extern crate ethabi; +extern crate ethereum_types; +extern crate ethkey; +extern crate ethjson; +extern crate fetch; +extern crate futures; +extern crate keccak_hash as hash; +extern crate parking_lot; +extern crate patricia_trie as trie; +extern crate rlp; +extern crate rustc_hex; +#[macro_use] +extern crate log; +#[macro_use] +extern crate ethabi_derive; +#[macro_use] +extern crate ethabi_contract; +#[macro_use] +extern crate error_chain; +#[macro_use] +extern crate rlp_derive; + +#[cfg(test)] +extern crate rand; +#[cfg(test)] +extern crate ethcore_logger; + +pub use encryptor::{Encryptor, SecretStoreEncryptor, EncryptorConfig, NoopEncryptor}; +pub use private_transactions::{PrivateTransactionDesc, VerificationStore, PrivateTransactionSigningDesc, SigningStore}; +pub use messages::{PrivateTransaction, SignedPrivateTransaction}; +pub use error::{Error, ErrorKind}; + +use std::sync::{Arc, Weak}; +use std::collections::{HashMap, HashSet}; +use ethereum_types::{H128, H256, U256, Address}; +use hash::keccak; +use rlp::*; +use parking_lot::{Mutex, RwLock}; +use bytes::Bytes; +use ethkey::{Signature, recover, public_to_address}; +use io::IoChannel; +use ethcore::executive::{Executive, TransactOptions}; +use ethcore::executed::{Executed}; +use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction}; +use ethcore::{contract_address as ethcore_contract_address}; +use ethcore::client::{ + Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, + MiningBlockChainClient, ChainInfo, Nonce, CallContract +}; +use ethcore::account_provider::AccountProvider; +use ethcore_miner::transaction_queue::{TransactionDetailsProvider as TransactionQueueDetailsProvider, AccountDetails}; +use ethcore::miner::MinerService; +use ethcore::trace::{Tracer, VMTracer}; +use rustc_hex::FromHex; + +// Source avaiable at https://github.com/parity-contracts/private-tx/blob/master/contracts/PrivateContract.sol +const DEFAULT_STUB_CONTRACT: &'static str = include_str!("../res/private.evm"); + +use_contract!(private, "PrivateContract", "res/private.json"); + +/// Initialization vector length. +const INIT_VEC_LEN: usize = 16; + +struct TransactionDetailsProvider<'a> { + client: &'a MiningBlockChainClient, +} + +impl<'a> TransactionDetailsProvider<'a> { + pub fn new(client: &'a MiningBlockChainClient) -> Self { + TransactionDetailsProvider { + client: client, + } + } +} + +impl<'a> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a> { + fn fetch_account(&self, address: &Address) -> AccountDetails { + AccountDetails { + nonce: self.client.latest_nonce(address), + balance: self.client.latest_balance(address), + } + } + + fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256 { + tx.gas_required(&self.client.latest_schedule()).into() + } + + fn is_service_transaction_acceptable(&self, _tx: &SignedTransaction) -> Result { + Ok(false) + } +} + +/// Configurtion for private transaction provider +#[derive(Default, PartialEq, Debug, Clone)] +pub struct ProviderConfig { + /// Accounts that can be used for validation + pub validator_accounts: Vec
, + /// Account used for signing public transactions created from private transactions + pub signer_account: Option
, + /// Passwords used to unlock accounts + pub passwords: Vec, +} + +#[derive(Debug)] +/// Private transaction execution receipt. +pub struct Receipt { + /// Private transaction hash. + pub hash: H256, + /// Created contract address if any. + pub contract_address: Option
, + /// Execution status. + pub status_code: u8, +} + +/// Manager of private transactions +pub struct Provider { + encryptor: Box, + validator_accounts: HashSet
, + signer_account: Option
, + passwords: Vec, + notify: RwLock>>, + transactions_for_signing: Mutex, + transactions_for_verification: Mutex, + client: Arc, + accounts: Arc, + channel: IoChannel, +} + +#[derive(Debug)] +pub struct PrivateExecutionResult where T: Tracer, V: VMTracer { + code: Option, + state: Bytes, + contract_address: Option
, + result: Executed, +} + +impl Provider where { + /// Create a new provider. + pub fn new( + client: Arc, + accounts: Arc, + encryptor: Box, + config: ProviderConfig, + channel: IoChannel, + ) -> Result { + Ok(Provider { + encryptor, + validator_accounts: config.validator_accounts.into_iter().collect(), + signer_account: config.signer_account, + passwords: config.passwords, + notify: RwLock::default(), + transactions_for_signing: Mutex::default(), + transactions_for_verification: Mutex::default(), + client, + accounts, + channel, + }) + } + + // TODO [ToDr] Don't use `ChainNotify` here! + // Better to create a separate notification type for this. + /// Adds an actor to be notified on certain events + pub fn add_notify(&self, target: Arc) { + self.notify.write().push(Arc::downgrade(&target)); + } + + fn notify(&self, f: F) where F: Fn(&ChainNotify) { + for np in self.notify.read().iter() { + if let Some(n) = np.upgrade() { + f(&*n); + } + } + } + + /// 1. Create private transaction from the signed transaction + /// 2. Executes private transaction + /// 3. Save it with state returned on prev step to the queue for signing + /// 4. Broadcast corresponding message to the chain + pub fn create_private_transaction(&self, signed_transaction: SignedTransaction) -> Result { + trace!("Creating private transaction from regular transaction: {:?}", signed_transaction); + if self.signer_account.is_none() { + trace!("Signing account not set"); + bail!(ErrorKind::SignerAccountNotSet); + } + let tx_hash = signed_transaction.hash(); + match signed_transaction.action { + Action::Create => { + bail!(ErrorKind::BadTransactonType); + } + Action::Call(contract) => { + let data = signed_transaction.rlp_bytes(); + let encrypted_transaction = self.encrypt(&contract, &Self::iv_from_transaction(&signed_transaction), &data)?; + let private = PrivateTransaction { + encrypted: encrypted_transaction, + contract, + }; + // TODO [ToDr] Using BlockId::Latest is bad here, + // the block may change in the middle of execution + // causing really weird stuff to happen. + // We should retrieve hash and stick to that. IMHO + // best would be to change the API and only allow H256 instead of BlockID + // in private-tx to avoid such mistakes. + let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest)?; + let private_state = self.execute_private_transaction(BlockId::Latest, &signed_transaction)?; + trace!("Private transaction created, encrypted transaction: {:?}, private state: {:?}", private, private_state); + let contract_validators = self.get_validators(BlockId::Latest, &contract)?; + trace!("Required validators: {:?}", contract_validators); + let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce); + trace!("Hashed effective private state for sender: {:?}", private_state_hash); + self.transactions_for_signing.lock().add_transaction(private.hash(), signed_transaction, contract_validators, private_state, contract_nonce)?; + self.broadcast_private_transaction(private.rlp_bytes().into_vec()); + Ok(Receipt { + hash: tx_hash, + contract_address: None, + status_code: 0, + }) + } + } + } + + /// Calculate hash from united private state and contract nonce + pub fn calculate_state_hash(&self, state: &Bytes, nonce: U256) -> H256 { + let state_hash = keccak(state); + let mut state_buf = [0u8; 64]; + state_buf[..32].clone_from_slice(&state_hash); + state_buf[32..].clone_from_slice(&H256::from(nonce)); + keccak(&state_buf.as_ref()) + } + + /// Extract signed transaction from private transaction + fn extract_original_transaction(&self, private: PrivateTransaction, contract: &Address) -> Result { + let encrypted_transaction = private.encrypted; + let transaction_bytes = self.decrypt(contract, &encrypted_transaction)?; + let original_transaction: UnverifiedTransaction = UntrustedRlp::new(&transaction_bytes).as_val()?; + Ok(original_transaction) + } + + /// Process received private transaction + pub fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { + trace!("Private transaction received"); + let private_tx: PrivateTransaction = UntrustedRlp::new(rlp).as_val()?; + let contract = private_tx.contract; + let contract_validators = self.get_validators(BlockId::Latest, &contract)?; + + let validation_account = contract_validators + .iter() + .find(|address| self.validator_accounts.contains(address)); + + match validation_account { + None => { + // Not for verification, broadcast further to peers + self.broadcast_private_transaction(rlp.into()); + return Ok(()); + }, + Some(&validation_account) => { + let hash = private_tx.hash(); + trace!("Private transaction taken for verification"); + let original_tx = self.extract_original_transaction(private_tx, &contract)?; + trace!("Validating transaction: {:?}", original_tx); + let details_provider = TransactionDetailsProvider::new(&*self.client as &MiningBlockChainClient); + let insertion_time = self.client.chain_info().best_block_number; + // Verify with the first account available + trace!("The following account will be used for verification: {:?}", validation_account); + self.transactions_for_verification.lock() + .add_transaction(original_tx, contract, validation_account, hash, &details_provider, insertion_time)?; + self.channel.send(ClientIoMessage::NewPrivateTransaction).map_err(|_| ErrorKind::ClientIsMalformed.into()) + } + } + } + + /// Private transaction for validation added into queue + pub fn on_private_transaction_queued(&self) -> Result<(), Error> { + self.process_queue() + } + + /// Retrieve and verify the first available private transaction for every sender + fn process_queue(&self) -> Result<(), Error> { + let mut verification_queue = self.transactions_for_verification.lock(); + let ready_transactions = verification_queue.ready_transactions(); + let fetch_nonce = |a: &Address| self.client.latest_nonce(a); + for transaction in ready_transactions { + let transaction_hash = transaction.hash(); + match verification_queue.private_transaction_descriptor(&transaction_hash) { + Ok(desc) => { + if !self.validator_accounts.contains(&desc.validator_account) { + trace!("Cannot find validator account in config"); + bail!(ErrorKind::ValidatorAccountNotSet); + } + let account = desc.validator_account; + if let Action::Call(contract) = transaction.action { + let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest)?; + let private_state = self.execute_private_transaction(BlockId::Latest, &transaction)?; + let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce); + trace!("Hashed effective private state for validator: {:?}", private_state_hash); + let password = find_account_password(&self.passwords, &*self.accounts, &account); + let signed_state = self.accounts.sign(account, password, private_state_hash)?; + let signed_private_transaction = SignedPrivateTransaction::new(desc.private_hash, signed_state, None); + trace!("Sending signature for private transaction: {:?}", signed_private_transaction); + self.broadcast_signed_private_transaction(signed_private_transaction.rlp_bytes().into_vec()); + } else { + trace!("Incorrect type of action for the transaction"); + bail!(ErrorKind::BadTransactonType); + } + }, + Err(e) => { + trace!("Cannot retrieve descriptor for transaction with error {:?}", e); + bail!(e); + } + } + verification_queue.remove_private_transaction(&transaction_hash, &fetch_nonce); + } + Ok(()) + } + + /// Add signed private transaction into the store + /// Creates corresponding public transaction if last required singature collected and sends it to the chain + pub fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { + let tx: SignedPrivateTransaction = UntrustedRlp::new(rlp).as_val()?; + trace!("Signature for private transaction received: {:?}", tx); + let private_hash = tx.private_transaction_hash(); + let desc = match self.transactions_for_signing.lock().get(&private_hash) { + None => { + // Not our transaction, broadcast further to peers + self.broadcast_signed_private_transaction(rlp.into()); + return Ok(()); + }, + Some(desc) => desc, + }; + + let last = self.last_required_signature(&desc, tx.signature())?; + + if last { + let mut signatures = desc.received_signatures.clone(); + signatures.push(tx.signature()); + let rsv: Vec = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect(); + //Create public transaction + let public_tx = self.public_transaction( + desc.state.clone(), + &desc.original_transaction, + &rsv, + desc.original_transaction.nonce, + desc.original_transaction.gas_price + )?; + trace!("Last required signature received, public transaction created: {:?}", public_tx); + //Sign and add it to the queue + let chain_id = desc.original_transaction.chain_id(); + let hash = public_tx.hash(chain_id); + let signer_account = self.signer_account.ok_or_else(|| ErrorKind::SignerAccountNotSet)?; + let password = find_account_password(&self.passwords, &*self.accounts, &signer_account); + let signature = self.accounts.sign(signer_account, password, hash)?; + let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?; + match self.client.miner().import_own_transaction(&*self.client, signed.into()) { + Ok(_) => trace!("Public transaction added to queue"), + Err(err) => { + trace!("Failed to add transaction to queue, error: {:?}", err); + bail!(err); + } + } + //Remove from store for signing + match self.transactions_for_signing.lock().remove(&private_hash) { + Ok(_) => {} + Err(err) => { + trace!("Failed to remove transaction from signing store, error: {:?}", err); + bail!(err); + } + } + } else { + //Add signature to the store + match self.transactions_for_signing.lock().add_signature(&private_hash, tx.signature()) { + Ok(_) => trace!("Signature stored for private transaction"), + Err(err) => { + trace!("Failed to add signature to signing store, error: {:?}", err); + bail!(err); + } + } + } + Ok(()) + } + + fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result { + if desc.received_signatures.contains(&sign) { + return Ok(false); + } + let state_hash = self.calculate_state_hash(&desc.state, desc.contract_nonce); + match recover(&sign, &state_hash) { + Ok(public) => { + let sender = public_to_address(&public); + match desc.validators.contains(&sender) { + true => { + Ok(desc.received_signatures.len() + 1 == desc.validators.len()) + } + false => { + trace!("Sender's state doesn't correspond to validator's"); + bail!(ErrorKind::StateIncorrect); + } + } + } + Err(err) => { + trace!("Sender's state doesn't correspond to validator's, error {:?}", err); + bail!(err); + } + } + } + + /// Broadcast the private transaction message to the chain + fn broadcast_private_transaction(&self, message: Bytes) { + self.notify(|notify| notify.broadcast(ChainMessageType::PrivateTransaction(message.clone()))); + } + + /// Broadcast signed private transaction message to the chain + fn broadcast_signed_private_transaction(&self, message: Bytes) { + self.notify(|notify| notify.broadcast(ChainMessageType::SignedPrivateTransaction(message.clone()))); + } + + fn iv_from_transaction(transaction: &SignedTransaction) -> H128 { + let nonce = keccak(&transaction.nonce.rlp_bytes()); + let (iv, _) = nonce.split_at(INIT_VEC_LEN); + H128::from_slice(iv) + } + + fn iv_from_address(contract_address: &Address) -> H128 { + let address = keccak(&contract_address.rlp_bytes()); + let (iv, _) = address.split_at(INIT_VEC_LEN); + H128::from_slice(iv) + } + + fn encrypt(&self, contract_address: &Address, initialisation_vector: &H128, data: &[u8]) -> Result { + trace!("Encrypt data using key(address): {:?}", contract_address); + Ok(self.encryptor.encrypt(contract_address, &*self.accounts, initialisation_vector, data)?) + } + + fn decrypt(&self, contract_address: &Address, data: &[u8]) -> Result { + trace!("Decrypt data using key(address): {:?}", contract_address); + Ok(self.encryptor.decrypt(contract_address, &*self.accounts, data)?) + } + + fn get_decrypted_state(&self, address: &Address, block: BlockId) -> Result { + let contract = private::PrivateContract::default(); + let state = contract.functions() + .state() + .call(&|data| self.client.call_contract(block, *address, data)) + .map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?; + + self.decrypt(address, &state) + } + + fn get_decrypted_code(&self, address: &Address, block: BlockId) -> Result { + let contract = private::PrivateContract::default(); + let code = contract.functions() + .code() + .call(&|data| self.client.call_contract(block, *address, data)) + .map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?; + + self.decrypt(address, &code) + } + + pub fn get_contract_nonce(&self, address: &Address, block: BlockId) -> Result { + let contract = private::PrivateContract::default(); + Ok(contract.functions() + .nonce() + .call(&|data| self.client.call_contract(block, *address, data)) + .map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?) + } + + fn snapshot_to_storage(raw: Bytes) -> HashMap { + let items = raw.len() / 64; + (0..items).map(|i| { + let offset = i * 64; + let key = H256::from_slice(&raw[offset..(offset + 32)]); + let value = H256::from_slice(&raw[(offset + 32)..(offset + 64)]); + (key, value) + }).collect() + } + + fn snapshot_from_storage(storage: &HashMap) -> Bytes { + let mut raw = Vec::with_capacity(storage.len() * 64); + for (key, value) in storage { + raw.extend_from_slice(key); + raw.extend_from_slice(value); + }; + raw + } + + pub fn execute_private(&self, transaction: &SignedTransaction, options: TransactOptions, block: BlockId) -> Result, Error> + where + T: Tracer, + V: VMTracer, + { + let mut env_info = self.client.env_info(block).ok_or(ErrorKind::StatePruned)?; + env_info.gas_limit = transaction.gas; + + let mut state = self.client.state_at(block).ok_or(ErrorKind::StatePruned)?; + // TODO: in case of BlockId::Latest these need to operate on the same state + let contract_address = match transaction.action { + Action::Call(ref contract_address) => { + let contract_code = Arc::new(self.get_decrypted_code(contract_address, block)?); + let contract_state = self.get_decrypted_state(contract_address, block)?; + trace!("Patching contract at {:?}, code: {:?}, state: {:?}", contract_address, contract_code, contract_state); + state.patch_account(contract_address, contract_code, Self::snapshot_to_storage(contract_state))?; + Some(*contract_address) + }, + Action::Create => None, + }; + + let engine = self.client.engine(); + let contract_address = contract_address.or({ + let sender = transaction.sender(); + let nonce = state.nonce(&sender)?; + let (new_address, _) = ethcore_contract_address(engine.create_address_scheme(env_info.number), &sender, &nonce, &transaction.data); + Some(new_address) + }); + let result = Executive::new(&mut state, &env_info, engine.machine()).transact_virtual(transaction, options)?; + let (encrypted_code, encrypted_storage) = match contract_address { + None => bail!(ErrorKind::ContractDoesNotExist), + Some(address) => { + let (code, storage) = state.into_account(&address)?; + let enc_code = match code { + Some(c) => Some(self.encrypt(&address, &Self::iv_from_address(&address), &c)?), + None => None, + }; + (enc_code, self.encrypt(&address, &Self::iv_from_transaction(transaction), &Self::snapshot_from_storage(&storage))?) + }, + }; + trace!("Private contract executed. code: {:?}, state: {:?}, result: {:?}", encrypted_code, encrypted_storage, result.output); + Ok(PrivateExecutionResult { + code: encrypted_code, + state: encrypted_storage, + contract_address, + result, + }) + } + + fn generate_constructor(validators: &[Address], code: Bytes, storage: Bytes) -> Bytes { + let constructor_code = DEFAULT_STUB_CONTRACT.from_hex().expect("Default contract code is valid"); + let private = private::PrivateContract::default(); + private.constructor(constructor_code, validators.iter().map(|a| *a).collect::>(), code, storage) + } + + fn generate_set_state_call(signatures: &[Signature], storage: Bytes) -> Bytes { + let private = private::PrivateContract::default(); + private.functions().set_state().input( + storage, + signatures.iter().map(|s| { + let mut v: [u8; 32] = [0; 32]; + v[31] = s.v(); + v + }).collect::>(), + signatures.iter().map(|s| s.r()).collect::>(), + signatures.iter().map(|s| s.s()).collect::>() + ) + } + + /// Returns the key from the key server associated with the contract + pub fn contract_key_id(&self, contract_address: &Address) -> Result { + //current solution uses contract address extended with 0 as id + let contract_address_extended: H256 = contract_address.into(); + + Ok(H256::from_slice(&contract_address_extended)) + } + + /// Create encrypted public contract deployment transaction. + pub fn public_creation_transaction(&self, block: BlockId, source: &SignedTransaction, validators: &[Address], gas_price: U256) -> Result<(Transaction, Option
), Error> { + if let Action::Call(_) = source.action { + bail!(ErrorKind::BadTransactonType); + } + let sender = source.sender(); + let state = self.client.state_at(block).ok_or(ErrorKind::StatePruned)?; + let nonce = state.nonce(&sender)?; + let executed = self.execute_private(source, TransactOptions::with_no_tracing(), block)?; + let gas: u64 = 650000 + + validators.len() as u64 * 30000 + + executed.code.as_ref().map_or(0, |c| c.len() as u64) * 8000 + + executed.state.len() as u64 * 8000; + Ok((Transaction { + nonce: nonce, + action: Action::Create, + gas: gas.into(), + gas_price: gas_price, + value: source.value, + data: Self::generate_constructor(validators, executed.code.unwrap_or_default(), executed.state) + }, + executed.contract_address)) + } + + /// Create encrypted public contract deployment transaction. Returns updated encrypted state. + pub fn execute_private_transaction(&self, block: BlockId, source: &SignedTransaction) -> Result { + if let Action::Create = source.action { + bail!(ErrorKind::BadTransactonType); + } + let result = self.execute_private(source, TransactOptions::with_no_tracing(), block)?; + Ok(result.state) + } + + /// Create encrypted public transaction from private transaction. + pub fn public_transaction(&self, state: Bytes, source: &SignedTransaction, signatures: &[Signature], nonce: U256, gas_price: U256) -> Result { + let gas: u64 = 650000 + state.len() as u64 * 8000 + signatures.len() as u64 * 50000; + Ok(Transaction { + nonce: nonce, + action: source.action.clone(), + gas: gas.into(), + gas_price: gas_price, + value: 0.into(), + data: Self::generate_set_state_call(signatures, state) + }) + } + + /// Call into private contract. + pub fn private_call(&self, block: BlockId, transaction: &SignedTransaction) -> Result { + let result = self.execute_private(transaction, TransactOptions::with_no_tracing(), block)?; + Ok(result.result) + } + + /// Returns private validators for a contract. + pub fn get_validators(&self, block: BlockId, address: &Address) -> Result, Error> { + let contract = private::PrivateContract::default(); + Ok(contract.functions() + .get_validators() + .call(&|data| self.client.call_contract(block, *address, data)) + .map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?) + } +} + +/// Try to unlock account using stored password, return found password if any +fn find_account_password(passwords: &Vec, account_provider: &AccountProvider, account: &Address) -> Option { + for password in passwords { + if let Ok(true) = account_provider.test_password(account, password) { + return Some(password.clone()); + } + } + None +} + +impl ChainNotify for Provider { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + if !imported.is_empty() { + trace!("New blocks imported, try to prune the queue"); + if let Err(err) = self.process_queue() { + trace!("Cannot prune private transactions queue. error: {:?}", err); + } + } + } +} + diff --git a/ethcore/private-tx/src/messages.rs b/ethcore/private-tx/src/messages.rs new file mode 100644 index 0000000000..f465f752be --- /dev/null +++ b/ethcore/private-tx/src/messages.rs @@ -0,0 +1,76 @@ +// 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 . + +use ethereum_types::{H256, U256, Address}; +use bytes::Bytes; +use hash::keccak; +use rlp::Encodable; +use ethkey::Signature; +use transaction::signature::{add_chain_replay_protection, check_replay_protection}; + +/// Message with private transaction encrypted +#[derive(Default, Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Eq)] +pub struct PrivateTransaction { + /// Encrypted data + pub encrypted: Bytes, + /// Address of the contract + pub contract: Address, +} + +impl PrivateTransaction { + /// Compute hash on private transaction + pub fn hash(&self) -> H256 { + keccak(&*self.rlp_bytes()) + } +} + +/// Message about private transaction's signing +#[derive(Default, Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Eq)] +pub struct SignedPrivateTransaction { + /// Hash of the corresponding private transaction + private_transaction_hash: H256, + /// Signature of the validator + /// The V field of the signature + v: u64, + /// The R field of the signature + r: U256, + /// The S field of the signature + s: U256, +} + +impl SignedPrivateTransaction { + /// Construct a signed private transaction message + pub fn new(private_transaction_hash: H256, sig: Signature, chain_id: Option) -> Self { + SignedPrivateTransaction { + private_transaction_hash: private_transaction_hash, + r: sig.r().into(), + s: sig.s().into(), + v: add_chain_replay_protection(sig.v() as u64, chain_id), + } + } + + pub fn standard_v(&self) -> u8 { check_replay_protection(self.v) } + + /// Construct a signature object from the sig. + pub fn signature(&self) -> Signature { + Signature::from_rsv(&self.r.into(), &self.s.into(), self.standard_v()) + } + + /// Get the hash of of the original transaction. + pub fn private_transaction_hash(&self) -> H256 { + self.private_transaction_hash + } +} diff --git a/ethcore/private-tx/src/private_transactions.rs b/ethcore/private-tx/src/private_transactions.rs new file mode 100644 index 0000000000..502694294e --- /dev/null +++ b/ethcore/private-tx/src/private_transactions.rs @@ -0,0 +1,173 @@ +// 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 . + +use ethkey::Signature; +use bytes::Bytes; +use std::collections::HashMap; +use ethereum_types::{H256, U256, Address}; +use transaction::{UnverifiedTransaction, SignedTransaction}; +use ethcore_miner::transaction_queue::{TransactionQueue, RemovalReason, + TransactionDetailsProvider as TransactionQueueDetailsProvider, TransactionOrigin}; +use error::{Error, ErrorKind}; +use ethcore::header::BlockNumber; + +/// Maximum length for private transactions queues. +const MAX_QUEUE_LEN: usize = 8312; + +/// Desriptor for private transaction stored in queue for verification +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct PrivateTransactionDesc { + /// Hash of the private transaction + pub private_hash: H256, + /// Contract's address used in private transaction + pub contract: Address, + /// Address that should be used for verification + pub validator_account: Address, +} + +/// Storage for private transactions for verification +#[derive(Default)] +pub struct VerificationStore { + /// Descriptors for private transactions in queue for verification with key - hash of the original transaction + descriptors: HashMap, + /// Queue with transactions for verification + transactions: TransactionQueue, +} + +impl VerificationStore { + /// Adds private transaction for verification into the store + pub fn add_transaction( + &mut self, + transaction: UnverifiedTransaction, + contract: Address, + validator_account: Address, + private_hash: H256, + details_provider: &TransactionQueueDetailsProvider, + insertion_time: BlockNumber, + ) -> Result<(), Error> { + if self.descriptors.len() > MAX_QUEUE_LEN { + bail!(ErrorKind::QueueIsFull); + } + + if self.descriptors.get(&transaction.hash()).is_some() { + bail!(ErrorKind::PrivateTransactionAlreadyImported); + } + let transaction_hash = transaction.hash(); + let signed_transaction = SignedTransaction::new(transaction)?; + self.transactions + .add(signed_transaction, TransactionOrigin::External, insertion_time, None, details_provider) + .and_then(|_| { + self.descriptors.insert(transaction_hash, PrivateTransactionDesc{ + private_hash, + contract, + validator_account, + }); + Ok(()) + }) + .map_err(Into::into) + } + + /// Returns transactions ready for verification + /// Returns only one transaction per sender because several cannot be verified in a row without verification from other peers + pub fn ready_transactions(&self) -> Vec { + // TODO [ToDr] Performance killer, re-work with new transaction queue. + let mut transactions = self.transactions.top_transactions(); + // TODO [ToDr] Potential issue (create low address to have your transactions processed first) + transactions.sort_by(|a, b| a.sender().cmp(&b.sender())); + transactions.dedup_by(|a, b| a.sender().eq(&b.sender())); + transactions + } + + /// Returns descriptor of the corresponding private transaction + pub fn private_transaction_descriptor(&self, transaction_hash: &H256) -> Result<&PrivateTransactionDesc, Error> { + self.descriptors.get(transaction_hash).ok_or(ErrorKind::PrivateTransactionNotFound.into()) + } + + /// Remove transaction from the queue for verification + pub fn remove_private_transaction(&mut self, transaction_hash: &H256, fetch_nonce: &F) + where F: Fn(&Address) -> U256 { + + self.descriptors.remove(transaction_hash); + self.transactions.remove(transaction_hash, fetch_nonce, RemovalReason::Invalid); + } +} + +/// Desriptor for private transaction stored in queue for signing +#[derive(Debug, Clone)] +pub struct PrivateTransactionSigningDesc { + /// Original unsigned transaction + pub original_transaction: SignedTransaction, + /// Supposed validators from the contract + pub validators: Vec
, + /// Already obtained signatures + pub received_signatures: Vec, + /// State after transaction execution to compare further with received from validators + pub state: Bytes, + /// Build-in nonce of the contract + pub contract_nonce: U256, +} + +/// Storage for private transactions for signing +#[derive(Default)] +pub struct SigningStore { + /// Transactions and descriptors for signing + transactions: HashMap, +} + +impl SigningStore { + /// Adds new private transaction into the store for signing + pub fn add_transaction( + &mut self, + private_hash: H256, + transaction: SignedTransaction, + validators: Vec
, + state: Bytes, + contract_nonce: U256, + ) -> Result<(), Error> { + if self.transactions.len() > MAX_QUEUE_LEN { + bail!(ErrorKind::QueueIsFull); + } + + self.transactions.insert(private_hash, PrivateTransactionSigningDesc { + original_transaction: transaction.clone(), + validators: validators.clone(), + received_signatures: Vec::new(), + state, + contract_nonce, + }); + Ok(()) + } + + /// Get copy of private transaction's description from the storage + pub fn get(&self, private_hash: &H256) -> Option { + self.transactions.get(private_hash).cloned() + } + + /// Removes desc from the store (after verification is completed) + pub fn remove(&mut self, private_hash: &H256) -> Result<(), Error> { + self.transactions.remove(private_hash); + Ok(()) + } + + /// Adds received signature for the stored private transaction + pub fn add_signature(&mut self, private_hash: &H256, signature: Signature) -> Result<(), Error> { + let desc = self.transactions.get_mut(private_hash).ok_or_else(|| ErrorKind::PrivateTransactionNotFound)?; + if !desc.received_signatures.contains(&signature) { + desc.received_signatures.push(signature); + } + Ok(()) + } +} diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs new file mode 100644 index 0000000000..ba918c9636 --- /dev/null +++ b/ethcore/private-tx/tests/private_contract.rs @@ -0,0 +1,137 @@ +// 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 . + +//! Contract for private transactions tests. + +extern crate rustc_hex; +extern crate ethcore; +extern crate ethkey; +extern crate keccak_hash as hash; +extern crate ethcore_io; +extern crate ethcore_logger; +extern crate ethcore_private_tx; +extern crate ethcore_transaction; + +#[macro_use] +extern crate log; + +use std::sync::Arc; +use rustc_hex::FromHex; + +use ethcore::CreateContractAddress; +use ethcore::account_provider::AccountProvider; +use ethcore::client::BlockChainClient; +use ethcore::client::BlockId; +use ethcore::executive::{contract_address}; +use ethcore::test_helpers::{generate_dummy_client, push_block_with_transactions}; +use ethcore_transaction::{Transaction, Action}; +use ethkey::{Secret, KeyPair, Signature}; +use hash::keccak; + +use ethcore_private_tx::{NoopEncryptor, Provider, ProviderConfig}; + +#[test] +fn private_contract() { + // This uses a simple private contract: contract Test1 { bytes32 public x; function setX(bytes32 _x) { x = _x; } } + ethcore_logger::init_log(); + let client = generate_dummy_client(0); + let chain_id = client.signing_chain_id(); + let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000011")).unwrap(); + let _key2 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000012")).unwrap(); + let key3 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000013")).unwrap(); + let key4 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000014")).unwrap(); + let ap = Arc::new(AccountProvider::transient_provider()); + ap.insert_account(key1.secret().clone(), "").unwrap(); + ap.insert_account(key3.secret().clone(), "").unwrap(); + ap.insert_account(key4.secret().clone(), "").unwrap(); + + let config = ProviderConfig{ + validator_accounts: vec![key3.address(), key4.address()], + signer_account: None, + passwords: vec!["".into()], + }; + + let io = ethcore_io::IoChannel::disconnected(); + let pm = Arc::new(Provider::new(client.clone(), ap.clone(), Box::new(NoopEncryptor::default()), config, io).unwrap()); + + let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]); + + trace!("Creating private contract"); + let private_contract_test = "6060604052341561000f57600080fd5b60d88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146046578063bc64b76d14607457600080fd5b3415605057600080fd5b60566098565b60405180826000191660001916815260200191505060405180910390f35b3415607e57600080fd5b6096600480803560001916906020019091905050609e565b005b60005481565b8060008160001916905550505600a165627a7a723058206acbdf4b15ca4c2d43e1b1879b830451a34f1e9d02ff1f2f394d8d857e79d2080029".from_hex().unwrap(); + let mut private_create_tx = Transaction::default(); + private_create_tx.action = Action::Create; + private_create_tx.data = private_contract_test; + private_create_tx.gas = 200000.into(); + let private_create_tx_signed = private_create_tx.sign(&key1.secret(), None); + let validators = vec![key3.address(), key4.address()]; + let (public_tx, _) = pm.public_creation_transaction(BlockId::Latest, &private_create_tx_signed, &validators, 0.into()).unwrap(); + let public_tx = public_tx.sign(&key1.secret(), chain_id); + trace!("Transaction created. Pushing block"); + push_block_with_transactions(&client, &[public_tx]); + + trace!("Modifying private state"); + let mut private_tx = Transaction::default(); + private_tx.action = Action::Call(address.clone()); + private_tx.data = "bc64b76d2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); //setX(42) + private_tx.gas = 120000.into(); + private_tx.nonce = 1.into(); + let private_tx = private_tx.sign(&key1.secret(), None); + let private_contract_nonce = pm.get_contract_nonce(&address, BlockId::Latest).unwrap(); + let private_state = pm.execute_private_transaction(BlockId::Latest, &private_tx).unwrap(); + let nonced_state_hash = pm.calculate_state_hash(&private_state, private_contract_nonce); + let signatures: Vec<_> = [&key3, &key4].iter().map(|k| + Signature::from(::ethkey::sign(&k.secret(), &nonced_state_hash).unwrap().into_electrum())).collect(); + let public_tx = pm.public_transaction(private_state, &private_tx, &signatures, 1.into(), 0.into()).unwrap(); + let public_tx = public_tx.sign(&key1.secret(), chain_id); + push_block_with_transactions(&client, &[public_tx]); + + trace!("Querying private state"); + let mut query_tx = Transaction::default(); + query_tx.action = Action::Call(address.clone()); + query_tx.data = "0c55699c".from_hex().unwrap(); // getX + query_tx.gas = 50000.into(); + query_tx.nonce = 2.into(); + let query_tx = query_tx.sign(&key1.secret(), chain_id); + let result = pm.private_call(BlockId::Latest, &query_tx).unwrap(); + assert_eq!(&result.output[..], &("2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()[..])); + assert_eq!(pm.get_validators(BlockId::Latest, &address).unwrap(), validators); + + // Now try modification with just one signature + trace!("Modifying private state"); + let mut private_tx = Transaction::default(); + private_tx.action = Action::Call(address.clone()); + private_tx.data = "bc64b76d2b00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); //setX(43) + private_tx.gas = 120000.into(); + private_tx.nonce = 2.into(); + let private_tx = private_tx.sign(&key1.secret(), None); + let private_state = pm.execute_private_transaction(BlockId::Latest, &private_tx).unwrap(); + let private_state_hash = keccak(&private_state); + let signatures: Vec<_> = [&key4].iter().map(|k| + Signature::from(::ethkey::sign(&k.secret(), &private_state_hash).unwrap().into_electrum())).collect(); + let public_tx = pm.public_transaction(private_state, &private_tx, &signatures, 2.into(), 0.into()).unwrap(); + let public_tx = public_tx.sign(&key1.secret(), chain_id); + push_block_with_transactions(&client, &[public_tx]); + + trace!("Querying private state"); + let mut query_tx = Transaction::default(); + query_tx.action = Action::Call(address.clone()); + query_tx.data = "0c55699c".from_hex().unwrap(); // getX + query_tx.gas = 50000.into(); + query_tx.nonce = 3.into(); + let query_tx = query_tx.sign(&key1.secret(), chain_id); + let result = pm.private_call(BlockId::Latest, &query_tx).unwrap(); + assert_eq!(result.output, "2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()); +} diff --git a/ethcore/service/Cargo.toml b/ethcore/service/Cargo.toml index 4b53f5d00a..608d591e09 100644 --- a/ethcore/service/Cargo.toml +++ b/ethcore/service/Cargo.toml @@ -5,8 +5,11 @@ authors = ["Parity Technologies "] [dependencies] ansi_term = "0.10" +error-chain = { version = "0.11", default-features = false } ethcore = { path = ".." } ethcore-io = { path = "../../util/io" } +ethcore-private-tx = { path = "../private-tx" } +ethsync = { path = "../../sync" } kvdb = { path = "../../util/kvdb" } log = "0.3" stop-guard = { path = "../../util/stop-guard" } diff --git a/ethcore/service/src/error.rs b/ethcore/service/src/error.rs new file mode 100644 index 0000000000..bb403d0bfc --- /dev/null +++ b/ethcore/service/src/error.rs @@ -0,0 +1,30 @@ +// Copyright 2015-2018 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 . + +use ethcore; +use io; +use ethcore_private_tx; + +error_chain! { + links { + PrivateTransactions(ethcore_private_tx::Error, ethcore_private_tx::ErrorKind); + } + + foreign_links { + Ethcore(ethcore::error::Error); + IoError(io::IoError); + } +} diff --git a/ethcore/service/src/lib.rs b/ethcore/service/src/lib.rs index 83d9a8fe10..5bd1c39de5 100644 --- a/ethcore/service/src/lib.rs +++ b/ethcore/service/src/lib.rs @@ -17,18 +17,25 @@ extern crate ansi_term; extern crate ethcore; extern crate ethcore_io as io; +extern crate ethsync; extern crate kvdb; +extern crate ethcore_private_tx; extern crate stop_guard; +#[macro_use] +extern crate error_chain; + #[macro_use] extern crate log; #[cfg(test)] extern crate tempdir; +mod error; +mod service; + #[cfg(test)] extern crate kvdb_rocksdb; -mod service; - -pub use service::ClientService; +pub use error::{Error, ErrorKind}; +pub use service::{ClientService, PrivateTxService}; diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 4337996e2b..27f58b4215 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -24,18 +24,50 @@ use io::{IoContext, TimerToken, IoHandler, IoService, IoError}; use kvdb::{KeyValueDB, KeyValueDBHandler}; use stop_guard::StopGuard; +use ethsync::PrivateTxHandler; use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage}; -use ethcore::error::Error; use ethcore::miner::Miner; use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams}; use ethcore::snapshot::{RestorationStatus}; use ethcore::spec::Spec; +use ethcore::account_provider::AccountProvider; + +use ethcore_private_tx; +use Error; + +pub struct PrivateTxService { + provider: Arc, +} + +impl PrivateTxService { + fn new(provider: Arc) -> Self { + PrivateTxService { + provider, + } + } + + /// Returns underlying provider. + pub fn provider(&self) -> Arc { + self.provider.clone() + } +} + +impl PrivateTxHandler for PrivateTxService { + fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), String> { + self.provider.import_private_transaction(rlp).map_err(|e| e.to_string()) + } + + fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), String> { + self.provider.import_signed_private_transaction(rlp).map_err(|e| e.to_string()) + } +} /// Client service setup. Creates and registers client and network services with the IO subsystem. pub struct ClientService { io_service: Arc>, client: Arc, snapshot: Arc, + private_tx: Arc, database: Arc, _stop_guard: StopGuard, } @@ -50,6 +82,9 @@ impl ClientService { restoration_db_handler: Box, _ipc_path: &Path, miner: Arc, + account_provider: Arc, + encryptor: Box, + private_tx_conf: ethcore_private_tx::ProviderConfig, ) -> Result { let io_service = IoService::::start()?; @@ -70,9 +105,13 @@ impl ClientService { }; let snapshot = Arc::new(SnapshotService::new(snapshot_params)?); + let provider = Arc::new(ethcore_private_tx::Provider::new(client.clone(), account_provider, encryptor, private_tx_conf, io_service.channel())?); + let private_tx = Arc::new(PrivateTxService::new(provider)); + let client_io = Arc::new(ClientIoHandler { client: client.clone(), snapshot: snapshot.clone(), + private_tx: private_tx.clone(), }); io_service.register_handler(client_io)?; @@ -84,6 +123,7 @@ impl ClientService { io_service: Arc::new(io_service), client: client, snapshot: snapshot, + private_tx, database: client_db, _stop_guard: stop_guard, }) @@ -104,6 +144,11 @@ impl ClientService { self.snapshot.clone() } + /// Get private transaction service. + pub fn private_tx_service(&self) -> Arc { + self.private_tx.clone() + } + /// Get network service component pub fn io(&self) -> Arc> { self.io_service.clone() @@ -122,6 +167,7 @@ impl ClientService { struct ClientIoHandler { client: Arc, snapshot: Arc, + private_tx: Arc, } const CLIENT_TICK_TIMER: TimerToken = 0; @@ -180,6 +226,9 @@ impl IoHandler for ClientIoHandler { ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) { trace!(target: "poa", "Invalid message received: {}", e); }, + ClientIoMessage::NewPrivateTransaction => if let Err(e) = self.private_tx.provider.on_private_transaction_queued() { + warn!("Failed to handle private transaction {:?}", e); + }, _ => {} // ignore other messages } } @@ -192,6 +241,7 @@ mod tests { use tempdir::TempDir; + use ethcore::account_provider::AccountProvider; use ethcore::client::ClientConfig; use ethcore::miner::Miner; use ethcore::spec::Spec; @@ -200,6 +250,8 @@ mod tests { use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile}; use super::*; + use ethcore_private_tx; + #[test] fn it_can_be_started() { let tempdir = TempDir::new("").unwrap(); @@ -241,6 +293,9 @@ mod tests { restoration_db_handler, tempdir.path(), Arc::new(Miner::with_spec(&spec)), + Arc::new(AccountProvider::transient_provider()), + Box::new(ethcore_private_tx::NoopEncryptor), + Default::default() ); assert!(service.is_ok()); drop(service.unwrap()); diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 2280b40dea..8e1fac1792 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -645,7 +645,7 @@ pub fn enact_verified( #[cfg(test)] mod tests { - use tests::helpers::get_temp_state_db; + use test_helpers::get_temp_state_db; use super::*; use engines::EthEngine; use vm::LastHashes; diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index ae5ac18eb9..5dffc9ec37 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1421,7 +1421,7 @@ mod tests { use ethereum_types::*; use receipt::{Receipt, TransactionOutcome}; use blockchain::{BlockProvider, BlockChain, Config, ImportRoute}; - use tests::helpers::{ + use test_helpers::{ generate_dummy_blockchain, generate_dummy_blockchain_with_extra, generate_dummy_empty_blockchain }; diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index d05c95b8c8..bdd8d00278 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -17,6 +17,16 @@ use ethereum_types::H256; use bytes::Bytes; +/// Messages to broadcast via chain +pub enum ChainMessageType { + /// Consensus message + Consensus(Vec), + /// Message with private transaction + PrivateTransaction(Vec), + /// Message with signed private transaction + SignedPrivateTransaction(Vec), +} + /// Represents what has to be handled by actor listening to chain events pub trait ChainNotify : Send + Sync { /// fires when chain has new blocks. @@ -45,7 +55,7 @@ pub trait ChainNotify : Send + Sync { } /// fires when chain broadcasts a message - fn broadcast(&self, _data: Vec) {} + fn broadcast(&self, _message_type: ChainMessageType) {} /// fires when new transactions are received from a peer fn transactions_received(&self, diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 31f8f2f25d..a8ce3f65c3 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -45,7 +45,7 @@ use client::{ use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, - ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo + ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType }; use encoded; use engines::{EthEngine, EpochTransition}; @@ -2126,7 +2126,7 @@ impl super::traits::EngineClient for Client { } fn broadcast_consensus_message(&self, message: Bytes) { - self.notify(|notify| notify.broadcast(message.clone())); + self.notify(|notify| notify.broadcast(ChainMessageType::Consensus(message.clone()))); } fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition> { @@ -2237,7 +2237,7 @@ mod tests { #[test] fn should_not_cache_details_before_commit() { use client::{BlockChainClient, ChainInfo}; - use tests::helpers::{generate_dummy_client, get_good_dummy_block_hash}; + use test_helpers::{generate_dummy_client, get_good_dummy_block_hash}; use std::thread; use std::time::Duration; diff --git a/ethcore/src/client/io_message.rs b/ethcore/src/client/io_message.rs index c2823a39f6..e19d3054fe 100644 --- a/ethcore/src/client/io_message.rs +++ b/ethcore/src/client/io_message.rs @@ -36,6 +36,8 @@ pub enum ClientIoMessage { /// Take a snapshot for the block with given number. TakeSnapshot(u64), /// New consensus message received. - NewMessage(Bytes) + NewMessage(Bytes), + /// New private transaction arrived + NewPrivateTransaction, } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index b92240591b..2ae3436aa9 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -31,11 +31,12 @@ pub use self::error::Error; pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; pub use self::io_message::ClientIoMessage; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; -pub use self::chain_notify::ChainNotify; +pub use self::chain_notify::{ChainNotify, ChainMessageType}; pub use self::traits::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter }; +//pub use self::private_notify::PrivateNotify; pub use state::StateInfo; pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient, ProvingBlockChainClient}; @@ -53,3 +54,4 @@ pub use verification::VerifierType; mod traits; mod chain_notify; +mod private_notify; diff --git a/ethcore/src/client/private_notify.rs b/ethcore/src/client/private_notify.rs new file mode 100644 index 0000000000..2b865a9e2c --- /dev/null +++ b/ethcore/src/client/private_notify.rs @@ -0,0 +1,23 @@ +// 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 . + +use error::TransactionImportError; + +/// Represent private transactions handler inside the client +pub trait PrivateNotify : Send + Sync { + /// fires when private transaction message queued via client io queue + fn private_transaction_queued(&self) -> Result<(), TransactionImportError>; +} diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 0acde347e2..8282e5738a 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1326,7 +1326,7 @@ mod tests { use header::Header; use rlp::encode; use block::*; - use tests::helpers::{ + use test_helpers::{ generate_dummy_client_with_spec_and_accounts, get_temp_state_db, generate_dummy_client, TestNotify }; diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 4d1f38dce4..c4eafd851c 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -199,7 +199,7 @@ mod tests { use hash::keccak; use ethereum_types::H520; use block::*; - use tests::helpers::get_temp_state_db; + use test_helpers::get_temp_state_db; use account_provider::AccountProvider; use header::Header; use spec::Spec; diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index af997c022e..40a96e2b71 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -67,7 +67,7 @@ impl Engine for InstantSeal mod tests { use std::sync::Arc; use ethereum_types::{H520, Address}; - use tests::helpers::{get_temp_state_db}; + use test_helpers::get_temp_state_db; use spec::Spec; use header::Header; use block::*; diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 4d0656749a..011e3f8d42 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -514,7 +514,6 @@ impl Engine for Tendermint { fn fmt_err(x: T) -> EngineError { EngineError::MalformedMessage(format!("{:?}", x)) } - let rlp = UntrustedRlp::new(rlp); let message: ConsensusMessage = rlp.as_val().map_err(fmt_err)?; if !self.votes.is_old_or_known(&message) { @@ -783,7 +782,7 @@ mod tests { use header::Header; use client::ChainInfo; use miner::MinerService; - use tests::helpers::{ + use test_helpers::{ TestNotify, get_temp_state_db, generate_dummy_client, generate_dummy_client_with_spec_and_accounts }; diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index 319d96db93..fb9fccf3e2 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -145,8 +145,8 @@ mod tests { use account_provider::AccountProvider; use miner::MinerService; use types::ids::BlockId; + use test_helpers::generate_dummy_client_with_spec_and_accounts; use client::{BlockChainClient, ChainInfo, BlockInfo, CallContract}; - use tests::helpers::generate_dummy_client_with_spec_and_accounts; use super::super::ValidatorSet; use super::ValidatorContract; diff --git a/ethcore/src/engines/validator_set/multi.rs b/ethcore/src/engines/validator_set/multi.rs index 2794b57a2a..9c287f9a37 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -155,7 +155,7 @@ mod tests { use header::Header; use miner::MinerService; use spec::Spec; - use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; + use test_helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; use types::ids::BlockId; use ethereum_types::Address; diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 668feac26f..82befdadff 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -459,7 +459,7 @@ mod tests { use client::{ChainInfo, BlockInfo, ImportBlock}; use ethkey::Secret; use miner::MinerService; - use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; + use test_helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; use super::super::ValidatorSet; use super::{ValidatorSafeContract, EVENT_NAME_HASH}; diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index aae2241168..defb301dcb 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -16,7 +16,7 @@ //! General error types for use in ethcore. -use std::fmt; +use std::{fmt, error}; use kvdb; use ethereum_types::{H256, U256, Address, Bloom}; use util_error::UtilError; @@ -268,6 +268,13 @@ impl fmt::Display for Error { } } +impl error::Error for Error { + fn description(&self) -> &str { + // improve description + "ethcore error" + } +} + /// Result of import block operation. pub type ImportResult = Result; diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 68a07d0cda..41ab777d4a 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -487,7 +487,7 @@ mod tests { use std::sync::Arc; use ethereum_types::{H64, H256, U256, Address}; use block::*; - use tests::helpers::get_temp_state_db; + use test_helpers::get_temp_state_db; use error::{BlockError, Error}; use header::Header; use spec::Spec; diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index aea53ecaea..1bdcb01e14 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -145,7 +145,7 @@ mod tests { use ethereum_types::U256; use state::*; use super::*; - use tests::helpers::get_temp_state_db; + use test_helpers::get_temp_state_db; use views::BlockView; #[test] diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index c33eb2ecd6..a97ee37081 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -701,7 +701,7 @@ mod tests { use error::ExecutionError; use machine::EthereumMachine; use state::{Substate, CleanupMode}; - use tests::helpers::{get_temp_state_with_factory, get_temp_state}; + use test_helpers::{get_temp_state_with_factory, get_temp_state}; use trace::trace; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer}; use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer}; @@ -746,7 +746,6 @@ mod tests { assert_eq!(state.storage_at(&address, &H256::new()).unwrap(), H256::from(&U256::from(0xf9u64))); assert_eq!(state.balance(&sender).unwrap(), U256::from(0xf9)); assert_eq!(state.balance(&address).unwrap(), U256::from(0x7)); - // 0 cause contract hasn't returned assert_eq!(substate.contracts_created.len(), 0); // TODO: just test state root. diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 732d3499a8..5d35d1109a 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -414,7 +414,7 @@ mod tests { use ethereum_types::{U256, Address}; use evm::{EnvInfo, Ext, CallType}; use state::{State, Substate}; - use tests::helpers::get_temp_state; + use test_helpers::get_temp_state; use super::*; use trace::{NoopTracer, NoopVMTracer}; diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 0ec60d4931..404b1c25e6 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -25,7 +25,7 @@ use vm::{ CreateContractAddress, ReturnData, }; use externalities::*; -use tests::helpers::get_temp_state; +use test_helpers::get_temp_state; use ethjson; use trace::{Tracer, NoopTracer}; use trace::{VMTracer, NoopVMTracer}; diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index d822195d32..c71a266f74 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -94,6 +94,7 @@ extern crate ansi_term; extern crate unexpected; extern crate kvdb; extern crate kvdb_memorydb; +extern crate kvdb_rocksdb; extern crate util_error; extern crate snappy; @@ -128,9 +129,6 @@ extern crate trace_time; #[cfg_attr(test, macro_use)] extern crate evm; -#[cfg(test)] -extern crate kvdb_rocksdb; - pub extern crate ethstore; pub mod account_provider; @@ -142,6 +140,7 @@ pub mod engines; pub mod error; pub mod ethereum; pub mod executed; +pub mod executive; pub mod header; pub mod machine; pub mod miner; @@ -150,6 +149,8 @@ pub mod snapshot; pub mod spec; pub mod state; pub mod state_db; +// Test helpers made public for usage outside ethcore +pub mod test_helpers; pub mod trace; pub mod verification; pub mod views; @@ -159,7 +160,6 @@ mod blooms; mod pod_account; mod account_db; mod builtin; -mod executive; mod externalities; mod blockchain; mod factory; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index b0628b3e0b..96094dce41 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -24,7 +24,7 @@ use ethereum_types::{H256, U256, Address}; use parking_lot::{Mutex, RwLock}; use bytes::Bytes; use engines::{EthEngine, Seal}; -use error::*; +use error::{ExecutionError, Error}; use ethcore_miner::banning_queue::{BanningTransactionQueue, Threshold}; use ethcore_miner::local_transactions::{Status as LocalTransactionStatus}; use ethcore_miner::transaction_queue::{ @@ -1327,8 +1327,7 @@ mod tests { use spec::Spec; use transaction::{SignedTransaction, Transaction, PendingTransaction, Action}; use miner::MinerService; - - use tests::helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts}; + use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts}; #[test] fn should_prepare_block_to_seal() { diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index b85f8f4013..222875b842 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -210,7 +210,7 @@ pub fn from_fat_rlp( mod tests { use account_db::{AccountDB, AccountDBMut}; use basic_account::BasicAccount; - use tests::helpers::get_temp_state_db; + use test_helpers::get_temp_state_db; use snapshot::tests::helpers::fill_storage; use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP, keccak}; diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index fad150645d..7d5eea1eff 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -635,7 +635,7 @@ mod tests { use snapshot::{ManifestData, RestorationStatus, SnapshotService}; use super::*; use tempdir::TempDir; - use tests::helpers::restoration_db_handler; + use test_helpers::restoration_db_handler; struct NoopDBRestore; impl DatabaseRestore for NoopDBRestore { diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index 101de5c586..7283a05863 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -25,7 +25,7 @@ use client::{Client, BlockChainClient, ChainInfo}; use ethkey::Secret; use snapshot::tests::helpers as snapshot_helpers; use spec::Spec; -use tests::helpers; +use test_helpers::generate_dummy_client_with_spec_and_accounts; use transaction::{Transaction, Action, SignedTransaction}; use tempdir::TempDir; @@ -89,7 +89,7 @@ enum Transition { // create a chain with the given transitions and some blocks beyond that transition. fn make_chain(accounts: Arc, blocks_beyond: usize, transitions: Vec) -> Arc { - let client = helpers::generate_dummy_client_with_spec_and_accounts( + let client = generate_dummy_client_with_spec_and_accounts( spec_fixed_to_contract, Some(accounts.clone())); let mut cur_signers = vec![*RICH_ADDR]; diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 4548741f39..7e81b05796 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -24,7 +24,7 @@ use ids::BlockId; use snapshot::service::{Service, ServiceParams}; use snapshot::{self, ManifestData, SnapshotService}; use spec::Spec; -use tests::helpers::{generate_dummy_client_with_spec_and_data, restoration_db_handler}; +use test_helpers::{generate_dummy_client_with_spec_and_data, restoration_db_handler}; use io::IoChannel; use kvdb_rocksdb::{Database, DatabaseConfig}; diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index f0b3b9203b..ec1b5edf3d 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -892,7 +892,7 @@ impl Spec { mod tests { use super::*; use state::State; - use tests::helpers::get_temp_state_db; + use test_helpers::get_temp_state_db; use views::BlockView; use tempdir::TempDir; diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index 9d72ed158c..f9c8f258e6 100755 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -180,6 +180,16 @@ impl Account { self.init_code(code); } + /// Reset this account's code and storage to given values. + pub fn reset_code_and_storage(&mut self, code: Arc, storage: HashMap) { + self.code_hash = keccak(&*code); + self.code_cache = code; + self.code_size = Some(self.code_cache.len()); + self.code_filth = Filth::Dirty; + self.storage_cache = Self::empty_storage_cache(); + self.storage_changes = storage; + } + /// Set (and cache) the contents of the trie's storage at `key` to `value`. pub fn set_storage(&mut self, key: H256, value: H256) { self.storage_changes.insert(key, value); diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 757f545115..9fd3fd8525 100755 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -494,6 +494,13 @@ impl State { (self.root, self.db) } + /// Destroy the current object and return single account data. + pub fn into_account(self, account: &Address) -> trie::Result<(Option>, HashMap)> { + // TODO: deconstruct without cloning. + let account = self.require(account, true)?; + Ok((account.code().clone(), account.storage_changes().clone())) + } + /// Return reference to root pub fn root(&self) -> &H256 { &self.root @@ -1014,6 +1021,11 @@ impl State { } })) } + + /// Replace account code and storage. Creates account if it does not exist. + pub fn patch_account(&self, a: &Address, code: Arc, storage: HashMap) -> trie::Result<()> { + Ok(self.require(a, false)?.reset_code_and_storage(code, storage)) + } } // State proof implementations; useful for light client protocols. @@ -1099,7 +1111,7 @@ mod tests { use super::*; use ethkey::Secret; use ethereum_types::{H256, U256, Address}; - use tests::helpers::{get_temp_state, get_temp_state_db}; + use test_helpers::{get_temp_state, get_temp_state_db}; use machine::EthereumMachine; use vm::EnvInfo; use spec::*; diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 346ad9cc2a..3b00a42ee6 100755 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -480,7 +480,7 @@ unsafe impl Sync for SyncAccount {} mod tests { use ethereum_types::{H256, U256, Address}; use kvdb::DBTransaction; - use tests::helpers::{get_temp_state_db}; + use test_helpers::get_temp_state_db; use state::{Account, Backend}; use ethcore_logger::init_log; diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/test_helpers.rs similarity index 82% rename from ethcore/src/tests/helpers.rs rename to ethcore/src/test_helpers.rs index 14dcf3630b..4c013dd251 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -14,12 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Set of different helpers for client tests + use account_provider::AccountProvider; -use ethereum_types::{H256, U256}; +use ethereum_types::{H256, U256, Address}; use block::{OpenBlock, Drain}; use blockchain::{BlockChain, Config as BlockChainConfig}; use bytes::Bytes; -use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify}; +use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify, ChainMessageType, PrepareOpenBlock}; use ethkey::KeyPair; use evm::Factory as EvmFactory; use factory::Factories; @@ -39,6 +41,7 @@ use views::BlockView; use kvdb::{KeyValueDB, KeyValueDBHandler}; use kvdb_rocksdb::{Database, DatabaseConfig}; +/// Creates test block with corresponding header pub fn create_test_block(header: &Header) -> Bytes { let mut rlp = RlpStream::new_list(3); rlp.append(header); @@ -76,6 +79,7 @@ fn create_unverifiable_block(order: u32, parent_hash: H256) -> Bytes { create_test_block(&create_unverifiable_block_header(order, parent_hash)) } +/// Creates test block with corresponding header and data pub fn create_test_block_with_data(header: &Header, transactions: &[SignedTransaction], uncles: &[Header]) -> Bytes { let mut rlp = RlpStream::new_list(3); rlp.append(header); @@ -87,23 +91,27 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[SignedTransa rlp.out() } +/// Generates dummy client (not test client) with corresponding amount of blocks pub fn generate_dummy_client(block_number: u32) -> Arc { generate_dummy_client_with_spec_and_data(Spec::new_test, block_number, 0, &[]) } +/// Generates dummy client (not test client) with corresponding amount of blocks and txs per every block pub fn generate_dummy_client_with_data(block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> Arc { generate_dummy_client_with_spec_and_data(Spec::new_null, block_number, txs_per_block, tx_gas_prices) } - +/// Generates dummy client (not test client) with corresponding amount of blocks, txs per block and spec pub fn generate_dummy_client_with_spec_and_data(test_spec: F, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> Arc where F: Fn()->Spec { generate_dummy_client_with_spec_accounts_and_data(test_spec, None, block_number, txs_per_block, tx_gas_prices) } +/// Generates dummy client (not test client) with corresponding spec and accounts pub fn generate_dummy_client_with_spec_and_accounts(test_spec: F, accounts: Option>) -> Arc where F: Fn()->Spec { generate_dummy_client_with_spec_accounts_and_data(test_spec, accounts, 0, 0, &[]) } +/// Generates dummy client (not test client) with corresponding blocks, accounts and spec pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accounts: Option>, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> Arc where F: Fn()->Spec { let test_spec = test_spec(); let client_db = new_db(); @@ -174,6 +182,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun client } +/// Adds blocks to the client pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting_number: usize, block_number: usize) { let test_spec = Spec::new_test(); let state_root = test_spec.genesis_header().state_root().clone(); @@ -203,6 +212,29 @@ pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting } } +/// Adds one block with transactions +pub fn push_block_with_transactions(client: &Arc, transactions: &[SignedTransaction]) { + let test_spec = Spec::new_test(); + let test_engine = &*test_spec.engine; + let block_number = client.chain_info().best_block_number as u64 + 1; + + let mut b = client.prepare_open_block(Address::default(), (0.into(), 5000000.into()), Bytes::new()); + b.set_timestamp(block_number * 10); + + for t in transactions { + b.push_transaction(t.clone(), None).unwrap(); + } + let b = b.close_and_lock().seal(test_engine, vec![]).unwrap(); + + if let Err(e) = client.import_block(b.rlp_bytes()) { + panic!("error importing block which is valid by definition: {:?}", e); + } + + client.flush_queue(); + client.import_verified_blocks(); +} + +/// Creates dummy client (not test client) with corresponding blocks pub fn get_test_client_with_blocks(blocks: Vec) -> Arc { let test_spec = Spec::new_test(); let client_db = new_db(); @@ -229,6 +261,7 @@ fn new_db() -> Arc<::kvdb::KeyValueDB> { Arc::new(::kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))) } +/// Generates dummy blockchain with corresponding amount of blocks pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); @@ -242,6 +275,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { bc } +/// Generates dummy blockchain with corresponding amount of blocks (using creation with extra method for blocks creation) pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); @@ -256,17 +290,20 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { bc } +/// Returns empty dummy blockchain pub fn generate_dummy_empty_blockchain() -> BlockChain { let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); bc } +/// Returns temp state pub fn get_temp_state() -> State<::state_db::StateDB> { let journal_db = get_temp_state_db(); State::new(journal_db, U256::from(0), Default::default()) } +/// Returns temp state using coresponding factory pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::StateDB> { let journal_db = get_temp_state_db(); let mut factories = Factories::default(); @@ -274,17 +311,20 @@ pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::Sta State::new(journal_db, U256::from(0), factories) } +/// Returns temp state db pub fn get_temp_state_db() -> StateDB { let db = new_db(); let journal_db = ::journaldb::new(db, ::journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); StateDB::new(journal_db, 5 * 1024 * 1024) } +/// Returns sequence of hashes of the dummy blocks pub fn get_good_dummy_block_seq(count: usize) -> Vec { let test_spec = Spec::new_test(); get_good_dummy_block_fork_seq(1, count, &test_spec.genesis_header().hash()) } +/// Returns sequence of hashes of the dummy blocks beginning from corresponding parent pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_hash: &H256) -> Vec { let test_spec = Spec::new_test(); let genesis_gas = test_spec.genesis_header().gas_limit().clone(); @@ -308,6 +348,7 @@ pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_h r } +/// Returns hash and header of the correct dummy block pub fn get_good_dummy_block_hash() -> (H256, Bytes) { let mut block_header = Header::new(); let test_spec = Spec::new_test(); @@ -322,11 +363,13 @@ pub fn get_good_dummy_block_hash() -> (H256, Bytes) { (block_header.hash(), create_test_block(&block_header)) } +/// Returns hash of the correct dummy block pub fn get_good_dummy_block() -> Bytes { let (_, bytes) = get_good_dummy_block_hash(); bytes } +/// Returns hash of the dummy block with incorrect state root pub fn get_bad_state_dummy_block() -> Bytes { let mut block_header = Header::new(); let test_spec = Spec::new_test(); @@ -342,17 +385,25 @@ pub fn get_bad_state_dummy_block() -> Bytes { create_test_block(&block_header) } +/// Test actor for chain events #[derive(Default)] pub struct TestNotify { + /// Messages store pub messages: RwLock>, } impl ChainNotify for TestNotify { - fn broadcast(&self, data: Vec) { + fn broadcast(&self, message: ChainMessageType) { + let data = match message { + ChainMessageType::Consensus(data) => data, + ChainMessageType::SignedPrivateTransaction(data) => data, + ChainMessageType::PrivateTransaction(data) => data, + }; self.messages.write().push(data); } } +/// Creates new instance of KeyValueDBHandler pub fn restoration_db_handler(config: DatabaseConfig) -> Box { use kvdb::Error; diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 8091ae73e1..e6333f56ad 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -23,7 +23,7 @@ use state::{self, State, CleanupMode}; use executive::{Executive, TransactOptions}; use ethereum; use block::IsBlock; -use tests::helpers::{ +use test_helpers::{ generate_dummy_client, push_blocks_to_client, get_test_client_with_blocks, get_good_dummy_block_seq, generate_dummy_client_with_data, get_good_dummy_block, get_bad_state_dummy_block }; diff --git a/ethcore/src/tests/evm.rs b/ethcore/src/tests/evm.rs index 60d5e12b06..4f4ad4241f 100644 --- a/ethcore/src/tests/evm.rs +++ b/ethcore/src/tests/evm.rs @@ -22,7 +22,7 @@ use vm::{EnvInfo, ActionParams, ActionValue, CallType, ParamsType}; use evm::{Factory, VMType}; use executive::Executive; use state::Substate; -use tests::helpers::get_temp_state_with_factory; +use test_helpers::get_temp_state_with_factory; use trace::{NoopVMTracer, NoopTracer}; use transaction::SYSTEM_ADDRESS; diff --git a/ethcore/src/tests/mod.rs b/ethcore/src/tests/mod.rs index eec71efafb..8b509d2afc 100644 --- a/ethcore/src/tests/mod.rs +++ b/ethcore/src/tests/mod.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -pub mod helpers; mod client; mod evm; mod trace; diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 5483c62634..4646bc091f 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -24,7 +24,7 @@ use ethereum_types::{U256, Address}; use io::*; use spec::*; use client::*; -use tests::helpers::get_temp_state_db; +use test_helpers::get_temp_state_db; use client::{BlockChainClient, Client, ClientConfig}; use kvdb_rocksdb::{Database, DatabaseConfig}; use std::sync::Arc; diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 58b1bb7bb3..b6e60d042a 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -731,7 +731,7 @@ mod tests { use spec::Spec; use super::{BlockQueue, Config, State}; use super::kind::blocks::Unverified; - use tests::helpers::{get_good_dummy_block_seq, get_good_dummy_block}; + use test_helpers::{get_good_dummy_block_seq, get_good_dummy_block}; use error::*; use views::*; diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index e6289c2b0d..e50eb79194 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -359,7 +359,7 @@ mod tests { use error::BlockError::*; use ethkey::{Random, Generator}; use spec::{CommonParams, Spec}; - use tests::helpers::{create_test_block_with_data, create_test_block}; + use test_helpers::{create_test_block_with_data, create_test_block}; use transaction::{SignedTransaction, Transaction, UnverifiedTransaction, Action}; use types::log_entry::{LogEntry, LocalizedLogEntry}; use rlp; diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index d458e1f602..4df63294bd 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -77,6 +77,25 @@ pub enum Condition { Timestamp(u64), } +/// Replay protection logic for v part of transaction's signature +pub mod signature { + /// Adds chain id into v + pub fn add_chain_replay_protection(v: u64, chain_id: Option) -> u64 { + v + if let Some(n) = chain_id { 35 + n * 2 } else { 27 } + } + + /// Returns refined v + /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. + pub fn check_replay_protection(v: u64) -> u8 { + match v { + v if v == 27 => 0, + v if v == 28 => 1, + v if v > 36 => ((v - 1) % 2) as u8, + _ => 4 + } + } +} + /// A set of information describing an externally-originating message call /// or contract creation operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -186,7 +205,7 @@ impl Transaction { unsigned: self, r: sig.r().into(), s: sig.s().into(), - v: sig.v() as u64 + if let Some(n) = chain_id { 35 + n * 2 } else { 27 }, + v: signature::add_chain_replay_protection(sig.v() as u64, chain_id), hash: 0.into(), }.compute_hash() } @@ -330,8 +349,7 @@ impl UnverifiedTransaction { &self.unsigned } - /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. - pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => ((v - 1) % 2) as u8, _ => 4 } } + pub fn standard_v(&self) -> u8 { signature::check_replay_protection(self.v) } /// The `v` value that appears in the RLP. pub fn original_v(&self) -> u64 { self.v } diff --git a/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index b3a9356ea2..ce2e44054e 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -153,7 +153,7 @@ impl HashFetch for Client { .into_future() .and_then(move |url| { debug!(target: "fetch", "Resolved {:?} to {:?}. Fetching...", hash, url); - remote_fetch.fetch(&url, abort).from_err() + remote_fetch.get(&url, abort).from_err() }) .and_then(move |response| { if !response.is_success() { @@ -199,7 +199,7 @@ mod tests { use parking_lot::Mutex; use futures::future; use futures_cpupool::CpuPool; - use fetch::{self, Fetch, Url}; + use fetch::{self, Fetch, Url, Method}; use parity_reactor::Remote; use urlhint::tests::{FakeRegistrar, URLHINT}; use super::{Error, Client, HashFetch, random_temp_path}; @@ -214,7 +214,7 @@ mod tests { impl Fetch for FakeFetch { type Result = future::Ok; - fn fetch(&self, url: &str, abort: fetch::Abort) -> Self::Result { + fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { assert_eq!(url, "https://parity.io/assets/images/ethcore-black-horizontal.png"); let u = Url::parse(url).unwrap(); future::ok(if self.return_success { diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 26eae45976..c2c6f2aa5c 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -25,6 +25,7 @@ use hash::{keccak, KECCAK_NULL_RLP}; use ethereum_types::{U256, H256, Address}; use bytes::ToPretty; use rlp::PayloadInfo; +use ethcore::account_provider::AccountProvider; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock}; use ethcore::db::NUM_COLUMNS; use ethcore::error::ImportError; @@ -39,6 +40,7 @@ use helpers::{to_client_config, execute_upgrades, open_client_db, client_db_conf use dir::Directories; use user_defaults::UserDefaults; use fdlimit; +use ethcore_private_tx; #[derive(Debug, PartialEq)] pub enum DataFormat { @@ -389,6 +391,9 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { restoration_db_handler, &cmd.dirs.ipc_path(), Arc::new(Miner::with_spec(&spec)), + Arc::new(AccountProvider::transient_provider()), + Box::new(ethcore_private_tx::NoopEncryptor), + Default::default() ).map_err(|e| format!("Client service error: {:?}", e))?; // free up the spec in memory. @@ -576,6 +581,9 @@ fn start_client( restoration_db_handler, &dirs.ipc_path(), Arc::new(Miner::with_spec(&spec)), + Arc::new(AccountProvider::transient_provider()), + Box::new(ethcore_private_tx::NoopEncryptor), + Default::default() ).map_err(|e| format!("Client service error: {:?}", e))?; drop(spec); diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 2cc0ef7c29..a160661b91 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -350,6 +350,35 @@ usage! { "--password=[FILE]...", "Provide a file containing a password for unlocking an account. Leading and trailing whitespace is trimmed.", + ["Private transactions options"] + FLAG flag_private_enabled: (bool) = false, or |c: &Config| c.private_tx.as_ref()?.enabled, + "--private-tx-enabled", + "Enable private transactions.", + + ARG arg_private_signer: (Option) = None, or |c: &Config| c.private_tx.as_ref()?.signer.clone(), + "--private-signer=[ACCOUNT]", + "Specify the account for signing public transaction created upon verified private transaction.", + + ARG arg_private_validators: (Option) = None, or |c: &Config| c.private_tx.as_ref()?.validators.as_ref().map(|vec| vec.join(",")), + "--private-validators=[ACCOUNTS]", + "Specify the accounts for validating private transactions. ACCOUNTS is a comma-delimited list of addresses.", + + ARG arg_private_account: (Option) = None, or |c: &Config| c.private_tx.as_ref()?.account.clone(), + "--private-account=[ACCOUNT]", + "Specify the account for signing requests to secret store.", + + ARG arg_private_sstore_url: (Option) = None, or |c: &Config| c.private_tx.as_ref()?.sstore_url.clone(), + "--private-sstore-url=[URL]", + "Specify secret store URL used for encrypting private transactions.", + + ARG arg_private_sstore_threshold: (Option) = None, or |c: &Config| c.private_tx.as_ref()?.sstore_threshold.clone(), + "--private-sstore-threshold=[NUM]", + "Specify secret store threshold used for encrypting private transactions.", + + ARG arg_private_passwords: (Option) = None, or |c: &Config| c.private_tx.as_ref()?.passwords.clone(), + "--private-passwords=[FILE]...", + "Provide a file containing passwords for unlocking accounts (signer, private account, validators).", + ["UI options"] FLAG flag_force_ui: (bool) = false, or |c: &Config| c.ui.as_ref()?.force.clone(), "--force-ui", @@ -462,7 +491,7 @@ usage! { "--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.", - ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), + ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,private,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--jsonrpc-apis=[APIS]", "Specify the APIs available through the JSONRPC interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", @@ -495,7 +524,7 @@ usage! { "--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.", - ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), + ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,private,traces,rpc,shh,shh_pubsub", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--ws-apis=[APIS]", "Specify the APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", @@ -520,7 +549,7 @@ usage! { "--ipc-path=[PATH]", "Specify custom path for JSON-RPC over IPC service.", - ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces,rpc,shh,shh_pubsub", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), + ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,private,traces,rpc,shh,shh_pubsub", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--ipc-apis=[APIS]", "Specify custom API set available via JSON-RPC over IPC using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", @@ -1014,6 +1043,7 @@ struct Config { ipc: Option, dapps: Option, secretstore: Option, + private_tx: Option, ipfs: Option, mining: Option, footprint: Option, @@ -1057,6 +1087,18 @@ struct Account { fast_unlock: Option, } +#[derive(Default, Debug, PartialEq, Deserialize)] +#[serde(deny_unknown_fields)] +struct PrivateTransactions { + enabled: Option, + signer: Option, + validators: Option>, + account: Option, + passwords: Option, + sstore_url: Option, + sstore_threshold: Option, +} + #[derive(Default, Debug, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] struct Ui { @@ -1501,6 +1543,15 @@ mod tests { flag_no_hardware_wallets: false, flag_fast_unlock: false, + // -- Private Transactions Options + flag_private_enabled: true, + arg_private_signer: Some("0xdeadbeefcafe0000000000000000000000000000".into()), + arg_private_validators: Some("0xdeadbeefcafe0000000000000000000000000000".into()), + arg_private_passwords: Some("~/.safe/password.file".into()), + arg_private_account: Some("0xdeadbeefcafe0000000000000000000000000000".into()), + arg_private_sstore_url: Some("http://localhost:8082".into()), + arg_private_sstore_threshold: Some(0), + flag_force_ui: false, flag_no_ui: false, arg_ui_port: 8180u16, @@ -1834,6 +1885,7 @@ mod tests { http_port: Some(8082), path: None, }), + private_tx: None, ipfs: Some(Ipfs { enable: Some(false), port: Some(5001), diff --git a/parity/cli/tests/config.full.toml b/parity/cli/tests/config.full.toml index 2e546b5f1e..08df68ee50 100644 --- a/parity/cli/tests/config.full.toml +++ b/parity/cli/tests/config.full.toml @@ -23,6 +23,15 @@ unlock = ["0xdeadbeefcafe0000000000000000000000000000"] password = ["~/.safe/password.file"] keys_iterations = 10240 +[private_tx] +enabled = true +signer = "0xdeadbeefcafe0000000000000000000000000000" +validators = ["0xdeadbeefcafe0000000000000000000000000000"] +passwords = "~/.safe/password.file" +account = "0xdeadbeefcafe0000000000000000000000000000" +sstore_url = "http://localhost:8082" +sstore_threshold = 0 + [ui] force = false disable = false diff --git a/parity/configuration.rs b/parity/configuration.rs index eb6ce713db..7ce3db1240 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -38,13 +38,14 @@ use rpc_apis::ApiSet; use parity_rpc::NetworkSettings; use cache::CacheConfig; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, -to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy}; +to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy, passwords_from_files}; use dir::helpers::{replace_home, replace_home_and_local}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType}; use ethcore_logger::Config as LogConfig; use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; use dapps::Configuration as DappsConfiguration; use ipfs::Configuration as IpfsConfiguration; +use ethcore_private_tx::{ProviderConfig, EncryptorConfig}; use secretstore::{NodeSecretKey, Configuration as SecretStoreConfiguration, ContractAddress as SecretStoreContractAddress}; use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack}; use run::RunCmd; @@ -341,6 +342,7 @@ impl Configuration { let verifier_settings = self.verifier_settings(); let whisper_config = self.whisper_config(); + let (private_provider_conf, private_enc_conf, private_tx_enabled) = self.private_provider_config()?; let run_cmd = RunCmd { cache_config: cache_config, @@ -379,6 +381,9 @@ impl Configuration { ipfs_conf: ipfs_conf, ui_conf: ui_conf, secretstore_conf: secretstore_conf, + private_provider_conf: private_provider_conf, + private_encryptor_conf: private_enc_conf, + private_tx_enabled, dapp: self.dapp_to_open()?, ui: self.args.cmd_ui, name: self.args.arg_identity, @@ -934,6 +939,29 @@ impl Configuration { Ok(conf) } + fn private_provider_config(&self) -> Result<(ProviderConfig, EncryptorConfig, bool), String> { + let provider_conf = ProviderConfig { + validator_accounts: to_addresses(&self.args.arg_private_validators)?, + signer_account: self.args.arg_private_signer.clone().and_then(|account| to_address(Some(account)).ok()), + passwords: match self.args.arg_private_passwords.clone() { + Some(file) => passwords_from_files(&vec![file].as_slice())?, + None => Vec::new(), + }, + }; + + let encryptor_conf = EncryptorConfig { + base_url: self.args.arg_private_sstore_url.clone(), + threshold: self.args.arg_private_sstore_threshold.unwrap_or(0), + key_server_account: self.args.arg_private_account.clone().and_then(|account| to_address(Some(account)).ok()), + passwords: match self.args.arg_private_passwords.clone() { + Some(file) => passwords_from_files(&vec![file].as_slice())?, + None => Vec::new(), + }, + }; + + Ok((provider_conf, encryptor_conf, self.args.flag_private_enabled)) + } + fn network_settings(&self) -> Result { let http_conf = self.http_config()?; let net_addresses = self.net_addresses()?; @@ -1468,6 +1496,9 @@ mod tests { ipfs_conf: Default::default(), ui_conf: Default::default(), secretstore_conf: Default::default(), + private_provider_conf: Default::default(), + private_encryptor_conf: Default::default(), + private_tx_enabled: false, ui: false, dapp: None, name: "".into(), diff --git a/parity/main.rs b/parity/main.rs index 30c3cf0e98..9ff3d97ab3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -53,14 +53,15 @@ extern crate ethcore_logger; extern crate ethcore_migrations as migrations; extern crate ethcore_miner as miner; extern crate ethcore_network as network; +extern crate ethcore_private_tx; extern crate ethcore_service; extern crate ethcore_transaction as transaction; extern crate ethereum_types; -extern crate migration as migr; -extern crate kvdb; -extern crate kvdb_rocksdb; extern crate ethkey; extern crate ethsync; +extern crate kvdb; +extern crate kvdb_rocksdb; +extern crate migration as migr; extern crate node_health; extern crate panic_hook; extern crate parity_hash_fetch as hash_fetch; diff --git a/parity/modules.rs b/parity/modules.rs index 36cffe2ec6..22f8afe9f1 100644 --- a/parity/modules.rs +++ b/parity/modules.rs @@ -21,7 +21,7 @@ use ethsync::{self, AttachedProtocol, SyncConfig, NetworkConfiguration, Params, use ethcore::snapshot::SnapshotService; use light::Provider; -pub use ethsync::{EthSync, SyncProvider, ManageNetwork}; +pub use ethsync::{EthSync, SyncProvider, ManageNetwork, PrivateTxHandler}; pub use ethcore::client::ChainNotify; use ethcore_logger::Config as LogConfig; @@ -32,6 +32,7 @@ pub fn sync( net_cfg: NetworkConfiguration, client: Arc, snapshot_service: Arc, + private_tx_handler: Arc, provider: Arc, _log_settings: &LogConfig, attached_protos: Vec, @@ -42,6 +43,7 @@ pub fn sync( chain: client, provider: provider, snapshot_service: snapshot_service, + private_tx_handler, network_config: net_cfg, attached_protos: attached_protos, }, diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 5ba18dc09b..23a69755ff 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -22,6 +22,7 @@ use std::sync::{Arc, Weak}; pub use parity_rpc::signer::SignerService; pub use parity_rpc::dapps::{DappsService, LocalDapp}; +use ethcore_service::PrivateTxService; use ethcore::account_provider::AccountProvider; use ethcore::client::Client; use ethcore::miner::Miner; @@ -40,6 +41,7 @@ use parity_rpc::dispatch::{FullDispatcher, LightDispatcher}; use parity_rpc::informant::{ActivityNotifier, ClientNotifier}; use parity_rpc::{Metadata, NetworkSettings, Host}; use parking_lot::{Mutex, RwLock}; +use ethcore_private_tx::Provider as PrivateTransactionManager; use updater::Updater; #[derive(Debug, PartialEq, Clone, Eq, Hash)] @@ -70,6 +72,8 @@ pub enum Api { Rpc, /// SecretStore (UNSAFE: arbitrary hash signing) SecretStore, + /// Private transaction manager (Safe) + Private, /// Whisper (Safe) // TODO: _if_ someone guesses someone else's key or filter IDs they can remove // BUT these are all ephemeral so it seems fine. @@ -98,6 +102,7 @@ impl FromStr for Api { "traces" => Ok(Traces), "rpc" => Ok(Rpc), "secretstore" => Ok(SecretStore), + "private" => Ok(Private), "shh" => Ok(Whisper), "shh_pubsub" => Ok(WhisperPubSub), api => Err(format!("Unknown api: {}", api)) @@ -183,6 +188,7 @@ fn to_modules(apis: &HashSet) -> BTreeMap { Api::Traces => ("traces", "1.0"), Api::Rpc => ("rpc", "1.0"), Api::SecretStore => ("secretstore", "1.0"), + Api::Private => ("private", "1.0"), Api::Whisper => ("shh", "1.0"), Api::WhisperPubSub => ("shh_pubsub", "1.0"), }; @@ -214,6 +220,7 @@ pub struct FullDependencies { pub sync: Arc, pub net: Arc, pub secret_store: Option>, + pub private_tx_service: Option>, pub miner: Arc, pub external_miner: Arc, pub logger: Arc, @@ -385,7 +392,10 @@ impl FullDependencies { ); } } - } + }, + Api::Private => { + handler.extend_with(PrivateClient::new(self.private_tx_service.as_ref().map(|p| p.provider())).to_delegate()); + }, } } } @@ -437,6 +447,7 @@ pub struct LightDependencies { pub geth_compatibility: bool, pub remote: parity_reactor::Remote, pub whisper_rpc: Option<::whisper::RpcFactory>, + pub private_tx_service: Option>, pub gas_price_percentile: usize, } @@ -587,12 +598,18 @@ impl LightDependencies { let whisper = whisper_rpc.make_handler(self.net.clone()); handler.extend_with(::parity_whisper::rpc::Whisper::to_delegate(whisper)); } - } + }, Api::WhisperPubSub => { if let Some(ref whisper_rpc) = self.whisper_rpc { let whisper = whisper_rpc.make_handler(self.net.clone()); handler.extend_with(::parity_whisper::rpc::WhisperPubSub::to_delegate(whisper)); } + }, + Api::Private => { + if let Some(ref tx_manager) = self.private_tx_service { + let private_tx_service = Some(tx_manager.clone()); + handler.extend_with(PrivateClient::new(private_tx_service).to_delegate()); + } } } } @@ -629,6 +646,7 @@ impl ApiSet { Api::Rpc, Api::Whisper, Api::WhisperPubSub, + Api::Private, ].into_iter().cloned().collect(); match *self { @@ -693,6 +711,7 @@ mod test { assert_eq!(Api::Traces, "traces".parse().unwrap()); assert_eq!(Api::Rpc, "rpc".parse().unwrap()); assert_eq!(Api::SecretStore, "secretstore".parse().unwrap()); + assert_eq!(Api::Private, "private".parse().unwrap()); assert_eq!(Api::Whisper, "shh".parse().unwrap()); assert_eq!(Api::WhisperPubSub, "shh_pubsub".parse().unwrap()); assert!("rp".parse::().is_err()); @@ -712,7 +731,7 @@ mod test { fn test_api_set_unsafe_context() { let expected = vec![ // make sure this list contains only SAFE methods - Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, + Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, Api::Private, ].into_iter().collect(); assert_eq!(ApiSet::UnsafeContext.list_apis(), expected); } @@ -721,7 +740,7 @@ mod test { fn test_api_set_ipc_context() { let expected = vec![ // safe - Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, + Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, Api::Private, // semi-safe Api::ParityAccounts ].into_iter().collect(); @@ -732,7 +751,7 @@ mod test { fn test_api_set_safe_context() { let expected = vec![ // safe - Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub, + Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub, Api::Private, // semi-safe Api::ParityAccounts, // Unsafe @@ -747,7 +766,8 @@ mod test { Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub, Api::ParityAccounts, Api::ParitySet, Api::Signer, - Api::Personal + Api::Personal, + Api::Private, ].into_iter().collect())); } @@ -757,13 +777,14 @@ mod test { Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub, Api::ParityAccounts, Api::ParitySet, Api::Signer, + Api::Private ].into_iter().collect())); } #[test] fn test_safe_parsing() { assert_eq!("safe".parse::().unwrap(), ApiSet::List(vec![ - Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, + Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, Api::Private, ].into_iter().collect())); } } diff --git a/parity/run.rs b/parity/run.rs index 816ddd4dd3..fbc24a90d7 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -50,7 +50,7 @@ use parity_rpc::{NetworkSettings, informant, is_major_importing}; use parking_lot::{Condvar, Mutex}; use updater::{UpdatePolicy, Updater}; use parity_version::version; - +use ethcore_private_tx::{ProviderConfig, EncryptorConfig, SecretStoreEncryptor}; use params::{ SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch, tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool @@ -120,6 +120,9 @@ pub struct RunCmd { pub ipfs_conf: ipfs::Configuration, pub ui_conf: rpc::UiConfiguration, pub secretstore_conf: secretstore::Configuration, + pub private_provider_conf: ProviderConfig, + pub private_encryptor_conf: EncryptorConfig, + pub private_tx_enabled: bool, pub dapp: Option, pub ui: bool, pub name: String, @@ -388,6 +391,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: restoration_db_handler, &cmd.dirs.ipc_path(), miner.clone(), + account_provider.clone(), + Box::new(SecretStoreEncryptor::new(cmd.private_encryptor_conf, fetch.clone()).map_err(|e| e.to_string())?), + cmd.private_provider_conf, ).map_err(|e| format!("Client service error: {:?}", e))?; let connection_filter_address = spec.params().node_permission_contract; @@ -630,6 +637,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // take handle to client let client = service.client(); + // take handle to private transactions service + let private_tx_service = service.private_tx_service(); + let private_tx_provider = private_tx_service.provider(); let connection_filter = connection_filter_address.map(|a| Arc::new(NodeFilter::new(Arc::downgrade(&client) as Weak, a))); let snapshot_service = service.snapshot_service(); @@ -697,6 +707,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: net_conf.clone().into(), client.clone(), snapshot_service.clone(), + private_tx_service.clone(), client.clone(), &cmd.logger_config, attached_protos, @@ -705,6 +716,15 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: service.add_notify(chain_notify.clone()); + // provider not added to a notification center is effectively disabled + // TODO [debris] refactor it later on + if cmd.private_tx_enabled { + service.add_notify(private_tx_provider.clone()); + // TODO [ToDr] PrivateTX should use separate notifications + // re-using ChainNotify for this is a bit abusive. + private_tx_provider.add_notify(chain_notify.clone()); + } + // start network if network_enabled { chain_notify.start(); @@ -796,6 +816,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: pool: cpu_pool.clone(), remote: event_loop.remote(), whisper_rpc: whisper_factory, + private_tx_service: Some(private_tx_service.clone()), gas_price_percentile: cmd.gas_price_percentile, }); diff --git a/parity/snapshot.rs b/parity/snapshot.rs index ae7a0698b7..9096732808 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -21,6 +21,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use hash::keccak; +use ethcore::account_provider::AccountProvider; use ethcore::snapshot::{Progress, RestorationStatus, SnapshotService as SS}; use ethcore::snapshot::io::{SnapshotReader, PackedReader, PackedWriter}; use ethcore::snapshot::service::Service as SnapshotService; @@ -35,6 +36,7 @@ use helpers::{to_client_config, execute_upgrades, client_db_config, open_client_ use dir::Directories; use user_defaults::UserDefaults; use fdlimit; +use ethcore_private_tx; /// Kinds of snapshot commands. #[derive(Debug, PartialEq, Clone, Copy)] @@ -192,7 +194,10 @@ impl SnapshotCommand { &snapshot_path, restoration_db_handler, &self.dirs.ipc_path(), - Arc::new(Miner::with_spec(&spec)) + Arc::new(Miner::with_spec(&spec)), + Arc::new(AccountProvider::transient_provider()), + Box::new(ethcore_private_tx::NoopEncryptor), + Default::default() ).map_err(|e| format!("Client service error: {:?}", e))?; Ok(service) diff --git a/price-info/src/lib.rs b/price-info/src/lib.rs index e233062b43..9be27a1319 100644 --- a/price-info/src/lib.rs +++ b/price-info/src/lib.rs @@ -96,7 +96,7 @@ impl Client { /// Gets the current ETH price and calls `set_price` with the result. pub fn get(&self, set_price: G) { - let future = self.fetch.fetch(&self.api_endpoint, fetch::Abort::default()) + let future = self.fetch.get(&self.api_endpoint, fetch::Abort::default()) .from_err() .and_then(|response| { if !response.is_success() { @@ -140,7 +140,7 @@ mod test { use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use fetch; - use fetch::{Fetch, Url}; + use fetch::{Fetch, Url, Method}; use futures_cpupool::CpuPool; use futures::future::{self, FutureResult}; use Client; @@ -158,7 +158,7 @@ mod test { impl Fetch for FakeFetch { type Result = FutureResult; - fn fetch(&self, url: &str, abort: fetch::Abort) -> Self::Result { + fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { assert_eq!(url, "https://api.etherscan.io/api?module=stats&action=ethprice"); let u = Url::parse(url).unwrap(); let mut val = self.1.lock(); diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 51f2e8ff36..ed59a91e8d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -44,6 +44,7 @@ ethcore-io = { path = "../util/io" } ethcore-light = { path = "../ethcore/light" } ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } +ethcore-private-tx = { path = "../ethcore/private-tx" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index a08a1a88a8..79911938b8 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -67,6 +67,7 @@ extern crate rlp; extern crate stats; extern crate keccak_hash as hash; extern crate hardware_wallet; +extern crate ethcore_private_tx; extern crate patricia_trie as trie; #[macro_use] diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 9393fc53a0..e86ab630f5 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -23,6 +23,7 @@ use ethcore::error::{Error as EthcoreError, CallError}; use jsonrpc_core::{futures, Error, ErrorCode, Value}; use rlp::DecoderError; use transaction::Error as TransactionError; +use ethcore_private_tx::Error as PrivateTransactionError; mod codes { // NOTE [ToDr] Codes from [-32099, -32000] @@ -39,6 +40,7 @@ mod codes { pub const ACCOUNT_LOCKED: i64 = -32020; pub const PASSWORD_INVALID: i64 = -32021; pub const ACCOUNT_ERROR: i64 = -32023; + pub const PRIVATE_ERROR: i64 = -32024; pub const REQUEST_REJECTED: i64 = -32040; pub const REQUEST_REJECTED_LIMIT: i64 = -32041; pub const REQUEST_NOT_FOUND: i64 = -32042; @@ -288,6 +290,22 @@ pub fn password(error: AccountError) -> Error { } } +pub fn private_message(error: PrivateTransactionError) -> Error { + Error { + code: ErrorCode::ServerError(codes::PRIVATE_ERROR), + message: "Private transactions call failed.".into(), + data: Some(Value::String(format!("{:?}", error))), + } +} + +pub fn private_message_block_id_not_supported() -> Error { + Error { + code: ErrorCode::ServerError(codes::PRIVATE_ERROR), + message: "Pending block id not supported.".into(), + data: None, + } +} + pub fn transaction_message(error: TransactionError) -> String { use self::TransactionError::*; diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index a1344fa69b..0a6c2c5a57 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -128,7 +128,7 @@ impl ParitySet for ParitySetClient { } fn hash_content(&self, url: String) -> BoxFuture { - let future = self.fetch.fetch(&url, Default::default()).then(move |result| { + let future = self.fetch.get(&url, Default::default()).then(move |result| { result .map_err(errors::fetch) .and_then(move |response| { diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index d3e0554c24..4edaf6bcd2 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -32,6 +32,7 @@ mod rpc; mod secretstore; mod traces; mod web3; +mod private; pub mod light; @@ -51,3 +52,4 @@ pub use self::traces::TracesClient; pub use self::web3::Web3Client; pub use self::rpc::RpcClient; pub use self::secretstore::SecretStoreClient; +pub use self::private::PrivateClient; diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 9d07118723..1be136e1de 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -170,7 +170,7 @@ impl ParitySet for ParitySetClient where } fn hash_content(&self, url: String) -> BoxFuture { - let future = self.fetch.fetch(&url, Default::default()).then(move |result| { + let future = self.fetch.get(&url, Default::default()).then(move |result| { result .map_err(errors::fetch) .and_then(move |response| { diff --git a/rpc/src/v1/impls/private.rs b/rpc/src/v1/impls/private.rs new file mode 100644 index 0000000000..bf797d5a58 --- /dev/null +++ b/rpc/src/v1/impls/private.rs @@ -0,0 +1,122 @@ +// 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 . + +//! Privte transaction signing RPC implementation. + +use std::sync::Arc; + +use rlp::UntrustedRlp; + +use ethcore_private_tx::Provider as PrivateTransactionManager; +use ethereum_types::Address; +use transaction::SignedTransaction; + +use jsonrpc_core::{Error}; +use v1::types::{Bytes, PrivateTransactionReceipt, H160, H256, TransactionRequest, U256, + BlockNumber, PrivateTransactionReceiptAndTransaction, CallRequest, block_number_to_id}; +use v1::traits::Private; +use v1::metadata::Metadata; +use v1::helpers::{errors, fake_sign}; + +/// Private transaction manager API endpoint implementation. +pub struct PrivateClient { + private: Option>, +} + +impl PrivateClient { + /// Creates a new instance. + pub fn new(private: Option>) -> Self { + PrivateClient { + private, + } + } + + fn unwrap_manager(&self) -> Result<&PrivateTransactionManager, Error> { + match self.private { + Some(ref arc) => Ok(&**arc), + None => Err(errors::public_unsupported(None)), + } + } +} + +impl Private for PrivateClient { + type Metadata = Metadata; + + fn send_transaction(&self, request: Bytes) -> Result { + let signed_transaction = UntrustedRlp::new(&request.into_vec()).as_val() + .map_err(errors::rlp) + .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))?; + let client = self.unwrap_manager()?; + let receipt = client.create_private_transaction(signed_transaction).map_err(|e| errors::private_message(e))?; + Ok(receipt.into()) + } + + fn compose_deployment_transaction(&self, block_number: BlockNumber, request: Bytes, validators: Vec, gas_price: U256) -> Result { + let signed_transaction = UntrustedRlp::new(&request.into_vec()).as_val() + .map_err(errors::rlp) + .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))?; + let client = self.unwrap_manager()?; + + let addresses: Vec
= validators.into_iter().map(Into::into).collect(); + let id = match block_number { + BlockNumber::Pending => return Err(errors::private_message_block_id_not_supported()), + num => block_number_to_id(num) + }; + + let (transaction, contract_address) = client.public_creation_transaction(id, &signed_transaction, addresses.as_slice(), gas_price.into()) + .map_err(|e| errors::private_message(e))?; + let tx_hash = transaction.hash(None); + let request = TransactionRequest { + from: Some(signed_transaction.sender().into()), + to: None, + nonce: Some(transaction.nonce.into()), + gas_price: Some(transaction.gas_price.into()), + gas: Some(transaction.gas.into()), + value: Some(transaction.value.into()), + data: Some(transaction.data.into()), + condition: None, + }; + + Ok(PrivateTransactionReceiptAndTransaction { + transaction: request, + receipt: PrivateTransactionReceipt { + transaction_hash: tx_hash.into(), + contract_address: contract_address.map(|address| address.into()), + status_code: 0, + } + }) + } + + fn private_call(&self, meta: Self::Metadata, block_number: BlockNumber, request: CallRequest) -> Result { + let id = match block_number { + BlockNumber::Pending => return Err(errors::private_message_block_id_not_supported()), + num => block_number_to_id(num) + }; + + let request = CallRequest::into(request); + let signed = fake_sign::sign_call(request, meta.is_dapp())?; + let client = self.unwrap_manager()?; + let executed_result = client.private_call(id, &signed).map_err(|e| errors::private_message(e))?; + Ok(executed_result.output.into()) + } + + fn private_contract_key(&self, contract_address: H160) -> Result { + let client = self.unwrap_manager()?; + let key = client.contract_key_id(&contract_address.into()).map_err(|e| errors::private_message(e))?; + Ok(key.into()) + } +} + diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index b5e1cfa4db..154317eb2f 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -41,7 +41,7 @@ pub mod informant; pub mod metadata; pub mod traits; -pub use self::traits::{Web3, Eth, EthFilter, EthPubSub, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, PubSub, Signer, Personal, Traces, Rpc, SecretStore}; +pub use self::traits::{Web3, Eth, EthFilter, EthPubSub, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, PubSub, Signer, Personal, Traces, Rpc, SecretStore, Private}; pub use self::impls::*; pub use self::helpers::{NetworkSettings, block_import, dispatch}; pub use self::metadata::Metadata; diff --git a/rpc/src/v1/tests/helpers/fetch.rs b/rpc/src/v1/tests/helpers/fetch.rs index 316d068255..f3b7543f70 100644 --- a/rpc/src/v1/tests/helpers/fetch.rs +++ b/rpc/src/v1/tests/helpers/fetch.rs @@ -18,7 +18,7 @@ use std::thread; use jsonrpc_core::futures::{self, Future}; -use fetch::{self, Fetch, Url}; +use fetch::{self, Fetch, Url, Method}; use hyper; /// Test implementation of fetcher. Will always return the same file. @@ -28,7 +28,7 @@ pub struct TestFetch; impl Fetch for TestFetch { type Result = Box + Send + 'static>; - fn fetch(&self, url: &str, abort: fetch::Abort) -> Self::Result { + fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { let u = Url::parse(url).unwrap(); let (tx, rx) = futures::oneshot(); thread::spawn(move || { diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index 528463a4a4..26a43fa3f8 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -31,6 +31,7 @@ pub mod signer; pub mod traces; pub mod rpc; pub mod secretstore; +pub mod private; pub use self::web3::Web3; pub use self::eth::{Eth, EthFilter}; @@ -47,3 +48,4 @@ pub use self::signer::Signer; pub use self::traces::Traces; pub use self::rpc::Rpc; pub use self::secretstore::SecretStore; +pub use self::private::Private; diff --git a/rpc/src/v1/traits/private.rs b/rpc/src/v1/traits/private.rs new file mode 100644 index 0000000000..7106e0bf43 --- /dev/null +++ b/rpc/src/v1/traits/private.rs @@ -0,0 +1,45 @@ +// 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 . + +//! SecretStore-specific rpc interface. + +use jsonrpc_core::Error; + +use v1::types::{Bytes, PrivateTransactionReceipt, H160, H256, U256, BlockNumber, + PrivateTransactionReceiptAndTransaction, CallRequest}; + +build_rpc_trait! { + /// Private transaction management RPC interface. + pub trait Private { + type Metadata; + + /// Sends private transaction; Transaction will be added to the validation queue and sent out when ready. + #[rpc(name = "private_sendTransaction")] + fn send_transaction(&self, Bytes) -> Result; + + /// Creates a transaction for contract's deployment from origin (signed transaction) + #[rpc(name = "private_composeDeploymentTransaction")] + fn compose_deployment_transaction(&self, BlockNumber, Bytes, Vec, U256) -> Result; + + /// Make a call to the private contract + #[rpc(meta, name = "private_call")] + fn private_call(&self, Self::Metadata, BlockNumber, CallRequest) -> Result; + + /// Retrieve the id of the key associated with the contract + #[rpc(name = "private_contractKey")] + fn private_contract_key(&self, H160) -> Result; + } +} diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 7f1e51fad0..e7f764b8b1 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -44,6 +44,7 @@ mod transaction_request; mod transaction_condition; mod uint; mod work; +mod private_receipt; pub mod pubsub; @@ -80,6 +81,7 @@ pub use self::transaction_request::TransactionRequest; pub use self::transaction_condition::TransactionCondition; pub use self::uint::{U128, U256, U64}; pub use self::work::Work; +pub use self::private_receipt::{PrivateTransactionReceipt, PrivateTransactionReceiptAndTransaction}; // TODO [ToDr] Refactor to a proper type Vec of enums? /// Expected tracing type. diff --git a/rpc/src/v1/types/private_receipt.rs b/rpc/src/v1/types/private_receipt.rs new file mode 100644 index 0000000000..328013d7f6 --- /dev/null +++ b/rpc/src/v1/types/private_receipt.rs @@ -0,0 +1,54 @@ +// 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 . + +use v1::types::{H160, H256, TransactionRequest}; +use ethcore_private_tx::{Receipt as EthPrivateReceipt}; + +/// Receipt +#[derive(Debug, Serialize)] +pub struct PrivateTransactionReceipt { + /// Transaction Hash + #[serde(rename="transactionHash")] + pub transaction_hash: H256, + /// Private contract address + #[serde(rename="contractAddress")] + pub contract_address: Option, + /// Status code + #[serde(rename="status")] + pub status_code: u8, +} + +impl From for PrivateTransactionReceipt { + fn from(r: EthPrivateReceipt) -> Self { + PrivateTransactionReceipt { + transaction_hash: r.hash.into(), + contract_address: r.contract_address.map(Into::into), + status_code: r.status_code.into(), + } + } +} + +/// Receipt and Transaction +#[derive(Debug, Serialize)] +pub struct PrivateTransactionReceiptAndTransaction { + /// Receipt + #[serde(rename="receipt")] + pub receipt: PrivateTransactionReceipt, + /// Transaction + #[serde(rename="transaction")] + pub transaction: TransactionRequest, +} + diff --git a/sync/Cargo.toml b/sync/Cargo.toml index c5384de71d..23cbbcf341 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -18,6 +18,7 @@ ethcore = { path = "../ethcore" } ethereum-types = "0.3" plain_hasher = { path = "../util/plain_hasher" } rlp = { path = "../util/rlp" } +rustc-hex = "1.0" keccak-hash = { path = "../util/hash" } triehash = { path = "../util/triehash" } kvdb = { path = "../util/kvdb" } diff --git a/sync/src/api.rs b/sync/src/api.rs index 735b6eb033..62a237da48 100644 --- a/sync/src/api.rs +++ b/sync/src/api.rs @@ -24,7 +24,7 @@ use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, Protocol use ethereum_types::{H256, H512, U256}; use io::{TimerToken}; use ethcore::ethstore::ethkey::Secret; -use ethcore::client::{BlockChainClient, ChainNotify}; +use ethcore::client::{BlockChainClient, ChainNotify, ChainMessageType}; use ethcore::snapshot::SnapshotService; use ethcore::header::BlockNumber; use sync_io::NetSyncIo; @@ -32,11 +32,13 @@ use chain::{ChainSync, SyncStatus as EthSyncStatus}; use std::net::{SocketAddr, AddrParseError}; use std::str::FromStr; use parking_lot::RwLock; -use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT}; +use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT, ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_62, + PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3}; use light::client::AsLightClient; use light::Provider; use light::net::{self as light_net, LightProtocol, Params as LightParams, Capabilities, Handler as LightHandler, EventContext}; use network::IpFilter; +use private_tx::PrivateTxHandler; /// Parity sync protocol pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par"; @@ -227,6 +229,8 @@ pub struct Params { pub chain: Arc, /// Snapshot service. pub snapshot_service: Arc, + /// Private tx service. + pub private_tx_handler: Arc, /// Light data provider. pub provider: Arc<::light::Provider>, /// Network layer configuration. @@ -288,7 +292,7 @@ impl EthSync { }) }; - let chain_sync = ChainSync::new(params.config, &*params.chain); + let chain_sync = ChainSync::new(params.config, &*params.chain, params.private_tx_handler.clone()); let service = NetworkService::new(params.network_config.clone().into_basic()?, connection_filter)?; let sync = Arc::new(EthSync { @@ -392,9 +396,10 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { - self.sync.write().maintain_peers(&mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay)); - self.sync.write().maintain_sync(&mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay)); - self.sync.write().propagate_new_transactions(&mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay)); + let mut io = NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay); + self.sync.write().maintain_peers(&mut io); + self.sync.write().maintain_sync(&mut io); + self.sync.write().propagate_new_transactions(&mut io); } } @@ -411,7 +416,8 @@ impl ChainNotify for EthSync { use light::net::Announcement; self.network.with_context(self.subprotocol_name, |context| { - let mut sync_io = NetSyncIo::new(context, &*self.eth_handler.chain, &*self.eth_handler.snapshot_service, &self.eth_handler.overlay); + let mut sync_io = NetSyncIo::new(context, &*self.eth_handler.chain, &*self.eth_handler.snapshot_service, + &self.eth_handler.overlay); self.eth_handler.sync.write().chain_new_blocks( &mut sync_io, &imported, @@ -448,10 +454,10 @@ impl ChainNotify for EthSync { Err(err) => warn!("Error starting network: {}", err), _ => {}, } - self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, ETH_PACKET_COUNT, &[62u8, 63u8]) + self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, ETH_PACKET_COUNT, &[ETH_PROTOCOL_VERSION_62, ETH_PROTOCOL_VERSION_63]) .unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e)); // register the warp sync subprotocol - self.network.register_protocol(self.eth_handler.clone(), WARP_SYNC_PROTOCOL_ID, SNAPSHOT_SYNC_PACKET_COUNT, &[1u8, 2u8]) + self.network.register_protocol(self.eth_handler.clone(), WARP_SYNC_PROTOCOL_ID, SNAPSHOT_SYNC_PACKET_COUNT, &[PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3]) .unwrap_or_else(|e| warn!("Error registering snapshot sync protocol: {:?}", e)); // register the light protocol. @@ -469,10 +475,14 @@ impl ChainNotify for EthSync { self.network.stop().unwrap_or_else(|e| warn!("Error stopping network: {:?}", e)); } - fn broadcast(&self, message: Vec) { + fn broadcast(&self, message_type: ChainMessageType) { self.network.with_context(WARP_SYNC_PROTOCOL_ID, |context| { let mut sync_io = NetSyncIo::new(context, &*self.eth_handler.chain, &*self.eth_handler.snapshot_service, &self.eth_handler.overlay); - self.eth_handler.sync.write().propagate_consensus_packet(&mut sync_io, message.clone()); + match message_type { + ChainMessageType::Consensus(message) => self.eth_handler.sync.write().propagate_consensus_packet(&mut sync_io, message), + ChainMessageType::PrivateTransaction(message) => self.eth_handler.sync.write().propagate_private_transaction(&mut sync_io, message), + ChainMessageType::SignedPrivateTransaction(message) => self.eth_handler.sync.write().propagate_signed_private_transaction(&mut sync_io, message), + } }); } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 9780245912..b2494e1f03 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -88,6 +88,7 @@ /// All other messages are ignored. /// +use std::sync::Arc; use std::collections::{HashSet, HashMap}; use std::cmp; use std::time::Instant; @@ -111,15 +112,23 @@ use rand::Rng; use snapshot::{Snapshot, ChunkType}; use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; use transactions_stats::{TransactionsStats, Stats as TransactionStats}; +use private_tx::PrivateTxHandler; known_heap_size!(0, PeerInfo); type PacketDecodeError = DecoderError; -const PROTOCOL_VERSION_63: u8 = 63; -const PROTOCOL_VERSION_62: u8 = 62; -const PROTOCOL_VERSION_1: u8 = 1; -const PROTOCOL_VERSION_2: u8 = 2; +/// 63 version of Ethereum protocol. +pub const ETH_PROTOCOL_VERSION_63: u8 = 63; +/// 62 version of Ethereum protocol. +pub const ETH_PROTOCOL_VERSION_62: u8 = 62; +/// 1 version of Parity protocol. +pub const PAR_PROTOCOL_VERSION_1: u8 = 1; +/// 2 version of Parity protocol (consensus messages added). +pub const PAR_PROTOCOL_VERSION_2: u8 = 2; +/// 3 version of Parity protocol (private transactions messages added). +pub const PAR_PROTOCOL_VERSION_3: u8 = 3; + const MAX_BODIES_TO_SEND: usize = 256; const MAX_HEADERS_TO_SEND: usize = 512; const MAX_NODE_DATA_TO_SEND: usize = 1024; @@ -160,8 +169,10 @@ const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12; const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13; const SNAPSHOT_DATA_PACKET: u8 = 0x14; const CONSENSUS_DATA_PACKET: u8 = 0x15; +const PRIVATE_TRANSACTION_PACKET: u8 = 0x16; +const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17; -pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x16; +pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; @@ -384,6 +395,8 @@ pub struct ChainSync { transactions_stats: TransactionsStats, /// Enable ancient block downloading download_old_blocks: bool, + /// Shared private tx service. + private_tx_handler: Arc, /// Enable warp sync. warp_sync: WarpSync, } @@ -392,7 +405,7 @@ type RlpResponseResult = Result, PacketDecodeError impl ChainSync { /// Create a new instance of syncing strategy. - pub fn new(config: SyncConfig, chain: &BlockChainClient) -> ChainSync { + pub fn new(config: SyncConfig, chain: &BlockChainClient, private_tx_handler: Arc) -> ChainSync { let chain_info = chain.chain_info(); let best_block = chain.chain_info().best_block_number; let state = match config.warp_sync { @@ -417,6 +430,7 @@ impl ChainSync { snapshot: Snapshot::new(), sync_start_time: None, transactions_stats: TransactionsStats::default(), + private_tx_handler, warp_sync: config.warp_sync, }; sync.update_targets(chain); @@ -428,7 +442,7 @@ impl ChainSync { let last_imported_number = self.new_blocks.last_imported_block_number(); SyncStatus { state: self.state.clone(), - protocol_version: PROTOCOL_VERSION_63, + protocol_version: ETH_PROTOCOL_VERSION_63, network_id: self.network_id, start_block_number: self.starting_block, last_imported_block_number: Some(last_imported_number), @@ -662,7 +676,8 @@ impl ChainSync { trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, self.network_id, peer.network_id); return Ok(()); } - if (warp_protocol && peer.protocol_version != PROTOCOL_VERSION_1 && peer.protocol_version != PROTOCOL_VERSION_2) || (!warp_protocol && peer.protocol_version != PROTOCOL_VERSION_63 && peer.protocol_version != PROTOCOL_VERSION_62) { + if (warp_protocol && peer.protocol_version != PAR_PROTOCOL_VERSION_1 && peer.protocol_version != PAR_PROTOCOL_VERSION_2 && peer.protocol_version != PAR_PROTOCOL_VERSION_3) + || (!warp_protocol && peer.protocol_version != ETH_PROTOCOL_VERSION_63 && peer.protocol_version != ETH_PROTOCOL_VERSION_62) { io.disable_peer(peer_id); trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); return Ok(()); @@ -1493,6 +1508,7 @@ impl ChainSync { } if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "{} Ignoring transactions from unconfirmed/unknown peer", peer_id); + return Ok(()); } let item_count = r.item_count()?; @@ -1515,7 +1531,7 @@ impl ChainSync { fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), network::Error> { let warp_protocol_version = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer); let warp_protocol = warp_protocol_version != 0; - let protocol = if warp_protocol { warp_protocol_version } else { PROTOCOL_VERSION_63 }; + let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63 }; trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol); let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 }); let chain = io.chain().chain_info(); @@ -1792,6 +1808,8 @@ impl ChainSync { NEW_BLOCK_HASHES_PACKET => self.on_peer_new_hashes(io, peer, &rlp), SNAPSHOT_MANIFEST_PACKET => self.on_snapshot_manifest(io, peer, &rlp), SNAPSHOT_DATA_PACKET => self.on_snapshot_data(io, peer, &rlp), + PRIVATE_TRANSACTION_PACKET => self.on_private_transaction(io, peer, &rlp), + SIGNED_PRIVATE_TRANSACTION_PACKET => self.on_signed_private_transaction(io, peer, &rlp), _ => { debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id); Ok(()) @@ -1945,7 +1963,11 @@ impl ChainSync { } fn get_consensus_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version == PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() + } + + fn get_private_transaction_peers(&self) -> Vec { + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3 { Some(*id) } else { None }).collect() } /// propagates latest block to a set of peers @@ -2223,6 +2245,54 @@ impl ChainSync { self.send_packet(io, peer_id, CONSENSUS_DATA_PACKET, packet.clone()); } } + + /// Called when peer sends us new private transaction packet + fn on_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + trace!(target: "sync", "Received private transaction packet from {:?}", peer_id); + + if let Err(e) = self.private_tx_handler.import_private_transaction(r.as_raw()) { + trace!(target: "sync", "Ignoring the message, error queueing: {}", e); + } + Ok(()) + } + + /// Broadcast private transaction message to peers. + pub fn propagate_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&self.get_private_transaction_peers()); + trace!(target: "sync", "Sending private transaction packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + self.send_packet(io, peer_id, PRIVATE_TRANSACTION_PACKET, packet.clone()); + } + } + + /// Called when peer sends us signed private transaction packet + fn on_signed_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + trace!(target: "sync", "Received signed private transaction packet from {:?}", peer_id); + if let Err(e) = self.private_tx_handler.import_signed_private_transaction(r.as_raw()) { + trace!(target: "sync", "Ignoring the message, error queueing: {}", e); + } + Ok(()) + } + + /// Broadcast signed private transaction message to peers. + pub fn propagate_signed_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&self.get_private_transaction_peers()); + trace!(target: "sync", "Sending signed private transaction packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + self.send_packet(io, peer_id, SIGNED_PRIVATE_TRANSACTION_PACKET, packet.clone()); + } + } + } /// Checks if peer is able to process service transactions @@ -2247,7 +2317,7 @@ mod tests { use std::collections::{HashSet, VecDeque}; use ethkey; use network::PeerId; - use tests::helpers::*; + use tests::helpers::{TestIo}; use tests::snapshot::TestSnapshotService; use ethereum_types::{H256, U256, Address}; use parking_lot::RwLock; @@ -2260,6 +2330,7 @@ mod tests { use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; use ethcore::miner::MinerService; use transaction::UnverifiedTransaction; + use private_tx::NoopPrivateTxHandler; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); @@ -2483,7 +2554,7 @@ mod tests { } fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync { - let mut sync = ChainSync::new(SyncConfig::default(), client); + let mut sync = ChainSync::new(SyncConfig::default(), client, Arc::new(NoopPrivateTxHandler)); insert_dummy_peer(&mut sync, 0, peer_latest_hash); sync } @@ -2608,7 +2679,7 @@ mod tests { client.add_blocks(2, EachBlockWith::Uncle); let queue = RwLock::new(VecDeque::new()); let block = client.block(BlockId::Latest).unwrap().into_inner(); - let mut sync = ChainSync::new(SyncConfig::default(), &client); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); sync.peers.insert(0, PeerInfo { // Messaging protocol @@ -2695,7 +2766,7 @@ mod tests { client.add_blocks(100, EachBlockWith::Uncle); client.insert_transaction_to_queue(); // Sync with no peers - let mut sync = ChainSync::new(SyncConfig::default(), &client); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); @@ -2765,7 +2836,7 @@ mod tests { let mut client = TestBlockChainClient::new(); client.insert_transaction_with_gas_price_to_queue(U256::zero()); let block_hash = client.block_hash_delta_minus(1); - let mut sync = ChainSync::new(SyncConfig::default(), &client); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); @@ -2798,7 +2869,7 @@ mod tests { let tx1_hash = client.insert_transaction_to_queue(); let tx2_hash = client.insert_transaction_with_gas_price_to_queue(U256::zero()); let block_hash = client.block_hash_delta_minus(1); - let mut sync = ChainSync::new(SyncConfig::default(), &client); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 9aee8f3d4e..a6e0c7db24 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -44,6 +44,7 @@ extern crate ethcore_light as light; #[cfg(test)] extern crate ethkey; #[cfg(test)] extern crate kvdb_memorydb; +#[cfg(test)] extern crate rustc_hex; #[macro_use] extern crate macros; @@ -56,6 +57,7 @@ mod chain; mod blocks; mod block_sync; mod sync_io; +mod private_tx; mod snapshot; mod transactions_stats; @@ -70,3 +72,4 @@ pub use api::*; pub use chain::{SyncStatus, SyncState}; pub use devp2p::{validate_node_url, ConnectionFilter, ConnectionDirection}; pub use network::{NonReservedPeerMode, Error, ErrorKind}; +pub use private_tx::{PrivateTxHandler, NoopPrivateTxHandler, SimplePrivateTxHandler}; diff --git a/sync/src/light_sync/tests/test_net.rs b/sync/src/light_sync/tests/test_net.rs index f935680573..badd35668b 100644 --- a/sync/src/light_sync/tests/test_net.rs +++ b/sync/src/light_sync/tests/test_net.rs @@ -205,6 +205,10 @@ impl PeerLike for Peer { } fn restart_sync(&self) { } + + fn process_all_io_messages(&self) { } + + fn process_all_new_block_messages(&self) { } } impl TestNet { diff --git a/sync/src/private_tx.rs b/sync/src/private_tx.rs new file mode 100644 index 0000000000..ded5de2d86 --- /dev/null +++ b/sync/src/private_tx.rs @@ -0,0 +1,60 @@ +// 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 . + +use parking_lot::Mutex; + +/// Trait which should be implemented by a private transaction handler. +pub trait PrivateTxHandler: Send + Sync + 'static { + /// Function called on new private transaction received. + fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), String>; + + /// Function called on new signed private transaction received. + fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), String>; +} + +/// Nonoperative private transaction handler. +pub struct NoopPrivateTxHandler; + +impl PrivateTxHandler for NoopPrivateTxHandler { + fn import_private_transaction(&self, _rlp: &[u8]) -> Result<(), String> { + Ok(()) + } + + fn import_signed_private_transaction(&self, _rlp: &[u8]) -> Result<(), String> { + Ok(()) + } +} + +/// Simple private transaction handler. Used for tests. +#[derive(Default)] +pub struct SimplePrivateTxHandler { + /// imported private transactions + pub txs: Mutex>>, + /// imported signed private transactions + pub signed_txs: Mutex>>, +} + +impl PrivateTxHandler for SimplePrivateTxHandler { + fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), String> { + self.txs.lock().push(rlp.to_vec()); + Ok(()) + } + + fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), String> { + self.signed_txs.lock().push(rlp.to_vec()); + Ok(()) + } +} diff --git a/sync/src/tests/consensus.rs b/sync/src/tests/consensus.rs index 951c027afe..f4a58a18af 100644 --- a/sync/src/tests/consensus.rs +++ b/sync/src/tests/consensus.rs @@ -17,8 +17,8 @@ use std::sync::Arc; use hash::keccak; use ethereum_types::{U256, Address}; -use io::{IoHandler, IoContext, IoChannel}; -use ethcore::client::{Client, ChainInfo, ClientIoMessage}; +use io::{IoHandler, IoChannel}; +use ethcore::client::{ChainInfo, ClientIoMessage}; use ethcore::spec::Spec; use ethcore::miner::MinerService; use ethcore::account_provider::AccountProvider; @@ -27,21 +27,6 @@ use transaction::{Action, PendingTransaction, Transaction}; use super::helpers::*; use SyncConfig; -struct TestIoHandler { - client: Arc, -} - -impl IoHandler for TestIoHandler { - fn message(&self, _io: &IoContext, net_message: &ClientIoMessage) { - match *net_message { - ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) { - panic!("Invalid message received: {}", e); - }, - _ => {} // ignore other messages - } - } -} - fn new_tx(secret: &Secret, nonce: U256, chain_id: u64) -> PendingTransaction { let signed = Transaction { nonce: nonce.into(), @@ -63,9 +48,9 @@ fn authority_round() { ap.insert_account(s1.secret().clone(), "").unwrap(); let chain_id = Spec::new_test_round().chain_id(); - let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap)); - let io_handler0: Arc> = Arc::new(TestIoHandler { client: net.peer(0).chain.clone() }); - let io_handler1: Arc> = Arc::new(TestIoHandler { client: net.peer(1).chain.clone() }); + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap), false); + let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); + let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // 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(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap(); @@ -150,9 +135,9 @@ fn tendermint() { ap.insert_account(s1.secret().clone(), "").unwrap(); let chain_id = Spec::new_test_tendermint().chain_id(); - let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap)); - let io_handler0: Arc> = Arc::new(TestIoHandler { client: net.peer(0).chain.clone() }); - let io_handler1: Arc> = Arc::new(TestIoHandler { client: net.peer(1).chain.clone() }); + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap), false); + let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); + let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them issues a proposal. net.peer(0).chain.miner().set_engine_signer(s0.address(), "".to_owned()).unwrap(); trace!(target: "poa", "Peer 0 is {}.", s0.address()); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 32a90b414f..495603020d 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -17,21 +17,23 @@ use std::collections::{VecDeque, HashSet, HashMap}; use std::sync::Arc; use ethereum_types::H256; -use parking_lot::RwLock; +use parking_lot::{RwLock, Mutex}; use bytes::Bytes; use network::{self, PeerId, ProtocolId, PacketId, SessionInfo}; use tests::snapshot::*; -use ethcore::client::{TestBlockChainClient, BlockChainClient, Client as EthcoreClient, ClientConfig, ChainNotify}; +use ethcore::client::{TestBlockChainClient, BlockChainClient, Client as EthcoreClient, + ClientConfig, ChainNotify, ChainMessageType, ClientIoMessage}; use ethcore::header::BlockNumber; use ethcore::snapshot::SnapshotService; use ethcore::spec::Spec; use ethcore::account_provider::AccountProvider; use ethcore::miner::Miner; use sync_io::SyncIo; -use io::IoChannel; +use io::{IoChannel, IoContext, IoHandler}; use api::WARP_SYNC_PROTOCOL_ID; -use chain::ChainSync; -use ::SyncConfig; +use chain::{ChainSync, ETH_PROTOCOL_VERSION_63, PAR_PROTOCOL_VERSION_3}; +use SyncConfig; +use private_tx::{NoopPrivateTxHandler, PrivateTxHandler, SimplePrivateTxHandler}; pub trait FlushingBlockChainClient: BlockChainClient { fn flush(&self) {} @@ -131,11 +133,11 @@ impl<'p, C> SyncIo for TestIo<'p, C> where C: FlushingBlockChainClient, C: 'p { } fn eth_protocol_version(&self, _peer: PeerId) -> u8 { - 63 + ETH_PROTOCOL_VERSION_63 } fn protocol_version(&self, protocol: &ProtocolId, peer_id: PeerId) -> u8 { - if protocol == &WARP_SYNC_PROTOCOL_ID { 2 } else { self.eth_protocol_version(peer_id) } + if protocol == &WARP_SYNC_PROTOCOL_ID { PAR_PROTOCOL_VERSION_3 } else { self.eth_protocol_version(peer_id) } } fn chain_overlay(&self) -> &RwLock> { @@ -143,6 +145,16 @@ impl<'p, C> SyncIo for TestIo<'p, C> where C: FlushingBlockChainClient, C: 'p { } } +/// Mock for emulution of async run of new blocks +struct NewBlockMessage { + imported: Vec, + invalid: Vec, + enacted: Vec, + retracted: Vec, + sealed: Vec, + proposed: Vec, +} + /// Abstract messages between peers. pub trait Message { /// The intended recipient of this message. @@ -184,6 +196,12 @@ pub trait Peer { /// Restart sync for a peer. fn restart_sync(&self); + + /// Process the queue of pending io messages + fn process_all_io_messages(&self); + + /// Process the queue of new block messages + fn process_all_new_block_messages(&self); } pub struct EthPeer where C: FlushingBlockChainClient { @@ -191,6 +209,41 @@ pub struct EthPeer where C: FlushingBlockChainClient { pub snapshot_service: Arc, pub sync: RwLock, pub queue: RwLock>, + pub private_tx_handler: Arc, + pub io_queue: RwLock>, + new_blocks_queue: RwLock>, +} + +impl EthPeer where C: FlushingBlockChainClient { + fn is_io_queue_empty(&self) -> bool { + self.io_queue.read().is_empty() + } + + fn is_new_blocks_queue_empty(&self) -> bool { + self.new_blocks_queue.read().is_empty() + } + + fn process_io_message(&self, message: ChainMessageType) { + let mut io = TestIo::new(&*self.chain, &self.snapshot_service, &self.queue, None); + match message { + ChainMessageType::Consensus(data) => self.sync.write().propagate_consensus_packet(&mut io, data), + ChainMessageType::PrivateTransaction(data) => self.sync.write().propagate_private_transaction(&mut io, data), + ChainMessageType::SignedPrivateTransaction(data) => self.sync.write().propagate_signed_private_transaction(&mut io, data), + } + } + + fn process_new_block_message(&self, message: NewBlockMessage) { + let mut io = TestIo::new(&*self.chain, &self.snapshot_service, &self.queue, None); + self.sync.write().chain_new_blocks( + &mut io, + &message.imported, + &message.invalid, + &message.enacted, + &message.retracted, + &message.sealed, + &message.proposed + ); + } } impl Peer for EthPeer { @@ -198,7 +251,12 @@ impl Peer for EthPeer { fn on_connect(&self, other: PeerId) { self.sync.write().update_targets(&*self.chain); - self.sync.write().on_peer_connected(&mut TestIo::new(&*self.chain, &self.snapshot_service, &self.queue, Some(other)), other); + self.sync.write().on_peer_connected(&mut TestIo::new( + &*self.chain, + &self.snapshot_service, + &self.queue, + Some(other)), + other); } fn on_disconnect(&self, other: PeerId) { @@ -219,7 +277,7 @@ impl Peer for EthPeer { } fn is_done(&self) -> bool { - self.queue.read().is_empty() + self.queue.read().is_empty() && self.is_io_queue_empty() && self.is_new_blocks_queue_empty() } fn sync_step(&self) { @@ -232,6 +290,22 @@ impl Peer for EthPeer { fn restart_sync(&self) { self.sync.write().restart(&mut TestIo::new(&*self.chain, &self.snapshot_service, &self.queue, None)); } + + fn process_all_io_messages(&self) { + if !self.is_io_queue_empty() { + while let Some(message) = self.io_queue.write().pop_front() { + self.process_io_message(message); + } + } + } + + fn process_all_new_block_messages(&self) { + if !self.is_new_blocks_queue_empty() { + while let Some(message) = self.new_blocks_queue.write().pop_front() { + self.process_new_block_message(message); + } + } + } } pub struct TestNet

{ @@ -260,20 +334,35 @@ impl TestNet> { for _ in 0..n { let chain = TestBlockChainClient::new(); let ss = Arc::new(TestSnapshotService::new()); - let sync = ChainSync::new(config.clone(), &chain); + let private_tx_handler = Arc::new(NoopPrivateTxHandler); + let sync = ChainSync::new(config.clone(), &chain, private_tx_handler.clone()); net.peers.push(Arc::new(EthPeer { sync: RwLock::new(sync), snapshot_service: ss, chain: Arc::new(chain), queue: RwLock::new(VecDeque::new()), + private_tx_handler, + io_queue: RwLock::new(VecDeque::new()), + new_blocks_queue: RwLock::new(VecDeque::new()), })); } net } + + // relies on Arc uniqueness, which is only true when we haven't registered a ChainNotify. + pub fn peer_mut(&mut self, i: usize) -> &mut EthPeer { + Arc::get_mut(&mut self.peers[i]).expect("Arc never exposed externally") + } } impl TestNet> { - pub fn with_spec_and_accounts(n: usize, config: SyncConfig, spec_factory: F, accounts: Option>) -> Self + pub fn with_spec_and_accounts( + n: usize, + config: SyncConfig, + spec_factory: F, + accounts: Option>, + private_tx_handler: bool, + ) -> Self where F: Fn() -> Spec { let mut net = TestNet { @@ -282,11 +371,42 @@ impl TestNet> { disconnect_events: Vec::new(), }; for _ in 0..n { - net.add_peer(config.clone(), spec_factory(), accounts.clone()); + if private_tx_handler { + net.add_peer_with_private_config(config.clone(), spec_factory(), accounts.clone()); + } else { + net.add_peer(config.clone(), spec_factory(), accounts.clone()); + } } net } + pub fn add_peer_with_private_config(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { + let channel = IoChannel::disconnected(); + let client = EthcoreClient::new( + ClientConfig::default(), + &spec, + Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), + Arc::new(Miner::with_spec_and_accounts(&spec, accounts.clone())), + channel.clone() + ).unwrap(); + + let private_tx_handler = Arc::new(SimplePrivateTxHandler::default()); + let ss = Arc::new(TestSnapshotService::new()); + let sync = ChainSync::new(config, &*client, private_tx_handler.clone()); + let peer = Arc::new(EthPeer { + sync: RwLock::new(sync), + snapshot_service: ss, + chain: client, + queue: RwLock::new(VecDeque::new()), + private_tx_handler, + io_queue: RwLock::new(VecDeque::new()), + new_blocks_queue: RwLock::new(VecDeque::new()), + }); + peer.chain.add_notify(peer.clone()); + //private_provider.add_notify(peer.clone()); + self.peers.push(peer); + } + pub fn add_peer(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { let client = EthcoreClient::new( ClientConfig::default(), @@ -297,12 +417,16 @@ impl TestNet> { ).unwrap(); let ss = Arc::new(TestSnapshotService::new()); - let sync = ChainSync::new(config, &*client); + let private_tx_handler = Arc::new(NoopPrivateTxHandler); + let sync = ChainSync::new(config, &*client, private_tx_handler.clone()); let peer = Arc::new(EthPeer { sync: RwLock::new(sync), snapshot_service: ss, chain: client, queue: RwLock::new(VecDeque::new()), + private_tx_handler, + io_queue: RwLock::new(VecDeque::new()), + new_blocks_queue: RwLock::new(VecDeque::new()), }); peer.chain.add_notify(peer.clone()); self.peers.push(peer); @@ -366,6 +490,8 @@ impl

TestNet

where P: Peer { let mut total_steps = 0; while !self.done() { self.sync_step(); + self.deliver_io_messages(); + self.deliver_new_block_messages(); total_steps += 1; } total_steps @@ -378,15 +504,20 @@ impl

TestNet

where P: Peer { } } - pub fn done(&self) -> bool { - self.peers.iter().all(|p| p.is_done()) + pub fn deliver_io_messages(&mut self) { + for peer in self.peers.iter() { + peer.process_all_io_messages(); + } } -} -impl TestNet> { - // relies on Arc uniqueness, which is only true when we haven't registered a ChainNotify. - pub fn peer_mut(&mut self, i: usize) -> &mut EthPeer { - Arc::get_mut(&mut self.peers[i]).expect("Arc never exposed externally") + pub fn deliver_new_block_messages(&mut self) { + for peer in self.peers.iter() { + peer.process_all_new_block_messages(); + } + } + + pub fn done(&self) -> bool { + self.peers.iter().all(|p| p.is_done()) } } @@ -397,6 +528,34 @@ impl TestNet> { } } +pub struct TestIoHandler { + pub client: Arc, + pub private_tx_queued: Mutex, +} + +impl TestIoHandler { + pub fn new(client: Arc) -> Self { + TestIoHandler { + client, + private_tx_queued: Mutex::default(), + } + } +} + +impl IoHandler for TestIoHandler { + fn message(&self, _io: &IoContext, net_message: &ClientIoMessage) { + match *net_message { + ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) { + panic!("Invalid message received: {}", e); + }, + ClientIoMessage::NewPrivateTransaction => { + *self.private_tx_queued.lock() += 1; + }, + _ => {} // ignore other messages + } + } +} + impl ChainNotify for EthPeer { fn new_blocks(&self, imported: Vec, @@ -407,23 +566,21 @@ impl ChainNotify for EthPeer { proposed: Vec, _duration: u64) { - let mut io = TestIo::new(&*self.chain, &self.snapshot_service, &self.queue, None); - self.sync.write().chain_new_blocks( - &mut io, - &imported, - &invalid, - &enacted, - &retracted, - &sealed, - &proposed); + self.new_blocks_queue.write().push_back(NewBlockMessage { + imported, + invalid, + enacted, + retracted, + sealed, + proposed, + }); } fn start(&self) {} fn stop(&self) {} - fn broadcast(&self, message: Vec) { - let mut io = TestIo::new(&*self.chain, &self.snapshot_service, &self.queue, None); - self.sync.write().propagate_consensus_packet(&mut io, message.clone()); + fn broadcast(&self, message_type: ChainMessageType) { + self.io_queue.write().push_back(message_type) } } diff --git a/util/fetch/src/client.rs b/util/fetch/src/client.rs index fee3130c42..b3274ca4f7 100644 --- a/util/fetch/src/client.rs +++ b/util/fetch/src/client.rs @@ -119,13 +119,23 @@ pub trait Fetch: Clone + Send + Sync + 'static { /// The result future. type Result: Future + Send + 'static; + /// Make a request to given URL + fn fetch(&self, url: &str, method: Method, abort: Abort) -> Self::Result; + /// Get content from some URL. - fn fetch(&self, url: &str, abort: Abort) -> Self::Result; + fn get(&self, url: &str, abort: Abort) -> Self::Result { + self.fetch(url, Method::Get, abort) + } + + /// Post content to some URL. + fn post(&self, url: &str, abort: Abort) -> Self::Result { + self.fetch(url, Method::Post, abort) + } } type TxResponse = oneshot::Sender>; type TxStartup = std::sync::mpsc::SyncSender>; -type ChanItem = Option<(Url, Abort, TxResponse)>; +type ChanItem = Option<(Url, Method, Abort, TxResponse)>; /// An implementation of `Fetch` using a `hyper` client. // Due to the `Send` bound of `Fetch` we spawn a background thread for @@ -203,17 +213,17 @@ impl Client { let future = rx_proto.take_while(|item| Ok(item.is_some())) .map(|item| item.expect("`take_while` is only passing on channel items != None; qed")) - .for_each(|(url, abort, sender)| + .for_each(|(url, method, abort, sender)| { trace!(target: "fetch", "new request to {}", url); if abort.is_aborted() { return future::ok(sender.send(Err(Error::Aborted)).unwrap_or(())) } - let ini = (hyper.clone(), url, abort, 0); - let fut = future::loop_fn(ini, |(client, url, abort, redirects)| { + let ini = (hyper.clone(), url, method, abort, 0); + let fut = future::loop_fn(ini, |(client, url, method, abort, redirects)| { let url2 = url.clone(); let abort2 = abort.clone(); - client.request(get(&url)) + client.request(build_request(&url, method.clone())) .map(move |resp| Response::new(url2, resp, abort2)) .from_err() .and_then(move |resp| { @@ -225,7 +235,7 @@ impl Client { if redirects >= abort.max_redirects() { return Err(Error::TooManyRedirects) } - Ok(Loop::Continue((client, next_url, abort, redirects + 1))) + Ok(Loop::Continue((client, next_url, method, abort, redirects + 1))) } else { let content_len = resp.headers.get::().cloned(); if content_len.map(|n| *n > abort.max_size() as u64).unwrap_or(false) { @@ -257,7 +267,7 @@ impl Client { impl Fetch for Client { type Result = Box + Send>; - fn fetch(&self, url: &str, abort: Abort) -> Self::Result { + fn fetch(&self, url: &str, method: Method, abort: Abort) -> Self::Result { debug!(target: "fetch", "fetching: {:?}", url); if abort.is_aborted() { return Box::new(future::err(Error::Aborted)) @@ -269,7 +279,7 @@ impl Fetch for Client { let (tx_res, rx_res) = oneshot::channel(); let maxdur = abort.max_duration(); let sender = self.core.clone(); - let future = sender.send(Some((url.clone(), abort, tx_res))) + let future = sender.send(Some((url.clone(), method, abort, tx_res))) .map_err(|e| { error!(target: "fetch", "failed to schedule request: {}", e); Error::BackgroundThreadDead @@ -308,10 +318,10 @@ fn redirect_location(u: Url, r: &Response) -> Option { } } -// Build a simple GET request for the given Url. -fn get(u: &Url) -> hyper::Request { +// Build a simple request for the given Url and method +fn build_request(u: &Url, method: Method) -> hyper::Request { let uri = u.as_ref().parse().expect("Every valid URL is aso a URI."); - let mut rq = Request::new(Method::Get, uri); + let mut rq = Request::new(method, uri); rq.headers_mut().set(UserAgent::new("Parity Fetch Neo")); rq } @@ -350,6 +360,11 @@ impl Response { self.status() == StatusCode::Ok } + /// Status code == 404. + pub fn is_not_found(&self) -> bool { + self.status() == StatusCode::NotFound + } + /// Is the content-type text/html? pub fn is_html(&self) -> bool { if let Some(ref mime) = self.content_type() { @@ -512,7 +527,7 @@ mod test { use futures::future; use futures::sync::mpsc; use futures_timer::Delay; - use hyper::StatusCode; + use hyper::{StatusCode, Method}; use hyper::server::{Http, Request, Response, Service}; use std; use std::io::Read; @@ -524,7 +539,7 @@ mod test { fn it_should_fetch() { let server = TestServer::run(); let client = Client::new().unwrap(); - let future = client.fetch(&format!("http://{}?123", server.addr()), Default::default()); + let future = client.fetch(&format!("http://{}?123", server.addr()), Method::Get, Default::default()); let resp = future.wait().unwrap(); assert!(resp.is_success()); let body = resp.concat2().wait().unwrap(); @@ -536,7 +551,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_duration(Duration::from_secs(1)); - match client.fetch(&format!("http://{}/delay?3", server.addr()), abort).wait() { + match client.fetch(&format!("http://{}/delay?3", server.addr()), Method::Get, abort).wait() { Err(Error::Timeout) => {} other => panic!("expected timeout, got {:?}", other) } @@ -547,7 +562,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default(); - let future = client.fetch(&format!("http://{}/redirect?http://{}/", server.addr(), server.addr()), abort); + let future = client.fetch(&format!("http://{}/redirect?http://{}/", server.addr(), server.addr()), Method::Get, abort); assert!(future.wait().unwrap().is_success()) } @@ -556,7 +571,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_redirects(4); - let future = client.fetch(&format!("http://{}/redirect?/", server.addr()), abort); + let future = client.fetch(&format!("http://{}/redirect?/", server.addr()), Method::Get, abort); assert!(future.wait().unwrap().is_success()) } @@ -565,7 +580,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_redirects(3); - match client.fetch(&format!("http://{}/loop", server.addr()), abort).wait() { + match client.fetch(&format!("http://{}/loop", server.addr()), Method::Get, abort).wait() { Err(Error::TooManyRedirects) => {} other => panic!("expected too many redirects error, got {:?}", other) } @@ -576,7 +591,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default(); - let future = client.fetch(&format!("http://{}?abcdefghijklmnopqrstuvwxyz", server.addr()), abort); + let future = client.fetch(&format!("http://{}?abcdefghijklmnopqrstuvwxyz", server.addr()), Method::Get, abort); let resp = future.wait().unwrap(); assert!(resp.is_success()); assert_eq!(&resp.concat2().wait().unwrap()[..], b"abcdefghijklmnopqrstuvwxyz") @@ -587,7 +602,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_size(3); - let resp = client.fetch(&format!("http://{}/?1234", server.addr()), abort).wait().unwrap(); + let resp = client.fetch(&format!("http://{}/?1234", server.addr()), Method::Get, abort).wait().unwrap(); assert!(resp.is_success()); match resp.concat2().wait() { Err(Error::SizeLimit) => {} @@ -600,7 +615,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_size(3); - let resp = client.fetch(&format!("http://{}/?1234", server.addr()), abort).wait().unwrap(); + let resp = client.fetch(&format!("http://{}/?1234", server.addr()), Method::Get, abort).wait().unwrap(); assert!(resp.is_success()); let mut buffer = Vec::new(); let mut reader = BodyReader::new(resp); diff --git a/util/fetch/src/lib.rs b/util/fetch/src/lib.rs index a5722dfe26..55785633f5 100644 --- a/util/fetch/src/lib.rs +++ b/util/fetch/src/lib.rs @@ -36,4 +36,5 @@ pub mod client; pub use url::Url; pub use self::client::{Client, Fetch, Error, Response, Abort, BodyReader}; +pub use hyper::Method; -- GitLab From d97cf341388ced3f5eb501bc9e06cb461e349758 Mon Sep 17 00:00:00 2001 From: Akira Takizawa Date: Mon, 9 Apr 2018 23:18:00 +0900 Subject: [PATCH 048/263] Add Ethereum Social support (#8325) --- ethcore/res/ethereum/social.json | 8857 ++++++++++++++++++++++++++++++ ethcore/src/ethereum/mod.rs | 5 + parity/cli/mod.rs | 2 +- parity/params.rs | 4 + 4 files changed, 8867 insertions(+), 1 deletion(-) create mode 100644 ethcore/res/ethereum/social.json diff --git a/ethcore/res/ethereum/social.json b/ethcore/res/ethereum/social.json new file mode 100644 index 0000000000..87d1f2e4b1 --- /dev/null +++ b/ethcore/res/ethereum/social.json @@ -0,0 +1,8857 @@ +{ + "name": "Ethereum Social", + "dataDir": "social", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x2B5E3AF16B1880000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "ecip1017EraRounds": 5000000, + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x0000000000000000000000000000000000000000", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x1C", + "chainID": "0x1C", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x0400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x3230313820457468657265756d20536f6369616c2050726f6a656374", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://54d0824a268747046b6cabc7ee3afda48edba319f0d175e9e505aa9d425a1872b8b6f9ebf8f3b0a10dc7611a4c44ddec0fc691e5a5cde23e06fc4e4b3ff9dbef@13.125.185.147:30303", + "enode://7e150d47637177f675e20d663fc2500987f2149332caf23da522d92363be8a7880ef9150a6183e9031288a441e0457239474967a111eafce17e19a4288076ea9@18.219.40.235:30303", + "enode://6244c9d9cd288015d7ff165e90f3bb5649e34467e095a47c6d3c56e8fb8c849b3b4db683ff3c7ae8a654bbdc07ef12ee2fd7d72831ac213723281c1b0cc90599@13.250.220.98:30303", + "enode://e39f162b9f4b6ed6f098550f7867c2fb068fc66f362b3db0f45124c43ea18508f5ceef4e0e4de53d301e14a6f1683226aeb931d7401b4e83b5a583153ffdd7fd@52.57.98.157:30303", + "enode://54b4a117d66dc3aa93358dec1b31d4f38e72e4381b3e28a65ac6f1aaac3b304ebbe41d32cc864fa69a9a6815c34cf9b8965690dc174a5f72af14547b601b7924@222.239.255.71:30303", + "enode://851f14c5cc86cbc0a81acfcbe5dd99ad5c823435357219df736932c5f89ad4318f6973a553857a32d97a71793f5a35c062d46320be282aa0a80b06b9c6b624e4@13.125.232.71:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "ceed1c8254abaf069669fc6045e90482543d1f2e": { + "balance": "38000000000000000000000000" + }, + "6f22d7f8c38e0135e36be87e77fc8d4ae4b3d965": { + "balance": "38000000000000000000000000" + }, + "d016e982b7886302428d7c741392c658337513d2": { + "balance": "38000000000000000000000000" + }, + "defa96db5c8a41772bc56f68f95e307ff71a2c60": { + "balance": "38000000000000000000000000" + }, + "951ffd4253ffcf31b2895dd3f7f2a8a9bb2933e5": { + "balance": "38000000000000000000000000" + }, + "b7071dba21cfbe1b70abd7ddfd2f0f83d5d19a61": { + "balance": "38000000000000000000000000" + }, + "6ca420cd8d5407c61a9b14adcb38bee0f26e2848": { + "balance": "38000000000000000000000000" + }, + "b50d185b6cd04499a38afc0fcfcb59eaa74d0956": { + "balance": "38000000000000000000000000" + }, + "7ba8c49a444c117f2d2a50650b3f700d4ee659fe": { + "balance": "38000000000000000000000000" + }, + "83f9959ecc532dce071fcd0c62dc23cd571b689b": { + "balance": "38000000000000000000000000" + }, + "001327afce7ebb623a7d0f17b2ffc358fb863b5a": { + "balance": "9844198127334000000000" + }, + "0015ac7f8bb2a2c7d954fc2dbd4e20c0db5942a5": { + "balance": "1000000000000000000000000" + }, + "0021e69c041be2d28744b69361105ff51295da59": { + "balance": "1379639894000000000" + }, + "002cfd27bbb8164681b8762e71b2891beb127fdd": { + "balance": "25105286685000000000" + }, + "0033cf217bc765ccfc338869451588ce448fde65": { + "balance": "23425485280069000000000" + }, + "0048f1d1735979cd8ac9c0886088336b2d4a43a6": { + "balance": "10000000000000000000" + }, + "006a79cc154917cf204d8097728f290e29716d43": { + "balance": "20000000000000000000000" + }, + "007c8db36e4f649b14516dd78202670b671ba753": { + "balance": "1000000000000000000" + }, + "007d131b58388f251075a3c61020ce301106c5cf": { + "balance": "381079535880476000000000" + }, + "008e8fbffc2fdbefaa7e3be4f4a9160db826d05f": { + "balance": "10000000000000000000000" + }, + "0126d86b9814b0e78c4e01a3916bee6a7778145b": { + "balance": "10000000000000000000000" + }, + "012cb961297c837630251a173b7861e77724856d": { + "balance": "494562376059000000000" + }, + "0145886dfab5ef4f2def50a56b4a074cf5b18acf": { + "balance": "680585022951000000000" + }, + "0167918bab62aa2118cfa4d3eb80da0e71c71d8b": { + "balance": "122395119468000000000" + }, + "0182f7286ae9d4d6bc514d5175d14685d520bde7": { + "balance": "10000000000000000000000" + }, + "0184e9c8fe99d85100fe28a0e8877b14768b372a": { + "balance": "193295614762000000000" + }, + "019eff7dce7f31c2d4f7318da71d212cbf89d36e": { + "balance": "64004138198000000000" + }, + "01f3351ea66c352346244dbb79189066bed62fc5": { + "balance": "937056266523000000000" + }, + "0202ddd7f4f32bc575f7df24612f8aa9f9a7ae42": { + "balance": "106905151080000000000" + }, + "022b8c65e959cab71f56688b7073257b58bbef4a": { + "balance": "9682681149566000000000" + }, + "0245ff6382eb93ab1e8ed2e3c0bce7a1b9a9713d": { + "balance": "289000000000000000000" + }, + "025e117a69ca9244ed430732c11e550e3ee67577": { + "balance": "1861905310567000000000" + }, + "026e7457eeaeaec7898fdee1ad39be89e92733b3": { + "balance": "7529030978000000000" + }, + "028d2def8c54fcc77bf0191b183c0bc4570ec1c5": { + "balance": "9056720934000000000" + }, + "0291a087605b516e465134797b5459436d320e6a": { + "balance": "481100929805000000000" + }, + "02a4b18b3e13ec79307e712fba1867cbf7fb6155": { + "balance": "9000000000000000000" + }, + "02a812d4cebcac1a92ae470ade92fde7bead127d": { + "balance": "66793603497000000000" + }, + "02f718c94b2c8e8d62752f8632443504c1e4b6e2": { + "balance": "1000000000000000000000000" + }, + "030dab52b47b37505b72e5ca0985f65ead590816": { + "balance": "1376851176362000000000" + }, + "031c59846f75de1aefb0e8a95e0fb822fd06555b": { + "balance": "140978338628000000000" + }, + "031ee87c672d83ec73059c86a312a9e972142054": { + "balance": "96406273341000000000" + }, + "033182e860564cf695cb403c8c0f078053368d7d": { + "balance": "1504349255824000000000" + }, + "03788dc6528fa33a90e90e03295ae4b792d56644": { + "balance": "24356250426000000000" + }, + "037aae119047028157c5b3bc9d3d202b02cbce42": { + "balance": "105627739575000000000" + }, + "037d45b323cbc5cbac999c5001169646e690b94c": { + "balance": "2000000000000000000" + }, + "0390ba35c454a24519d845405a7e24df71250748": { + "balance": "1872501898509000000000" + }, + "03ab8c1e7f904db62437b16d28aeb539b2dee55e": { + "balance": "55000000000000000000000000" + }, + "03af4c69728a888fa26b1aefa439005989771fdf": { + "balance": "27704588237757000000000" + }, + "03b33fb19d165e5e33bcfbbfc009f418d71f30fb": { + "balance": "1999139000000000000" + }, + "03b34c79f8167a4e8be0f6133254d2b50cbd878d": { + "balance": "111065050160000000000" + }, + "03d7e8638b74ae44a2770287285489a95fa1ea11": { + "balance": "20000000000000000000000" + }, + "03d870bf719f03250c0dc5156a36751b3aa21f18": { + "balance": "981119649953000000000" + }, + "03de52c12b05fb8bcba3a1cfe02a0ad1bc9761d3": { + "balance": "362007990932000000000" + }, + "03e516db27b1abe008ffc57ced48f72f872d8b08": { + "balance": "3389116345657000000000" + }, + "03ef5ff863ee5f1167f38cdf316e4d52a242b750": { + "balance": "12395856876000000000" + }, + "03f27766760f2bd1cae1cb85ddf43ab59c871e47": { + "balance": "49000000000000000000" + }, + "03f4e1a8fb4eedc776f4835fcc85d0f236612f9c": { + "balance": "27210590272692000000000" + }, + "0404936ee04cc79cbb3aedfa33a53f94940f772c": { + "balance": "29919204637416000000000" + }, + "040501ffde9649be794b7d41643273ed6285ab39": { + "balance": "686000000000000000000" + }, + "040e449de680f69614120f0a2e894cde36e4adf1": { + "balance": "81993180085000000000" + }, + "041531e906dbdc70d89f5e255151d9865a059308": { + "balance": "2163418749315000000000" + }, + "041ad9f6bf970541e4ea8a14dde1e789d0fe4367": { + "balance": "44999979000000000000" + }, + "0446420c07cf73d2b3741b945c1cc8444b4ba6b6": { + "balance": "138749371512564000000000" + }, + "044c1a540b8ab286c218c2fa9d5bfbc2761e7626": { + "balance": "1" + }, + "04526b2c62911e78a939816aa4575fe30baa06c7": { + "balance": "2983093150081000000000" + }, + "04adf59f8a0ad3820a7972c6243202b3b0617fcf": { + "balance": "50000000000000000000" + }, + "04bbb42882a475eed58aae47fe530ed19c1cedaa": { + "balance": "278038763863000000000" + }, + "04cff7a7c2b9b0bf31c5ad4a5de8b0eade70aafc": { + "balance": "515406205244000000000" + }, + "04dcd325dc1fd37ff3c87da3b21c47ddfcc37cc2": { + "balance": "5831887315000000000" + }, + "04ec8d0b5157370f5a2671a2aa68ae486b7a7842": { + "balance": "10000000000000000000000" + }, + "04f50f2a6e89ee497a64c11baa90759a10a1247a": { + "balance": "25443071621949000000000" + }, + "0513a769ebef58ad3a4fd7011ddbe19799ff5600": { + "balance": "64369494797000000000" + }, + "0514c1151f356070ace281435f25c86b58280715": { + "balance": "38967380881301000000000" + }, + "052fda414fe1279c6276a237b07e1b4148a8cc77": { + "balance": "10000000000000000000000" + }, + "05431089cc62a987d0e99847e10a006233146f6d": { + "balance": "268977485219000000000" + }, + "054ed2f55028257212b996f9a3d34758d1d4ffd1": { + "balance": "100000000000000000000000" + }, + "05a68cc758560addde302baf814f2fdbe0ef2c2b": { + "balance": "10000000000000000000" + }, + "05c669d9ded79fe9e4e3718052bc7ca18a3205ab": { + "balance": "7347158140000000000" + }, + "05d77ce5c87477b05e90e829dafd8eb3a8c87823": { + "balance": "21191998933000000000" + }, + "05ef2894a2a1c6eb6c0a768d04ef5b573f357712": { + "balance": "20000000000000000000000" + }, + "0601011f80279190b96f641205c6a524a8ad5a28": { + "balance": "12025716447696000000000" + }, + "061a8acdb1a340ba7c550814831e27262708fc98": { + "balance": "234029764576000000000" + }, + "06219483e217c9ad479f76a95426f689ef4d5951": { + "balance": "1509408723551000000000" + }, + "062d0db8a650f2241f8a4295326a2570a7c771bb": { + "balance": "717459720227000000000" + }, + "0633ba746235d8fc8243751b1aa31646c299f262": { + "balance": "49000000000000000000" + }, + "06b6a5cadfe1fdc88015512e835d840e58ae4123": { + "balance": "1000000000000000000" + }, + "06d08fcbe96791514d900d2cb6c0f029d8d791d0": { + "balance": "19196168602258000000000" + }, + "06e5c0bad43a7011878b12a682abf01ccdfaa151": { + "balance": "30000000000000000000" + }, + "070656bb11ec36074d47c791c0b306394b703401": { + "balance": "1245216075291000000000" + }, + "070d84c938217163b60ed38e4937eea7158c03d9": { + "balance": "27507979787000000000" + }, + "07428c95ef3862026e54d3a963911cdc673dbcd9": { + "balance": "13792309994528000000000" + }, + "0781cb21df142ec5f67b956bf995f02f6f24985f": { + "balance": "224940990659000000000" + }, + "078c38c153b414cc4c12818fce2ea7ba09a34e51": { + "balance": "1410646136000000000" + }, + "07bfd0de7a9a1c927446aaf2d7ede55b471daa87": { + "balance": "77778844734000000000" + }, + "07d1ac83140188b8d7f4c8c607d0da22c5ba523f": { + "balance": "7713686418107000000000" + }, + "07d8ef8fc6dcde319a5af5b6cea18983bdc4c8fe": { + "balance": "3801361173000000000" + }, + "07dfab72dd3e44fcbb1ced625899bf20e0c52ffc": { + "balance": "154177778806000000000" + }, + "0817ce33d943e84c7b3261cc3e37b86b5d6d76ae": { + "balance": "90753785862000000000" + }, + "081be00a2ff62cbcb95a8eb020ac0efa33f93a42": { + "balance": "1027889807304000000000" + }, + "085ffdc6043b04653e51b1a34af20b609d158607": { + "balance": "3314058000000000" + }, + "0882c2228f5df24064bc37e8b7199199de308bb8": { + "balance": "98420617420000000000" + }, + "08918776e9a7136cedad5d0cee52f5d9dd833ece": { + "balance": "1263170315026000000000" + }, + "08bdbcff16919abc5e15fa68ece56eceef33f48d": { + "balance": "2552990000000000" + }, + "08fc8c7bd03fe1249266b233edfcf830693d0e10": { + "balance": "283490111768000000000" + }, + "090f79a4178b5180150444805f62c26cd21be897": { + "balance": "884195010282000000000" + }, + "0914a9dfc9d6ecc063a55e5320050112f305fe17": { + "balance": "15373898854941000000000" + }, + "091791ab5f8ab86f1d8f566ed221b268cbc55347": { + "balance": "2207516004000000000" + }, + "09529f8b1633ce4375451bb44b1025f6e5f9facd": { + "balance": "151697652792000000000" + }, + "09600bbb9d9b23661d269dbe1ed066d8e573b5e1": { + "balance": "802935104935000000000" + }, + "0964d2af1d5883fc0e0a77459f6a141824de7356": { + "balance": "9610980935058000000000" + }, + "097c731d1fc6792ac0f0ff92be4403c3749cc1dd": { + "balance": "165134479709000000000" + }, + "097f152b3f837d38ab1e8c0683d62f5a01d67902": { + "balance": "20000000000000000000000" + }, + "09a6772629ef0bf402ae6d27cd32e6eefb220a12": { + "balance": "20000000000000000000000" + }, + "09addb954d4e4b4e95e0c66d324115d609df5a99": { + "balance": "8435321515000000000" + }, + "09b2eb03e0fa321102196578eb40dcba3a46ec9c": { + "balance": "12723517962933000000000" + }, + "09ba0ed4dce470ba0bcb4d46b507c3b024b83070": { + "balance": "99999979000000000000" + }, + "09efbd6dfea375065be1b3a8f4541f024da21a34": { + "balance": "5870833623000000000" + }, + "0a24d4ae66edc7723bbb314e9b96dc7b9a31e813": { + "balance": "70000000000000000000" + }, + "0a3ee710909382f762648deff8ac7c8b30e2ce10": { + "balance": "407656462445000000000" + }, + "0a42b3145257154e76a97db8147c93be4cffd97b": { + "balance": "10000000000000000000000" + }, + "0a7cb6037f1eba5d19fe781335ecd37b7229c5f7": { + "balance": "74113322448000000000" + }, + "0a85d1bec4d44e309068b115abd517d3733fc56e": { + "balance": "14836218750000000000000" + }, + "0a891ba9ca7b99ecd815b1dcec9243dd4deff866": { + "balance": "178004857988000000000" + }, + "0ab69370b537d4ff5b45704fed293e46e3464f87": { + "balance": "1258876668246000000000" + }, + "0ab77a2e8ab9a3b659d1f1d37956c3607a0f9a60": { + "balance": "6283300817712000000000" + }, + "0abc7e8d52f5b0dcf1d4713e5fa4909102251dfb": { + "balance": "39307290577000000000" + }, + "0af2c0471c802d2e2b20aadf9dd4ec842d313ab0": { + "balance": "1529468143183000000000" + }, + "0b08c717bb3982fc8b92d5b3d30e5b41265a0d0f": { + "balance": "1184600154874000000000" + }, + "0b3f2aa9dc5b57b0469398d62f60a13774ec0e87": { + "balance": "132187640280004000000000" + }, + "0b3ffe85aa89e71a6e51e938c7265d2a7173061b": { + "balance": "2106793086824000000000" + }, + "0b468562e712d22b37e1a65f54b1fa825beebd1b": { + "balance": "15130906006000000000" + }, + "0b5333eb668dee29ebc0e335d74f33ffeaae9ac5": { + "balance": "125953133109000000000" + }, + "0b59a20107495e951b509187307782ca9dfa441f": { + "balance": "25000000000000000000" + }, + "0b8b7fb066601ea7744b81f6e1a21b8e489359cf": { + "balance": "101782000000000000000" + }, + "0bd7791097f79066d71ac0a2c94bce6628a63373": { + "balance": "44389955028000000000" + }, + "0be541af06e167206b5d1cbe08e8fb2b5ebc82cb": { + "balance": "9000000000000000000" + }, + "0bf178bba463f4f6c33e3d81b1a78d220f7b5d4b": { + "balance": "111784804790646000000000" + }, + "0c1f000249b1f1ac9e43c4f10e2da1cc2adf886f": { + "balance": "91251997635000000000" + }, + "0c74e46b115e19726997dd559d2b6ff1bfb79af6": { + "balance": "879229287149000000000" + }, + "0c7c1ec152c920a068c25626c22c4fae7f435536": { + "balance": "39849464104000000000" + }, + "0c85fbd7492d1ae87bf3d286c4750a34f1fd3121": { + "balance": "20000000000000000000000" + }, + "0c9fd6123e313f7d1f0cb25d99839102da08b2c5": { + "balance": "10000000000000000000000" + }, + "0cb051e3bdd9d96e667fbcc00a766d4f149f89e4": { + "balance": "1000000000000000000000" + }, + "0ce32bf6c433cbd26c6f09a1214db0374002784e": { + "balance": "3293279842000000000" + }, + "0ce6374ff04430e34edec8b6323feab2bccab92d": { + "balance": "93983447000000000" + }, + "0ce646412a1524c3f73edfd753c0ba3ee7338275": { + "balance": "10000000000000000000000" + }, + "0ced803e56eac3c99269ff7409d2d200d62d7c25": { + "balance": "49539379000000000" + }, + "0d1dc2be9f78ce2b2591e7f5b8af9dc778499bd5": { + "balance": "2235348003595000000000" + }, + "0d235583458a168e810275f907b5f87bebb2d1cf": { + "balance": "83106439283110000000000" + }, + "0d28fe6e8b7d4b8c90ef7c52b9656511ce5867f1": { + "balance": "1347248794799000000000" + }, + "0d5cbe0da660cbca831787efc45fecb20e06e02b": { + "balance": "297528508941000000000" + }, + "0d7a24f324176f6d793c3a2eb6c54d6ee47eca79": { + "balance": "25637813467000000000" + }, + "0da26a24e3650e84c52fedb36ef76225a8d9d259": { + "balance": "15467820321000000000" + }, + "0db7eaceaf3df21ebb49c56fa2d2e2c8e85dec52": { + "balance": "196000000000000000000" + }, + "0dde52823bd8fb2cb179e6d417c07ff285c31775": { + "balance": "347321514878000000000" + }, + "0df9585f1aa83189e0a813f5eac6e6e0b2bbb8d8": { + "balance": "2891430551000000000" + }, + "0e09af9368f05b476164953b7b9db60ac95248f0": { + "balance": "573644391203000000000" + }, + "0e18315dd2b663ce4859b5bed854403191452c2f": { + "balance": "24174325261000000000" + }, + "0e29bef5f4f66c38a0f05cca1e4938d57ff09c70": { + "balance": "10000000000000000000000" + }, + "0e443353b42e042ff5168e9b3c6de37070368223": { + "balance": "20000000000000000000000" + }, + "0e8cb6e439516b312158f169b546937b715db3f2": { + "balance": "8049136367000000000" + }, + "0e980fab23be601f3abec7b9a24e1335a5e765c8": { + "balance": "8301885845897000000000" + }, + "0ea63fef218ebf570a4ee62ef6ed712dbe623c44": { + "balance": "10000000000000000000000" + }, + "0eb60e3512336e4447ceeb8664ce0ecaa3eb0bdc": { + "balance": "41401696400000000000" + }, + "0edafc1058879a9568e711445b18ec4da31d2480": { + "balance": "10000000000000000000000" + }, + "0efce4565062b23b43dbc1e261463e363e4a5b4c": { + "balance": "10000000000000000000000" + }, + "0f08782c04bf7249ab08f4e251abc60aee792a96": { + "balance": "1380257622493000000000" + }, + "0f19bfe1eb24def828bf1be69791c63ba1de1263": { + "balance": "2223687184885000000000" + }, + "0f2171161eb9674218add261be61d18d86b846a6": { + "balance": "121000000000000000000" + }, + "0f42ef6c5690b6c95f8b8c9dbdc16f717c04852e": { + "balance": "81000000000000000000" + }, + "0f47f5063d321b34a0d800951bcdc3f53c07e32c": { + "balance": "5288516165000000000" + }, + "0f529a9beedb2c2a087a220f0013cea4f8454bfc": { + "balance": "114585457979000000000" + }, + "0f6751d10aaf855454a6e9e4241cfcae3b0ed732": { + "balance": "94160300063000000000" + }, + "0f6ed5a4c3ec100afcd59e9066ba7fcb63cfa6dc": { + "balance": "1000000000000000000" + }, + "0f77025519cc76c38e1cf0bd8721f4a5b9c814d4": { + "balance": "834620571043000000000" + }, + "0f773db2a1a96b775e4481575704f5f087b067e0": { + "balance": "554268361745000000000" + }, + "0fa0f73adbe82f8e09f8adbce15b051971e289c3": { + "balance": "11329911975000000000" + }, + "0fa6397d747d88a25d0c755b3be4eee0e3f68912": { + "balance": "31394936138000000000" + }, + "0fac8635a61bf7652d86725cc75c307949bd4f2a": { + "balance": "49000000000000000000" + }, + "0fb0ce787306ce13dcd614ab3d0e15d9772106ac": { + "balance": "50000000000000000000000" + }, + "0fb1d306d240360056f60f197dc7f68f732ac515": { + "balance": "20000000000000000000000" + }, + "0fe3571f498a6d945e123ac8ff6e3fed348d9432": { + "balance": "20000000000000000000000" + }, + "0ffd6b01ea9a7bd2576fe4a5838fe09e44c1639e": { + "balance": "100000000000000000000" + }, + "100bde3d73fda700369e78229127b58d2ade9177": { + "balance": "10000000000000000000000" + }, + "102028c7626970a28677bbdc7733484c8b14c2d2": { + "balance": "500000000000000000000000" + }, + "10245044be6a46ad41d4559129cb59e843379cf8": { + "balance": "857437279765000000000" + }, + "10417d0ff25c115b25915dd10ca57b16be497bf6": { + "balance": "10000000000000000000000" + }, + "10579870e6685ed7e97dd2c79a6dc3528bae968e": { + "balance": "5187866041491000000000" + }, + "109736465b4bbe31ea65ad01fc98f04498271e6c": { + "balance": "20000000000000000000000" + }, + "109c0535a4a86244c5094e99167d312a77657dd5": { + "balance": "138277702073000000000" + }, + "10aa08064689ee97d5f030a537f3cd4d8bbdaf74": { + "balance": "10000000000000000000000" + }, + "10d8bc8c3d3e2010e83009290586ad85b73321d1": { + "balance": "25000000000000000000" + }, + "10f22b82460252345753875555de2cebebe63a93": { + "balance": "765947730644000000000" + }, + "11111c3a2cfa55e52d6aacf533e1d412f8c8c01c": { + "balance": "4827254128275000000000" + }, + "11386103a0bf199db9504b617ccb3bbd780eb9fe": { + "balance": "10000000000000" + }, + "1156a129183e5bdfdf2bf7a70963285a979363a0": { + "balance": "10000000000000000000000" + }, + "11589cf70a6a4fbaac25224e2ddab222333f78e6": { + "balance": "49000000000000000000" + }, + "1162fabeb3eb1e4124179b00c4a1e01503023f54": { + "balance": "817145350625000000000" + }, + "116a7d140f4b7f9b4689063a8417ac07a32bae00": { + "balance": "106088220142108000000000" + }, + "116dc38ddb4b138b19ce6a51e5922c287da5c86b": { + "balance": "100000000000000000000" + }, + "1175f84f835a5ae40d49b8ca17e3e474c1eceef7": { + "balance": "1698584794716000000000" + }, + "119f822a796fee9c41a488949fcb14b589ffa628": { + "balance": "20000000000000000000000" + }, + "11a99f6019b6a53f5dc8cbd0c34f1ee75ced33b8": { + "balance": "102126982156000000000" + }, + "11b9324406068e8bf598d3a9ea59ef31c52f51fa": { + "balance": "6525925895203000000000" + }, + "11cb7be6869a10f5f9e8a47c6c92f729b083084b": { + "balance": "182959434323344000000000" + }, + "11d96a76166ec579e2b6cfa903f66da4af669351": { + "balance": "1000000000000000000000000" + }, + "11fcee55f78278df60f50096d45da1aafe72722d": { + "balance": "222859488179000000000" + }, + "120a1fc914718acd85bf92d9492330165d78075a": { + "balance": "3736627235906000000000" + }, + "12366136d83c77befdc30e04d4f5d808419f504f": { + "balance": "88008649003000000000" + }, + "12435af3f2f92ec43e8f2894be9c72fa932880fe": { + "balance": "1590548436852000000000" + }, + "124ff67125a00aed24e58b6d64ffa887a59b48a4": { + "balance": "20613022349070000000000" + }, + "1296f04910ebc89556ec7ab1b178fdbf14d0295c": { + "balance": "36000000000000000000" + }, + "1299f180e42bfaa1162d36110d29ab062e43e1c8": { + "balance": "321570118362000000000" + }, + "12abac62150c526866ec958cd0e3721b2c78d550": { + "balance": "51898545633262000000000" + }, + "12b345087cee385b9adccaaaa6741b767c82d7ea": { + "balance": "36000000000000000000" + }, + "12cd5e8c0c93f8e34b589b95954b719f54d1515b": { + "balance": "1000000000000000000" + }, + "12d262cdd25edc39b6fd9ae78184eb548e513927": { + "balance": "500976168000000000" + }, + "12d933448218629702c48547b3446b629ec65883": { + "balance": "2168010577395000000000" + }, + "13054aa42d3e119220ac359641c15f8b54bfffef": { + "balance": "24986834005530000000000" + }, + "130bda09f463a982199849ae617062a1d68f3a85": { + "balance": "154504844790000000000" + }, + "131a5da679863c05dc627d53634f2925ba0ce731": { + "balance": "10000000000000000000000" + }, + "1334f2752b5c21f681ba9e23a9fe95a85f8e05f1": { + "balance": "121000000000000000000" + }, + "13634512e2ae79fe3febb9e55e03b47bc350d7ba": { + "balance": "338331304738000000000" + }, + "136fae842aab625768bef9079ee1711e8c007d8f": { + "balance": "2759741687626000000000" + }, + "139fa969e8b74bee1f6113a362f15060ea998b15": { + "balance": "10000000000000000000000" + }, + "13c7e1d694bde6f8f6a31eb6c99f38dc739d61fe": { + "balance": "10901074773586000000000" + }, + "13c849944ad6ad12a46c46973d562bee8284f46d": { + "balance": "35114615504000000000" + }, + "13ec3aa8f4a427ecdecc7901060ccac9bea7a61e": { + "balance": "10000000000000000000000" + }, + "13f478c74acfd6897d13e602a8d362893f4fd038": { + "balance": "3521111850000000000" + }, + "14403970d0784a6458a7bf2584a53d14234e8860": { + "balance": "25000000000000000000" + }, + "14440bb7410337e34a064a92206075575f5362ee": { + "balance": "14918844868393000000000" + }, + "144a88e7a8af70b8bef5c4b70ee0cff771d0c252": { + "balance": "67961927542000000000" + }, + "146b79f474176a4b0069199b03669ab6467a4787": { + "balance": "122518123211000000000" + }, + "148893e7811c36c6bd1ada367681ab8327b3b2fa": { + "balance": "1313118418375000000000" + }, + "14900a17784e3b4d89d98b6cb31c74c685418b89": { + "balance": "131112181597000000000" + }, + "149a483758a98ffe28f7f25cfa17d7433f852ebe": { + "balance": "10000000000000000000000" + }, + "14a03c8e84f07c5596687a98d1e0b1859e9b34ac": { + "balance": "55000000000000000000000000" + }, + "14c7899cb34b5447d6363d4e8355113ebf4bcc66": { + "balance": "197554844582000000000" + }, + "14efa63ee285277c0f8e0d5cc22193e17984e11b": { + "balance": "106221254735000000000" + }, + "151c6099b3fb5b18e0e36a3335dff186dcd2904d": { + "balance": "4304311254087000000000" + }, + "1525dce233a971eb1387f130fdf0e5bf3455723b": { + "balance": "45004174531000000000" + }, + "15271904676f2bc2511294e500152d05ea9acc85": { + "balance": "9300898622566000000000" + }, + "1556ba42ea69d72c1d0faf802906645268e36aac": { + "balance": "171939212653000000000" + }, + "156558fb71ff986953d899c9916a121fd047675c": { + "balance": "290926338537000000000" + }, + "156fbf32614aac2cf462952ec1a3f141f797316e": { + "balance": "6084388860000000000" + }, + "15b9497d6bde8017baf3c29e12430e05a47efbf4": { + "balance": "206126229839000000000" + }, + "15d532e828bdcaf1246696d679a2eb66a154db5d": { + "balance": "69656571015000000000" + }, + "15e26a60cfaf23dfd9bbb999a30904d11b6ddd05": { + "balance": "9839303178835000000000" + }, + "15f3be2f11ee3b19472cc3d171931f050d8629a2": { + "balance": "13572825921000000000" + }, + "16254bed335420e5f793de2295b0081ac41a08d1": { + "balance": "144000000000000000000" + }, + "163aa91bc2ad588116141d48fcbd943985455cac": { + "balance": "618250979557000000000" + }, + "164cff4b9341d536b8aaf2d1dd0e3ed35ecb1db7": { + "balance": "671554639913000000000" + }, + "164d2a9a63868ac25bfe26ecba446d7ce256c351": { + "balance": "7233638188261000000000" + }, + "164e759b64d3ee0a23ec3030f50a1b454a6ec15b": { + "balance": "12281161499000000000" + }, + "165d4a0f23c016b8064adf0dcf7e31bc06350777": { + "balance": "256757922324741000000000" + }, + "166b862954dacddc3333aba4edbe523d693df858": { + "balance": "123677971414000000000" + }, + "16858eb1a6f0e7ff01b91aa9c92d0a433a5f767c": { + "balance": "500000000000000000000000" + }, + "168909a1c2a43cff1fe4faeac32a609c25fbd1e8": { + "balance": "62258808044224000000000" + }, + "16987ad8e10dda7f9e5d95c0f0ee36f46b10e168": { + "balance": "10000000000000000000000" + }, + "16b5dffce79573300a6514ace5f2e844d26fc64e": { + "balance": "5576805697087000000000" + }, + "16e01370a93befe24f6ae6076cd04c84cd3515b1": { + "balance": "1922179181578000000000" + }, + "16fbafd4fc871c7589e63062133793ab244c2019": { + "balance": "2865030627000000000" + }, + "16fdf76180796c6e4335eaa2842775b2e4a22e0b": { + "balance": "20000000000000000000000" + }, + "17081d4d6ebb9f4b163e181a59c2102c99fce6bd": { + "balance": "490625378000000000000" + }, + "17218ff455aa87b29ad4c4f7ba21e9c6f74fc97a": { + "balance": "1607392037652000000000" + }, + "1725bce47f3700f4646efb343f950e2e8ba66607": { + "balance": "58472967071000000000" + }, + "172c5f71aabf072507664471ebaa435779d74a32": { + "balance": "16000000000000000000" + }, + "173a065f351ee0513cfebfe9b950fd2c641fc8cc": { + "balance": "25000000000000000000" + }, + "174e1793c96cefb584ae0a67fff85c65065dafc5": { + "balance": "50221000010000000000" + }, + "1794bc4d622d514f95da5404358ed404b3f59aa3": { + "balance": "36000000000000000000" + }, + "179839d61e7c7a0382fe08e0573bcfbe42a108ca": { + "balance": "203299791419000000000" + }, + "179eb30b5b28a961eac70a919d26ca96e6472166": { + "balance": "55000000000000000000000000" + }, + "17be72168606fb5d27761157e48fc14789f84634": { + "balance": "311205588354000000000" + }, + "17cefb6611033759b8755197b983de2d7e98315e": { + "balance": "10000000000000000000000" + }, + "17e07cc7d89bcd1708b1f05ab6e1252c629d71cc": { + "balance": "903234908997000000000" + }, + "1811be559b657685c2f163122479101c404325b0": { + "balance": "10060694170000000000" + }, + "181417a4883c429ef26a4baeb48e70d4f00278b4": { + "balance": "4621446218088000000000" + }, + "181d345cd6b5f518bdab8d40f5d4896a725b3f3d": { + "balance": "114349561983000000000" + }, + "184625e544aa31552d2911023a892f739df84be7": { + "balance": "5303698708000000000" + }, + "185e4f6eee203ca3c089baa1e643ff1aab7cc8f4": { + "balance": "33969718257699000000000" + }, + "188e4a1a7b23ff35ec90b7bf7561db9e3c0f53bb": { + "balance": "394325508701000000000" + }, + "18a4dbf513be132f9ecfd69e3eb683d710e28c4b": { + "balance": "5997985132329000000000" + }, + "18c9298f62635ef47d0ef215b8a693af60829c27": { + "balance": "100000000000000000000" + }, + "18e7e2ee0c86bc1ba3595fee3d40257776fe8172": { + "balance": "185584626033000000000" + }, + "196575e74499b741877793f8c8facf2f3b1ddb8f": { + "balance": "30318381929000000000" + }, + "196df33f2d3ed473e6e07650419969f4a39fd03b": { + "balance": "15442864665000000000" + }, + "1975c5293ec9c72a28e6cc74173cdfd8de682fea": { + "balance": "103624886552134000000000" + }, + "19832cd1b2fc4138c8d9291a0f404d3c4326b48f": { + "balance": "4732362673000000000" + }, + "198705f46f31c7ca22f5b88fab210bc5b0c7647c": { + "balance": "548940869737000000000" + }, + "19a5a213e6abfee29f17e871222cbe9ac45322c8": { + "balance": "10000000000000000000000" + }, + "19ab9a7a4e9f9c08c9b4295c406b78389a864ba7": { + "balance": "369299839157000000000" + }, + "19f19f5f01b3f6a1c4f645dc7e3992b1196ccb7a": { + "balance": "97759406000000000000" + }, + "1a11a0b0081522e60e16f154e093ac2e005d24ee": { + "balance": "88024675252000000000" + }, + "1a27309b0c09be2234fd64afdbcfb099f8e2e7cd": { + "balance": "10000000000000000000000" + }, + "1a3d61754974bea23503a61ef0fe584b7b6e6cf3": { + "balance": "326950210355000000000" + }, + "1a49bbde1457a8d4c247606b206ac8d4d389da5a": { + "balance": "402438941516000000000" + }, + "1a7a4b41be64fff3a31eb6166db59741e073d0f7": { + "balance": "250000000000000000000" + }, + "1a8d282e82c606e992f69ce618ba634d98bf2683": { + "balance": "20000000000000000000000" + }, + "1aa0ba27662816e5e3d79e223cc18f5dfef089cf": { + "balance": "187581622694000000000" + }, + "1acab416a1d3e8caa65faca378c79aaf2065b851": { + "balance": "1000000000000000000" + }, + "1acd37af3f87da1dff743dfcb97038d178b1dc4f": { + "balance": "708034481300000000000" + }, + "1ad8f036022c3e5258455d6aa05fb4be5dd121b1": { + "balance": "42957064709000000000" + }, + "1aee811e06c579c21fbcc3b53d2dcf9d5f24808e": { + "balance": "52480060284048000000000" + }, + "1b03b7a4e9908c3531618f49f8d050ba6afb4de6": { + "balance": "28410489187000000000" + }, + "1b073d026e93de51db34d5a8e19047784c277ea1": { + "balance": "20579129628026000000000" + }, + "1b0b87e414bc8fe4920fe104b6de7d17db3a1a19": { + "balance": "10720000000000000000" + }, + "1b411c692c80948e59cd805a0f8574dd67519288": { + "balance": "5416615538000000000" + }, + "1b8d57e995749618c7bb3e60194ac6fc57e9b3eb": { + "balance": "10000000000000000000000" + }, + "1b913efde1255516346b40ae2a48ebf62251682d": { + "balance": "100000000000000000000" + }, + "1ba7276c133f93d43db2f2caddec08e0167eaf15": { + "balance": "82559173174000000000" + }, + "1ba919f7742160cabf2756eb6eae67b92530f3f3": { + "balance": "1102304139883000000000" + }, + "1bb20857de494694fe15bd11f8cac1218435fbc0": { + "balance": "10221322567000000000" + }, + "1bb5c5e81d451f03e899852edc8556a9f7aac5df": { + "balance": "18781017696028000000000" + }, + "1be3507349ed07d3e7902951d490f560a75e96be": { + "balance": "660691718918000000000" + }, + "1bf1c0b2e6f64b612f35f2bf98d894b13dda9bf7": { + "balance": "3050161851140000000000" + }, + "1bfd3c2ba6a537e97cedd542cd554a5050963d54": { + "balance": "20000000000000000000000" + }, + "1c4af5003f9e7223f4141107d21640e4a85a4827": { + "balance": "612390629874000000000" + }, + "1c6a94810bd0afcf79ceea11afe86c34f6813211": { + "balance": "10000000000000000000000" + }, + "1c7e277460191c886cb1647173d27122c2146252": { + "balance": "209062806527000000000" + }, + "1c818ffa9caa61d512fa5d7d6e566f3ae37d5434": { + "balance": "454897845316000000000" + }, + "1c9599d5f8e5eaf8f68d35d52132e15a153f6d3c": { + "balance": "36000000000000000000" + }, + "1c95ab5229fd08c638a1728c022f09291b8dc55d": { + "balance": "20000000000000000000000" + }, + "1c962808c175ee5e5e365483d066c8ea95993700": { + "balance": "1362779746855000000000" + }, + "1cafad295b2188f10192c8a32440931f7e3554e4": { + "balance": "36000000000000000000" + }, + "1cdc2899ec563d79569d1ba776bc03cff331e786": { + "balance": "572163587827000000000" + }, + "1ce0042e7b4f13589f5f8490836dc63e0ca60c3c": { + "balance": "25000000000000000000" + }, + "1ce62051fd7801d294bf31a7b44cd87510e8b545": { + "balance": "2008112411284000000000" + }, + "1cf20f30cd901b2e5fef3f948289dafaaabaa77d": { + "balance": "1444000000000000000000" + }, + "1d449764d38b7a4ac848f49e2dc99df02dfd8a53": { + "balance": "48215693645000000000" + }, + "1d635125c494b1137ca5f15ac95dd6d93c3a9546": { + "balance": "10000000000000000000000" + }, + "1d85a61353c3e0b6d34e105e35c8c7833b6a1e35": { + "balance": "16000000000000000000" + }, + "1d969134ee156c41c98c3721c5dbb092c0b581a6": { + "balance": "64000000000000000000" + }, + "1da12434596a9c318dab854f06d404fe61f0a69d": { + "balance": "16675185416000000000" + }, + "1db0d23fb63681958a66e716e99df3e0b848fd12": { + "balance": "1103581911968000000000" + }, + "1dc628820da657f07ab5eb887d5f512378b5b61f": { + "balance": "6272287019755000000000" + }, + "1e05cba75b0dd379037940352e0073564957b7d9": { + "balance": "12453446342664000000000" + }, + "1e13f037a92ab6f19c4484ae3301b3ac6f48575d": { + "balance": "106244918916000000000" + }, + "1e167bc07f094915c00e7aa4c43b607ed2c998b9": { + "balance": "1000000000000000000" + }, + "1e1f9409bf92c3ef59aa2fd82dce55cd90e23f19": { + "balance": "99139000000000000" + }, + "1e4dfea7871d941e72a161022b62fdb01818c86d": { + "balance": "81000000000000000000" + }, + "1e5d0b525228167334e94314a201388bba08153b": { + "balance": "1138044078759000000000" + }, + "1e6633290c9898abf5fcac54396de770164edc5a": { + "balance": "25052055674000000000" + }, + "1e76296584058670ea80fe9a39d8f457c03747c5": { + "balance": "10000000000000000000000" + }, + "1e88b2c8dcd289929e51a15c636d0b0f3b035569": { + "balance": "87357600832000000000" + }, + "1eb59a1732a159a91a9371650943840e0eb61174": { + "balance": "20542821429000000000" + }, + "1ee077bdef6d45d491602342cee008cd1e2912e3": { + "balance": "10000000000000000000000" + }, + "1f1ebf2f80afced68424cb7b0b966fdf42d508a4": { + "balance": "1460082126494000000000" + }, + "1f3d4a903bd32a537efae19592f5516698c95a20": { + "balance": "10000000000000000000000" + }, + "1f6431696efc6f1ab98dcc2ef0e8553da697e6f1": { + "balance": "20000000000000000000000" + }, + "1f657552b745acbdf731f2ad107d6362480abc88": { + "balance": "162042599568000000000" + }, + "1f699a7682c1266291a3f49e19cac0846470abf5": { + "balance": "712268213248000000000" + }, + "1f7a332dabb00851705274c59187817d859cb9a4": { + "balance": "199999999160000000000000" + }, + "1f7c333047e168f5d3408c42a4919bd44b8f7961": { + "balance": "3918096658000000000" + }, + "1f8226f7a4525b9f3cd4da3acc1bb34529f8d28a": { + "balance": "3530829464000000000" + }, + "1f8b6fcea9e0991ad0b0b25dc65748518a28713f": { + "balance": "142069368416000000000" + }, + "1fa3de6913e4de78cc4828e246554785950c3c8e": { + "balance": "178437291360000000000" + }, + "1faa75d57fd597d2b58d2ac6f65bc2bd5946911f": { + "balance": "13092024644362000000000" + }, + "1faf1721dba3266cde1e04a7e9c789bdabdd930d": { + "balance": "862698523071976000000000" + }, + "1fb861559361701fca1df6ab4ef4d2fb9d2d7e13": { + "balance": "100000000000000000000" + }, + "20154d678cdde9ca1c0acb94726f26617a4da0d8": { + "balance": "2288800561677000000000" + }, + "202484a46ca9d54d0d456bc38e2a74ec5f469349": { + "balance": "50178714107336000000000" + }, + "20324278018b4d8e0c49e0fd1be35d3494079165": { + "balance": "484082383314000000000" + }, + "2033ef68ef6297e9229bb73e6486330543aa3eb7": { + "balance": "51260669473000000000" + }, + "20b1e0ab7b9d62a314946b55a5775f24ae3cfa00": { + "balance": "1540424185584000000000" + }, + "20b61f2eb5e18b1e8568d18235918f9e2f596c32": { + "balance": "10000000000000000000000" + }, + "20ed8ca39dd148edf22e03b8021af32cecadd42a": { + "balance": "20000000000000000000000" + }, + "20fd5feb799fbb021ba262d28332b4dda8f44a2c": { + "balance": "7607475714434000000000" + }, + "215ab8aad1c8960838225294d086f0786c2dd796": { + "balance": "19929201327000000000" + }, + "21681cda53aa1a4cfb3e3ea645c8eeaecfc3ba4f": { + "balance": "10000000000000000000000" + }, + "217b75eaf2c0be12108120ba56ddb709e1885324": { + "balance": "36000000000000000000" + }, + "21be1d75b93e96017f088f1ca64ba7076c8edf07": { + "balance": "150798073752000000000" + }, + "21ccdbe0216b486cb39c94ed13767aa061c75ce9": { + "balance": "11070639373000000000" + }, + "21f2289f2d274bddd7928622fffdf3850d42d383": { + "balance": "268859368544000000000" + }, + "21f54f92a7d9a91915e1751ceb02cb8e3ed3d622": { + "balance": "10000000000000000000000" + }, + "2202c70ec23f4605394d69944edd9f90e488eb61": { + "balance": "9000000000000000000" + }, + "220e2253e1ab9ec348cc28d38bae4cb2d5d9cf8f": { + "balance": "116100821631000000000" + }, + "22328e434957107884854999e666ad0710187e3b": { + "balance": "233364805270000000000" + }, + "22851c0487d119ee3f150010515358d6ff14807a": { + "balance": "104464221701684000000000" + }, + "22a38000f5eca29001e387b52c18fb6030683fac": { + "balance": "55000000000000000000000000" + }, + "22b655a19810307750ed1b6b093da10a863d4fe2": { + "balance": "11840799203605000000000" + }, + "22cc48cf48e8ee207bc08411240f913a4e594529": { + "balance": "10000000000000000000000" + }, + "22d6ea6cb8a9206285ccddd3b6d0d1471ba66f17": { + "balance": "64000000000000000000" + }, + "22e2f41b31a0c69472a1a02d419886539b7b6197": { + "balance": "39885451304000000000" + }, + "22e962f91d01480d027ee0060030f529a7a64c8f": { + "balance": "93285203531000000000" + }, + "22f169328fb1104b386ad7fa69f0c7bf3e9a7d3b": { + "balance": "63366769386000000000" + }, + "22f35f5e0e7a8405714de66a5875c7ef84ec4891": { + "balance": "60944382032000000000" + }, + "23041bdc8d371dc29ffc890f19317dabeef12634": { + "balance": "402327389857000000000" + }, + "230eff5e8595f418686737ae671f1f1d225080a5": { + "balance": "114574598112000000000" + }, + "2331e1756d9800800fc9b54ee6e43e1150b6e58b": { + "balance": "44594796226000000000" + }, + "233a72b132e4ab1d3884274d4402d1a2a6399f0b": { + "balance": "1372148909093000000000" + }, + "2369d9dbbfd0f8aa8a3d84d8f2aea840a0cdf760": { + "balance": "500000000000000000000000" + }, + "23754e5cef31ab60aa97a0c8f9ccb4f2969f2d6c": { + "balance": "24764775861000000000" + }, + "2387973589fb07a8c1ec92492c0b8ba9ab5e52a2": { + "balance": "11642113696681000000000" + }, + "23950cd6f23912758ebe9d412166e27994fe6ec2": { + "balance": "100000000000000000000" + }, + "23b383e11573f3ca9be84e1e11694f58a432324b": { + "balance": "206558238838000000000" + }, + "23c329bb641fa51122ea476e3bc614f5d4f9cf00": { + "balance": "35908627324000000000" + }, + "23cb9f997c39853486adfc1a8b029874d1a6af15": { + "balance": "1400984459856000000000" + }, + "23ee14215c531f6ff1baef2c74b1754306f4532d": { + "balance": "10000000000000000000000" + }, + "23f641f765cf15665b6c28d77229d3b2a58fd857": { + "balance": "266570948120000000000" + }, + "23febb49d9541360b9d099377df16b5630dfbb52": { + "balance": "228513797641000000000" + }, + "24082040652a09cbed6504f3dd6491e0ee9d2bff": { + "balance": "91160839809000000000" + }, + "240d3edf4aaf42e99d366ca36d82c370271b8e8d": { + "balance": "65535355843947000000000" + }, + "242b63ebf47678f17c176d5d4a670e46e66a823c": { + "balance": "469668185647000000000" + }, + "2433612fb939236a87a97261ff7b3bc7b754afb1": { + "balance": "20000000000000000000000" + }, + "246bb03a3fab572b3c64fc23b03dfda42b7ea34c": { + "balance": "936364046000000000" + }, + "246c510dfaf5b49bc0fe01c8256d3879c1b5f89a": { + "balance": "100000000000000000000000" + }, + "24bf4d255bd3db4e33bff1effd73b5aa61ae1ac2": { + "balance": "302436106595000000000" + }, + "24c0378e1a02113c6f0c9f0f2f68167051735111": { + "balance": "36000000000000000000" + }, + "24cf04b7450a0fac4283fa6fcfef6215274b273e": { + "balance": "83714002622000000000" + }, + "24f5f8e7d6a23b55c95fcdc1300de05f9d2abd83": { + "balance": "20000000000000000000000" + }, + "25204bfb27a08dbdee826ad6d9c3398ec6d14fe1": { + "balance": "5929256591480000000000" + }, + "253d95911b4174805d13706b449879413b1672be": { + "balance": "37012901440000000000" + }, + "256065f7e919c508b68957b1d2c9120d29181e12": { + "balance": "25000000000000000000" + }, + "25624542c14c2ecb9a0fe7daec9ac5af16868ee7": { + "balance": "16000000000000000000" + }, + "256d05b6de445179e504a6c94ce1253ae159e19a": { + "balance": "12048598744001000000000" + }, + "256d37fc8980a969063b1f7e7fda8b87d4210da6": { + "balance": "107293553721000000000" + }, + "2588af91a0e8f3ba3ab636781bb84e263acd1f52": { + "balance": "8910000000000000000" + }, + "259774584d4fcae1d84f5997c00beee8a380e46c": { + "balance": "1140713354605000000000" + }, + "25bda1418853a22eb6a5380e8a2862d2a74949bc": { + "balance": "10000000000000000000000" + }, + "25cafdab7f79f7b95d55b4c2dda1f4080aa74d64": { + "balance": "2525573681000000000" + }, + "25cca69b41bb51c51b387c47ece83f30b9a78daa": { + "balance": "163449631440000000000" + }, + "25ce9dabd0a72b02e0056931155ba99c94cbc837": { + "balance": "230073284349000000000" + }, + "25d9d1785c96acddd926b3ed52987ff74f9083f6": { + "balance": "780460361789000000000" + }, + "25e56bd3e1461f27db4eb0cce8bb5ca1574401f8": { + "balance": "1001937531200000000000" + }, + "25fa2162d5c86cda10e4be42c14a24329e455ad8": { + "balance": "50000000000000000000000" + }, + "260a932a23b344056acb8e676714ffac0a13ad2b": { + "balance": "2000000000000000" + }, + "2622efe8836095fcf48d9c8019f48c8320d6e0f2": { + "balance": "5451866545636000000000" + }, + "262447c4d8826ed23ea25e9703a11b4ad3ae9388": { + "balance": "33992454005000000000" + }, + "263eee3badb9b0dd13579c09361806503705a1de": { + "balance": "1134831344000000000" + }, + "266f4c232ebc946c46979cd90d70868380e186d8": { + "balance": "20000000000000000000000" + }, + "267dfe6fa918686942f5e1d19d5fa615f6f2086d": { + "balance": "3569373363935000000000" + }, + "268ad2272c2b71243a7391020a600fd8dfa42d45": { + "balance": "122768017414906000000000" + }, + "269e4f43be9865f05a277933c2fbb466659ada7f": { + "balance": "22064992930948000000000" + }, + "26ae161c20acb26a320fbfbd60c97335cda28bca": { + "balance": "170710653621000000000" + }, + "26b4da905780fb0c5c3e7e5315989fed3aeef135": { + "balance": "20000000000000000000000" + }, + "2704312aa5a4202f14fa3b08e587e4f0ef13accf": { + "balance": "124259630994000000000" + }, + "2704e4b0e8df0c1f298843109ae3bb26c29a22c4": { + "balance": "3155521256785000000000" + }, + "2709347d12251c01aac6455108c6bebe72f0af2d": { + "balance": "220898650215000000000" + }, + "270a32b41dde877463d2106ea4f4529557a5e1d3": { + "balance": "10000000000000000000000" + }, + "2738b3746d6bda9bd72858eaa76f8b5ce7a88c8c": { + "balance": "10000000000000000000000" + }, + "27593d2271aced83e81034e8dd603d098238320c": { + "balance": "20000000000000000000000" + }, + "2771ba4b5944bb12d74b1888255c60e0db215fd2": { + "balance": "412946979808000000000" + }, + "27780086136ea3e97d264584d819dcb2176d7544": { + "balance": "292224348060000000000" + }, + "278936fff8afb553043f038c39fe93906bdb1f4f": { + "balance": "1448466441752000000000" + }, + "27aa0d45d3506f8446816e0e2e9675d46285f6e0": { + "balance": "20000000000000000000000" + }, + "27e655dcc5728b97b3b03fb2796c561090dced1a": { + "balance": "9841344000000000" + }, + "27eb0529279f7a71e50efb70bb1767cbe1ffa4ce": { + "balance": "10000000000000000000000" + }, + "27f564956c837d7949739f419d6ac99deb33d790": { + "balance": "1505247707018000000000" + }, + "280f5618a23c41ac8c60d8bef585aa1cc628a67d": { + "balance": "1316618646306000000000" + }, + "28167a591d66ae52ab22a990954a46e1555c8098": { + "balance": "1000000000000000000000000" + }, + "28257eeb8d20f2fe5f73b0ff2eca3214e30ece4f": { + "balance": "95924728584000000000" + }, + "2827abfc49828db0370b0e3f79de448d46af534e": { + "balance": "769862008499000000000" + }, + "2832b92434e3c922206c2408442bc8274606cbd9": { + "balance": "103421320914027000000000" + }, + "2854f190a38e9b9c04cf499259c6577a68b0b5ed": { + "balance": "144000000000000000000" + }, + "288923bd91be164496e5378ee484f0e4c6c16ed6": { + "balance": "10137243270703000000000" + }, + "2897ff80794153edb721801fb91c6d8373c965f4": { + "balance": "10000000000000000000000" + }, + "28aa06e2290010374097aa2f87a67556d8d68083": { + "balance": "84783245638916000000000" + }, + "28b04ec8eb18b0c6a384f9d92cfb44d1d43ecb51": { + "balance": "14364248730194000000000" + }, + "28db0c000cad3a524bb68dfdd74ffd47b42fb13a": { + "balance": "43586590410000000000" + }, + "28ecd4c5fe98cff66a5b8423f4a27cba9634e2d0": { + "balance": "56106658052000000000" + }, + "2930822031420731f09dce572554a8b8c1eaa09b": { + "balance": "1170839742000000000" + }, + "295154c4522d7bcb2e24b7de9c543dcd1c5f51d9": { + "balance": "179028680906000000000" + }, + "296be4ef7402b00d7af673c1770a50162d7ab602": { + "balance": "8206640005889000000000" + }, + "297b84150756fa89101dd59750a7beb36fb8785c": { + "balance": "1168894124400000000000" + }, + "297cfb72cd1b8b2808fd1b25cdcf7d8de279ad96": { + "balance": "500000000000000000000000" + }, + "29cec0eca9f8508a1ba192a90bb6dee18c40745a": { + "balance": "260217025084000000000" + }, + "29d8f7e72bfa297f17fdce9cf8f4a398f547e200": { + "balance": "307787433251000000000" + }, + "29e14b01c59ba894dd090382fb193ea441164b90": { + "balance": "229028661439000000000" + }, + "29ed634e165084b720e446d28893dbeecd6a7018": { + "balance": "226530464200000000000" + }, + "2a0f8136d43248233f652fe579ef3bd2281dde24": { + "balance": "4007544428000000000" + }, + "2a10204a0c7c9f7701e33c1b71c9427ea16e2e45": { + "balance": "50000000000000000000000" + }, + "2a319ee7a9dbe5b832beae324290f7df6d66f516": { + "balance": "28127560161000000000" + }, + "2a50bfda2b06a9fb28c73f14aaff4f7ef865db65": { + "balance": "10483823413828000000000" + }, + "2a7b7feb145c331cb385b9fcb9555859c16820f6": { + "balance": "1017182951264000000000" + }, + "2ae076c36b18a60f1e3c05d434276a1e16f3f838": { + "balance": "10000000000000000000000" + }, + "2ae2e51ea2ee6a848acde342db2bf6eac927e5af": { + "balance": "494279795271000000000" + }, + "2afd69fac54c167e7ca9d8198a8de386f3acee50": { + "balance": "227162683047000000000" + }, + "2b08018d6e65a7b74ddb5ce1af99976a484b9f50": { + "balance": "16000000000000000000" + }, + "2b0c1d629ad2958ab91e31f351a91219fdbca39e": { + "balance": "113239399820000000000" + }, + "2b2bb67fe9e44165d2108676579a9437c760da30": { + "balance": "20000000000000000000000" + }, + "2b2c99e88e938d1f1416a408a7d0041a605bce16": { + "balance": "6118539729000000000" + }, + "2b5c97b6402ac189e14bbca3e7759319ca8a9222": { + "balance": "10000000000000000000000" + }, + "2b813339c7f818f578b45f17c41c7e931c7828e2": { + "balance": "842834712955000000000" + }, + "2ba6fc21f743968d51f80113aadfc0fdfe8499ed": { + "balance": "309973507270000000000" + }, + "2bb75b272b279cb54498f12b6805261af643c8b1": { + "balance": "1426727673809000000000" + }, + "2bdac062364abd9cf67ba7de214a2cceb0511033": { + "balance": "1090525272063000000000" + }, + "2bea658caa805241aa921f48c8f10cb49e16ffae": { + "balance": "1295499213027000000000" + }, + "2befe7e34299a7c1ad53fc9988ce77e2d9fab20b": { + "balance": "4326342236300000000000" + }, + "2bf466a83cd44aaf0f627606a1c954fd31deb782": { + "balance": "1388986370166000000000" + }, + "2c016a23890e9633fc17b0a8d328ec1ec7ee0113": { + "balance": "92483174342000000000" + }, + "2c45a87a63cc5c8c102d12b83bd9a3501ee41995": { + "balance": "394657687589000000000" + }, + "2c600a596368405e584f3b869f7fabef4ce54aa4": { + "balance": "9879984853585000000000" + }, + "2c7032da8b7816e16095735aee43d1c3f1c43acb": { + "balance": "10000000000000000000" + }, + "2c7275511fe06ee86663b3a618497168b35b0cdf": { + "balance": "10000000000000000000000" + }, + "2ca4074843e9519265447c0dd9ac84ddc2033c1a": { + "balance": "179612279567000000000" + }, + "2cac03ba2c45a6c8186bdceb095b7c5feced3114": { + "balance": "2022060470376000000000" + }, + "2cb8c2cd506b2d7b4cac88ce63230022d412c62d": { + "balance": "211378154058000000000" + }, + "2cd27561cf37ec229982dd592c71d1aab9c2d7d8": { + "balance": "42189968284000000000" + }, + "2cd2e85310a4fbb7f296c3d0d1cee07b191239eb": { + "balance": "1940327317417000000000" + }, + "2ceca4501c5f2194518b411def28985e84d42913": { + "balance": "25000000000000000000" + }, + "2cf7abd42394634689aa2a36d263a6345116b7df": { + "balance": "3553167226295000000000" + }, + "2cf88f29356c166df8383d3312cea10397e25150": { + "balance": "76961677759000000000" + }, + "2d0b62fe49592752cfebaa19003a60b8b39b1cb9": { + "balance": "10277397502735000000000" + }, + "2d2051887107bbd8ed45b405b9be6974a13172d9": { + "balance": "1928781992000000000" + }, + "2d2c9525e2811f4d1016c042f476faf23274aa31": { + "balance": "1000000000000000000000000" + }, + "2d2ef9e1c7a6b66d9a2994adb3ac4a9921408e69": { + "balance": "10000000000000000000" + }, + "2d3bcd18e5c97ddbf1cd28ab37eabe070e9a04d1": { + "balance": "323879852538000000000" + }, + "2d3e60496d0092a4efc665389a916be1a9f8b378": { + "balance": "161958437779000000000" + }, + "2d3fb0ae9b17d3a57d23549ae5500fbb163de25d": { + "balance": "25000000000000000000" + }, + "2d8106dbee6f728c0ff11887690a6370a7d9f5a5": { + "balance": "3102418708000000000" + }, + "2da48eeb788686811ac8270ef3baf0159fc47446": { + "balance": "252187695395000000000" + }, + "2da9d2a6f0b92651a36b05c5e9d2a717c6e166de": { + "balance": "500000000000000000000000" + }, + "2dad81b23d8447190259119019c04a4ef61ab91f": { + "balance": "53428719965000000000" + }, + "2db1faf35901e272aee74a2469a278fdaa6e6e18": { + "balance": "100000000000000000000000" + }, + "2dbae8e1ad37384ca5ff0b4470d3dbc73559841c": { + "balance": "10000000000000000000000" + }, + "2ddf9e23945c181b8592d7965e782068b4c38b37": { + "balance": "100000000000000000" + }, + "2def05d1f2abbaa193a219b87e5319c7ecd48dea": { + "balance": "51359946957000000000" + }, + "2dfd221f96a21e41ffe4dca67b15cd352fe9637e": { + "balance": "36000000000000000000" + }, + "2e1371fcfea9d8dc8e692897a91753400caa9c3a": { + "balance": "5199902650733000000000" + }, + "2e2e04945adbfaeec698ea0f5275f1ad5ffd3d5b": { + "balance": "42034514567000000000" + }, + "2e41f865cfbcf8b89f848405e04de9114087f4ff": { + "balance": "44875730962000000000" + }, + "2e530254768ce94db0ef1204ede0e12b3558e7eb": { + "balance": "14319506377747000000000" + }, + "2e5c43868f45de268967fb22f3f4107da401510d": { + "balance": "20000000000000000000000" + }, + "2e5d2e117d2ba9af9697ec023a4d10b5a2436902": { + "balance": "16000000000000000000" + }, + "2e6000778fb225ddb3e1a2f297d56774e85d9c9d": { + "balance": "10000000000000000000000" + }, + "2eb64b8ab13f0d7823158217d15ba310ed3d0e58": { + "balance": "58724606000000000" + }, + "2ec3973ff33a06d355ad4e8f73b657af8a5ed8e9": { + "balance": "1165606294808000000000" + }, + "2ed4362ea5edf510e210af733089b294f87e8f67": { + "balance": "427561040806000000000" + }, + "2ed8788f1c31b508e37079098a7337bff77b49cc": { + "balance": "10000000000000000000000" + }, + "2edbbe1e2ea482920c76a4ff4c14602b4d37c955": { + "balance": "294409476945451000000000" + }, + "2edcba2bd76128750c8aa00f832c62db30aa7868": { + "balance": "25000000000000000000" + }, + "2ee5abcc0d0d51d4b18947b5aaaa95d037be4e2c": { + "balance": "20000000000000000000000" + }, + "2f058187ef141c06c7c87da86cc1953d2fcf70fa": { + "balance": "9000000000000000000" + }, + "2f16b101da9986a18f4b0d30a26557860338c4e0": { + "balance": "254907899725000000000" + }, + "2f4363df2c61273d230071286bb0157dfefee2cc": { + "balance": "64000000000000000000" + }, + "2f6099a8cb7bc3713b87dab20994d8dc09342003": { + "balance": "1902400000000000000000" + }, + "2f7b3902ce56f74adb0f83cc7d3a99df440cca1c": { + "balance": "825246221388000000000" + }, + "2f7d0298ff6a363375b7eecfe754fca0963c8a1b": { + "balance": "101000000000000000000" + }, + "2fb7c16232b3b1f2e3a676d6d5c93ae6fe5cb14e": { + "balance": "1000000000000000000" + }, + "2fbd5ccc716d2f510d10ec84def3fa69e49f46ca": { + "balance": "1000000000000000000" + }, + "2fd84376be11772e5d072cd74c96b0d9a49c27fb": { + "balance": "1000000000000000000" + }, + "2fdab070e20e2c8923a24c196bec72c33ff0f220": { + "balance": "64000000000000000000" + }, + "3003e6007f69902a0f5e4b4e6d0468277897fc70": { + "balance": "1501210602075000000000" + }, + "30095e6a4ccd1ac2014c3d1d98dce003d775708e": { + "balance": "500000000000000000000000" + }, + "300e47e0fa556371f6c882eb98423be44de7c239": { + "balance": "9108837665958000000000" + }, + "3011231224920b62bcfcbf0aed4fde35dd0a4bdb": { + "balance": "374689586073000000000" + }, + "304be24debce62e70943efddd20457d34e85ab40": { + "balance": "81000000000000000000" + }, + "30912555bb14023e9b7c90aa2314721918cdf1f9": { + "balance": "10000000000000000000000" + }, + "309a94ca7b44bc84a7909ee2b93ed1c94eaf75a1": { + "balance": "39000000000000" + }, + "30bcc93965fa36bbaabcd781326e42227c4e1a51": { + "balance": "10000000000000000000000" + }, + "30c71fed91d24bff69f286ff8f0c6c02a21736a8": { + "balance": "409782329653000000000" + }, + "30cbaf4103757013fd8fb71c44a985939e212b86": { + "balance": "7424807960947000000000" + }, + "30dd59e66093d0bfd87b09c5f6588b9857e9a6f7": { + "balance": "26123006239871345154" + }, + "30f692235f254b02f583d5b515f4701a35c7f692": { + "balance": "148184457997000000000" + }, + "310763019a24a927ce42b00604ee664ca53ff6d0": { + "balance": "393757908273000000000" + }, + "3118a5d4d06ca8b7c8835f4860e6973228000ee2": { + "balance": "56188713212579000000000" + }, + "311adec5bfcaed44680691cc644ee120a484aa05": { + "balance": "169000000000000000000" + }, + "3124e387aa7023995643344c782dac84b9d8c7d4": { + "balance": "1393596696367000000000" + }, + "31379702391cb5a737db3f3ffc336bd03aaa181f": { + "balance": "10000000000000000000000" + }, + "3145606c3ccbaf337610185ffac14ac4f0583c0b": { + "balance": "196454968572000000000" + }, + "315e11501d2c57a62af1631fc2662d4d8745401e": { + "balance": "225000000000000000000" + }, + "31a785ad3eea177c59fb575cad0b44f9a48a12e9": { + "balance": "38039017162416000000000" + }, + "31ae64035e95c1205bf957afb5e1636df00dea3d": { + "balance": "1718600907000000000" + }, + "31c0bb22fd2e9d22984f248a16ec3ed9ad834517": { + "balance": "5982762676000000000" + }, + "31e73a3b5451ebe1163571e9e0567c425bbbfb83": { + "balance": "10000000000000000000000" + }, + "322543c74039ef61fd051021b5e6f16b54bc7c1c": { + "balance": "101346282441000000000" + }, + "3233c7ed11c25bfc41d506c3ae0daf5a3c7c1278": { + "balance": "20000000000000000000" + }, + "325dae17b5225f6734a02c677d43fd126bea89b7": { + "balance": "365067246683000000000" + }, + "326ce8166a4094b93c15557f50f2b1d47811e72c": { + "balance": "16641460224765000000000" + }, + "32cf76046ae48b609524b1a6203eb6296d04853d": { + "balance": "1094839482061000000000" + }, + "33456a28f36aa240262cf95b78b4ac2cd8aa77f6": { + "balance": "3077123488326000000000" + }, + "3348bce2ef90ffd6a59ef5079e1af84b2dd604a7": { + "balance": "9000000000000000000" + }, + "334e5f0ae77dcd3d32dfc2c4ec6ab5e2826dc4b1": { + "balance": "3176777762079000000000" + }, + "335775e19200cd0305e529bc4cdf7295a47cb2d3": { + "balance": "2945631571804000000000" + }, + "336ba81ea6ec4f0da38c1a1761ed3d97fd3ca28c": { + "balance": "3587379203826000000000" + }, + "339191e03e9d5a08ae7b58f4c860235a0721b5a1": { + "balance": "2732237722000000000" + }, + "3399bf9f94c5488c89450257b39fdf3ec8c7f413": { + "balance": "477423805836000000000" + }, + "33cb8556a6c6c867e1be7de591cb22c1b7e9824e": { + "balance": "62293494164000000000" + }, + "33ed633804f39367078e830328dd223254be3366": { + "balance": "22842013797896000000000" + }, + "3409025dce86ad441a5a80f30ce03768d37e40bc": { + "balance": "1381667933000000000" + }, + "34153174cd4d3f1eaed7438638d302f6414d5965": { + "balance": "50000000000000000000000" + }, + "343c6b82b13f0dc82d4269e2c806d2d58e6dde35": { + "balance": "9546969736042000000000" + }, + "346089ea81f7dcb79caf2444df34bd6ee78be4bb": { + "balance": "4344080889000000000" + }, + "34984a8f96dbbfd1f977826a4c2187482559a2e4": { + "balance": "25000000000000000000" + }, + "34a5cce96d2211feb04472260c4cd368bda8432e": { + "balance": "1240050112677000000000" + }, + "34c026a39e44955d1051e8669f9cc58a027455c1": { + "balance": "20000000000000000000000" + }, + "34d730652f4aa002a9f39a47212ca3bc47506b8b": { + "balance": "418050617956000000000" + }, + "34e1d8c8a32ce0f6378abb9bd05ea1f9bfdc5782": { + "balance": "20000000000000000000000" + }, + "350b228870445141f4417ea5dba4f009d693b96c": { + "balance": "76995849736776000000000" + }, + "350eaec708d5d862831aa31be2c37b2fdcef97c6": { + "balance": "258753545822704000000000" + }, + "351fc1f25e88b4ccf090266ebb408593418d8fde": { + "balance": "10000000000000000000000" + }, + "3523ac7a6e79162bb8400bf161cb59389432aa51": { + "balance": "436606776923000000000" + }, + "354d490095e79a29bda2fa11823328450f14333b": { + "balance": "50000000000000000000" + }, + "355a555a36e319e76042e62875a15e1db3012b86": { + "balance": "20000000000000000000000" + }, + "3568840d0a26f39248ab088653ede831f150ce29": { + "balance": "16000000000000000000" + }, + "357096b9c1c7c8d51b682ed3c43d150f55629ff2": { + "balance": "900090781248000000000" + }, + "3588c47ba9204b672c456ee9b5c1ae70f3c738ac": { + "balance": "10000000000000000000000" + }, + "3591edeb9c036e871b4fc6fb3ae6d42e0c0d7203": { + "balance": "1000000000000000000" + }, + "359d92e3e8757a4a97187a96d408c0c11f5c7eb9": { + "balance": "22330509101591000000000" + }, + "35aac2a948f316ba93ed111ac127e29ee9a3adb0": { + "balance": "364387817746000000000" + }, + "35b20459a7daa5f44ae423fd4a1b451ea5090b09": { + "balance": "20000000000000000000000" + }, + "35cdaa84c1f3bc2673bc0c60222c133bae0d3db1": { + "balance": "15234182435000000000" + }, + "35d554233ca690130aaa43501e121a208c657226": { + "balance": "10000000000000000000000" + }, + "35ed399940ece44d01ac873b9c0d3212e659a97e": { + "balance": "55000000000000000000000000" + }, + "35f164612afc2d678bb770f317085ae68cce19bc": { + "balance": "693763596328000000000" + }, + "3601b36cb475101d0d0976a8de9d38e5f3483a08": { + "balance": "1000021000000000000" + }, + "361368bc42c8daf365bce9f9ff3b611373d7b690": { + "balance": "21658400518000000000" + }, + "361bc43be077a269e3e37c11e91479017c47f847": { + "balance": "268900383140000000000" + }, + "363c7a2203f6f93287de091bde3c87eb6800e7a7": { + "balance": "20874859005000000000" + }, + "365dc06856dc6ef35b75b1d4eabb00a7220f4fb5": { + "balance": "30000000000000000000" + }, + "3660e246bce68e2b6e4a802681f188587d2c1c99": { + "balance": "55000000000000000000000000" + }, + "366868ef8e193d7e649ee970d476e6774d5ff1ac": { + "balance": "2544456626840000000000" + }, + "366f7f762887cfb2d09cefa4a5108cf390bdeb41": { + "balance": "26837527714000000000" + }, + "36759f9c92a016b940424404de6548632c8721b1": { + "balance": "1033159825798000000000" + }, + "36a939be88508646709d36841110015bf7cedd90": { + "balance": "144000000000000000000" + }, + "36adca6635db6b00d28a250228532fe560127efb": { + "balance": "3370820618318000000000" + }, + "36bfaed8099ee9f216193ade26d21656c98ce4b5": { + "balance": "1353728563832000000000" + }, + "36df854d0123e271529a8767d1cded4e7b5f31d6": { + "balance": "10000000000000000000000" + }, + "36f59989a902cd10725ff7fe2cab1689aa4e9326": { + "balance": "20000000000000000000000" + }, + "370d6999ae70e781c81d12dc259ea304183b01eb": { + "balance": "45563989086590000000000" + }, + "370e8af59a64a3171b422913921a1e2f982dd512": { + "balance": "170263356254000000000" + }, + "372e01083072214134018f50bde3c8ac4f6e071d": { + "balance": "1400474252324000000000" + }, + "37410fda52f94185d824258ad5f3c9ad9a331257": { + "balance": "11830521097085000000000" + }, + "3752b7e1628275522cd693307787b9564501d959": { + "balance": "67839627078000000000" + }, + "3776f82701c384ce6cbf6a8fea40772cb882b66d": { + "balance": "50000000000000000000000" + }, + "379f63e538168925ba6313f9a6a3b6e7f0e8ed52": { + "balance": "292876625446000000000" + }, + "37a24c1a8080ab429a136c5582782b276eaa931f": { + "balance": "6099055841000000000" + }, + "37abbeaf24b5e6264c87633734852e243d377010": { + "balance": "1051360014489000000000" + }, + "37c50cecab8fe9dcd81aaede95050d27c53f4d45": { + "balance": "106051638566000000000" + }, + "37f82962c3097f0cd9ff605db66e792025a540cb": { + "balance": "10000000000000000000000" + }, + "382ba1e6c53cd7b9c360ef894962d281d557561f": { + "balance": "216789631461000000000" + }, + "38309b458993916efc1ac8b0b5d41302fec21095": { + "balance": "999139000000000000" + }, + "3847f25956a97a32caac059fd9e4cdc105756e25": { + "balance": "876497264905000000000" + }, + "384fe5f399638d277d4fb93f26d527497939287a": { + "balance": "280035151914000000000" + }, + "388335d8b92b445b1b19a3107547bb6ca7c0763c": { + "balance": "167140942784000000000" + }, + "3894a1e65973a542101caa4dc01e9553a5521d63": { + "balance": "34262479791000000000" + }, + "38a0e019c6120a19acaf0e651dd8338982cdaab1": { + "balance": "153843170492000000000" + }, + "38d4bdb10819a7d4ae9a32f4abb82402dff319b5": { + "balance": "1471131830647000000000" + }, + "38e56a55e2ac8320a480562f4a7cea9220306ee3": { + "balance": "907464312139000000000" + }, + "38f18123f3643e03d24ad759afbefc90ed923a2a": { + "balance": "943729130798000000000" + }, + "38f764c861def6d5d65e5ec099536f4cfcc3af55": { + "balance": "20000000000000000000000" + }, + "391e12b51fc85fb879a72fa746ca06c7a5659e6c": { + "balance": "9000000000000000000" + }, + "392342dc7b475c3975877a41622be0fed8e386be": { + "balance": "218719857770000000000" + }, + "3944cc960b8f1993ad841629a79e53d0535a88c8": { + "balance": "210571656485000000000" + }, + "396219864b8cfb0ffb3c675690ccd7026424ad4b": { + "balance": "138984508746000000000" + }, + "396403f26b388150b4876485b124a49845101464": { + "balance": "10000000000000000000000" + }, + "396f1e0f9e7ee86d1b2159ab8f9353677d12d340": { + "balance": "121000000000000000000" + }, + "397cc9f6254d56c721c767e41628a9078bea878c": { + "balance": "225000000000000000000" + }, + "39878b0c7049fb179aba0015279eff6cc3136816": { + "balance": "33962071375000000000" + }, + "3a06b58d0cceee5b091fe6aeb0fc0db5774e9395": { + "balance": "272033811720000000000" + }, + "3a3330e0152d86c5aa1d9bdfe9e1697645d3377e": { + "balance": "2165107207206000000000" + }, + "3a3bb8ed3130e09fbdfc21db3571d4711fc92d60": { + "balance": "885484658836000000000" + }, + "3a4ac96c489c864765cb1997a0084ba745b67a87": { + "balance": "1257436384863000000000" + }, + "3a69e1c351978ced418cea6cee019f220bcb065f": { + "balance": "579242822216000000000" + }, + "3a76a23d81929bed05ef7e1982d32b456e62aa7c": { + "balance": "1027078338792000000000" + }, + "3a7beadd1e11d0e3326c0dcd0f670530612931a5": { + "balance": "20633069818937000000000" + }, + "3a867c44d0dd06517a82ad467d0aefd7f11ce729": { + "balance": "12323708574000000000" + }, + "3a969ae486215e24c7ab89e38929562e2f85d923": { + "balance": "18955477335000000000" + }, + "3ab81366d898a8b798afb08a4b722ab0eb883652": { + "balance": "1220090012596000000000" + }, + "3ac1e14ed5929d382f6488c5444e717373ed29ba": { + "balance": "2030543873000000000" + }, + "3accf4b8ef20e4fea983f13f99ab257a5f9e988d": { + "balance": "156030342415000000000" + }, + "3ad38fa6e3c078025794e213d9dcc5aa397050c2": { + "balance": "36561766773000000000" + }, + "3adef81b2c861ae39c418d55be99aee2306e29fc": { + "balance": "15752410974000000000" + }, + "3b21ff4d5801d3976643899f195fbfd1b72a50b3": { + "balance": "8971221745646000000000" + }, + "3b2f2635dd428ac0b5873088a9a81800f09d6e02": { + "balance": "56922872447000000000" + }, + "3b39919c7bc8d0afec792288c56ab7f4934dc7d2": { + "balance": "1678237240464000000000" + }, + "3b468d9d5546810aa837c29ccb8349548b0e8170": { + "balance": "1100000000000000000" + }, + "3b83d1b651f117f1559a19b04ef408619c2dc4a7": { + "balance": "53628552066000000000" + }, + "3b9a72201bb1e8e678e36129cb1570e3ac99270e": { + "balance": "25000000000000000000" + }, + "3bcab1535b04a0a3fbb673bc41fedaa80bf7901c": { + "balance": "1526488015042000000000" + }, + "3bed42c3d0c49ffac87b9d482f6338fdc9e3880e": { + "balance": "26189771073000000000" + }, + "3bf736b57f0ae47f3714a6bb852090a543b9d367": { + "balance": "652395174320000000000" + }, + "3bfd481651956105ed909eeb98be404ec5ae77e9": { + "balance": "177520143473000000000" + }, + "3c0a12a327545b5f8b7b5c1f7a1ec6a341ec9578": { + "balance": "4184342789398000000000" + }, + "3c132698d59927fe08cba433a41d08acc96c0edd": { + "balance": "151913899135971000000000" + }, + "3c27bd92c4be1a19974ec773bd20b13afe582c9f": { + "balance": "10000000000000000000000" + }, + "3c2ad171573a608286f1fa3f5ef9e6099823983e": { + "balance": "3240802189194000000000" + }, + "3c4b5e808b9fb8baab1144b981b6cd53e216fcdd": { + "balance": "61214114118619000000000" + }, + "3c4cfc6ead044819ceb41c1c64ceda1a228af801": { + "balance": "9000000000000000000" + }, + "3c553afd45535f7c2a70c701d00890e607b96ffe": { + "balance": "2678827200938000000000" + }, + "3c620d55268c55b6deea3b7dc7f59dbe93b6e141": { + "balance": "55494311990000000000" + }, + "3c9b204db23b902d4295e6aba3405917efd59449": { + "balance": "55543672571000000000" + }, + "3cf233b7730a175d05a861318b7bb917bb5bee06": { + "balance": "1867187351033000000000" + }, + "3d292272992397ed5f27d5202da693128d023d35": { + "balance": "79770828413000000000" + }, + "3d353cfe84e9a93aef90547fbeb6e4b4bef83069": { + "balance": "36000000000000000000" + }, + "3d54da4ddd0621822a114581ecd15572e6488be9": { + "balance": "1623867132383000000000" + }, + "3d62ddc67d366fb055eaf92c936a6e7df5085454": { + "balance": "124933526793000000000" + }, + "3d754df1151b9b62a6ed48b477225121c29af063": { + "balance": "50000000000000000000000" + }, + "3d79d1ebd5224ffdc13e27924ab7f9f8e3452ec9": { + "balance": "520163228474000000000" + }, + "3d84fd9785a6bd3148847038c6f1e135042a892e": { + "balance": "10000000000000000000000" + }, + "3d9574c3860f30bcb42523a0cbb08aa7dd83e733": { + "balance": "15259904884000000000" + }, + "3da809a5911ccc77f892034049a97a9022c35e7d": { + "balance": "1415009021101000000000" + }, + "3db9a6c6ab3d0cf6d3bd7e04bdad39b4d419ab13": { + "balance": "9999781764000000000" + }, + "3dc7367c3218f88de8867c425f89102d2f2056f4": { + "balance": "10000000000000000000000" + }, + "3dd273dedb28824d1309c7d60a0744a6b6353e79": { + "balance": "9000000000000000000" + }, + "3dd6b25eb91dd2f3468e0786e8beb465abe7f515": { + "balance": "275172962210000000000" + }, + "3e0d14f83b304136311a33bbac2720c0cd66f117": { + "balance": "3390479675000000000" + }, + "3e15e947ee76f52f0f2a7d84da7c4ab060eb5cbf": { + "balance": "6751398714759000000000" + }, + "3e1b5469e1da4ec27537513f4df3f1a338a7dc2d": { + "balance": "161899580000000000000" + }, + "3e3329bcc90e47e4dabb5c93572b18b5e0efa024": { + "balance": "10000000000000000000000" + }, + "3e5a585ad0f34d78899433edaed574af052616f0": { + "balance": "910225655353000000000" + }, + "3e6be9615713bb06198bf354ef434a9db649699b": { + "balance": "783525278181000000000" + }, + "3e7c7c082f2f99b1ad579400a2e93586a24ed992": { + "balance": "159035553843000000000" + }, + "3e86ea5713f90022c0914fcc25e97c39487eb957": { + "balance": "101867287023438000000000" + }, + "3e9dabab6e50a696edfba6bcd44230d087c8d04c": { + "balance": "3315882414579000000000" + }, + "3ed956f86fe78223c86e164e4f372c9a0bf4a279": { + "balance": "119959915220000000000" + }, + "3ee87e776fb12e9c894e36fd5a61daa984e8a5cb": { + "balance": "50000000000000000000" + }, + "3ef1c8f294443f776a794563ce7569a8fe4d5d20": { + "balance": "25000000000000000000" + }, + "3ef6a396d6611df6c79ec1e6ad6bbd253917fbe9": { + "balance": "10000000000000000000000" + }, + "3ef727346fc631ae6473e9a36e2e5e54df696195": { + "balance": "121000000000000000000" + }, + "3efdcf2c0998637cb82d2b5fc24f27162578d207": { + "balance": "1054861112990000000000" + }, + "3f2cb2335e2bc07744175c497e2f437e87c2a146": { + "balance": "48999979000000000000" + }, + "3f4d16663a4f76ade93eb8bd6ca8fe2158e24322": { + "balance": "237117597268000000000" + }, + "3f7c5e6aea7f3f74d764df50f0fc1aa758fc99a7": { + "balance": "63372222562060000000000" + }, + "3f92239fdb41c6ec228252248c2db3f23675e275": { + "balance": "28538064487000000000" + }, + "3f9610454b621c04f00f01f4d54046502edb21fb": { + "balance": "16000000000000000000" + }, + "3fcfb30cbfe53c0c43f58c28386d9a6e5b49f7cd": { + "balance": "79080579219000000000" + }, + "3fda0c9a3d3f0000635376f064481d05d1b930bb": { + "balance": "10599947385000000000" + }, + "3ffce0475430de0bd9b09a412e404bc63aa28eea": { + "balance": "10000000000000000000000" + }, + "3ffe7583b568448ded5183e1544bca0d283680d2": { + "balance": "1076944549283000000000" + }, + "4003a137e577351a4ad7e42d1fc2d2cf1f906b6f": { + "balance": "25000000000000000000" + }, + "40215fc4c6300d8d8179383d9028fd2d909c6cc4": { + "balance": "3941346079000000000" + }, + "4027d7bbfa5d12c1ab9d08933a1659ae8dd023ee": { + "balance": "1156537386462000000000" + }, + "4039439c960070394dbda457726d97121c7b3669": { + "balance": "4444061364102000000000" + }, + "405978c24a12d930ada6163a44fc4a70c16569e1": { + "balance": "707298643296000000000" + }, + "405d2c1b55ba3f67c8634456b99c19092b407a10": { + "balance": "1462185951849000000000" + }, + "405ddfcf45005cf5a0ee1bfa605a7346a0167945": { + "balance": "88775535985000000000" + }, + "405f72a6940acf5d36a29498075f2d0d7a75bc22": { + "balance": "402796678569000000000" + }, + "407253b005ae97857f812fc60d441e5367b4bac8": { + "balance": "1484147810895000000000" + }, + "4091e1fb1c7af51a64c201d6a0c8f0183dfb7ca5": { + "balance": "10000000000000000000000" + }, + "40950bad9580d4b111955da7d3f9ada26dd9f05a": { + "balance": "500000000000000000000000" + }, + "409a28106192cae7a76c6aa8add0f73dcd63d2c0": { + "balance": "214832616721000000000" + }, + "409d5b872b059aea9a773e854f9a17ed2d5c2ef3": { + "balance": "64000000000000000000" + }, + "40a6e3c753b04c42fcf89cc30df8f50418caecb8": { + "balance": "754228409494000000000" + }, + "40e5ce1e18c78d6c792f46ed6246bfb31bcdb6af": { + "balance": "500000000000000000000000" + }, + "4121692a14554ddca1ca662fb577d7152d4fa7d0": { + "balance": "49000000000000000000" + }, + "412acb10c8ca937ddd64cf0d413b1dd34760f72b": { + "balance": "6073360870000000000" + }, + "4166a5c94d5ae48ced410f950d40656182bf8990": { + "balance": "55000000000000000000000000" + }, + "41752b7d0d3ee58a6b69d8ba721c0894ff701237": { + "balance": "585556720807000000000" + }, + "417c86d6bf734e99892a15294230771bbfd7e1e1": { + "balance": "38233258264000000000" + }, + "418414498f7361b29428c54732e1f49fb394f813": { + "balance": "2063786326155000000000" + }, + "41a424dcbff6bf31686f5c936e00d21e8a4e0f78": { + "balance": "33554754580438000000000" + }, + "41a893429d5f8487c1866b87779155d4bfe33198": { + "balance": "20000000000000000000000" + }, + "41bbedd607fa576d130305486824cd2871bf6b05": { + "balance": "649728993301000000000" + }, + "41ee42c1fb1bcdc9c7a97a199fdcf9b63623521a": { + "balance": "7906012418597000000000" + }, + "41feffaf56d1712af6965fa6eee1b06bd624e7b8": { + "balance": "49000000000000000000" + }, + "42107e765e77ea76b3d6069d3775bc3aef7d692c": { + "balance": "25320783684183000000000" + }, + "421f4dab3240e15a1c78e3ce8642de9b578b8e4a": { + "balance": "832511242936000000000" + }, + "4246c52c3601541a873d4bbaafedf28b9bad5b73": { + "balance": "10000000000000000000" + }, + "424efe1ba28bb1aeedc38a3a5135547d0fe80751": { + "balance": "25622294162729000000000" + }, + "424fb0a3ec325bf42e7edbef7e450f2ffd1cf318": { + "balance": "20000000000000000000000" + }, + "42714c04d17f6c29029daf7f50d1cbad6590cfad": { + "balance": "271755674161000000000" + }, + "42b66e9123d304b70fef3dbcfe8587fd6189b5c4": { + "balance": "1030481609000000000" + }, + "42dacbc412b829cb304ffbc316b3f81b379bfc80": { + "balance": "304208485736000000000" + }, + "42e3d9832c8b6cdea39c97525570391803dee276": { + "balance": "2581020833000000000" + }, + "42f757898f95c1b46f64a4a6b7f86ab03022d672": { + "balance": "100000000000000000000" + }, + "42f7956fd659e00d3be2f3d1d4f3ed187aef04d6": { + "balance": "50000000000000000000000" + }, + "43160b2bc00f7f8f7fc806e2f6e2ffdc62b3a651": { + "balance": "1000000000000000000000000" + }, + "431b77cdd067003eeed26c1aee32f67fb94f7092": { + "balance": "902514849986000000000" + }, + "434e44583786e354731bca250d94ef0d8860a538": { + "balance": "1187789683866000000000" + }, + "434f1b9b193c88bf58685124aac0167fe69f9014": { + "balance": "500000000000000000000000" + }, + "43535982688844fa703cb9bd5723790cab364049": { + "balance": "100000000000000000000000" + }, + "43559f405590592c254e427fa25f03e774d8defd": { + "balance": "6913200000000000000" + }, + "435c08c481d59308a64afec0d6f936321bb120bf": { + "balance": "9005920819593000000000" + }, + "43629748a92b846f21f637aac5103412fbabb9a6": { + "balance": "1177513692845000000000" + }, + "43650b37552882d225ccc977aa2b7a86a4ca9bb1": { + "balance": "16000000000000000000" + }, + "4385de394371d26a45f18e8b3842effd015027bf": { + "balance": "187331693412000000000" + }, + "4386ff9648fe420503c9a36fe7b97c079de3b770": { + "balance": "2714401478778000000000" + }, + "43b370c4457cf39a3be86cc00c2b27614ca6e638": { + "balance": "8316429850934000000000" + }, + "43c464ea740172fe6f4f09974106fd24029837b9": { + "balance": "129643160399000000000" + }, + "43ddd2d33dcb7e578f4e59ad6b9c61a24c793aa8": { + "balance": "500000000000000000000000" + }, + "43e0f8065eb7faf3bbd13bc7c5d5d8f5ff1bdac3": { + "balance": "4454324716300000000000" + }, + "43e96cd065d7934b246d0fec8cd2dc6b36d56d7a": { + "balance": "81721481452000000000" + }, + "43e99acabfbdc6cafee3afb12fa7ed1345370b2d": { + "balance": "4595292398872000000000" + }, + "43fae764c7555b859b93d2126edfa59cfbf298b5": { + "balance": "105746805109558000000000" + }, + "44052eb938c02776b5240f38ec99f5ef51ef0d87": { + "balance": "38446396949881000000000" + }, + "440fc7621cc17f121f0bdf2a68c5be2c3af4fd3b": { + "balance": "1026958147051000000000" + }, + "4440ccbc77249a4d891d9ab5a5f2026b17aff7c7": { + "balance": "10000000000000000000000" + }, + "447f3f702c13a3fbdc8675c6285702b5aa2b66bc": { + "balance": "1089533398014000000000" + }, + "448f152be153fdb0497403f70e37d876946a5021": { + "balance": "614429461682000000000" + }, + "44a1e3a044f5d1fb00f4beb3772a3ee08d8b7093": { + "balance": "1000000000000000000" + }, + "4515edc7154bedd7143b69a04c4e738f8aa4ab18": { + "balance": "10000000000000000000000" + }, + "4572148fe5ea9d4795e1f1ed93097aac1d70991c": { + "balance": "2873782218000000000" + }, + "457581f223b8eacd757abb292613e317d6f59305": { + "balance": "3582446780073000000000" + }, + "45b450961882850f7038d5cdcd2a8fa2dc4b5469": { + "balance": "20000000000000000000000" + }, + "45bdfdf3840d4341503cd7fc87e4b66f6179e5fe": { + "balance": "10000000000000000000000" + }, + "45dd9baa87b3c94df66308d8ed4f3a5bb65c3dcb": { + "balance": "25000000000000000000" + }, + "45de332b8ee95d886cf11b99291b46f46c1ddd45": { + "balance": "36000000000000000000" + }, + "45e06afdbc70288a2cc55bccc4fb2d8195aea028": { + "balance": "790360485306000000000" + }, + "45fce5fd1acb2bc5507723c897cb340437e39735": { + "balance": "100000000000000000000" + }, + "46045cddd940d80596826ce5354489b3047663bb": { + "balance": "100000000000000000000000" + }, + "4610286f8a2649dcfbc6d91735745f418a6abc75": { + "balance": "10000000000000000000000" + }, + "4615905ecc6f7df0ccb7b86a3e1d3770adb2f874": { + "balance": "1000000000000000" + }, + "46256e00ff927d54b0ca139ddccac2148784273b": { + "balance": "10000000000000000000000" + }, + "465e40e7d129ad310fc60ff0f17c0f968611118f": { + "balance": "677971225649000000000" + }, + "4664a920f7fe9b0d78a665e1a4aeb95f287d6059": { + "balance": "20000000000000000000000" + }, + "46679de1c6143138fd9c44ff05853a52371915ff": { + "balance": "363627463229000000000" + }, + "467cdc210ae48ba99740d37ee79fa57c4216bc81": { + "balance": "10000000000000000000000" + }, + "468053d193debb88735571acb24b764f2676272e": { + "balance": "49000000000000000000" + }, + "46826d1f1418abbe4e7b9236d643e5b57a0f0208": { + "balance": "37752144164916000000000" + }, + "468df2ea57972ddeb88d470a5f3c2c0e2284ac17": { + "balance": "757320434551000000000" + }, + "4695ad5b686520ee8426d24b50ff7a5f0d703443": { + "balance": "2851082366000000000" + }, + "46a149bc8ec2b85fdf938f753a6c53777dcca2b1": { + "balance": "10123698633000000000" + }, + "46c081440f760a21b74c2499bdda13aef8245930": { + "balance": "180752319265000000000" + }, + "46e615324f6e4fb242f9bfecffc0c802ba7733c9": { + "balance": "10000000000000000000000" + }, + "46eb54f09dbdaaf3b97a1f79a3d82ee2e902b3b8": { + "balance": "3430510380318000000000" + }, + "46ebb24b04919ec0164f0bafcebca2309f2d3035": { + "balance": "129155832233000000000" + }, + "4701f9fe78111011f820fe28c47522e601655678": { + "balance": "9000000000000000000" + }, + "473f44e2c1d5d7aa53cf7041d7ad19a0d9eaf1d8": { + "balance": "162679637505000000000" + }, + "474f8bf4d03a7efa4d190905ce062eea7c75118c": { + "balance": "1259904506149000000000" + }, + "47598330e862a4f7cbda8be74ac10cd5d370a55e": { + "balance": "291763101699000000000" + }, + "476455d48fc858a06bd7854fcf1bd60bcfde9ed3": { + "balance": "10000000000000000000000" + }, + "476826d58192ad822f4686311d6c6d4d4f66ee5f": { + "balance": "453184657722000000000" + }, + "47a231eb3fdbc24f2d008f06228624b2a45ae5fa": { + "balance": "1000000000000000000" + }, + "4805f4c0eb1c83c436118ec9148019e5fc1962e3": { + "balance": "1311161626928000000000" + }, + "4809f373cdd56c8481ba3bce5a401d55a7e50a50": { + "balance": "2284845194349000000000" + }, + "4839bf9ad56873abd5695057bf71972806cde827": { + "balance": "42264923611000000000" + }, + "486dba2a47decabc9a85d1d64d74687983ab273b": { + "balance": "49000000000000000000" + }, + "4877993f5ecf02451f8d4591594cb2f30dcf9f26": { + "balance": "100000000000000000000" + }, + "489723e325f609e27be14528c4111fb3eec13f7c": { + "balance": "2489030141000000000" + }, + "48b710d16e9da736b773453089d69cc6ede116b5": { + "balance": "26651593216000000000" + }, + "491088e1e4b5c3d65870f2deef9be6ec3dc6c7c7": { + "balance": "1446809481953000000000" + }, + "49174451320ad2e14cb2b05ecdd251b75ace3038": { + "balance": "15533380764616000000000" + }, + "4956ead915594b621131b2fc2dbbb49ba43c5559": { + "balance": "1175638488000000000" + }, + "4973a0d32147ba89f525a18f989518dcfce93b0e": { + "balance": "522848489444000000000" + }, + "498c6f9063705054fae07260d4176c3d55a97650": { + "balance": "732941433000000000" + }, + "49991f68f2a76bd1cffa3e9721be36f3fd8351b8": { + "balance": "17742568700019000000000" + }, + "499a8af194e0040f349e893937fe3858f8267fca": { + "balance": "80704784160862000000000" + }, + "49bcbb7b263febf54f8ff498525bac8e7241f966": { + "balance": "603044032468000000000" + }, + "49bd72773656c4e1a4d16284aea2fb05546d2b31": { + "balance": "1896607093054000000000" + }, + "49bf80fcdefebe8cd4830ba09e46ccd7231c8e6f": { + "balance": "10000000000000000000" + }, + "49c9d82dea78f14b1c52efc0196b67f508f7859b": { + "balance": "2313040051399000000000" + }, + "4a2daeacf0468d137e3bc464d6d5fa3893a9136b": { + "balance": "10000000000000000000000" + }, + "4a6c428f245e8d9115b34764bab17eb86ac472be": { + "balance": "10000000000000000000000" + }, + "4a6e8d037acf1960dbbf14e7a02fec0ac656f9c1": { + "balance": "6516295825438000000000" + }, + "4a7e7fc3c72f2f9b92bf0dcd5297cfb19f077d7c": { + "balance": "99426213999999999" + }, + "4aaa6817a5000bb7596e000135b3051c5931e7c5": { + "balance": "102884105546478000000000" + }, + "4abcdc3d7d3d314a163da92aee53a56b87313a2e": { + "balance": "44402243657000000000" + }, + "4ac9385ade2377b061f4211b392ed6a6e7fb83cc": { + "balance": "1000000000000000000" + }, + "4ac96e1e26cb66ff788ed8c62db811d7b4fdbc74": { + "balance": "68476115774000000000" + }, + "4b10c247caf33fb872d9bf86572424410aa86752": { + "balance": "337915294240000000000" + }, + "4b23ffff1894df49005c7afc0828880924571299": { + "balance": "169848767272000000000" + }, + "4b486895caf3a0b5afa198df744de7082eec8666": { + "balance": "1672587376054000000000" + }, + "4b98fc960610573be456c0e1e319f4f863bf9095": { + "balance": "259382246718303000000000" + }, + "4bc0cc483be20223f40ed6deef63dd9645c216c4": { + "balance": "4322684620000000000" + }, + "4bf4a046afdd4ec9d0e50730ff6ded5ef2327442": { + "balance": "70601389160000000000" + }, + "4c0149058e2e74f7c900e6d6e5fa12eea882c5e0": { + "balance": "2017399852886000000000" + }, + "4c17a3997fb70599794d01a33a27a6d5b52b6f01": { + "balance": "469002093209000000000" + }, + "4c4559e7b32340dce112cf7a021ced1b113f6dd9": { + "balance": "25000000000000000000" + }, + "4c4f02b3f232b8ce8485d425639271510cd0486f": { + "balance": "68828038140000000000" + }, + "4c52ec56142bb6e8c8830e5c17b01b5165915f3c": { + "balance": "321766233041000000000" + }, + "4c58defa57875e709ca039a54a2be5aed6672f6d": { + "balance": "121000000000000000000" + }, + "4c5a886ab90b6bac68677a7eb92a06bf33ff2930": { + "balance": "236899852150000000000" + }, + "4c60539363edbd812334a54543c40ecab8af2ac8": { + "balance": "3281904094699000000000" + }, + "4c76897d0d5d39195354194710c5e7f99bef63d1": { + "balance": "10232271258305000000000" + }, + "4ca3c03780c20a64f3b5ebb75669982a71ee8a71": { + "balance": "377172198976000000000" + }, + "4caf77eefe062a6f053a464171bc75254b47f52b": { + "balance": "20000000000000000000000" + }, + "4cb7d7ce805e56f6e47e94cd755b6d97f8f996a0": { + "balance": "120998866000000000000" + }, + "4cd34f8f3299d3b7aaee180baa0b432369e1b3d6": { + "balance": "197088135242000000000" + }, + "4cd7aaa5415d809f405f520e4c0319a6029b981b": { + "balance": "686627368232000000000" + }, + "4d01067555f1ef63883f25c562b07168f79fa80d": { + "balance": "17547055698000000000" + }, + "4d2cb4c1da53e227b08c0a269402e9243a13f08d": { + "balance": "324000000000000000000" + }, + "4d38bb5f48ec37b751d16de32a4896fbda479ce1": { + "balance": "802530078718000000000" + }, + "4db3e76e2f68896cecc9826e10a5e09df0352c28": { + "balance": "555180306924000000000" + }, + "4dc8730d9f032d33dc493bcd3c6375b38f41afff": { + "balance": "5726933881000000000" + }, + "4ddde96556f5185a13617f01ebd9102800bc9e9c": { + "balance": "1181822708402000000000" + }, + "4df9359cb204bf649668ff8086a7f5e24709083c": { + "balance": "262998978400000000000" + }, + "4e0a1a3dff0d33c418758263664b490140da9e01": { + "balance": "100000000000000000000" + }, + "4e0dd6d8de5caa3a3bf9fdd6f2d7b30618623cc0": { + "balance": "10000000000000000000" + }, + "4e11af85d184b7f5e56d6b54a99198e4a5594b38": { + "balance": "76658631121000000000" + }, + "4e314349abc52c686d47dc771ebc8040966be386": { + "balance": "632341985941000000000" + }, + "4e3fb09c35375106bece137dbe0e5491e872871b": { + "balance": "153648535396000000000" + }, + "4e4f0d606f7065bfb1545e60b5e684ae1934e055": { + "balance": "48998635468000000000" + }, + "4e50957aa6c91c548075add8ec625b74c0973abd": { + "balance": "1000000000000000000" + }, + "4e5c6efa76493f0e9422582016aac50539ae60d9": { + "balance": "2078967343000000000" + }, + "4e70bbcb50c4e875fd573dcb694908abf3b30b37": { + "balance": "20000000000000000000000" + }, + "4e7f5670a7dd168a0803e53b8bf72f4db280e3ae": { + "balance": "1658463113665000000000" + }, + "4edaf859990a10977bf378df45b32f93422c84b4": { + "balance": "121000000000000000000" + }, + "4ef41923a1a426772832d3c267adbd84e5994edd": { + "balance": "5432615017384000000000" + }, + "4f11a70d80f36f46ed0c2a5fff1a39b711f3bae5": { + "balance": "8415785077000000000" + }, + "4f159095afcc75b8f5cfc90c9d07a0d77ac8ed69": { + "balance": "25000000000000000000" + }, + "4f2652322736cc18b24af582d4022fe329a9dfb7": { + "balance": "9000000000000000000" + }, + "4f328173f352f3dfdca0ff5e3185f26de77c6f75": { + "balance": "10722917874680000000000" + }, + "4f47a62aba6ea049fc0e92d8afbe1682472d98bf": { + "balance": "10000000000000000000000" + }, + "4f4c3e89f1474fe0f20125fae97db0054e9e14e0": { + "balance": "50203638983000000000" + }, + "4f5ac8dfe79c366010eb340c6135fbee56f781d8": { + "balance": "50000000000000000000000" + }, + "4f672cbd373183d77d8bd791096c6ebb82fa9a2a": { + "balance": "978111227765000000000" + }, + "4fb179c9c88decaa9b21d8fc165889b8b5c56706": { + "balance": "24750205150000000000" + }, + "4fbcf391c765b244b321875d6ab4381c44d0747a": { + "balance": "99999580000000000000" + }, + "4fc979b38b981fca67dfa96c6a38a17816d00013": { + "balance": "1088876196468000000000" + }, + "4fdfdd1832b114b4404aae23305c346beee14e1d": { + "balance": "278724179057000000000" + }, + "4feffb1836029cd0e9b8f4aa94b35ae3982fa770": { + "balance": "1674590934924000000000" + }, + "50045745a859f8fce8a2becf2c2b883b3723b2c8": { + "balance": "169000000000000000000" + }, + "5028bde29fe88e03e3de069b3907fa9df551c379": { + "balance": "196000000000000000000" + }, + "507096ed771fa8a1d004ee5377c01506df461b32": { + "balance": "2669205000000000" + }, + "50788574a0967580fdaddc4758f834d8978455f6": { + "balance": "1648581593000000000" + }, + "508d8e8f338ca98d3c09f0f15fd9e7baa80701e8": { + "balance": "16000000000000000000" + }, + "50a4dc916845172b83764a6c8b4b00d6d02d41d3": { + "balance": "3020744393592000000000" + }, + "50da06418780c220ced4898af0b1fca533f73cca": { + "balance": "36486700700823000000000" + }, + "50fb6fd8432a66219e754234e9eea1dabcc07676": { + "balance": "489500000000000000" + }, + "5104bb1b831902333732dd25209afee810dfb4fe": { + "balance": "1333614132000000000" + }, + "513963743ec6ec9dc91abf356b807ebad64df221": { + "balance": "1508002412172000000000" + }, + "51397ca69d36e515a58882a04266179843727304": { + "balance": "941648956414000000000" + }, + "514a58f2b36c2cf1b6293c36360cf658d8af30ed": { + "balance": "1233397704089000000000" + }, + "514fe0cdb3de692cab9f2ef2fd774244df71be66": { + "balance": "9670444445882000000000" + }, + "51583128081fd800d9550144afebdf3fe88149cb": { + "balance": "231190355520000000000" + }, + "517384fe92391187d0e65747a17bfaadf967c331": { + "balance": "1943121865489000000000" + }, + "51aebfaa26a54071cfe6c2d8f81157ec313984ad": { + "balance": "1422225031261000000000" + }, + "51d4f1205b272e491e94fe21f0341465f14141fc": { + "balance": "552384783614000000000" + }, + "51de598faa85276bb26a68b135028755304b6700": { + "balance": "2068484560002000000000" + }, + "51e08e0304f08ef768c80ca149da4721fcf482b0": { + "balance": "194629207228000000000" + }, + "51fa3da695e24f602952a71966f37ac3596a94a4": { + "balance": "17008166261720000000000" + }, + "520b22776b1befd3064636da0dd251afe569ef13": { + "balance": "18538137781909000000000" + }, + "52219a1e1aa82b78b971088c30583a3bbe675c8e": { + "balance": "411959222637000000000" + }, + "5252b8a0688096523498cb5c1f42bcd1f61923d7": { + "balance": "1863936864000000000" + }, + "5259154e1a5a809b2e3dab80372124cebbfd56e2": { + "balance": "110000000000000" + }, + "5264f2de516835e549710bfe34ef03b08b8557dd": { + "balance": "1216000000000000000000" + }, + "52b17fae7e9cac447f026db71dba4034a1d53174": { + "balance": "99001631977000000000" + }, + "52b3363ae882a99354faeb76733d0fa2cbb89787": { + "balance": "102517584327000000000" + }, + "52bee7fb24a7fc1f34cf0874ec2f06c5fe847cb1": { + "balance": "54443400591000000000" + }, + "52d1f12d391c7a2f3b52939a61a20da5f85eecc3": { + "balance": "2707175772061000000000" + }, + "52f27099483589e883e7eb789896de39c61e46da": { + "balance": "358944977251000000000" + }, + "52f3b715b678de95d1befb292de14c70f89f5e03": { + "balance": "2989868434000000000" + }, + "53259780569f6dd6753c1da1d53d0b155c5b30d2": { + "balance": "200489122590000000000" + }, + "532e4908e8297c90d75d2280b432b469aaafa2ac": { + "balance": "20000000000000000" + }, + "5334d1e399feacabc9648cebcd93172db95d43be": { + "balance": "25000000000000000000" + }, + "5341665addfb5e367f7a7d35de95b87a0cceb3a9": { + "balance": "60544291695000000000" + }, + "535a39a854ed1c2f0afbc5944f1ee0e2e68cf65a": { + "balance": "2141913781000000000" + }, + "536515c0c08988ee69da1d75f18c706f6b9bf7a3": { + "balance": "169000000000000000000" + }, + "5387a1ce4cd2ef4f90075c15dc3c0744948ec356": { + "balance": "50000000000000000000000" + }, + "539a30ee5724978010990718bb8b0dd25f89fd15": { + "balance": "1306896514000000000" + }, + "53a5f87dfb17149b8c2934a2a9d519ace4ac9724": { + "balance": "4569449510000000000" + }, + "53b24fb36e72c22eb830dc93857a8188b03397a9": { + "balance": "64000000000000000000" + }, + "53cc35b3daf4b8e1982e0e63d0bc68d7252e7fcc": { + "balance": "68213426853658000000000" + }, + "53e1f85147e000ae1ff6a5910407395e388c683c": { + "balance": "20000000000000000000000" + }, + "541f43ff66ed5eb1a1ea0ae3f86355ecff665274": { + "balance": "49562725831000000000" + }, + "5428a31f736c0d2b3c4e80baefb75a76ed44d3f7": { + "balance": "10000000000000000000000" + }, + "542f732aec0873bf531f6941828b6f0ed0611106": { + "balance": "8407722276000000000" + }, + "54300b6a77b95545373b2bba73e60f37c31eb1c6": { + "balance": "1581215621996000000000" + }, + "5434bd65a492a4d14d3b97eb49f6e491350ef73c": { + "balance": "484000000000000000000" + }, + "5444a1735913eeac177d947ef38de7cd6bdfc0a6": { + "balance": "1000000000000000000000000" + }, + "544ffeab53bdc59ef8edaff0042b03c2ea123615": { + "balance": "10000000000000000000000" + }, + "54613713df6c5b89c3012a7835651f25cdac8331": { + "balance": "98684037547000000000" + }, + "5471fb39b4e48c118f855492830ad9e2eaa68179": { + "balance": "91791250228000000000" + }, + "5472591efd048dd60a4d6afdb549e95a65578b0a": { + "balance": "50000000000000000000000" + }, + "547b4c1ae70567fd77a896dc05eb536f502ac8a4": { + "balance": "14037444012000000000" + }, + "547fa9f6f86a2939f9144aacb74e0af60d434535": { + "balance": "428416957729000000000" + }, + "54841d6a478cb9b6e717a9de35577a1a4a504b0d": { + "balance": "144000000000000000000" + }, + "549157e5b1c92a88a0eef335b1bcf4d162482017": { + "balance": "21019502942000000000" + }, + "5492757c55c72ac5946b21514ee16c5065ecde7b": { + "balance": "10446737491000000000" + }, + "54984a41eeaa8e710e4e5b8a7f68c96057b7df3a": { + "balance": "10000000000000000000000" + }, + "549a3717a1bca3f38d24655197c3ccef1e8c273e": { + "balance": "4416133255000000000" + }, + "54b047fbe004191cd02f31163d29bd61ccfaadf7": { + "balance": "52649445905000000000" + }, + "54b125d8b260386633b756056b7d7e78e7071715": { + "balance": "10000000000000000000000" + }, + "54ffad1ae76ab45c4218ced27e49bf2745b2a2e7": { + "balance": "1426474871178000000000" + }, + "550b28968bae36f4e99780c6d7deb54c158be6d8": { + "balance": "10000000000000000000" + }, + "55117923e8393dbf233c0f10819e7de75569962c": { + "balance": "470094520022000000000" + }, + "554a2471e6ecf2320da545d559c40b8b622465ab": { + "balance": "4052895973949000000000" + }, + "55607b39da9480ed8f54d74d0818ab8798136589": { + "balance": "13704276648975000000000" + }, + "5561cbe99fd775f5d0f05903fd62ba4877b3319d": { + "balance": "1007596371374000000000" + }, + "559ba7ab58670d4a0b118bbf6aed7f6fdb276594": { + "balance": "3127762973000000000" + }, + "55b0bc444f2a5952a98f216f61cf07382da1e156": { + "balance": "18683409750727000000000" + }, + "55c0a02dc68123aca7ee0c9cd073ead50b16406e": { + "balance": "99999999580000000000000" + }, + "55c47d593952afd637050c5758a921a204f23fc6": { + "balance": "1615608723958000000000" + }, + "55c6855b3970e5a550f0c75d5727329476406d91": { + "balance": "600705012673000000000" + }, + "55eadbe33899f53138d0fb204f42e272f447cfd6": { + "balance": "1671128311341000000000" + }, + "55fa59fa0fbba06b7184ea78868d438176eb96eb": { + "balance": "1553000000000000000000" + }, + "560a11493b5a0ec28589e80276fe975ee26c6a3e": { + "balance": "10000000000000000000000" + }, + "560fbb31d83bf6dc49e5fb15bd582d70c49fd273": { + "balance": "46015432815000000000" + }, + "5620e17ccf094b1be1a93f6f3388fb96e3a90165": { + "balance": "484000000000000000000" + }, + "5633512298cf74f4d2b8663e6f291e9e25436e7f": { + "balance": "10026444446000000000" + }, + "564423f92b8841b3b1f8bdba443067b580916e65": { + "balance": "465451550122000000000" + }, + "56730e1d11a84970355c43ac7659f2f4786dadcd": { + "balance": "20000000000000000000000" + }, + "5678851984add045f3d054623c198dfd4665d54e": { + "balance": "227651903234000000000" + }, + "569cf18b4bcb99e3f3d27235f2c4c0d8d160af03": { + "balance": "4124979731000000000" + }, + "56ac5f2c3486a9ce744a71599ab89a606e7464a7": { + "balance": "9000000000000000000" + }, + "56bc5936a6ea37c1d0839bf64bcec0d366840ace": { + "balance": "14741201469670000000000" + }, + "56bf62e0135e903525cc46b0a3cce33f4a16880a": { + "balance": "534970476270000000000" + }, + "56da0781a80a0abf5dcda4da35861e9de601bfbb": { + "balance": "166898390441000000000" + }, + "56db15729e52d615a744a04f8a59d63e3b9f735b": { + "balance": "10000000000000000000000" + }, + "56e32ed78e7f5be6b00c28847efe7b3589cdae1a": { + "balance": "1046236086484000000000" + }, + "570f7a08150e0088178276f8116bc4103f885903": { + "balance": "1124393518440000000000" + }, + "57147fdd9b52ef53b4ebd4b5712d29da83f99374": { + "balance": "39000000000000" + }, + "57395fb355fe51f1b32c1baa4e9ee0fc2b8fe05c": { + "balance": "7701013675397000000000" + }, + "5752f0f11ed12bb1d5041b0cee4ddd500cd8806f": { + "balance": "151337200533000000000" + }, + "575907d73ad5ad4980a2037efbd20860afc67ad9": { + "balance": "3568754158000000000000" + }, + "576acb4c0bccc89903ad285ac08c70fde514aaf2": { + "balance": "25000000000000000000" + }, + "5784cb8a17cfb5392c4aeec2edbd173849ca6ee3": { + "balance": "15804767597000000000" + }, + "579234645eb857a3ca51230b3a02b964f8efa2f6": { + "balance": "20576922380000000000" + }, + "57989f9fa52b4c0502e7d0c3caac0c37a0b20516": { + "balance": "462711082812000000000" + }, + "57a55c376ea03c22e21c797d83e2fb039508ad3c": { + "balance": "10000000000000000000" + }, + "57d1612ea1fddacf088b62f625ad8cd49d7517cd": { + "balance": "18001023230648000000000" + }, + "5811590907050746b897efe65fea7b65710e1a2c": { + "balance": "310984892882000000000" + }, + "582ffd8c43966aa8ad3c6cecdfc18eddc56fe5c0": { + "balance": "69136214255000000000" + }, + "583b90b3c4d00b9ddf101efbce75bb811d969fe2": { + "balance": "7839200298177000000000" + }, + "5841fee8b1965141e51b8c146b6af00f6a879a8c": { + "balance": "1210322907244000000000" + }, + "5847a576f7799ba1a35e36906b2c2a5aadeb99b1": { + "balance": "183765768447000000000" + }, + "586dea7ada0a54150f5afcf54198db473ed046a2": { + "balance": "7123598380000000000" + }, + "586f545062ec7dc0ffc213eacd59af80660df570": { + "balance": "10000000000000000000000" + }, + "587187488758f67912bd5bb8a5be787a73d97ee3": { + "balance": "702757402654000000000" + }, + "58be0a3482dc3411571f047f4128387049cb9798": { + "balance": "1000000000000000000" + }, + "58d546e2ae82efc4d8efc887ac6fd30f7eb5dac6": { + "balance": "1486717153455000000000" + }, + "58e7010e6b8d97a556c0e7f0d90151224ebf674e": { + "balance": "20000000000000000000000" + }, + "58f991b3b12d29f09ff4cc2c6e83d576e95b1f59": { + "balance": "25000000000000000000" + }, + "5923a65a796934e69081715657e8dfec8874e40d": { + "balance": "10000000000000000000000" + }, + "593b7c43073b8954355ed76020ff3780dd6ae783": { + "balance": "1403468567787000000000" + }, + "5947f1dbd79a622bcc3fa64b19f9b6eda164dcce": { + "balance": "50000000000000000000" + }, + "596311e2fc09ae1eaee57900f2ca188afd5e68a6": { + "balance": "448723397560091000000000" + }, + "597a3adac4607d457c90817220f67eb4abcf129f": { + "balance": "18000240000000000000" + }, + "598201a9bcff0a773e9323338a8a094e9d9b3999": { + "balance": "74904485722481000000000" + }, + "599e93031704c2ce36308f44d4ff8166e71ae516": { + "balance": "100000000000000000000" + }, + "59af0178699f9f3d8f0ea645dda75356119a6e2e": { + "balance": "152462578058000000000" + }, + "59b0c06e40475cd75728797add9c69c3fdb17b4e": { + "balance": "23147237210000000000" + }, + "59b79577f183b9d39c2b458646a26b2fd6ed806e": { + "balance": "4244859516807000000000" + }, + "5a03b51d67a9c660258ebc030120d5d1d4f687c5": { + "balance": "4451691855300000000000" + }, + "5a0d03dff6754963c757eb15a3339ac6c4ba6196": { + "balance": "215126489934000000000" + }, + "5a34ab3937854e407a8739fa14574d3d20e30d6f": { + "balance": "1375979293937000000000" + }, + "5a352fbeb2fd78bbe0268b0efd34f68d401e2769": { + "balance": "27929247671418000000000" + }, + "5a47c2ca4c0fad7e2fc7bbdf5f2356d68843c564": { + "balance": "3218227936000000000" + }, + "5a538adb2c7f6a80634b0ec20ec5152ff6bb4d5f": { + "balance": "10000000000000000000000" + }, + "5a8fe770c221072a7cba79ae7759cae0185adde7": { + "balance": "11913943233694000000000" + }, + "5aafe1efac688583d7facb09d3e569d58fb5a357": { + "balance": "4713219466825000000000" + }, + "5ab68d762750d5185138187db7751c9f71db5836": { + "balance": "500000000000000000000000" + }, + "5acab69851959dd5a6f0673ef757009ed36dfa3b": { + "balance": "974443209942000000000" + }, + "5ad9f2ab11b5e59b756404395f350aad6019d7a7": { + "balance": "54151179981663000000000" + }, + "5b1dc013ba1a28235cc70e785a00eff8808faef6": { + "balance": "516289257133000000000" + }, + "5b1eeb44ef61c7f35482503b7041162bec9b1e32": { + "balance": "125493885394000000000" + }, + "5b3db31996bca4625d22330686128ec234270206": { + "balance": "362316593128000000000" + }, + "5b401fc9ff3be7cdf5f0df870843bbef94f43285": { + "balance": "1373804724122000000000" + }, + "5b47ba296069041f25768e61be14437b8a469e81": { + "balance": "3152706392234000000000" + }, + "5b5030b5057c0457c190489c5d709d7dbdddee8f": { + "balance": "1154404278000000000" + }, + "5b5a4a782d37154a307868cd79bec9cb2a8f0161": { + "balance": "100277816425153000000000" + }, + "5b5e0b6b7cc27b06456ba4c7816ac4e89e1e26a3": { + "balance": "1023749119000000000" + }, + "5b638e4b6dfdb6928b07586e63d5879dce69a1f8": { + "balance": "1000000000000000000000000" + }, + "5b7be81d6ff5228a2b8c2913deea3f86823f1dee": { + "balance": "36000000000000000000" + }, + "5b7c4804bc2b8c72f3112b73d44b59c0711f83cf": { + "balance": "6803857604000000000" + }, + "5ba26d941544d07100744d8ffd6595a8eb7770bc": { + "balance": "583051897662000000000" + }, + "5bd58fc88733632b63d4f26893bc5c08fb60e2ad": { + "balance": "3480620567502000000000" + }, + "5bd85b5f0ecad08133fceb486c43998e537b3451": { + "balance": "484263880245000000000" + }, + "5c12639a5ab107f9e580cbd2278568dde10758d6": { + "balance": "101293252434000000000" + }, + "5c5522df05d6c6d960394c4762599e74247ab102": { + "balance": "149088856773000000000" + }, + "5c722f3ac94421f95389756af9cd97d0eaa6b696": { + "balance": "1435349483553000000000" + }, + "5c7b14ce51abf629bb0953ee4e2d9d87fc86eb4d": { + "balance": "10000000000000000000000" + }, + "5c8b215403da4e7912c1a1704a949087e091b111": { + "balance": "1440961256910000000000" + }, + "5cab313964f6730888e4158234bbd4806db0286e": { + "balance": "32284637230203000000000" + }, + "5cd736bf65c99469490d0523b10a658178cab10b": { + "balance": "99740204082000000000" + }, + "5ce91ef7ae254b2bd6d910cbf0d380814200811b": { + "balance": "50000000000000000000000" + }, + "5d15fc3a0ba8b3d87b80f9bbf972320112c644f9": { + "balance": "64000000000000000000" + }, + "5d2ccc795b19df400f21f24c0dca4d0e9e898093": { + "balance": "10000000000000000000000" + }, + "5d879b8b31af1e400cf53eb7170f82583190b96f": { + "balance": "93765337844000000000" + }, + "5d8dd54178b68bb36e1963d47d29c123864fd0ef": { + "balance": "20000000000000000000000" + }, + "5da1653bbe8353134edfff6158211ad7ee21dbef": { + "balance": "1491149937915000000000" + }, + "5da733ef41a7bdc0cf7975f83ed24604fbb4d40b": { + "balance": "10343699901151000000000" + }, + "5ddf5d7306f7c603b8d3ff993f03906dca14cd8b": { + "balance": "862558469755000000000" + }, + "5de87ec54e2160c7c2a8eff2d859414737501ae2": { + "balance": "21579321171000000000" + }, + "5df1b805b1361c1f39ca844aebe5ecee8a8d06b2": { + "balance": "411820472746000000000" + }, + "5df86b0a183b5e7f702e4da582ce9a8116a05f61": { + "balance": "256000000000000000000" + }, + "5e22359e20dc14be6930c6c1ce5a0c81c039cac7": { + "balance": "10000000000000000000" + }, + "5e2d38a06f33c784303abf2012f9af12622d9e5a": { + "balance": "10000000000000000000000" + }, + "5e479e616585e7fa84bd6f7465d394a1c0302be7": { + "balance": "10000000000000000000000" + }, + "5e4a55027a0d372f6da042b7f73720b143347d9c": { + "balance": "16175516772000000000" + }, + "5e52e86eda3e05f96e353d7e3f0ee90f08864f84": { + "balance": "21255916842000000000" + }, + "5e91c4d3a21c9dfac2c0994ed8890c78d58626d5": { + "balance": "325349462011000000000" + }, + "5ea797b18caba45d5504e57b80b12f5f5ae630aa": { + "balance": "7805696321000000000" + }, + "5eaec8815e859c34dba88cfe7b7fe28572c964ba": { + "balance": "145852682588000000000" + }, + "5eb974b5716fc4712d431bec7fbb2c49057a7b84": { + "balance": "4890681156035000000000" + }, + "5ee5f8407dedbac839f509419051106219458006": { + "balance": "3042761975468000000000" + }, + "5ef782abb28d1ca889ceb3039eef98713effbf32": { + "balance": "40915083108000000000" + }, + "5f23b88f06430c42570ac3fa33b1c7503b388a3c": { + "balance": "2376070180325000000000" + }, + "5f2b1641c0f2605b090039851aacf297e35632ef": { + "balance": "141615261000000000" + }, + "5f44cc8083340e644d19d3debc84dc14a0cbc53f": { + "balance": "291829106275000000000" + }, + "5f633f89adcc70e9da0b66611a5da108b4b221cd": { + "balance": "50835573000000000" + }, + "5f94ef8e9612b03a5c6ffcf423ada9a19a40818f": { + "balance": "102566595099430000000000" + }, + "5fae1977b76a5e899b384f572e4d94855f9cb52f": { + "balance": "773616125740000000000" + }, + "5fbd22cb3de462c794e523fd1ce36f230cc84b83": { + "balance": "1009995132839000000000" + }, + "5fd91676bc95bd6b5e69db8b9216dc83ed9dddaa": { + "balance": "1000000000000000000" + }, + "5fdda8f5271a08cf1b830faa497019d75fa9d231": { + "balance": "4149626365000000000" + }, + "5fdea351c5eccedf2394fb54437b149ae423ecf3": { + "balance": "100000000000000000000000" + }, + "5fe70ee123cb2e03c768138b2f71c1e1ea75ad17": { + "balance": "1074496282650000000000" + }, + "5fec9df797214459f85a040a559b186ee9161c88": { + "balance": "205282872821268000000000" + }, + "60037df7e4092466656a6b9571437fc4600c66e3": { + "balance": "1000000000000000000000000" + }, + "6009a0bcf531640a5a7f1664a69fe0f64b564ede": { + "balance": "50170000000000000000" + }, + "601668d8b678c95ec5ef98d9d2624decbdd52e9b": { + "balance": "23592727870000000000" + }, + "6027bafcd0ade24fda8c345dcbc812d59df74bf7": { + "balance": "10000000000000000000000" + }, + "6029514f24825c1fadc68cf8614951de5d53268f": { + "balance": "1389262963614000000000" + }, + "606de6db14272a314d778cf0e67913b7fabea45c": { + "balance": "144000000000000000000" + }, + "6074f20675f975ae2c081930cae8f299710f0bba": { + "balance": "10000000000000000000000" + }, + "60850fa9e09d414af3690e4b5daefb1b906b0d20": { + "balance": "10000000000000000000000" + }, + "60ad0b6239dda5df7ac0f0ca941684cf20ae0fd8": { + "balance": "81000000000000000000" + }, + "60d6136e6db631be45fefb9667c3dfa69e9d6054": { + "balance": "651902184266000000000" + }, + "60d733dedec6886908520ba57cab8c9d5c2d7f7a": { + "balance": "555461746642000000000" + }, + "61202238aea4010d115c5c64322ad790576cee43": { + "balance": "10465801848035000000000" + }, + "6142d92b61111657de4b2d65698a3621411e3adc": { + "balance": "100000000000000000000" + }, + "61879bc1a022d9cac8b7d57c8f528065beb10bb2": { + "balance": "72766025231000000000" + }, + "618b15c9a60ad89e7fc28afc79bbf7f28d4998cf": { + "balance": "444855210015000000000" + }, + "61c1169e8ba43ee6b919e5be2eac19542eb913b4": { + "balance": "500000000000000000000000" + }, + "61f1cd6efce17f5458325f022f363fd9772d8f20": { + "balance": "19704989598372000000000" + }, + "61f7d39211a0af2e226d8cbc95fb673168653b0a": { + "balance": "484884476279000000000" + }, + "621aa67f09e6506efb2fd141f080fb1d96693a57": { + "balance": "1694451603196000000000" + }, + "62332fa5127b98bd2a627a0ac22d3a1bdb418efd": { + "balance": "926882233406000000000" + }, + "624a465696ad409586a2e67d84750ba50a971fee": { + "balance": "25000000000000000000" + }, + "624d866f0d61bdefc3ec2210bfe36b6d51018f9c": { + "balance": "199592183194000000000" + }, + "6255d6d3b49443891661b209056d530ecd63bcca": { + "balance": "10000000000000000000000" + }, + "626c484055e6739d46e2ff25190c8b3a4af3fe0f": { + "balance": "1485276462321000000000" + }, + "62865e637d723393ab9654d6439db7fb5abf8803": { + "balance": "10000000000000000000000" + }, + "628a47761d5ce755de88444aaf6d7736b911672f": { + "balance": "18625552918216000000000" + }, + "62df6a38e8b15a1c4f4a7aa7c1736c612f54a0e4": { + "balance": "16468111299582000000000" + }, + "631d7916ddbb5f7c469f8ba07cd48e377560319d": { + "balance": "2493487426430000000000" + }, + "632754f5afcae7dc36d9286cfcd91c14abf0f7bd": { + "balance": "1424933496931000000000" + }, + "635788343997ea9f145c508b0cd2ed36e180f46d": { + "balance": "143040938538000000000" + }, + "636973e7dbda9e3042a8c03e25696d0faf27f025": { + "balance": "5491869128148000000000" + }, + "63707efa26d34d7ceadf4e6439324e7bde0ebc3f": { + "balance": "1000000000000000000" + }, + "637d92494f7872d397340c9b5183dce354c8c43b": { + "balance": "724687404033000000000" + }, + "63b9c2e6762a431752f7669b8bbedae9f37120b3": { + "balance": "1360967549741000000000" + }, + "63bd281d8c4d1279519237a2b68f2a73c228f7e1": { + "balance": "217457311664000000000" + }, + "63c0eb8c9a0019e36ec9a731b4bd947271a5bed0": { + "balance": "36693488147419103230" + }, + "63c6362eff56de328a29b7e9d32ced28f3602b6b": { + "balance": "148335309448000000000" + }, + "63c979c787a7b037693cadfeda738ae33178c009": { + "balance": "81000000000000000000" + }, + "63d4621d91906215d32f6fbcee1ac48bd773f630": { + "balance": "1006939236069000000000" + }, + "63ff99fec1cbd2f6e83c0e6de3c0ea4b7c7e1398": { + "balance": "1201300688980000000000" + }, + "640ffd856e48528b05d5ef1e60348048ce291960": { + "balance": "20000000000000000000000" + }, + "641c25f7c380e2745c81a268384a029b2e2be0cf": { + "balance": "635133477665000000000" + }, + "6427792a164bbeab45f6c3acf17c76f721b90e81": { + "balance": "10000000000000000000000" + }, + "6437986b4c545af9c4a5ee96371a5807275e9221": { + "balance": "2951152516627000000000" + }, + "64460d09d1bc5c425d62bef5969eb0c5916963c3": { + "balance": "1680000000000000000" + }, + "646381f92216b97abbd86ca100a773eebdf7545b": { + "balance": "211234535515000000000" + }, + "649f73d1cafeb3ab0631432f04c9d08b9f438c22": { + "balance": "248900746448000000000" + }, + "64a239be45a92df83bb85b25f8ed7de5d82313b9": { + "balance": "100000000000000000000000" + }, + "64a3d97f82e3d42eea78bbcee31a95d33767b055": { + "balance": "2511466286000000000" + }, + "64ad579975888f455217e0f801e371900d9814c9": { + "balance": "7118859416319000000000" + }, + "64af5edbfec8adea679951662c08a781175688bb": { + "balance": "822966999709000000000" + }, + "64b7f2c22c20a59c07cb0dd7f8f692153c68f3f8": { + "balance": "20000000000000000000000" + }, + "64bc17e28d468b7b8368ee8a8375710d21c3ac5d": { + "balance": "875002262415000000000" + }, + "64d17aa662e56061cebb3c2e2421e637163e8dd3": { + "balance": "363241251465000000000" + }, + "64d714ec3145308e8f939bab7591b0773038b886": { + "balance": "338231954012000000000" + }, + "65199fc9ba95434382c108b44ac553534a9a3670": { + "balance": "2537340957145000000000" + }, + "6527c67c29e47833dc2440570596023318a7bd99": { + "balance": "555434226832000000000" + }, + "654b9d299077c90768c5ca6635e5802e8099f51a": { + "balance": "119004827465000000000" + }, + "655908513607cc38de35351ff3738b201bbf39d4": { + "balance": "652902936029000000000" + }, + "656ad16063b2d397788c231e537384ece94eb0d2": { + "balance": "63116382606000000000" + }, + "656e622970b8829a7cfe24f5b82696c7777683ba": { + "balance": "20390269890405000000000" + }, + "6583a6ff4dfcf447e3b163a61b0d5cb84ceee375": { + "balance": "3858529344000000000" + }, + "658d2b7e8a6517256efafd74321757d5c384a2b9": { + "balance": "221114751567000000000" + }, + "65920758857ee5b27b0f31487ccc3c5d6986df3a": { + "balance": "16272975796000000000" + }, + "659d60d67a07774ecc5cfea9e56809bec024d639": { + "balance": "20000000000000000000000" + }, + "65a1a3f968bab5fc1f097b8e297099a3d34ef45a": { + "balance": "16000000000000000000" + }, + "65b5e3163d20b2a6fc75c0219b7f97d83479a26d": { + "balance": "1716459529041000000000" + }, + "65c9bc3b8b0ce7c4d16b35abe1a5c285a59f672e": { + "balance": "20000000000000000000000" + }, + "65d5b458d9b1a9659c1125d20d970d5e6c29dc3e": { + "balance": "20000000000000000000000" + }, + "65e75bb8ade25eb7975ea12b9afdb17ac21063b3": { + "balance": "2270407774714000000000" + }, + "65ed78d0c4ef1150e8765b24b210f056e079cd59": { + "balance": "500000000000000000000000" + }, + "664ee5e334b8378928becfbf5d5e51daaf001125": { + "balance": "860160259186000000000" + }, + "6679bdb26adc179d046607d49f4b10c65d8a40d1": { + "balance": "436794739763000000000" + }, + "6680fe9d6eda3ab9fc4ac1ac933339b533eb682b": { + "balance": "551296206326000000000" + }, + "66a1249501cc5076b040bbb165ce032ace216ea2": { + "balance": "36000000000000000000" + }, + "66a475d014c2f976704bfb93ce78dbabbfc5e072": { + "balance": "1140135640169000000000" + }, + "66ae43d92e8fb2231fee8c72d720ff90cdd267ff": { + "balance": "796696150339000000000" + }, + "66b7e0c810d6959afa8210f6ca67e3e40bd24eb9": { + "balance": "16000000000000000000" + }, + "66bf8be16f33b111b2a425743bb7ebcdfbb35034": { + "balance": "538590591000000000" + }, + "66d2eaf7fe10900d93eab17823ebfde5486aa2b7": { + "balance": "121000000000000000000" + }, + "66e525bb01b3ede1a4a105bb6087ec8a76200616": { + "balance": "1506610219207000000000" + }, + "67291e0df83d6e9f1386e87a1792d7d147341df9": { + "balance": "272330177662000000000" + }, + "6730b27b62e064b9d63df3bcbb8c4bbb0e500afe": { + "balance": "331282968154000000000" + }, + "67318617bfe19b739fac9a126fd129223db52498": { + "balance": "12699924981000000000" + }, + "674dd0b036c91f3a83288af44897b4ceb2e15a12": { + "balance": "4352791270187000000000" + }, + "6751bffd04be55c86692994fed06694cb78b62ff": { + "balance": "26049487516000000000" + }, + "6768d99a0cdcd7bb7c7d0aeee466d6bdc7208bbc": { + "balance": "309909685000000000000" + }, + "677ba2de3e5c68a4c354c9e3129ed1c41025312b": { + "balance": "127426274611000000000" + }, + "67b83745856551f1878027843be20e1473191944": { + "balance": "185757248875000000000" + }, + "68170edcfaf2c6df4e6542b2856ad33e9e2d6623": { + "balance": "4003453949471000000000" + }, + "684ae403d9a08e4f4f971cfedf81094074daa77f": { + "balance": "25139713925794000000000" + }, + "684f3b8a749c002aa434bad6af7a3e2579c69315": { + "balance": "16000000000000000000" + }, + "68538a9e8246be5a5c5ea315cb325344062cf8c4": { + "balance": "14009193210480000000000" + }, + "68935ff3a3a3b6ef16ae7df58cee50b157658dd2": { + "balance": "20000000000000000000000" + }, + "689f508256ea64f5dbd6bb77f1ce1bdaf36d7152": { + "balance": "10000000000000000000000" + }, + "68a3e6e7c191a8c1add988bfbbb9b51d4f36f521": { + "balance": "10000000000000000000000" + }, + "68a74ff2a5577321f854b56d3834a55d3c41bd94": { + "balance": "88873831171000000000" + }, + "68e6da521bde13cf4e4f423a78fda2f69b3d1c2a": { + "balance": "538392460838000000000" + }, + "68ecd5cf8cf8d9704fafc36d8da53930afeb0553": { + "balance": "1090923641219767000000000" + }, + "68fd0b8e000bd2788be6cb10fc0496fe2cbe155d": { + "balance": "32853847745000000000" + }, + "6904045feb5ef94e096894b863d314ff8a0f206b": { + "balance": "9892165615000000000" + }, + "690fbae5153849bb20797af7b8dea66a728a06c3": { + "balance": "6082107223716000000000" + }, + "693d909842877d017e0f102e37a55024517dd0ae": { + "balance": "20000000000000000000000" + }, + "694cd00fac9cded484ef2cfcd44faf161354f288": { + "balance": "3049716150137000000000" + }, + "6964c3c2c7bc719ec94a51bc4bf412e137d2b4e9": { + "balance": "1000000000000000000000000" + }, + "69a5c692516940bebad8efaa2243a8fbdf2ade62": { + "balance": "2803346939929000000000" + }, + "69f566c44802b0140f5e1c9234f46006773c03d4": { + "balance": "20000000000000000000000" + }, + "6a17eef3a6bd407260f52067592226448182cdc3": { + "balance": "1116509364305000000000" + }, + "6a200e99a0f50aab32fa7373c7880817c81f472a": { + "balance": "1836680122795000000000" + }, + "6a2a29f5f441876816dd17856051040787f48a64": { + "balance": "1131603204000000000" + }, + "6a3f855c7dceb75d0de7fa18fbc2f40c81b76756": { + "balance": "32267494586000000000" + }, + "6a46af653b938643e781cc4a0edcf5357852fd21": { + "balance": "1140718780752000000000" + }, + "6a4b2e5b45da0d70621ce71f165a11078a1745e2": { + "balance": "3768326643000000000" + }, + "6a530c813595a5b7776cced05a865dedcb110d94": { + "balance": "270559347097000000000" + }, + "6a6e3e82f98ce891f47721770301dbe2652a9e25": { + "balance": "10000000000000000000000" + }, + "6a828d6f2f7f68bde4a12608024020e593540010": { + "balance": "7531817000000000" + }, + "6aaddd1f4ff6b4d414c87271619b826ead27f09f": { + "balance": "64000000000000000000" + }, + "6ae6bce1e2865ade0d02eff9899ea3767b5511cd": { + "balance": "6893781798524000000000" + }, + "6b04e7c6a837d218fd3322b87a267fdd979358ef": { + "balance": "302679180175000000000" + }, + "6b2210b8536803b134e69c5046904acafef48cdd": { + "balance": "47823456459000000000" + }, + "6b2da6f36c2e7f61cabd7580480065360c995c93": { + "balance": "55000000000000000000000000" + }, + "6b3401986f2be7ae5a4ec160b8f96b2a651fce73": { + "balance": "16000000000000000000" + }, + "6b3847774e99dec307dcf5bf5adba49df4a9f145": { + "balance": "43276069579000000000" + }, + "6b57f2d9d95cac67fd2f70c0911d48c7f09de072": { + "balance": "1000000000000000000" + }, + "6b65d736a8ca89ec8508b52e4aca5166f9703732": { + "balance": "766421968820000000000" + }, + "6bcc55d897829e98fc3f3ac8beb331e59c33b942": { + "balance": "318115956882000000000" + }, + "6bd76e7af1775b88743d5f53ede0ce846d3d7ced": { + "balance": "139548017482371000000000" + }, + "6bd7cca99acf6eed5842417c2327c642df5473fd": { + "balance": "3321731000000000" + }, + "6bf72c4d39d6700181954a8d386c3df216634412": { + "balance": "12742769034078000000000" + }, + "6bfd3aedeac7c6ec086c0a4ec29d2d0f5bd69bc5": { + "balance": "50000000000000000000000" + }, + "6c025962810a6fb8374af5e07d7fcd631d10b1ce": { + "balance": "674126722005000000000" + }, + "6c1b72df836f410038af9e020fa2ff2ead398ef4": { + "balance": "1851293017364000000000" + }, + "6c1fddb4254ff46b3750de322ebb7d6238c0a606": { + "balance": "9977629348276000000000" + }, + "6c37069a361c5c72355bb5a56879dd0a9735a237": { + "balance": "1062230154063000000000" + }, + "6cb166eeca248a234c971b2a864a7b3fdbe5a737": { + "balance": "390222992865000000000" + }, + "6cb797289059cadcfa77eab0365e6bf1ae12df46": { + "balance": "100000000000000000000" + }, + "6cc787e6bb4f484828b080330667b93953e7a3c9": { + "balance": "16106440380234000000000" + }, + "6cdf7b334fb2ef8115198d475d431eeb7d88df77": { + "balance": "1940904395351000000000" + }, + "6ced85b035b787e9e427d0904aaf96e011417310": { + "balance": "103417697874000000000" + }, + "6d6e09acc07f388cbab99e53959f75e9ad8f07bc": { + "balance": "1305917678000000000" + }, + "6da91b02f512f412d374392247a9aaa853e9dd59": { + "balance": "2300525907893000000000" + }, + "6de5d70481cd40db468f64227228cdd362ad9980": { + "balance": "10447389944082000000000" + }, + "6dea87255c9ebfa63f017209046e894ecbbc03b7": { + "balance": "1527216854064000000000" + }, + "6df6f6b9953c2f2a8ce5985e19dd6835ae2c566c": { + "balance": "6539856530000000000" + }, + "6e013c83cac111a38fbbf8d47778fda0d3af25d5": { + "balance": "12139181929380000000000" + }, + "6e18a484f402fd433a5ac4dee5a4b8bf6f22db47": { + "balance": "23215906572368000000000" + }, + "6e4fd058e4dcd502c2015f83f3677f680ec58110": { + "balance": "480059342014000000000" + }, + "6e501ac7357fc758caf5dff6c29a995c806a1a7f": { + "balance": "1573491311733000000000" + }, + "6e6912f9fc21dfba736055e6ccef074dd62dcc59": { + "balance": "256000000000000000000" + }, + "6e869c68511c1458f4fbed9a4c5296fe961eb47e": { + "balance": "68488423994541000000000" + }, + "6ea6827b377b3d3ecf7c7628ed8daad7fd8eab1e": { + "balance": "188825714738000000000" + }, + "6eb9237738339fcaad3763466509f23efd0c5054": { + "balance": "48417242786000000000" + }, + "6eb92a61390f9d9ecdac80a8833aa801c3926b13": { + "balance": "1412936326723000000000" + }, + "6ecb93f18153ef2d2a552286ea3b7436f1f8168c": { + "balance": "20272577229669000000000" + }, + "6ee087c04cf16f4768c783a548686448fd125914": { + "balance": "1397039628538000000000" + }, + "6efbae7a34c71233329d0bb4cbec45274824ebf4": { + "balance": "8910000000000000000" + }, + "6efcd6776f287c25a6eb3cf71018adc282eeab6d": { + "balance": "1310659853178000000000" + }, + "6f9ca805ddaaea5205e85778dedb2eff4a5aaa75": { + "balance": "2585733757016000000000" + }, + "6fbbea927469f4d18942ce0aade164828fe23a2a": { + "balance": "4671857880000000000" + }, + "6fbe9df6c42151c453502960d99170445dd3ac0a": { + "balance": "20060296562115000000000" + }, + "6fed121fb310431f1659e637f35f4c878a7256c7": { + "balance": "55170085399000000000" + }, + "6ff2dd5373bd72966ef48d3183c60d74a6549cb9": { + "balance": "24103445361000000000" + }, + "703a490c4783776da244384c964897491aed3711": { + "balance": "2001677632732000000000" + }, + "704dcd2d9f75f0bbfb73f2fe58bcbf4508374381": { + "balance": "439603954369000000000" + }, + "70859a14f33b8ab873fa5781a4af1ce40dff65c0": { + "balance": "10000000000000000000000" + }, + "70b9cdfa5f6d41c60e1c0d3f544f569c9b340ea2": { + "balance": "198355566698000000000" + }, + "70d0ee793e28e320b34267ef2df69050fca0a9e0": { + "balance": "8010660534227000000000" + }, + "70dc7e5951752c22a0e3c50e8e7b1f7af4971d51": { + "balance": "3991137321749000000000" + }, + "71057f5afbed7d82c92d50790e3797fd7395d036": { + "balance": "49000000000000000000" + }, + "7109a3b3d5d6af49693549728691099d696ce016": { + "balance": "4119694297000000000" + }, + "712231a5161745fa1b33c7b0f6e8c767e1de4f81": { + "balance": "1353809351914000000000" + }, + "712aa38999c0be211654e5c84f59e3b2e018f597": { + "balance": "160199774000000000000" + }, + "713229fc94a86b71a5bd1ea6498b9373e3f3c549": { + "balance": "98289185940000000000" + }, + "715de29a0b6f467b94d4a90dc767ad52d0fb3b9e": { + "balance": "948824982990000000000" + }, + "71776853ac97ce04b008c9a7b64156a3cafc52a4": { + "balance": "608309596513759000000000" + }, + "7189f6dcfe64e1ddbfb5e51fd5f3174bc636dd0e": { + "balance": "5674608906899000000000" + }, + "718a4da87464caf6e83ca374d5ef9255b8f7cc3e": { + "balance": "761891873568000000000" + }, + "71bc447761cdb68915cc2288b4929fdc0adce02d": { + "balance": "10000000000000000000" + }, + "71d78531896642069b725bf82fc385789c63217c": { + "balance": "33103960195000000000" + }, + "71e328deeafbb1724051d1062609c43eef56ecdf": { + "balance": "493550967964000000000" + }, + "71ed0310fb51b86a61794aea17a3c792dd301e3c": { + "balance": "3234918634449000000000" + }, + "71fa264f58041e41cfe36e8f8d4e0cb22ab71925": { + "balance": "5558941960000000000" + }, + "72059c57d0fc05bc02ba54ebea6cefd1efbeadf1": { + "balance": "4458278271443000000000" + }, + "720847a28916a532bcab33e1fcbde5d1c4d820bc": { + "balance": "1392418942284000000000" + }, + "723cd2b5b836b0ee8481d37b9c51b5f3f1beddd2": { + "balance": "1856420455522000000000" + }, + "72430c6664d23c7051b0e99912fa54dfadcfdeff": { + "balance": "102078926010505000000000" + }, + "72652c4320dda25348f15c0ecfeb4b3b3ceeb7c8": { + "balance": "307639955659000000000" + }, + "7288bd1b9f4c068dd5df9bcd6fec1ccecd240195": { + "balance": "80161087899000000000" + }, + "7299cb8a288abe8e1a22c11b53a903acb7db5827": { + "balance": "752198565719000000000" + }, + "72f6bc0c3ae437756c099e02e9c084febedc5569": { + "balance": "696294297587000000000" + }, + "730e5907b344c80e0a6115723a90a23e3635192f": { + "balance": "6056082041729000000000" + }, + "732e97b992e4f8a53034cf29cf11aacba7452261": { + "balance": "100000000000000000000000" + }, + "7339df65ce293b3d501647a04c83819099f0bd38": { + "balance": "706500983417000000000" + }, + "73482f8135ca2231db5e0e034a235a9d244a8656": { + "balance": "1143989148865000000000" + }, + "73769e43058d30a530048e5a2bea7e9333534e93": { + "balance": "113542901996000000000" + }, + "73bb9e6f1709fbb7964df7b3cc0f9170c3152f38": { + "balance": "1639793026701000000000" + }, + "73e261da7978764044ee916f88bf66680952607f": { + "balance": "100000000000000000000" + }, + "740154120c4f41c50b0aaa0636a2000ff1e870ad": { + "balance": "10000000000000000000000" + }, + "741fe2a1537284b70e97e3ff659eedfd7fc5b1b6": { + "balance": "75911502037000000000" + }, + "7420bb277d834763e4429db9bf37f053f71ab769": { + "balance": "3100160195046000000000" + }, + "74281371c3b569c774da6bab686e7d7a45d4dc4c": { + "balance": "25666397941223000000000" + }, + "7428d261b5418652c5ab248d6abc3d2af25d904a": { + "balance": "56252809397000000000" + }, + "742c876433297f5a8fd4a25f75ee9a607726bd3c": { + "balance": "4132793019677000000000" + }, + "74302036cf52e11aa3f32a371bb4992e2bdc3f39": { + "balance": "19557661364000000000" + }, + "7445c657c24d014f3a9dddc3e446868bc2dbd13e": { + "balance": "10000000000000000000000" + }, + "744b8fa69d2542be3557267edaeaf2cfa8a9e991": { + "balance": "16000000000000000000" + }, + "74728999963524e7cc1736abcb4deac630142c44": { + "balance": "37000250991000000000" + }, + "74926cbdacd0e871cad0d926c8e17cb2c00475b9": { + "balance": "20000000000000000000000" + }, + "749e115a9e675bb15af5e1c04f81fede07c40120": { + "balance": "440913547154000000000" + }, + "74b7e01acf825898544d6c1b61e53356be759c56": { + "balance": "25000000000000000000" + }, + "74c5fcf875e2e9b726a7cf6e176dc2f7eb84c200": { + "balance": "59208835472000000000" + }, + "74f44579859e4a7944dda7bd810088e116ae9910": { + "balance": "1038454108527000000000" + }, + "750b1e2955ba05c1fc8a1f9dbb1624ed11587edd": { + "balance": "9545712605000000000" + }, + "75375129cff2a051f656b91f868325c3b35ee1ae": { + "balance": "25000000000000000000" + }, + "753ca28fbd89081382a996fe938da7e6c3ae6cfd": { + "balance": "156582454263000000000" + }, + "753d91c04e554680cc32a97c1abc96280e8263ee": { + "balance": "725101425969000000000" + }, + "754e5b5d64c267e83fd4804d112725531cf5abe9": { + "balance": "83276113115000000000" + }, + "7588a96a2bc65569a6c124c4a4acc55863a8ab78": { + "balance": "24062602342000000000" + }, + "759075dc3a6b9d2499a74bc57e346c9ed7ff834e": { + "balance": "225000000000000000000" + }, + "7591d6fa043801fe12462e11d9e33a53f438c073": { + "balance": "1863874274000000000" + }, + "75bda5bdf6aa749bbd62b6107941a7dd9ce3880a": { + "balance": "36000000000000000000" + }, + "75c2d3a99f144c4b9962b49be9d0a81b203906e8": { + "balance": "9000000000000000000" + }, + "75f587a69a97eb4d1c4c4078418d5fa85dff6f94": { + "balance": "10000000000000000000000" + }, + "75f67649605f49d98d866102ea2d6881ead9bea0": { + "balance": "814929108418000000000" + }, + "7602abce0f510b6ca471fd8d734e21a2591886f6": { + "balance": "50000000001006000000000" + }, + "7629b788160531b0be28bf445bf305fbe2c514d2": { + "balance": "23022256366212000000000" + }, + "762aed2e3aa2293e69dc2110b1fc6c806ae799a5": { + "balance": "10000000000000000000000" + }, + "7637b89130bc3f87e90c618fd02d6dd27179101d": { + "balance": "77765738300000000000" + }, + "765136022facade53e7a95c0c7aa510787e674d5": { + "balance": "1478178932688000000000" + }, + "765274015a308a9e6b1f264e5bac592d267f2f7b": { + "balance": "3058788819393000000000" + }, + "765cbc0a89fd727a2c1a6b055139faee53f11330": { + "balance": "500000000000000000000000" + }, + "768bb6d4b190c18a0946d92073ee446d68d98a6f": { + "balance": "144000000000000000000" + }, + "76ae8079894c760f2850c02cf5a0d7bb41e5864d": { + "balance": "156059816821000000000" + }, + "76af4103a231b1302d314c486a0ba524d0427899": { + "balance": "10000000000000000000000" + }, + "76b6394cd02ddf761e981b6a6ce1654c0e575443": { + "balance": "1078304803757000000000" + }, + "76db33eafeaf965dcf15d5460b64a48b37285259": { + "balance": "1000000000000000000" + }, + "76e5721c0a39d41274f84cb572039967a07e9beb": { + "balance": "156298167226000000000" + }, + "76e6ca6ef145d2711ab27f82376a065cc6f62a29": { + "balance": "100000000000000000" + }, + "7705d637cf9f6ceaa452deaca7ccc581beb5fa34": { + "balance": "36254762908065000000000" + }, + "7706c80af4eb372e168501eedfe7bda6dc942243": { + "balance": "50000000000000000000000" + }, + "771493da92c9fc6c6b39a4071ae70d99f6a588d3": { + "balance": "2000677471360000000000" + }, + "7719206286f26144c0f20b5e1c35cf4495271152": { + "balance": "1380480863056000000000" + }, + "771adcba1409fa2df6db19d9f784abc81a7bbf36": { + "balance": "15416381820915000000000" + }, + "772f7baa80a852e05b2fb3903a36061da132b2d8": { + "balance": "121000000000000000000" + }, + "7731a4175eee5077e2ede48878e6e2a18fce0f9e": { + "balance": "10000000000000000000000" + }, + "77385deeba01e3cd7a63e13d6048011020f56724": { + "balance": "57204247488000000000" + }, + "776808e7688432755b9e91a838410d29e532c624": { + "balance": "120318608715941000000000" + }, + "776d1b406f63082b80e250c4a0073fa0d83b9090": { + "balance": "243779839900000000000" + }, + "779848a59036ee3cd23b93ff6d53620d874f0bee": { + "balance": "82228810849000000000" + }, + "77d02a031274bd4ed2a16f3cc29d94e755142036": { + "balance": "408567696646000000000" + }, + "77d609a407aa0d126d58090b8d635f5ab7a02d6d": { + "balance": "776754055755000000000" + }, + "77dec41e116301dbd6e542f139816bfd9bf6d154": { + "balance": "16335989583000000000" + }, + "780398b42f81167731a8ef6a8bd1d14942b83267": { + "balance": "25000000000000000000" + }, + "780a645d59027e7b0670d9565898dc00704cbe5f": { + "balance": "20000000000000000000000" + }, + "78182a7711c773f306ec42ce6da3e983cd49b00b": { + "balance": "580861257254000000000" + }, + "7822622f07fec12995c4bb8eb32d62aa7f00be05": { + "balance": "5018461926846000000000" + }, + "786410c679101c0ebf06fb4f36102368121f3c8b": { + "balance": "16098386724761000000000" + }, + "787d5476038ab0a09b846645285ada23ffd7318c": { + "balance": "492047430907000000000" + }, + "788e9e27ed979d1e7aefadda798f69df1de1d1bd": { + "balance": "30965301214000000000" + }, + "78ab2d2dfaf5d2580ed89c970e771572bc91d3be": { + "balance": "36000000000000000000" + }, + "78ab7ac6f379ff084a7acf4a1a31fe2e5a6834c0": { + "balance": "107332516726000000000" + }, + "78aba95da37385c736ef93d0ca8318baf6c5ff3e": { + "balance": "9000000000000000000" + }, + "78cecbd82229dc91a530bd555c9e45125e2a6bc7": { + "balance": "28474069251604000000000" + }, + "78d4df90990248f3ac67e492a0a1e3f4ee455507": { + "balance": "10000000000000000000" + }, + "78f6de3768abc604c49b10d798e0656948cd334e": { + "balance": "9000000000000000000" + }, + "7909aca95ed899743de222e56c231f9bed1b518a": { + "balance": "5355599376491000000000" + }, + "79193e660b4431e8aca9c821b7daa88064e33750": { + "balance": "100000000000000000000000" + }, + "792487caa23b0d9b9998002810cf29439f7190bb": { + "balance": "4828579961131000000000" + }, + "793f56adea51063243a9633ecc1d1e620a91f327": { + "balance": "926742377449000000000" + }, + "796d187077c1d7591583436ae64d10a641490ca5": { + "balance": "242664407084091000000000" + }, + "79a6b7fad3b5a655679450ca82818ec2d6f58688": { + "balance": "1400472715109000000000" + }, + "79acf627e67cedf48297c26fd135973bff6c57da": { + "balance": "444598475759000000000" + }, + "79ae0dda1964ff0191b98d28c9b52a79dc9ab078": { + "balance": "325908985422000000000" + }, + "79e71dcc52fa1b28226c519f715faa3cf63cfb09": { + "balance": "497898493594000000000" + }, + "79e98193ff8770f26af824734bbb1c2ce8197b6f": { + "balance": "10000000000000000000000" + }, + "79ff3d790d52c58b7317a415278e9058915d5241": { + "balance": "48502649691864000000000" + }, + "7a0b02d16d26e8f31e57106bbdad308f513d436c": { + "balance": "841000000000000000000" + }, + "7a1d422352ec7e6ca46131728e4b71f20ed84e2f": { + "balance": "50496873413000000000" + }, + "7a2a3fbe27e33df867ba8800788995d7662c046b": { + "balance": "100000000000000000000000" + }, + "7a629c4783079cd55633661d2b02e6706b45cf8e": { + "balance": "50000000000000000000000" + }, + "7a62d8875f53e54b775ee2f67f7e2ec137bf724f": { + "balance": "25000000000000000000" + }, + "7a67285fd883d36ea3107aa3fe7727c68a99eb2d": { + "balance": "254787158217000000000" + }, + "7a90fbec48492473d54b0fad128ceda94ea66100": { + "balance": "313715004199000000000" + }, + "7a9e11463d84a08140d698972e32e66bacf7a7c9": { + "balance": "3602603216258000000000" + }, + "7ac4f33e1b93ef0f9c15014e06da24904ef4419e": { + "balance": "101000000000000000" + }, + "7ae082ad247275fd5a9e77b127cee5693784e9e1": { + "balance": "1921957343533000000000" + }, + "7b27e070ca4158d13f8333b34842d4c28b678c92": { + "balance": "10000000000000000000000" + }, + "7b2e34374921e4dc10fd9cfc670a40f5d092da1b": { + "balance": "2098457950503000000000" + }, + "7b54c6c8041c8b09240de1ff06e0d3d2d8d877e0": { + "balance": "944752036841000000000" + }, + "7b5aecb798d8f4f5a04bdaef909e09a35bde8d47": { + "balance": "21975115049000000000" + }, + "7b88a7ef9201966bd1ca634779c3b7f40c22f0d7": { + "balance": "64344833519732000000000" + }, + "7b8c22ddc5c7e59e571587d7c776fa50e65f4845": { + "balance": "225108110445000000000" + }, + "7bb4d8a169f72432494ac362eeab005ce1e02d81": { + "balance": "2098993419448000000000" + }, + "7bbaaa6690698e749d095447bdd27207c0caee43": { + "balance": "490069993631000000000" + }, + "7bbf27f92f9f726381d4f68b21ed86af8f792d04": { + "balance": "806346082666000000000" + }, + "7bc6f172fd78953c3456c571ac8394756715d5fd": { + "balance": "81000000000000000000" + }, + "7bcca29b477730ee8f219a5d1bca24415c7a4625": { + "balance": "36273885000000000000" + }, + "7bd296e1cb29ad87ed28b0ed18440ee686b157e0": { + "balance": "35964679698000000000" + }, + "7bde6d49a1af34a5a9dac0b9007e9a5583c65ebd": { + "balance": "1041474566346000000000" + }, + "7bea6240f245e649563253fa4c1da39b12625da7": { + "balance": "100000000000000000000" + }, + "7bf096396c56f27f9c39c4056ee6cfcb0db44bc6": { + "balance": "407261849111000000000" + }, + "7c3b58d3ba283bd9b1580832e9d014eff48bff7f": { + "balance": "7074518779349000000000" + }, + "7c5a56c45f23c353ff9f6f71ec86c9a6a1a0ca67": { + "balance": "11277879639596900000000" + }, + "7c783ac9b07bc6576835635f37e7e3c137055c8c": { + "balance": "16253676225000000000" + }, + "7ca2fbc0a0d1370e95048a21a300eac4d6056df3": { + "balance": "2772084065617000000000" + }, + "7cbe95802a20eb765f9fcff0a068859cc35d2660": { + "balance": "255153842674000000000" + }, + "7d004fb3a6a81c00fd2872e8079ad2912841b0e0": { + "balance": "642630220843000000000" + }, + "7d30c788d4ea18849ebae1173373c8915ffd7a35": { + "balance": "61062263242000000000" + }, + "7d39324f5ff62e849b0f0f46ab8ee396fbd85581": { + "balance": "100000000000000000000000" + }, + "7db0ce6c04537417dca1dd3415a5bf213edc2028": { + "balance": "30393443462000000000" + }, + "7dcfaa795586c92f1ce7d5c7b10608fe6a773fe4": { + "balance": "183173395920000000000" + }, + "7ddd111cfdc3133f59b82568e3deefc3cf10b0d0": { + "balance": "5622149283840000000000" + }, + "7de81daaa7ed5cbf4d379cdd26ae353cbd5a2489": { + "balance": "10000000000000000000000" + }, + "7e0a11af993a41626c5564f719442c0dfd608ec5": { + "balance": "1532083534600000000000" + }, + "7e34971b187047e7f7980650630b936eedc11023": { + "balance": "10000000000000000000000" + }, + "7e5214e16851b33c4a4d29e5a06929461d3d9555": { + "balance": "371790231197000000000" + }, + "7e52ae9c7e4b888015a3a5af7a91444510aa18e2": { + "balance": "109879329128000000000" + }, + "7e69b383671f96b7abc2d1fed8b61477b87a58dd": { + "balance": "10000000000000000000000" + }, + "7e733b1fcadc9a20dc038fba74e236af0b5a39b3": { + "balance": "43583614302000000000" + }, + "7eadcf955c90040668fb0f75a61f687e4e41f314": { + "balance": "332201682206000000000" + }, + "7eb51f3ead1dd0f5384c199ad5518ec55f77d35c": { + "balance": "38487884822000000000" + }, + "7ee73c0d64caf46f47f439969060092ecafdecd9": { + "balance": "15063618320000000000" + }, + "7ee8e4c6742a4c6d8efbfacc4d56119bc6c74ea4": { + "balance": "31882319329000000000" + }, + "7f16d981521c06347db8324da38b25eab3cee23c": { + "balance": "400000000000000" + }, + "7f6ff7db81a26fe78dd80636f0b178c669344393": { + "balance": "10000000000000000" + }, + "7f792b094c0b96d6819823cf21bc0c402fc27bf9": { + "balance": "50000000000000000000000" + }, + "7f84ae97c21cc45a7e56603ddf97449d803fb246": { + "balance": "81000000000000000000" + }, + "7f89c2b9daba034841f19ae843cfb6cd6f75b1d7": { + "balance": "20000000000000000000000" + }, + "7fb18f8b0e1fd1ed8c863a66226082bdc0429ee6": { + "balance": "11465417544634000000000" + }, + "7fb4e30579c64efe981d0057204e5bd8770a1f87": { + "balance": "249801873762000000000" + }, + "7fcc4de10e837d98691acc52732e1568c890304a": { + "balance": "1000000000000000000" + }, + "7fcc77798cd50345b2784a78b81a25dd4c1e64ab": { + "balance": "2676882485895000000000" + }, + "7fe33e773a02b995278ff595d55a0741813b19d4": { + "balance": "5788279057355000000000" + }, + "7ff32b13d531ceef500ca6c6806ffc0773639264": { + "balance": "1000000000000000" + }, + "801380158ef8f24316bdceaa00eb89c3d886707e": { + "balance": "35627521347898000000000" + }, + "804fdccdc8603858d15dec88666437505b2a106a": { + "balance": "14607090269617000000000" + }, + "807915567eed99bb9146354a32409812b9490d70": { + "balance": "1083142734057000000000" + }, + "8092ceeb2be5b271f4c156d85fe14977e919c7e0": { + "balance": "761607160308000000000" + }, + "80962bf961d0d713395dbe00379a6e207b425a76": { + "balance": "524215754483000000000" + }, + "80a9787124075c8cd44b9c8674967a54445e2354": { + "balance": "7600078997429000000000" + }, + "80aacd59dd76bf443c47ca02976178af8453f23a": { + "balance": "411856023767000000000" + }, + "80db788f7fbd7613f0fff66c21389eedbbd4bd35": { + "balance": "956888725645000000000" + }, + "80e449a70e3c7707d6441ae8863a44aee2d7f3f2": { + "balance": "16260784762856000000000" + }, + "811a2c3d0ba4e1c36a848495585da824ec3a7620": { + "balance": "36000000000000000000" + }, + "812a3c55234d5849a854ad76891c34ee90c8a0e3": { + "balance": "703378980438000000000" + }, + "814b4b5eb67afb8d1a60e3d240fe804bb752f632": { + "balance": "17578964576000000000" + }, + "817025619f37838470b90d0a25af2c02de80dae6": { + "balance": "96000000000000000000" + }, + "817233a104d87cac34d9c90243aebd7f68e0a9ea": { + "balance": "510051038684000000000" + }, + "818be95c0c13c3018b4084ea177556705e84c1f5": { + "balance": "332239667000000000" + }, + "819618c19a4a490b821f8156c5633749ea782ca2": { + "balance": "10000000000000000000000" + }, + "81a80d26b70626e07e8747bc1569dd2855834f7c": { + "balance": "521696417321000000000" + }, + "81b2fb0db882bf2538cf8788bae1ad850cef3bab": { + "balance": "102457067052000000000" + }, + "81d4c3bf72837b21203b2a4f90bf42fda10acf48": { + "balance": "10000000000000000000000" + }, + "81df59e5d7b9a2db5463b53be83b4d7c7673d163": { + "balance": "887372337013000000000" + }, + "81ef38d074e0aa9ad618deaab01bcd135301fb67": { + "balance": "24072930558567000000000" + }, + "81f3a4c5291f13f8f97a067a6ed744a686331eaf": { + "balance": "56612148225000000000" + }, + "820610d0ddd3e9f3893f7cc13f32b1ad0d169f81": { + "balance": "50000000000000000000" + }, + "822d6388145e96cdeb2900420a0e0436e940b670": { + "balance": "20000000000000000000000" + }, + "82323b748fdee9f18e34aefc4ddebd4993ac6293": { + "balance": "112752706047881000000000" + }, + "82324995b36f4ff15be3559ccee14742d5b4c75a": { + "balance": "1184047304377000000000" + }, + "8235bfba0bf0fb664271ebe534616456a78852ce": { + "balance": "6804584686000000000" + }, + "824df7b17a61392f88f7e3067f8c261abb48806b": { + "balance": "144857897574000000000" + }, + "82555a7aebfc95a01a3773aa5370394cadef0302": { + "balance": "40069354268401000000000" + }, + "82831d451b8f92fbf6a763adb708010a3e66bb60": { + "balance": "8750983992240000000000" + }, + "8294176178418f46bb18440cc87a07cf40c1669d": { + "balance": "4439783816461000000000" + }, + "82a1c733c3c937ba0a1a49481e4d1f6226157d2a": { + "balance": "50000000000000000000000" + }, + "82ad0b5dc23bc763da0352f5983efceeaee6ea08": { + "balance": "171723633433000000000" + }, + "82b4a3d16655fd71f4020e6a562592a621ff6e1c": { + "balance": "190211621484000000000" + }, + "8357d5a016a00aa5e3ef05d3ce210826adf4c501": { + "balance": "10000000000000000" + }, + "836c41d7f9e72131eff839b7d510fd0ed412f939": { + "balance": "15575572364757000000000" + }, + "8377fff2b0eb03393543ddf5ffae90b3311af5d3": { + "balance": "2058810049054000000000" + }, + "838859e6fd751539a88d00581b0e19bc98c37e47": { + "balance": "338264241636000000000" + }, + "838da0414211392b644e73541e51e9f0fba26615": { + "balance": "20000000000000000000000" + }, + "83958896a43d23ef4ba01bdf6757c36105985096": { + "balance": "9000000000000000000" + }, + "83b88314b606df40d5e716df488980bc64125b46": { + "balance": "10985538717083000000000" + }, + "83bf53fa162e1d85751be0bc6f46e8ec881392e2": { + "balance": "1497107276676000000000" + }, + "83d7c52608b445e18fb1e28dc6198908d66bb6d8": { + "balance": "265446362740000000000" + }, + "83ee8ebaed62092d2116de6b4e90778454e8dfc4": { + "balance": "1000000000000000000000000" + }, + "8402fe573658250f50fbe111596ce35ea9ec01ca": { + "balance": "3479737676000000000" + }, + "8412b877e708a7d5db2a38d9b0f4f23d12231f63": { + "balance": "9225027744855000000000" + }, + "8418dcc09fe052febf2946ee22bcc8c53d548eb6": { + "balance": "3000000000000000" + }, + "84199f54ef96bda5e14f60aa1723e811f755d3bb": { + "balance": "129197612052433000000000" + }, + "841b1400f97ecd2ca008e7b4f5a95274bc3e99dc": { + "balance": "2095180906854000000000" + }, + "844177191a120d2dc4be9169ddbc3b5430e9e238": { + "balance": "3620793599287000000000" + }, + "84578fcffc73be7d65bfa81b0cdafd26885bafbc": { + "balance": "37592478429000000000" + }, + "8460acb05c6c476ca26495aec7224c2bf90996fc": { + "balance": "8999580000000000000" + }, + "84696cdb9f018d3e7bf453efdc174e1a586e9c25": { + "balance": "118007806297016000000000" + }, + "846a8a91d2890000d1e995fc1663cf5b7c22211c": { + "balance": "27266838638307000000000" + }, + "846b5ef52d5f7ccc17d9c7e5f49db807908c63f3": { + "balance": "375423381758000000000" + }, + "847409e5d6ed2c4e54ff97f2ed58217ac5fc3d68": { + "balance": "23972870617025000000000" + }, + "84bf432c967540caafb8bf49cdc9983e8953a18a": { + "balance": "453476687224000000000" + }, + "84eba1bb76f7a3f6d2b9052d068cc6c48d449d76": { + "balance": "17655334922000000000" + }, + "851245ef1637a07578241b3c35acf215908e1898": { + "balance": "1269389304110000000000" + }, + "853708e974fd4810655d9cd19fc8dbfd3d5e1e36": { + "balance": "18000534000000000000" + }, + "8547989af8c99a3432038a03d3fb30a054d90413": { + "balance": "10000000000000000000000" + }, + "854ba39bac4c7bf619804b6773fe43bc71f3255d": { + "balance": "15999580000000000000" + }, + "85636f3e113cbe1d1bbd1b3a23e9e98edbcb94f2": { + "balance": "1199038399611000000000" + }, + "857167896b859394babf897c4c6fa57b3a057117": { + "balance": "921057404898000000000" + }, + "85799226a1474371ca76f05597a1e3835c17e7d7": { + "balance": "562141544946000000000" + }, + "85a2221cbbb47e8b74fc2617d6087a98f47e2738": { + "balance": "10000000000000000000000" + }, + "85be0bd55fb9143ff17387914a82d0a2650224c4": { + "balance": "4038654147145000000000" + }, + "85c5ff0e4956ef0fb662a2cbf6a86325a53dac8a": { + "balance": "28690160424000000000" + }, + "85caff4ec0e1719ad963e97c1c02828683070370": { + "balance": "2022427900763000000000" + }, + "8630cc2780fee566f172ed0437264c45421ce675": { + "balance": "669721278148000000000" + }, + "8633d245c5f1b63403e3d7828dc197ce1cfafc0f": { + "balance": "10000000000000000000000" + }, + "867ccceae3192a27751d870ae13b1d3d2c3584dc": { + "balance": "1491436265909000000000" + }, + "868bed241f77983ff4a7a8d0bf121299b6b2248b": { + "balance": "5600000000000000000" + }, + "868ddd283a76a26c8bbb9761df3ca647bea267e2": { + "balance": "9000000000000000000" + }, + "8696e546f96f6e51f405905e095902db8bb90118": { + "balance": "533558981421000000000" + }, + "86ac0eae4e4c20cb7019325f4dbebad053f92213": { + "balance": "697960117764000000000" + }, + "86bef47f9d2cd7526495454eb4d1737510696a5f": { + "balance": "2938307902381000000000" + }, + "86ddd4e3f444b395be8b2b2b75c35c78877fefb7": { + "balance": "15615434748526000000000" + }, + "86f115ed19a32aba4f98270b8ad45820abbc4653": { + "balance": "151868798605000000000" + }, + "870f19e7ee358de61ad0fd3c7710441156d68f66": { + "balance": "674715936435000000000" + }, + "87141a2d3857fb8a328ef8e7b503ed965294c85d": { + "balance": "1609607183158000000000" + }, + "87257783d866af25a7a71b46ea6c2bd1e9ab9596": { + "balance": "64000000000000000000" + }, + "87298979a9a0dbc272b0e15b7e5f2e42639c9912": { + "balance": "722087160930000000000" + }, + "8757b784015f88d072229176cabefa358a0e95a4": { + "balance": "204003337866000000000" + }, + "8760e60a56c5b8b61276634a571400023f08e3ac": { + "balance": "1000000000000000000" + }, + "877e54ea7e8ab03bb8e2b842dadab16bf4ae0a4c": { + "balance": "341020957932000000000" + }, + "87919285fc5d98169bbd073cebb1b3a564264dd8": { + "balance": "579080463078000000000" + }, + "87c39cfaa9c82d84119f306e6a233a3abfbb0ad1": { + "balance": "121753433796000000000" + }, + "87d479659a472af7c8ea78a3c658605f8c40bec6": { + "balance": "20000000000000000000000" + }, + "87d933ad6fba603950da9d245b9387880e6d9def": { + "balance": "1087642723520000000000" + }, + "87ec448309024bb1b756116b81652ea518cf353d": { + "balance": "344562808694000000000" + }, + "87fbbe010837f8907cc01a5bbd967f402a216488": { + "balance": "185411503628000000000" + }, + "8805a3c529bef4d19a6491f3b7d7b1b7232bb93d": { + "balance": "264150205918000000000" + }, + "880ec9548864fcd51f711ab731d847260ed0e3d5": { + "balance": "723225945994000000000" + }, + "8818d160b56b18e196871a6c7ccf02112dc13342": { + "balance": "2857439182291000000000" + }, + "8836e25baa08c19a9b0155c57072582b49f7dbef": { + "balance": "5468425690148000000000" + }, + "885b6303d06142accf2ddddbbdd4a9379d1cd124": { + "balance": "11853214736000000000" + }, + "88656958d9cd758d71546ba52c4ea646b658c84c": { + "balance": "10000000000000000000000" + }, + "88740acdf9ab5711d015391fe8cf4a7c70a0bc86": { + "balance": "510027156671000000000" + }, + "8874966976d776c3154261afa802692afedf3d3d": { + "balance": "305634301700000000000" + }, + "88aea53c727d7a5dd8a416e49faba1c4f741f01a": { + "balance": "15358334295959000000000" + }, + "88b67d05997ae3852259ca638a00ce9b9e7e4a61": { + "balance": "278125551806452000000000" + }, + "88d730e074a102048008de81d3adcba831335736": { + "balance": "5984576042159000000000" + }, + "88da27b1f0a604a87fdedd9ea51087a331179cb4": { + "balance": "10000000000000000000000" + }, + "88efaa91dab9671f5c903e69aa6ca4d9a04b5ddb": { + "balance": "1996126782729000000000" + }, + "89a9d702f64f14fae4d1a69717744dd700208d9a": { + "balance": "251686323241000000000" + }, + "89ac81571265bebbf9d3c09e9459fd1ba7fb1297": { + "balance": "162368080974000000000" + }, + "89c75c4f0ce41d283587beba1a3e3efab05ca6ad": { + "balance": "16000000000000000000" + }, + "89d44cb81cc5a1bdf4d573c4954ee641f3cb91d1": { + "balance": "97965629614355000000000" + }, + "89e2fef4f7b7c255b36afa81cf4033b22de3db25": { + "balance": "7278615226888000000000" + }, + "89fe5d3cb5283c7b87daf6103bb568f92a230631": { + "balance": "64000000000000000000" + }, + "8a07242231f4a654aeea65b857d1519385a18065": { + "balance": "20000000000000000000000" + }, + "8a5a415f0fe2a8329e14628493d11ca20d4e482a": { + "balance": "157274758238000000000" + }, + "8a6ce9f270fe3ec33a013be9e5b1ef823c0dab53": { + "balance": "20672772672000000000" + }, + "8a6fe4fa2f86f879ec9b2bf643beeb0876da46d4": { + "balance": "1041983771868000000000" + }, + "8a765ff2b429dcdf59b65a34c4bb41798dfb5886": { + "balance": "355487172996000000000" + }, + "8a9b9b65a3d443a6e4dcf696a64983f3b625774f": { + "balance": "3185351572575000000000" + }, + "8ab1f5443cf9149773b9ddb69de3e6ea047ae38f": { + "balance": "161619949415000000000" + }, + "8abeacee0078e07fb417277e8bf15dcc2cdb9fa7": { + "balance": "144000000000000000000" + }, + "8ac0d9e0e77aa4ada4080604f2118b3a5a0f8102": { + "balance": "100000000000000000" + }, + "8adae0dc99300f60d31bfa619ec83d45b48ea22b": { + "balance": "697262590215000000000" + }, + "8aef59e59a27a8662043f1a4abcaf945a5e3fafc": { + "balance": "26780431538000000000" + }, + "8b3386f32e2d77526c223ee8bb95b7dd111ced92": { + "balance": "2179932854210000000000" + }, + "8b34d5e457ef6451bb7f5ecc93c80678a30e3194": { + "balance": "31492358338840000000000" + }, + "8b47e07f192c33bd7d298bae717dfcd68a8097ae": { + "balance": "1000000000000000000000000" + }, + "8b55bff4b281f6a24ab428d66b91f9bab06f7b96": { + "balance": "1596248680941000000000" + }, + "8b576b1e2391f22193bb4f91bec5f2a8aec02af7": { + "balance": "29660301836269000000000" + }, + "8b9097b762c7bc38a487974f3551fea697087553": { + "balance": "260887123991000000000" + }, + "8b92c50e1c39466f900a578edb20a49356c4fe24": { + "balance": "35654824979000000000" + }, + "8ba3933337108841a997accf0b5735e005373f53": { + "balance": "574965182000000000" + }, + "8ba3eeb2d1b27e021ed6bf5827280807f32c7897": { + "balance": "64000000000000000000" + }, + "8bb23a5b8c48ec5bde84f39b463559b7c048c853": { + "balance": "16186405874000000000" + }, + "8be0b6ab14e15b46905335d07df03726fb1df0e8": { + "balance": "500000000000000000000000" + }, + "8bfc53af1ae6931f47ad7f7ed2f807f70fddb24e": { + "balance": "20000000000000000000" + }, + "8c0599df87df142d3aea37d50c975c1813ecb642": { + "balance": "871085782287000000000" + }, + "8c2deeeaf095be075a2646ed7b8764d3665acf14": { + "balance": "10000000000000000000000" + }, + "8c3e7381b0598356ff81e860faf25390ae7de9d9": { + "balance": "36000000000000000000" + }, + "8c5671a6f4610ddbd05a5139659c7190f54117b5": { + "balance": "50000000000000000000000" + }, + "8c60582c4e4e60da665b4a5a2d18f514ded6c49d": { + "balance": "16806447782991000000000" + }, + "8c8464ea6b17687eec36ef04966d59c7c91fa092": { + "balance": "1872124465602000000000" + }, + "8c85c5a318cc0227576adba3e91dce6adc73f6a2": { + "balance": "52479305517000000000" + }, + "8c8f3796a2942a2298d14ff1a9e3264e9f63f2bd": { + "balance": "10000000000000000000000" + }, + "8cec1886f2cc71b09ca32a1cf77a280ae3a6a9fe": { + "balance": "500000000000000000000000" + }, + "8d0b26d57eb52a62814d7876d64c8274f4371464": { + "balance": "20794037603000000000" + }, + "8d40b92e41f3cfec06e767d64b4dafc5612133b6": { + "balance": "25000000000000000000" + }, + "8d41ea1cfb70d0ef1f6572fd72a6b417739ac7dc": { + "balance": "738777348304000000000" + }, + "8d4eb54646f9d14882fc8ebb0ef15f6056d1afbb": { + "balance": "1003867239086000000000" + }, + "8d51ab29ccd190bfe12bcd94a651e9f49a003253": { + "balance": "442251355663000000000" + }, + "8d6c0c8e4ca47626115433b39feb939014b8738f": { + "balance": "119828137027000000000" + }, + "8d7acd92d664a485625bb9884e7cac9cc6077f41": { + "balance": "1381910232084000000000" + }, + "8d7ee7a9c1c263ba8061f54dcf62d9f8420e2008": { + "balance": "20000000000000000000000" + }, + "8d941c5d0c6e2b8e2934c9f80f8a63e2fb5868ef": { + "balance": "116443644149000000000" + }, + "8da0dc43ed3ccefb18f21aa13f3fa42c13e540a6": { + "balance": "516000000000000000000" + }, + "8dab4500316475e8fc3bb6494be09f549dedf026": { + "balance": "2736245677000000000" + }, + "8db39a95f4e63bde0bd8c02e386122ce2c57a30f": { + "balance": "12577347153000000000" + }, + "8dc718b49fb68584d9472490743f9be1b0ad683b": { + "balance": "50000000000000000000000" + }, + "8dd05e26224aa8a6deb0904b6d3bbb34d268e901": { + "balance": "613146658282863000000000" + }, + "8dda0e7ddde515480ef08cf90a1eb4e78f50a2c4": { + "balance": "19265526663314000000000" + }, + "8dedad1511c11798c338334dde7be967de96e9b2": { + "balance": "50000000000000000000000" + }, + "8df63c04f18a854d7bb397bca3e2ba19202e9da1": { + "balance": "1479940547081000000000" + }, + "8dfd7edb7d28e8b3df1faab70a8ef9e3b923d998": { + "balance": "10000000000000000000000" + }, + "8e2c3af057e931b5f82e83873b336a7f68e7eb03": { + "balance": "27138009123000000000" + }, + "8e2f4eaddd60468bdc09d47f65839b96f50596ef": { + "balance": "970529157231000000000" + }, + "8e750010c88ba99d75b0b5943c716d6fc0d01802": { + "balance": "42271114987000000000" + }, + "8e889d47f3307a18490e53f2108dc31b14d6300e": { + "balance": "115722965933000000000" + }, + "8e9e1953c82217ba56365e7a9c54b1ded73914bd": { + "balance": "6248835752208000000000" + }, + "8ec980d3066cb6afa793577cf88ccb46ce8d13f2": { + "balance": "100000000000000000000000" + }, + "8ef324c861de7e042c445776bcc8ac026533bc15": { + "balance": "1869634994148000000000" + }, + "8efd14464465e50af087a80a5fbe652445de373d": { + "balance": "1157403424927000000000" + }, + "8f1b57304406fd8b2eb5dabcbd322e326dd873f5": { + "balance": "194188733254000000000" + }, + "8f36ffd921e12083e374335d3cc43fcfeeadfa46": { + "balance": "100000000000000000000000" + }, + "8f813b88e6e125eab71a63455f326322ef505501": { + "balance": "19087691927734000000000" + }, + "8f83892d4d2892cd57828fde2318610a54b14498": { + "balance": "22833507983000000000" + }, + "8f89c1bcba85757cf1718d5b9eb007e27e5195ab": { + "balance": "2241600478705000000000" + }, + "8f927ab63df4c2ce46f1ea35bc875a0c006d2d4f": { + "balance": "327487123409000000000" + }, + "8fc3c231df0f93a84bbe348aff12ab576284d70f": { + "balance": "25000000000000000000" + }, + "8ffa089b07ed1388a5d1a428daf54d9591e734e6": { + "balance": "1347580402248000000000" + }, + "90040e00f585f8be44c82597037fde452472e741": { + "balance": "2746884591879000000000" + }, + "9034eb46aad2a76bdb812c981565d4701dc10718": { + "balance": "10000000000000000000" + }, + "904ca1ac2381702bd18472b175262a8928cde5f1": { + "balance": "304421909590000000000" + }, + "90502c1123692c3b86e99b328d07fae473d4a283": { + "balance": "227491252462000000000" + }, + "9052ca7e9623c1bbe3568668673d6d252b56a764": { + "balance": "35268091378000000000" + }, + "9093d12d8410193293e1fda0cca98a43b85b91a8": { + "balance": "6829489147119000000000" + }, + "909ba8cdc707c12ba577dcd8ed1df1c02a7ce2ef": { + "balance": "60524108169000000000" + }, + "90a2cc3aa73495531691e027a8c02783cea7941d": { + "balance": "65263780625000000000" + }, + "90d7c82615f151953a8d71a68096cee4d428619c": { + "balance": "298774379499000000000" + }, + "90e02deb31d98b9c85fcaa7876eb5ec51d721dd4": { + "balance": "2000000000000000000" + }, + "90e538746bbfc6181514338a608181a3c4286d1d": { + "balance": "6069511690189000000000" + }, + "9106dddc1b693e7dcb85f1dc13563d6c7c9d8a6e": { + "balance": "1977000091291000000000" + }, + "910d1e0d3f71054835ee0d4cd87054dd7add3e38": { + "balance": "40104690362000000000" + }, + "912e2349b791fe702692a6c1ccbf6f0f06b826db": { + "balance": "6305336897000000000" + }, + "9144cc61c01eb819e654b46730620c230da9e936": { + "balance": "144000000000000000000" + }, + "91478d4c15d9ba02816456030915be08fa3aa208": { + "balance": "200078339107000000000" + }, + "9160c466b5f9020b0ab1c0ff497bf0345598ec90": { + "balance": "17705350930000000000" + }, + "919025625787101c572d8340ead1444a96593424": { + "balance": "2418027749789000000000" + }, + "91926323868c65f91b6d74c85c07279610651ede": { + "balance": "538073886450000000000" + }, + "91950cd6e2dd99e024854b65c09c5a7476777a21": { + "balance": "11629505934425000000000" + }, + "91ae8d74c26d3dcc291db208fc0783347fcc197f": { + "balance": "7604593786920000000000" + }, + "91b9ac26869abc9eb3090f1d8140eabe97f41001": { + "balance": "25000000000000000000" + }, + "91c349651afb604f9b00a08e097e02c0964e148a": { + "balance": "117290771022000000000" + }, + "91ddc95cadeb6dcf6ebbdb3300a29699ac8ded39": { + "balance": "20000000000000000000000" + }, + "91ebbd36714cc069f8ce46f3e0eda5504fdd3aa2": { + "balance": "203944728497000000000" + }, + "91f2765125b84923bd506a719d72b0c1de030e32": { + "balance": "452269960816000000000" + }, + "91f2e54a9d61ef52a33d150da50d5a8f2ebcd6bf": { + "balance": "242321058694000000000" + }, + "920dc90d11e087a0d8912c1d43db102e9ba4f43e": { + "balance": "20000000000000000000000" + }, + "922ff522cf7f3ce0bab9312132df51704caa755b": { + "balance": "1414824682473000000000" + }, + "9251449b0f757ef62f63c2774eb63ba15bf3712b": { + "balance": "102688517037000000000" + }, + "926255c17386720fdc1701747a2f024475063d4a": { + "balance": "25000000000000000000" + }, + "92808a38ffc5a339b1ab6b0b472f9975718d4a07": { + "balance": "500000000000000000000000" + }, + "9286c4497e820845341e3b9127813c1b7c884830": { + "balance": "101241387488275000000000" + }, + "9298e1df6730e91e9892d19f7ce18a3db9b5d2a1": { + "balance": "169000000000000000000" + }, + "92d98aed335c29402a43ba96c610251bed97308b": { + "balance": "3032350763000000000" + }, + "9319153f24814a81d920c60cbee9b5f2f275fac0": { + "balance": "56619610984000000000" + }, + "9347532d6396bc0b86bcd34eb80facd4c3690684": { + "balance": "258912194626000000000" + }, + "93487691d71e6248d88f06b1fbaee58b6fe34615": { + "balance": "1593901704394000000000" + }, + "9375154a7f19783b26ae1c9e48f114e1cfd1307a": { + "balance": "9000000000000000000" + }, + "9377947e0db688bb09c9ca3838ca2197fb262a1e": { + "balance": "323993393587000000000" + }, + "939ca9030b28d356dc1b071169f98b0728a9aef3": { + "balance": "218900305967000000000" + }, + "93b71636b8332515c2af031aac7a8805de716a62": { + "balance": "1640174743698000000000" + }, + "93bca153afd427b0c3c1de4a5584610e4a6595b7": { + "balance": "654782426410000000000" + }, + "93cb3b73fee80cedacf5197f8b4ac8f18f0d0184": { + "balance": "100000000000000000000" + }, + "940fcd215bab373d1b736e354f2def501244885a": { + "balance": "13133641534585000000000" + }, + "943f4bc76f20580b6546b6aff2800448f82cfdc0": { + "balance": "1927982550280000000000" + }, + "946ddb5c46fb13010b9c7ec56e4055b4f3e24b4a": { + "balance": "1410000000000000000" + }, + "947961dc367226f78d722361d5821cced52db01b": { + "balance": "115598797369000000000" + }, + "948eab3ffe44d5f1f381de2c8cadcb311c25df2a": { + "balance": "870664355820000000000" + }, + "94bf674593378243fb6b811f331f77561efb4106": { + "balance": "226539311455000000000" + }, + "94ce082887dd6324d7dcfa6cae17b653be021b25": { + "balance": "420000000000000000000" + }, + "94e2aaa4b5e2b36a12f866c96e3382a1150a97b4": { + "balance": "7344059136611000000000" + }, + "94ea5b1cdceb3f1a9d5ecacb6ac8dd2db9a461d7": { + "balance": "1951787237292000000000" + }, + "95218633176c0fe2f32fb55ad3df9f387e63aed1": { + "balance": "99999999580000000000000" + }, + "9543cb22853a46cce3aadc60e46cbddbd3fcf593": { + "balance": "2806074281914000000000" + }, + "958842c5389656d156aab05ac1731a20656716ff": { + "balance": "391064461038000000000" + }, + "958fd9bbc96531a00adc5c484d06dc61ccd717b6": { + "balance": "8021794447667000000000" + }, + "9593ce72919cb0648ddacc58af233d942963e2e6": { + "balance": "32322940730755000000000" + }, + "95a8e371af9128c97c9d4d7c4d58f5f75f2d07d4": { + "balance": "49000000000000000000" + }, + "95b9a9ad563a4c1ff7b6ebcf5fabcf5dbdb4a6a3": { + "balance": "10000000000000000000000" + }, + "95ef5fac6aa3ab1b4a87246fa800cfceff43dec7": { + "balance": "119666779022000000000" + }, + "961a3aa8015cd520de43bd47d81f5194ee4dfdc2": { + "balance": "248589901007000000000" + }, + "962bad39df25d64ee1c6b4ae9c14a18d316bfc06": { + "balance": "2404608291000000000" + }, + "96392119198c4b644c64284c9a75f61210a6292d": { + "balance": "1000000000000000000" + }, + "963c82319380587eeba0bd7b07eb63ea7042984b": { + "balance": "1480123630618000000000" + }, + "963e05fb6245ec11d67ed80e9feba6e2c0a8b4ae": { + "balance": "276053287417000000000" + }, + "964452b86b0d1d4b34aa881509a99e7b631d4a85": { + "balance": "64000000000000000000" + }, + "9644a2af2ff70eb43584a4351bfbe027c42ba3f9": { + "balance": "500000000000000000000000" + }, + "96572a017489450f2dfc0e31928576acd3bc6808": { + "balance": "1140183097730000000000" + }, + "9686bfcc0dc3de20604eb77787d0dba818cc5016": { + "balance": "10593448987804000000000" + }, + "96879780764b4433589d26573fc221f5218f1877": { + "balance": "154136576560000000000" + }, + "96ac1e62c95e33dbbd4f6ed389007e16c00b205e": { + "balance": "4130528000000000" + }, + "96ba703df3a8a6dc3c5d6be02cbf6a4afa2d1650": { + "balance": "2885298549532000000000" + }, + "96d516ded110f1d7e0290716689fd1b7964d9d42": { + "balance": "40665675241000000000" + }, + "96d75950c9354cec6084ba11058dd52d00fdb1f2": { + "balance": "903158106646000000000" + }, + "96f362c59c72fa1d39ae3ec37a7b715d2dd23679": { + "balance": "110000000000000000" + }, + "97115f7544cb05009b3fad2f0c2817f3ee77dd4d": { + "balance": "10000000000000000000000" + }, + "971cbaeafd4b0fdbad24fab946051b8949efaebf": { + "balance": "8462381628000000000" + }, + "971e195e980b4fd4db8d279c80968ca1bd390edd": { + "balance": "10000000000000000000" + }, + "9722648970c455929d621546fddbff27c49acd3c": { + "balance": "70337427969000000000" + }, + "9772027a4ea991eb9eb5ae6b8f34d750a917538b": { + "balance": "148918416138000000000" + }, + "97797e3919aa35567b9eb1224be87f96c6c2e1b4": { + "balance": "973342196399000000000" + }, + "9780a9c86160e27f627179535c3d3f23b6b29917": { + "balance": "10000000000000000000000" + }, + "97a85f4e3f53aa066825de15f1d0e25d4189b037": { + "balance": "2435764858719000000000" + }, + "97f46465e99910539bd3593c16a572e159bac87d": { + "balance": "25000000000000000000" + }, + "9882505fcb54ca2d2f4f79b03f0a5ead61936979": { + "balance": "249999580000000000000" + }, + "9898e969629502a891b758efecc9fdc5ada7d32c": { + "balance": "20000000000000000000000" + }, + "98a52d325e28ca9b4474846c7e4c07a223440fab": { + "balance": "418260286015000000000" + }, + "98a9b2f7d1ba7838e3242b5e4cbf1f2897aa4bc5": { + "balance": "500000000000000000000000" + }, + "98b8308c37a2f6cc1bb382dba2ba95a3c5ca2834": { + "balance": "10000000000000000000000" + }, + "98bf0170a61f98ab0710a68810bf152b7f6c56fd": { + "balance": "2279761566089000000000" + }, + "98c8a323a0022bd147a466fa1ac867977e12eb92": { + "balance": "10000000000000000000000" + }, + "98cd102caf0866ba0a74604b01f54049503905d6": { + "balance": "34739921273310000000000" + }, + "98d7e89c2765aaac224d4015aa277fef208953c3": { + "balance": "1291811952000000000" + }, + "98fe96bfd1e10fb60b343e512b15e955aefc0778": { + "balance": "464922897623000000000" + }, + "99064a57d693e45559a1a910c9ef7d46cce0e703": { + "balance": "8969733492948000000000" + }, + "991ea5429b91a8bfc4352a1d93304dc463be5b90": { + "balance": "149367286734000000000" + }, + "9921d405fada890fee6bf76acc39141fd34e5d2b": { + "balance": "5021308706457000000000" + }, + "9938d357d3d5dcc6f6fc7fb47a98405c0ab6830e": { + "balance": "516293591974000000000" + }, + "994f4e6521a3a5752359308b9f6b2722922c60b1": { + "balance": "23993133615000000000" + }, + "995a6a1c38f037b3a9f0a2e915b8fc0efdea082a": { + "balance": "1403498530728000000000" + }, + "99709e57748a7da6556b1670ba4f15c45aef4689": { + "balance": "36000000000000000000" + }, + "99789f65655c6f917d575169f4ba8192440e659a": { + "balance": "393071814319000000000" + }, + "998f66cbde2693603fa109ad7aaa8bc42a8765a9": { + "balance": "49000000000000000000" + }, + "99afd42a58af31daa54ad9ba35b06954330107ba": { + "balance": "25000000000000000000" + }, + "99b6a9ff2b2ac9ac0361af007aba107695ff5fad": { + "balance": "12860157225353000000000" + }, + "99d16a5955d43723ed8e2b1a642f8f1195f38b64": { + "balance": "62907829047000000000" + }, + "99df609926ca536ed3be80e35dbaecc42ae67f2f": { + "balance": "316809833612000000000" + }, + "99f3faf97a36fabea7306979b30b08fa70110e29": { + "balance": "173292373556000000000" + }, + "9a26110067b473e3bdc0fc32951b39596c967a56": { + "balance": "78192198764000000000" + }, + "9a3a8eff6fb82377da6c17ba658dca87ca0dfe26": { + "balance": "50000000000000000000000" + }, + "9a3b06257088ef8c17410a8f2d63392edb9b55ce": { + "balance": "239567000000000" + }, + "9a426842301802866cca0ef89794d928d3e8f843": { + "balance": "776173297821000000000" + }, + "9a5f2c0a6d41131d9aacdb4f8c274958cbdd377e": { + "balance": "441954000000000000000" + }, + "9a6893023ac6f34b493d33e4dc63ef697169a58d": { + "balance": "439689418527000000000" + }, + "9a86eefd848acafcbd9960003e90b22162b15ef9": { + "balance": "294190908093575000000000" + }, + "9aa711f3e4eb67d2f6405b5ee6290a014d203a72": { + "balance": "9101556549634000000000" + }, + "9abf9ccf6abb8d55ede458d2d12a279d0a823944": { + "balance": "17609693072000000000" + }, + "9ac1909b983c754f0800559174025c0f0baa9d31": { + "balance": "80921948093000000000" + }, + "9ad62cd855d629e1ddab632874a6dc2b812f2348": { + "balance": "2068118534000000000" + }, + "9afc2c33aa2c9a42600abb18aedaefa433326122": { + "balance": "2485353229354000000000" + }, + "9b18d230b221a99c74877d4a1dbdee2214c7d60c": { + "balance": "4024172228743000000000" + }, + "9b18e27788c9d59053072032a480569e142595a0": { + "balance": "110789164888000000000" + }, + "9b4535b23af0b8e5f488a6f318ff6badf71d16c1": { + "balance": "84756740661000000000" + }, + "9b5e7cf43aece7b38ea2af6d08bebe2d3b926840": { + "balance": "262771268227000000000" + }, + "9b77dac92fedd0ad3eb4326d4fafe0f4315a8844": { + "balance": "3616321626000000000" + }, + "9b8f6f223641f9b1bab319dd1e88c49fd411a765": { + "balance": "2054417462086000000000" + }, + "9b9f94861d80365464912e5c7213403405a6cd8d": { + "balance": "2367093088000000000" + }, + "9ba24397002929e6239848596b67b18a8dea1eef": { + "balance": "5000000000000000000" + }, + "9ba99736c5ac468d6b644e39b8d515c39151f51d": { + "balance": "311900650761999999999" + }, + "9bf2d4ff366e1bb2313ae9a93ccca75d6bc0d232": { + "balance": "764870206925000000000" + }, + "9bfce7dbfc9ae62d450e862261d1e21e68bac92c": { + "balance": "1000000000000000000000" + }, + "9c003e74b62f192a864045d678639580c672fc22": { + "balance": "50000000000000000000000" + }, + "9c128bd2c0c96b896db6c0f398e908c98302809e": { + "balance": "3251059363800000000000" + }, + "9c255daa89ee16f32fc0ab1ed8e22db39342e6ca": { + "balance": "37695843594589000000000" + }, + "9c32e714bcb601a56a8a4e6b3f7bcd9e1c7a1b54": { + "balance": "50000000000000000000" + }, + "9c503e087b04a540ed87056c9371d591afa72df2": { + "balance": "64229084991000000000" + }, + "9c54297dd3527cbbb8ca8c305291b89bfb7ab39d": { + "balance": "61682466962052000000000" + }, + "9c55bb1db3b2bb06e605a66ced9ea2ac95718205": { + "balance": "16512365324000000000" + }, + "9c59dbc48b9cf53fe668784e89d30493da9995b3": { + "balance": "50000000000000000000000" + }, + "9c61b58aa760265f7fd1b9e749df70122ea81175": { + "balance": "50590272373000000000" + }, + "9c6c7eaf4bec0566a7bf8acd30e10311a963267c": { + "balance": "999999999580000000000000" + }, + "9c91dd4006f9d01d8caf5f5fb4f2c4f35ee63ffc": { + "balance": "175730980227000000000" + }, + "9c99275f5dee14b426302b1a47a8488c16432f2b": { + "balance": "2000000000000000000" + }, + "9ccf7b23528d062da63f6af3e26531b775c83c52": { + "balance": "928373869120000000000" + }, + "9cd21c30ccbc1087c9b351395fdea17ad669cc2e": { + "balance": "529762292313000000000" + }, + "9cfee47d6f24880af7b281cc00e1fc58e0a4a718": { + "balance": "198888257958000000000" + }, + "9d08251f7d4cfd66d15c17e1ea6bae5c795e290b": { + "balance": "813841349140000000000" + }, + "9d5411490ce89359bfbacf9f9957ebfbbc18debb": { + "balance": "22263187467000000000" + }, + "9d61e1dfaa7d0e0c5f5d733a24a1883c4e201f3d": { + "balance": "144000000000000000000" + }, + "9d754d94a15ab6d738e511fe4c775ee6d20a53ee": { + "balance": "20000000000000000000000" + }, + "9daccedf104fdcc3c39f2961ddfa1c64eb632476": { + "balance": "1237093270947000000000" + }, + "9dad4968c0e44aa729fc5732f3ee903c6799637b": { + "balance": "838788687517000000000" + }, + "9db73ca677bacbb622f44fe90b53ee1d9f0c2009": { + "balance": "472858335000000000" + }, + "9dbcb5026e0f444a33197da240856f108db14ff0": { + "balance": "10000000000000000000000" + }, + "9dc46cf729187ceed8001c4ab14fa4fc21c35f32": { + "balance": "3320792646995000000000" + }, + "9dd895c1bdac2ed9864134aaa8c543473ee5f19b": { + "balance": "1430620966869000000000" + }, + "9de2687242cbf9fb94fee0ad873acc7494ebd2bf": { + "balance": "20000000000000000000000" + }, + "9deec036282717aac93ad5cc1b6d4a5354e85c2e": { + "balance": "2048627955362000000000" + }, + "9df8dc66395aeae9b4c831b4d63bdf48db08811a": { + "balance": "215874670561486000000000" + }, + "9e1fe68a70abd8ab517878b03961da8564b43eb5": { + "balance": "67908329894526000000000" + }, + "9e33293006982abc668e199aab20260b9b754463": { + "balance": "49000000000000000000" + }, + "9e65616282a0baf89469a58915fd8fdbed210e3f": { + "balance": "829209872657000000000" + }, + "9e7b7b522834dd7e83ff2bb6b6e4cd2972330899": { + "balance": "500000000000000000000000" + }, + "9ed134b3a8feccb4056b2e511cea9a8ec58a3e77": { + "balance": "18787546978390000000000" + }, + "9edcf477687a9dee79341ed5d89d576c9a854c2d": { + "balance": "500449025554000000000" + }, + "9eeb06d4b532118afa013a01c9e89216fe0475ae": { + "balance": "1823939486758000000000" + }, + "9ef20a338e85044922f08f3648355e834874d551": { + "balance": "50000000000000000000000" + }, + "9f0855f9cc429fd3590c6ad05bb66a9e038efdca": { + "balance": "8017999878252000000000" + }, + "9f3befcc1884d16b65ae429228d26fffc146c8dc": { + "balance": "1016482445089000000000" + }, + "9f4571748463eee19e59ff9bd734a62a66613850": { + "balance": "20000000000000000000000" + }, + "9f51de282745f77b8e531e1de0b7c14e3369ba54": { + "balance": "1010657089383000000000" + }, + "9f6527175a2b581cc79f2a68c35202e0a7f2af20": { + "balance": "216495522463000000000" + }, + "9f70204d1194f539c042a8b0f9a88b0a03bbcd8b": { + "balance": "10000000000000000000000" + }, + "9f70e44704049633110ecd444f9540e241b50783": { + "balance": "9139000000000000" + }, + "9f73fea741e8506ba7acb477745dab1cfab8366e": { + "balance": "4461472359634000000000" + }, + "9f88d33d26c90e74c39c9676b8b580d21bbad124": { + "balance": "54437240781000000000" + }, + "9fa47455be14ad2eecce495281ed0eea926ec6a6": { + "balance": "10000000000000000000000" + }, + "9fbb15b595d154754a2ae77c77283db9d4e9f27b": { + "balance": "6195722646556000000000" + }, + "9fc480ab1823a59fd6130c3948980f95ac99f1d2": { + "balance": "24101151540000000000" + }, + "9fe5f054165fbf1943b1b02c01063f04e0c3890b": { + "balance": "1000000000000000000" + }, + "9fe7d3d5976e7b8b5ad6baa15ceae96c43c60fea": { + "balance": "55000000000000000000000000" + }, + "9ff116ea0e219814970cf0030932f5ce2cd9a56f": { + "balance": "36000000000000000000" + }, + "a01f6c36193839bc3a31e6d0792324771040fc05": { + "balance": "48298750000000000000" + }, + "a0264706d668522b737bbdbe949ce3e5a60fe314": { + "balance": "1423066922869000000000" + }, + "a02b13bb3b13027045ffb9b44bc7380a942e8ebb": { + "balance": "86845430807181000000000" + }, + "a03d246a931c3d422e5d2bf90f64975923a93643": { + "balance": "5834171660287000000000" + }, + "a046caaee59425ea1040867c62a6fcda11652a23": { + "balance": "83087966538000000000" + }, + "a04b57b2dd8b2082c53517d956f5909d25e14b69": { + "balance": "4518538234851000000000" + }, + "a074ef9e0ffe15619103e3de490f5813be53dcbb": { + "balance": "4568113810000000000" + }, + "a07bae42b44c085067de16e7d9846db529059acf": { + "balance": "4000000000000000000" + }, + "a08530e5fb7e569102b2c226aa5e53dc74483e4e": { + "balance": "2325665286793000000000" + }, + "a095a2c666f4f3203a2714fb04867c13c2add4be": { + "balance": "14768043990000000000" + }, + "a0a967418a3fcb3ee3827a08efa851347c528a60": { + "balance": "20000000000000000000000" + }, + "a0bb293071e07418ecb2fefc073136569ebd1736": { + "balance": "25871128320000000000" + }, + "a0c6c220a53b7dc790f7a5b462a106245c761f70": { + "balance": "1000000000000000000000000" + }, + "a0f06c86c49b248f4835bff405b620d12ec80d07": { + "balance": "484572382390000000000" + }, + "a10bc9f4d05678b26c4ffd2d92ab358163020b61": { + "balance": "10000000000000000000000" + }, + "a10c1197f7bc96639d01a652df73e49c669165dc": { + "balance": "1205859101575000000000" + }, + "a1221b2001f85f71e0655551e300ce115284b8dd": { + "balance": "1376698025177000000000" + }, + "a13fce836d65124fe5bcfa2d817ab2a043acbcf8": { + "balance": "55000000000000000000000000" + }, + "a15f1f609f7464906e0eb9d5e1d26468b90d9198": { + "balance": "16000000000000000000" + }, + "a1617dcf3acda60737e5ca9e4d0ecd82a98ef667": { + "balance": "500000000000000000000000" + }, + "a165c5f151d0daab905ba4a6d1fe5d5114fd7686": { + "balance": "41039049526000000000" + }, + "a17d5bed36c1059561e184a8a90a38ce955b92e4": { + "balance": "10000000000000000000000" + }, + "a18efb4e0950e7ac95970cd4591dacc286241246": { + "balance": "12403188476000000000" + }, + "a191fa6be64f2f6d2b4a7fb5a586416a605552c6": { + "balance": "60340281461000000000" + }, + "a194c15518cefbe94edbef3a2421586b51f7e1f6": { + "balance": "4153525550636000000000" + }, + "a1d0e41aacf83fc62fbecf35f8e873f8d734ecaf": { + "balance": "9000000000000000000" + }, + "a1ddd1f615ed483ef895e341f3266b6891f9b59c": { + "balance": "180411786335000000000" + }, + "a1f4d1e03114707a56ef9069bc20c6094e810d34": { + "balance": "51949145435222000000000" + }, + "a1fe101a65616cd03e3af03092be63434b7bf203": { + "balance": "1005401878265000000000" + }, + "a25a8225ce67c54048737601eac5e0d063c2fa17": { + "balance": "272038848571000000000" + }, + "a2714999233bcaff7294fa3e3b64c63ad45a928b": { + "balance": "14560781294000000000" + }, + "a28db3f7fb1771a3d77dfb19b54f88fd55b15c8c": { + "balance": "8000940572576000000000" + }, + "a290101bfe5fbc73146c4ec3ab5266c043eb701c": { + "balance": "1397563244603000000000" + }, + "a2924cfbcd37d0b321d6abbe57c645f9ce32340e": { + "balance": "200000000000000000" + }, + "a2a26c34f3d950c795fc965f6b1df3990e111403": { + "balance": "34525064429023000000000" + }, + "a2a2855851711bfc051c1f298821ae89e4c872c5": { + "balance": "491025000000000" + }, + "a2b956dd6f1934a4a44a026a18ac345ddabe42d5": { + "balance": "20096625821563000000000" + }, + "a2b9a118a79be81711d95485aa12e3efe78ca256": { + "balance": "10451051632647000000000" + }, + "a2bcf08ddd1778b30ea7882518148edfba2d9b20": { + "balance": "347033754668000000000" + }, + "a2bd489ec4790f4145f8a9a95c9c829c5c020146": { + "balance": "100311110878000000000" + }, + "a2ee35300ddf6a2491ec0e1848f8b56defafd7fe": { + "balance": "500000000000000000000000" + }, + "a31adf082ffd212df18d5a84b105a937e83b1b1a": { + "balance": "7124891785000000000" + }, + "a32c944e6c5fe186794b88d6bcbf51c47bea55ab": { + "balance": "732129357042000000000" + }, + "a33105d543f5d2b1220d4e1ecfdcf85699324dad": { + "balance": "74798779358000000000" + }, + "a3330c73e2d79355a14e570da1ec2e80f8048c69": { + "balance": "10000000000000000000000" + }, + "a3580034590e3052b9de5abd635e514ec5ba8694": { + "balance": "10000000000000000000000" + }, + "a360d8e2519dc6d7793cc371d91ad6add75e3314": { + "balance": "192622260840000000000" + }, + "a36b9b8b2adb20fb4a84d3025bf2e35baa8b7fef": { + "balance": "20000000000000000000000" + }, + "a3771b191237bef48339aa77ad5357f6227b358c": { + "balance": "512633055119000000000" + }, + "a3892bfd25705387cfb4eeb6d21089753c22e3e2": { + "balance": "258136912825000000000" + }, + "a38c793775ebfc7330b4331fe2dc848abb862b73": { + "balance": "1193250172232000000000" + }, + "a39417002ab94845541aded4a614a5a04af8187b": { + "balance": "1185722898000000000" + }, + "a3a79a9f929b54075de43689adb665ef914812ca": { + "balance": "100000000000000000000" + }, + "a3b59ea3d366f818ca09980846ac533d4685c121": { + "balance": "59734700360000000000" + }, + "a3c7b7c594a64225922e02039669e4d0b43fc458": { + "balance": "11779233750000000000" + }, + "a3cc39a68184e51f6445d3ba681a55f4157d4383": { + "balance": "10000000000000000000" + }, + "a3d414d9f210f7b77f90790ce09f6128abe50adc": { + "balance": "10000000000000000000000" + }, + "a3dfda16e5ae534ac100f56741b77b6f86786615": { + "balance": "9000000000000000000" + }, + "a3f79b9d1fc9d6dbaaef49d48fa9c9fb5a822536": { + "balance": "108910000000000000000" + }, + "a3f87414bc9e6f01c2fbde966fc8fb6edbf58c29": { + "balance": "441000000000000000000" + }, + "a3fa3f58c802d9a9690de760716275f14449045a": { + "balance": "437227558095000000000" + }, + "a417ec5a9749064a6521ca2bf9d05f208eeaed54": { + "balance": "959205202638000000000" + }, + "a484d5b883d2b99b81b7bef27e307957ecb64b15": { + "balance": "126491152120000000000" + }, + "a488cd48258e57d66f44e73a60c121f963cb29f5": { + "balance": "20000000000000000000000" + }, + "a488e3b5096e964b21cdeba12ab423f391765b6d": { + "balance": "1712050478592000000000" + }, + "a49dba65f28909e9bd2ce5675bd091f498c6c5db": { + "balance": "216802821062000000000" + }, + "a49eb6a791022c1324facc23d8813f9954d1c639": { + "balance": "287438914902000000000" + }, + "a4cc080a5c4649f511b5844a8e0b031927e13a87": { + "balance": "20333578449000000000" + }, + "a4d2624ac5e027f72edaa625ef22134217203b5d": { + "balance": "1000000000000000000" + }, + "a4d30e35c9617eafeda82866c96c3ce6bf14400e": { + "balance": "1223254927978000000000" + }, + "a4deae7355bd2e1d57eefa56600601b8b475a501": { + "balance": "36000000000000000000" + }, + "a4ff3b5abfe4e50adad16d01aaf62c3d4cdb5260": { + "balance": "20000000000000000000000" + }, + "a502b109869ef07451576bf0e13ab294e1f236b9": { + "balance": "94843398055000000000" + }, + "a517a3b5e4324197902e16f8a29e47335cf39c11": { + "balance": "100000000000000000000" + }, + "a51e101088da23c82907e3e2c65a058f0454b131": { + "balance": "196000000000000000000" + }, + "a52bcff6a7e2e70cd714058bc30a16138fe39899": { + "balance": "30429750204000000000" + }, + "a544e84c2bc4b17859d06f136b6e377e4e398b22": { + "balance": "143977568178000000000" + }, + "a54ddacbc17a98b9fb6292aab3d92f4c5753fd0a": { + "balance": "100583192014000000000" + }, + "a557754f6637a19c1a48cb9bf58c1fe897acf434": { + "balance": "2087038692036000000000" + }, + "a56649205d9ea247b49e03dacbed6c78c21beb4a": { + "balance": "5046177099585000000000" + }, + "a568136446ee6b3bf62a20238db3b11397a065f2": { + "balance": "11652249158033000000000" + }, + "a56a7865b526e315a9eb41f4847485c7e0c952fd": { + "balance": "50000000000000000000000" + }, + "a56bab2a9aac9d08a7bc9265864a80089b68570d": { + "balance": "37138466291329000000000" + }, + "a5965a601c5df7765cd70e5dad27dd23da67ac99": { + "balance": "10000000000000000" + }, + "a5a3161c44c34c441784b7df795067760b0ee569": { + "balance": "35053289069000000000" + }, + "a5c245cf843e691956007b94e259b437a4e6b7e3": { + "balance": "18749166170000000000" + }, + "a5d7de961c3b991dc78f2d6c0448fa6225116d3f": { + "balance": "1574510758868000000000" + }, + "a5f47d2081ef728808786128549a28a5662e92a8": { + "balance": "1750000000000000000" + }, + "a610c90f5b7e5f33044956ba431a3887de1c969f": { + "balance": "25000000000000000000" + }, + "a61c1919bc3f3181dc94e2230d35574cfc972d78": { + "balance": "8990565120000000000" + }, + "a62f1aabd91cbc0112e796d1ec3727fcd26fa293": { + "balance": "1311277302001000000000" + }, + "a64fff0bb32e32f81a541c393982bc59fa183b1e": { + "balance": "8291357610655000000000" + }, + "a673dae555d367b8d4a784274577a1884615b9d9": { + "balance": "27416452091330000000000" + }, + "a6c780b585355d84d9d3c13be5bd05374588e240": { + "balance": "913657165911000000000" + }, + "a6cc1f6f51862c2798adaa1d266988022005a71a": { + "balance": "284500645805000000000" + }, + "a6d9c82784fa20dcf28266d047db441cfeb8855b": { + "balance": "10000000000000000000000" + }, + "a6dae08f99e4fb57b066a645a259d8e4f7ac2bc8": { + "balance": "9044922773690000000000" + }, + "a6f49f36f8d10a796bc2afc9e069cb0c76004ddd": { + "balance": "128555691078000000000" + }, + "a721ce1c294a0f1957ebf9be20b0fffcf90111ad": { + "balance": "3392103457630000000000" + }, + "a72b82c33bd3d6060e8a04392d236775d48ec3ae": { + "balance": "1434465940701000000000" + }, + "a7344654f2a1a44b3774e236f130dff8a4721e82": { + "balance": "100000000000000000000000" + }, + "a748cced92a87066db8b29f931fb92e827488a9e": { + "balance": "5487679824758000000000" + }, + "a78dcb2bcbec2d0a60661e1715c9a95c9d573a68": { + "balance": "346798292989000000000" + }, + "a7a6c0505e7090e0b2c21394877f91c50be6b45f": { + "balance": "4125233658872000000000" + }, + "a7dcdd9b9785a44a2dd4c5eeeb863ac1feae0f66": { + "balance": "10000000000000000000000" + }, + "a8013e9dca1bd38975748de2fb6cb3af5cae74d9": { + "balance": "10000000000000000000000" + }, + "a807bf78b15c15cd9e8edcf586849db716fedbb1": { + "balance": "1458293606310000000000" + }, + "a83410ff00fb4b913dd0ea2003b38c5c3247350a": { + "balance": "2876442029807000000000" + }, + "a848f61298a409e77a03900712017572f35a3319": { + "balance": "2783106133600000000000" + }, + "a85bb81d0dc57f824a763814759fd93fe3020569": { + "balance": "4558027813744000000000" + }, + "a860611cd098ce98974313030d9f6f462bb274d4": { + "balance": "961594154368000000000" + }, + "a8799eeff72929ee6cbfb5b0c02985cd4841be3c": { + "balance": "500000000000000000000000" + }, + "a8c29b9b1349fac0be9a65873e1911b7439c9a63": { + "balance": "1264035560749000000000" + }, + "a8c321024a3c015d881efca33bd1b2c1788b379e": { + "balance": "528752788000000000" + }, + "a8d02e8925ed48f4274d8bee62253dc0d4f2989c": { + "balance": "209083880937000000000" + }, + "a8d2bde2ccd6bad67ee1b9550c9310accb37cd79": { + "balance": "49000000000000000000" + }, + "a8d61abc6a403adc183aeb74c83e4221fd28ee1e": { + "balance": "50000000000000000000" + }, + "a8eb6aa5a0c5b6d9260a202dc76ab674d9a5f3b9": { + "balance": "1041257515142000000000" + }, + "a8efc57efc776dcaaf4003a8cfa63f215ab0284d": { + "balance": "166144142685000000000" + }, + "a8faba86d87678294e311cfa7f8cbeb6f9d8a499": { + "balance": "124541781000000000" + }, + "a912e02f8eab0cb620316129875f919455201117": { + "balance": "6454482105955000000000" + }, + "a929ac95281d1a77a3eda3b5ac90a761ef03ff16": { + "balance": "1074305309650000000000" + }, + "a92a4e40519003813f5574397ce328d046f75802": { + "balance": "9188437500000000000" + }, + "a93850ba8fff3bd18ab259f87c58bbce84165fff": { + "balance": "39018890852058000000000" + }, + "a9843660a17c2d972246028cb8045472abdd346d": { + "balance": "1052681604185000000000" + }, + "a9866c6271733971e46df3c9bb27b3d3c513c166": { + "balance": "200000000000000000000" + }, + "a9b1299c0c064e766f9f29f4301a78c6e4931fcd": { + "balance": "267785134400000000000" + }, + "a9bc33b9c99dd5a3967387c1e99766f9bc74d591": { + "balance": "65356157048000000000" + }, + "a9ccf1cd2f816b15182997e3207d9a681bf21b06": { + "balance": "17521053440000000000" + }, + "a9e54bd9826f853f65e0be1ec0bb9c28f95e0eea": { + "balance": "6260000000000000000000" + }, + "a9ef563c872342f49817a903a5725b504d455ea9": { + "balance": "50134015139000000000000" + }, + "aa0d69c7e1382cd16c527a3fee48db19c38e1398": { + "balance": "142562301500000000000" + }, + "aa12abcc3ab373d07bf560fd200652c8580fd967": { + "balance": "5509242259903000000000" + }, + "aa1d6b968b3f8046a94f128864bfc612fc2e2700": { + "balance": "489179780895000000000" + }, + "aa20b8559d6dd1543e8c528775ae4b04c6242471": { + "balance": "169000000000000000000" + }, + "aa227e9d6074a60ecd43e1cc24092ee58560374c": { + "balance": "596190898010000000000" + }, + "aa7b660fec7b05968ba656eae9a8aaef4481720e": { + "balance": "674642002744000000000" + }, + "aa9e04077d44d288978a3a3ab0d7c251c0447a4c": { + "balance": "10000000000000000000000" + }, + "aaaac1e72955e9d67625cf8bed73fa643fb1cc1a": { + "balance": "9781187987000000000" + }, + "aab46c0c2db4e330834081f97678906252746f97": { + "balance": "16440184245000000000" + }, + "aade5358c52b8aa5ad8ff285c6b297e86f49fa0f": { + "balance": "982846000000000" + }, + "aaedb3fa2cf0ebca0ef4a121a28a406264ccc900": { + "balance": "100000000000000000000000" + }, + "aaf30bf76362a03450aefaf5bd68d28b84eb4962": { + "balance": "509106199370000000000" + }, + "aafbaaa6b6369e986ba72b196bd5f08cc458e344": { + "balance": "216372214000000000" + }, + "abb03c888d61c9102827a1dc0950145beb9d96b3": { + "balance": "144000000000000000000" + }, + "abc6dc937d7703a6b0c83659a328cde0d5008e32": { + "balance": "4052429106341000000000" + }, + "abd3910139a97cb92dc09a8a0352575bcc9ebed3": { + "balance": "24028359215749000000000" + }, + "abdc3953ef293c98989802063f8cb55e0e506432": { + "balance": "64000000000000000000" + }, + "abf1a47c582bc87d36e47cfce24e0ad249f42e73": { + "balance": "71947491720909000000000" + }, + "ac0b6e7aadfb5ffafd5cb3ef3620ebb0691cc3fe": { + "balance": "10000000000000000000000" + }, + "ac1a182607046b56e7a4bbab87cc1182874f79ef": { + "balance": "453499500178000000000" + }, + "ac251b311f781ad7a43d01b0b4b20fe891004e7e": { + "balance": "304621378298000000000" + }, + "ac258cec5ef49f96612d659f66dd4e6ea88e3c87": { + "balance": "255185373455000000000" + }, + "ac4000d9ad080740ef4a2ebe4a3075877bea277e": { + "balance": "10000000000000000000000" + }, + "ac7445c09372f15259fd852cc458783d6140c0db": { + "balance": "10000000000000000000000" + }, + "ac8d29dc05ea6c2f5409a76abe04321bf9381f32": { + "balance": "22464474197854000000000" + }, + "accd52b63822d8cb5117d9deb56596e072462614": { + "balance": "20000000000000000000000" + }, + "ace63a86a2ddfc79f677344e93dc0c4750b8fdcf": { + "balance": "1355066360964000000000" + }, + "ace83deb83fa8d319979658592b75ed13bdf97c7": { + "balance": "20000000000000000000000" + }, + "acf91515df16b21f1e5f5474dbefe596e4929b96": { + "balance": "1153047238967000000000" + }, + "ad04381f7ba89220e8fcd7e200f98a476683a904": { + "balance": "2000000000000000000" + }, + "ad22225bf225d8f705f93bdcda8d301180ea28dd": { + "balance": "1272512717188000000000" + }, + "ad3f74034ff5ca89f97b2585edf12376820307ab": { + "balance": "12303261515593000000000" + }, + "ad43a3527ad2b9445417cb73cbcb42965a5f469c": { + "balance": "67607364133000000000" + }, + "ad61cf9bf560bd5da75d55738477bd9aa25fb0b8": { + "balance": "4358939446693000000000" + }, + "ad649e8a3e1436e0604b0b8c9b1a5f1c09e06d7c": { + "balance": "344000000000000000000" + }, + "ad6b584813814db4c72c4c7eb31447d224074b46": { + "balance": "18445595367000000000" + }, + "ad7d404afc67c0e457fd3ce142cd30b506408683": { + "balance": "48218702840000000000" + }, + "adaf4d39b6806d132128ac438c2862c0a1650cff": { + "balance": "500000000000000000000000" + }, + "adda124baed2e1fdc1acc7b4a048eab0cd249212": { + "balance": "1074765673925000000000" + }, + "adef437c429d90a350b99750d4b72bc8538c5f98": { + "balance": "931901903135000000000" + }, + "adf826a0ea7dc4322d26e9d8c54c4180c1827216": { + "balance": "323567723315099000000000" + }, + "ae01d8b1668f8bfe6e225bd9bc746f7e839ac0d8": { + "balance": "321211880744000000000" + }, + "ae17de3ae6127022e53ebcf9e08457174cdee0e9": { + "balance": "3817903000000000" + }, + "ae243b0186793eddc6ebbb1a2c1f0b1cd574b07c": { + "balance": "9000000000000000000" + }, + "ae3ae1d41dfb16e19a1817b3639cd4300fd166c1": { + "balance": "55437674845679000000000" + }, + "ae506999882d4c6f05cc7979c342c0ce559a8df0": { + "balance": "1391755905401000000000" + }, + "ae524cee5aa23025d6ad185ccab75a6974335d53": { + "balance": "797132751509000000000" + }, + "ae5a55075d0541f179b085152bfc8c72c74abe23": { + "balance": "589408139567000000000" + }, + "ae63d02b18b464f0bbab4de943766bdc7ba2926d": { + "balance": "300261019201000000000" + }, + "aed8ffb86a49c09ae3a83e93d9045851434a9f0c": { + "balance": "1031991707237000000000" + }, + "aee18a9a2ccdf6025d61005827753ce4f510f7e8": { + "balance": "1818639022863000000000" + }, + "aee67910c514fa63a228769d5e15ca40bc4b26c2": { + "balance": "5688989238568000000000" + }, + "aef744eb2ec682dca128dc3149afcf881e367121": { + "balance": "818801643225000000000" + }, + "af04430b3e40e746127623532353a0f177a88fe3": { + "balance": "100000000000000000000000" + }, + "af181833edb15c9b2ee2329dcf1845b977361b7d": { + "balance": "93228805338000000000" + }, + "af30db29765b4fda6f075af96e8acd5046b099c4": { + "balance": "1000000000000000000" + }, + "af31fd30cfb10f1b0a12c2e7dd7ca56bdf517745": { + "balance": "36000000000000000000" + }, + "af70d6820e1d26194b0a9965b55254a287b162f3": { + "balance": "87593999609754000000000" + }, + "af96a573fa86c07389a71db797bea689419b23ca": { + "balance": "36000000000000000000" + }, + "afa4c5b674934e31a9aa5e3e723d85060d51c4d0": { + "balance": "10000000000000000000000" + }, + "afa6e4b4060c2e5969c2329d13cc42924412efde": { + "balance": "127502378589556000000000" + }, + "aff2308ac607f85392f4c8a6a043af67b7b849cd": { + "balance": "11130371831000000000" + }, + "b00ea9c459105b650def1e8569c85fa01837454d": { + "balance": "94928352162000000000" + }, + "b02a7d16ea8663c88416e6f64eaf57787d230be3": { + "balance": "17215604601000000000" + }, + "b03f4e9aa5c352cb1cec953d1123c2f22cd94b5b": { + "balance": "206022552274000000000" + }, + "b051459b91d253c5e8251a5a68282c291833466a": { + "balance": "297127749975000000000" + }, + "b055bdc874ca5a7d2f4bcbc51f1cfc3671b55f72": { + "balance": "1421913523478000000000" + }, + "b06156b99b891b756262c5b40db9bbe39fddc77f": { + "balance": "49000000000000000000" + }, + "b076893b9841d2775ec8883f05b74f1e5aec327c": { + "balance": "22591055478000000000" + }, + "b095de644af3c9f960f67502da6ac5eb050a158e": { + "balance": "4958067562725000000000" + }, + "b0a1f794cf70422395f74395abc9a7d0b271846c": { + "balance": "812057322000000000" + }, + "b0d36e0f426a99416425689c657fc6d64ad698ca": { + "balance": "1157727077158000000000" + }, + "b0f35fa554d6ed657bf3996cc027d045c3971fcc": { + "balance": "64000000000000000000" + }, + "b0f76b4c9afdfe35c41d588265642da60f1b97d1": { + "balance": "1000000000000000000000000" + }, + "b0f76b4c9afdfe35c41d588265b42da60f1b97d1": { + "balance": "2028311808491377000000000" + }, + "b1445842d56c56bc532d2f33ab9b93509c732a3b": { + "balance": "13522982470164000000000" + }, + "b156bafe05973bc839c4f115be847bbde8a67cb1": { + "balance": "10000000000000000000000" + }, + "b182e4d318893dc1c4c585195dbde52a84ed4ffd": { + "balance": "329498977335000000000" + }, + "b18f506e77df4db80ca57cefeaca4f1010f78f50": { + "balance": "956339304078000000000" + }, + "b1b6f617b110dd79c8fd77e729584d1fdfa9aa09": { + "balance": "16000000000000000000" + }, + "b1bba36e2d9e272e0131f4bae09bcfd92e0a63db": { + "balance": "64000000000000000000" + }, + "b2285651e57ae0ff27c619207cceacd20884d152": { + "balance": "1345938295122000000000" + }, + "b2419a93732d0d324daf7707fac3782a77b0dff8": { + "balance": "625000000000000000000" + }, + "b27206e9f2ac430841fb8da69b49d505f1558b8b": { + "balance": "29507819229000000000" + }, + "b2801fe902c7bbc987ba12ecae98765c99980fef": { + "balance": "240016083000000000" + }, + "b2843d5215ceb761e78f281402a1660c3abadf5b": { + "balance": "3335539720927000000000" + }, + "b2a22e6a04a2ce3287da3b8b6eed4ea1f18f05dd": { + "balance": "99999978999999999999" + }, + "b2d55a061fc6f90d2a05e0cbd26ffe0a1c3321c2": { + "balance": "1000000000000000000" + }, + "b326aec1cd523948ffec2fd1e8f21bd2b4308f40": { + "balance": "913000000000000000" + }, + "b32abc82b251e2d310ea7588cae4ad4acb657cd9": { + "balance": "26946233911000000000" + }, + "b36924d578973aec05ce7ab556d7ed00004949ca": { + "balance": "393041705867000000000" + }, + "b37482114c83e857c730588d7d959d300b8142da": { + "balance": "29429544454000000000" + }, + "b39998bade135ac6ccadff41cd709e161d01aa60": { + "balance": "26272579375000000000" + }, + "b3a995ee94f1d63d12f10cea5ab3d596c7c6f284": { + "balance": "64000000000000000000" + }, + "b3bf35e936fdbb7d0bbeeb1cf076f243855ed477": { + "balance": "754081187934000000000" + }, + "b3c2ac85b99abed4a2a52b5f96a2c98040d16022": { + "balance": "50000000000000000000000" + }, + "b3d1a2c0ab2d8987446d74f49e357adf5bf15986": { + "balance": "10000000000000000000000" + }, + "b3fbcd24c8394a5d2b7fe877f18681a109a404e5": { + "balance": "2558689648423000000000" + }, + "b4110f4e38405adfc054e55ff73c55842db8e2cd": { + "balance": "129000000000000000000" + }, + "b417f4681fdd4e53cfdf8550e3d326dbb0a557ec": { + "balance": "1000000000000000000" + }, + "b422970fb8799d83642b7ff715fc941d69e86053": { + "balance": "81000000000000000000" + }, + "b4237be71920497715826eae8d85c26cb3c111a8": { + "balance": "10499979000000000000" + }, + "b431839de4b21dfb44150cfc6ed00ea430a81687": { + "balance": "26839560174813000000000" + }, + "b43a0d6399c7d1be943c4b45838156a47c88f909": { + "balance": "10000000000000000000" + }, + "b44ec608b95d0d51105ce5f4b48de5dd72f346fd": { + "balance": "448125120000000000" + }, + "b47f63e14f6de6c3413b2be95a725e367ac18fb6": { + "balance": "500000000000000000000000" + }, + "b48071cd1b15f45028e9dec2237f14f10b7aedf9": { + "balance": "38042711385000000000" + }, + "b4b874b323b560aa0e4811ca574bd48b65b3fc72": { + "balance": "18063913676592000000000" + }, + "b4e4d4af0667f8158cf817bf1bc3eada08a551ca": { + "balance": "2149067370317000000000" + }, + "b4ecd625ffe470ee1fa1d97832e42ddf3f9ddf6a": { + "balance": "1181738860120000000000" + }, + "b53f380ce92787c1db461524290e8fcede552fe7": { + "balance": "12640674931821000000000" + }, + "b547e04ab8a44d3cae38704356f1f59408457b67": { + "balance": "286604155735000000000" + }, + "b562e4010a0a5fd0906a4cd9f47fc28f6f51e210": { + "balance": "1000000000000000000000000" + }, + "b584de7b38a2a2e3d9ff9c055b309ca56e5da5a9": { + "balance": "237896887904000000000" + }, + "b5c1129961c4a43673324aaedb8296f5ade82516": { + "balance": "4213058948283000000000" + }, + "b5da6711c72bf27c87923aed4a39349b4192e6b4": { + "balance": "55180742586465000000000" + }, + "b5eac5e7e03b9d31e40393e16e956cd588cb7566": { + "balance": "4508019435556000000000" + }, + "b5fd46ee4e02946dca3485439f98bdab290c82b7": { + "balance": "108321600045000000000" + }, + "b5ff2a3caef6ec30365f4f0ecbecbdeec1cacbba": { + "balance": "979696597242000000000" + }, + "b609d05242f7c13a4ae4036f6da9c0bae18dd70c": { + "balance": "229121731278000000000" + }, + "b611156a2f87fb45c431a5cf5740ded90c2dc542": { + "balance": "401783365700000000000" + }, + "b61c7623144afbd0f6cf44c951e4219ef8096119": { + "balance": "36000000000000000000" + }, + "b61cbe0e58ff6fa4c810ad03c759c79d9ff052a5": { + "balance": "1034495371371000000000" + }, + "b622bb67e95a03f58dc9aecf82c217e86f2cf7c3": { + "balance": "500000000000000000000000" + }, + "b62a50be3ce0e7cf8f61991daf8fa7e23775141e": { + "balance": "1000000000000000000" + }, + "b63cbff6b1747ad5cda101d5f919ce81dd67e363": { + "balance": "2570089937000000000000" + }, + "b65e80551a8687c9cef2d852949177c0e3b56e51": { + "balance": "100000000000000000000" + }, + "b68126ebbcb5ab9b0371b62597a38d5c1685b0df": { + "balance": "671140851028000000000" + }, + "b69f5830c371cad5a74ae823eb8892d153ef3c23": { + "balance": "18446744063709551616" + }, + "b6b4468c4db64e0b85cddc251d02f32fffcd1f7c": { + "balance": "10308006217291000000000" + }, + "b6c129312505e571148dbe69833d30550efc12c9": { + "balance": "5105834767567000000000" + }, + "b6cee8ef00b8674a9a96447e4511b30d6564ff67": { + "balance": "667754569888000000000" + }, + "b70f805aeba260d44f0730f0a9dec60f2b4f54a1": { + "balance": "2751303297000000000" + }, + "b71a901dc4b6c6463f7d221f868677bcadbcc680": { + "balance": "169000000000000000000" + }, + "b7385bd8f8257331f4c7a87c7a23724f615cff8e": { + "balance": "196000000000000000000" + }, + "b755692bc027e30730dc1d0e0b2a883830a84115": { + "balance": "30713083153428000000000" + }, + "b765305dda3c1e069a7a022ec127ff2140d0a820": { + "balance": "603122990932000000000" + }, + "b77403a4c56ffc7715b4bfdfe4b054336aeca466": { + "balance": "130840969728386000000000" + }, + "b78b2f6dc731d7d84b7eea151805f9208a1d0cf0": { + "balance": "142084687500000000000" + }, + "b792a0fd762c002a7585cfdefd36cf7ffb42fc05": { + "balance": "10000000000000000000000" + }, + "b7ccd7164aa7fb871726d9d043a8f8f890068c0f": { + "balance": "1170997140237000000000" + }, + "b801f49018317caf30f310dbe116f4e876184874": { + "balance": "50000000000000000000000" + }, + "b81ca2bc63cb4008cebdda3ce8f4eaba322efca6": { + "balance": "4678481047354000000000" + }, + "b82e3d50bf8c5b471c525ec8dd37b06688ed6178": { + "balance": "1202448975553000000000" + }, + "b841162a7a8876296f10794d8847d8095426aa54": { + "balance": "73500210754000000000" + }, + "b8421d375c3f954e22b6fd304235dd7c43b68bd0": { + "balance": "6499782706009000000000" + }, + "b859b76d77eb604728093c61fcabe6f9d22433b0": { + "balance": "196000000000000000000" + }, + "b86536268ace9be93a1db2012d6e3e59023ef2cb": { + "balance": "52878034904067000000000" + }, + "b87e1ac4fc423ab37e10ffd221df8056537b1d03": { + "balance": "119159824674000000000" + }, + "b8825a99806c5a968423e69d22f2b61a2f0ae9e4": { + "balance": "999999999580000000000000" + }, + "b8835acaf63e0e5d41fb743eb0f954040a38d381": { + "balance": "64000000000000000000" + }, + "b8844c74b227781d4b3fafd32e39ff6fa9857f77": { + "balance": "490694157000000000" + }, + "b8962e8bcbcf0f69144f8fcd2ec3ae8e54c05034": { + "balance": "1425313342735000000000" + }, + "b898b4ece8e0eea375f6eb85615652cc5c221593": { + "balance": "2284038029169000000000" + }, + "b8a949bfd9751c29c4cd547cca2e584d8dac4e12": { + "balance": "50000000000000000000000" + }, + "b8ad5ce2ae781e2d245919c15bbbc992185e5ada": { + "balance": "733786526623000000000" + }, + "b8cb6a9bc5a52b9cfce26869e627b2af0ff5ed4a": { + "balance": "98364826821577000000000" + }, + "b8cf6aac7b9028649f0d55a57b61640d70cef120": { + "balance": "104799890645000000000" + }, + "b8e827b5d1e10a3944039adb1a3dd7ff6949145c": { + "balance": "172413427060000000000" + }, + "b8f6d7f33ee5755ba56647ab8fc9ca27b8aba677": { + "balance": "1430769696978000000000" + }, + "b9221177e2b09725bc95f08c72c17c42887eea62": { + "balance": "1212779749827000000000" + }, + "b936e0d83cde9bb810b85ad58eb5ff0fa9c11654": { + "balance": "4999580000000000000" + }, + "b961d435c457e205fdbed5442c8614ecfd59616c": { + "balance": "27847452621284000000000" + }, + "b969e9d89f32002cd4f90ef5907bebbbdca6fe6a": { + "balance": "12455448454838000000000" + }, + "b981c9137cfca5389f0123927852278d2d7ff618": { + "balance": "92180707865000000000" + }, + "b98abf0fe91b0d3a16c6ed37aea446baea33fd23": { + "balance": "560454425563614000000000" + }, + "b99ab4e6ae277b9fb04537adbb781e8390b490ad": { + "balance": "32814665223319000000000" + }, + "b99d0a433d7994743dd675894c18ed03164436e1": { + "balance": "16000000000000000000" + }, + "b9d8b6f0a505d217709bb9327f3b9b3f84813e00": { + "balance": "81000000000000000000" + }, + "b9dbd64e3c8e6ad84c9c67c66e678c06ea7bcb91": { + "balance": "1161140466507000000000" + }, + "ba361f7a6dff16a96f957c63e08267dec8f9ecf7": { + "balance": "2170060167590000000000" + }, + "ba47f4136f74b566f62ba373651332b59e74e1db": { + "balance": "906249296535000000000" + }, + "ba5287cf15de91daeaea2465da4d4c1a14dea716": { + "balance": "98978398162000000000" + }, + "ba77d056d52f84e740579aa527792f826591c858": { + "balance": "50000000000000000000000" + }, + "ba895406774ced5fd2e759b58f9ffaed5e04fb14": { + "balance": "10000000000000000000000" + }, + "ba96fab21a4926fd1137558ae996b52ec14538a6": { + "balance": "10000000000000000000000" + }, + "baacc247801eddbf152fd6ec39d659f265935743": { + "balance": "2661902597584000000000" + }, + "bab2eb9fab8e699a958699b15ddc7ada5428d33a": { + "balance": "27006404153000000000" + }, + "babeacd7933c817472875c86bf126e6d11886f8c": { + "balance": "2461234517292000000000" + }, + "baf7021d4d754d4478d3c3624c2376e3f1d4ee5e": { + "balance": "1352066301857000000000" + }, + "bb0760bd1da973d8f70dd0caa6cadfcfd8199231": { + "balance": "177674700430000000000" + }, + "bb278c6a52eebd0b8950e9b78ba211453ccb1b6a": { + "balance": "25000000000000000000" + }, + "bb327e5f260b2dfe25fb180c2d3f4b63211c1dee": { + "balance": "7694972715000000000" + }, + "bb643e768ab20c135e7df3f400284cf04c40a6f7": { + "balance": "385756449779000000000" + }, + "bb73d1d1c289b4953d0033b52d9d2d0d92573d22": { + "balance": "11000000000000000000" + }, + "bb89936d562b19e4c599826ce7cd0c60cb02b512": { + "balance": "725910446589000000000" + }, + "bbc509b7999b0e94534477b98ec8927cba879677": { + "balance": "20000000000000000000000" + }, + "bbcfa9ab62f4eab14d6a1b09c1aa554dae113183": { + "balance": "589417352665000000000" + }, + "bbe78301134249b52b74d73ee3855e7e3d288a40": { + "balance": "4456159000000000" + }, + "bbe7bb4c4f1b506b58f7e3334e6c89011cf2d6a7": { + "balance": "3889127030000000000" + }, + "bc016690596e077273465d1728d18553b185654c": { + "balance": "185932953686000000000" + }, + "bc16b2ab9c7ab309249f93b496b75c6a7392cb10": { + "balance": "5000000000000000000" + }, + "bc254e5405b154b98abb5fe5508d3e7c98663f4e": { + "balance": "144000000000000000000" + }, + "bc258aeb0f18150d3ca253c6bb04f63d657d99ac": { + "balance": "6011905701701000000000" + }, + "bc2620b5ebac12a88b287b625fa5b336568e7869": { + "balance": "534886892259000000000" + }, + "bc318687cfaae2be4c5ece4a18bb9252486a19d0": { + "balance": "147226513970000000000" + }, + "bc32dd123fcc2ef0dc36484c3ab1bae5d9890761": { + "balance": "16000000000000000000" + }, + "bc5c5151be06aaf6180bc9c1058b181a5a30366e": { + "balance": "113865120384000000000" + }, + "bc66241ca430dc31a3e2f44dedba868e16b9a6a1": { + "balance": "50000000000000000000000" + }, + "bc7c371af0688b1c409f4b07662609a1c9efd120": { + "balance": "20000000000000000000000" + }, + "bc9454f7efc86e25d18a8e8b6e230de42a51d967": { + "balance": "148103676062000000000" + }, + "bc9d5456b975bf0b95c161c3355e4ceb28898fd9": { + "balance": "28083912047000000000" + }, + "bce0b47bf13e4517c53bbbe6e51544b99f3147f6": { + "balance": "919711480389000000000" + }, + "bce2d1ec7c41b426f72b352f5f2b7da3edac4157": { + "balance": "908085365725000000000" + }, + "bcf0756789a57f16206dd78bf6e1322ba9b9b85b": { + "balance": "110888224252000000000" + }, + "bd0bc4a0730f9f55a2f65f62662c7553db52238e": { + "balance": "8440290043000000000" + }, + "bd29fda37c2581a3f040c77eead3143cff24a346": { + "balance": "126022762542000000000" + }, + "bd4c1270322a26a1b825040b239008a447c31918": { + "balance": "727012140904000000000" + }, + "bd6a3da2db66dc9fa26fa2b63b14003d26ef91d0": { + "balance": "5492112771780000000000" + }, + "bd80fcccac60078fcf09f5bddd8a25a92fb9cfdf": { + "balance": "10000000000000000000" + }, + "bd92dc94b6e81a3da5dc3ae6bd80782622658196": { + "balance": "10000000000000000000000" + }, + "bdb35c2c595fe7a2864ebe20dd56d6ddaf9d447c": { + "balance": "4346566125000000000" + }, + "bded4718cbad2150c9b6df9ee7356e0f5c713cea": { + "balance": "311694803600000000000" + }, + "be1804630ecd95ac411b935566cecc5a24c6f18a": { + "balance": "85033246331000000000" + }, + "be2318ad50b0a85b95870a81dce5c31029636159": { + "balance": "5185298019030000000000" + }, + "be3de52fc1119f02f4707f353c040b7c4222d847": { + "balance": "25267399461000000000" + }, + "be4feae01d429c872601ae84dfae8fddc3372686": { + "balance": "20000000000000000000000" + }, + "be7c09d704d16e4b2c9e19cc8c07808bb335f926": { + "balance": "25000000000000000000" + }, + "be873a9525899bdad5e4376b0115950e534dea2f": { + "balance": "404116929377000000000" + }, + "be891b1680ad835aab1ac05a30c0813306cf20f2": { + "balance": "144000000000000000000" + }, + "be8ed2d85a5e3f83c6105db1a1f304e9f174bfce": { + "balance": "50000000000000000000" + }, + "beb1cd80c2f8fabc27ee3a3b2a15e35fa52e7879": { + "balance": "11539095431000000000" + }, + "beb67375e46950830906bf281209be133075452f": { + "balance": "1305262446956000000000" + }, + "bebe54437722c6000bc6a8843f159538a2abf613": { + "balance": "41042548942568000000000" + }, + "bef2a05e283ae948efa9b0e3a6ab5d26a57f1de0": { + "balance": "180614450853000000000" + }, + "bf03950f265a4182b4402703723a0311158eef4f": { + "balance": "158997402149000000000" + }, + "bf06393654baa1ad15c2e717e06dbaa61834c214": { + "balance": "34409427774000000000" + }, + "bf2b867313a44bd04aceaa644771d1e95317c881": { + "balance": "10000000000000000000000" + }, + "bf350ccad91a2a2aff4cf27a291323a297a78009": { + "balance": "124593326152000000000" + }, + "bf3d86edfcf52733e91a9c59be606a95bd921885": { + "balance": "20000000000000000000000" + }, + "bf5b21d5e339752b33b180064d0e6047338650a5": { + "balance": "1000000000000000000" + }, + "bf64c2715db8f353600a45b9264e1f22a40ef8c1": { + "balance": "2952972677360000000000" + }, + "bfaff32c8b04a61658ff94f94e4687232b8d2d7a": { + "balance": "1117691379350000000000" + }, + "bfb00182321502e0729d9a0862ec1df1b3e2208e": { + "balance": "500000000000000000000000" + }, + "bfcdfc9f60610f0ca279ca2c89b9af831332aece": { + "balance": "1431082635308000000000" + }, + "bfe14356e86f6b2ad470bc77d250517c8dc03d15": { + "balance": "310115085185000000000" + }, + "c008bd3fb881da9dca4cadcc56b1d99c56db9abd": { + "balance": "12899598792000000000" + }, + "c01efea456d30360a78ee10c790d46bcb889ee61": { + "balance": "103203021492000000000" + }, + "c03d622627bba7d5db1a9f699924e9d5ff5640f2": { + "balance": "95102233308870000000000" + }, + "c0465ed806ce7ee730e5b6eb7b86a754bfd196a9": { + "balance": "1654379359619000000000" + }, + "c061c5b0d0ce7af95ded1805abb23f743e13c455": { + "balance": "500000000000000000000000" + }, + "c074f2024f79cf8d7aab2d858dd110fc2ee89d41": { + "balance": "18382732686000000000" + }, + "c085147a76d0336b4bd6e7d5b60d394bfd3c6f42": { + "balance": "3236912707535000000000" + }, + "c089416d2d679cb2abf44251de227d0a08fa1206": { + "balance": "497124416350000000000" + }, + "c09d8cfd85989397dc723f2df821dbfb2c0c39b3": { + "balance": "833485701262000000000" + }, + "c0aaf130e3b67250d9775d62e7cd3963daf0a627": { + "balance": "1249947125780000000000" + }, + "c0aebdb5c2e8c5ff9870535c738bfe892c9365dd": { + "balance": "360097616959000000000" + }, + "c0db5680ba88052652bfd5a617c4e8a5be188077": { + "balance": "509051625766000000000" + }, + "c0ee350e5e09a2daeff332a66a6e117fad102112": { + "balance": "10000000000000000000000" + }, + "c12c0a3fd42501f8772e4ad5d262eef3f0bc4701": { + "balance": "120398848512531000000000" + }, + "c135b48c7fd11670bbfba923b28767d21d7923ea": { + "balance": "20000000000000000000" + }, + "c1397c66b7f150c0062b0e87c981c107d771b109": { + "balance": "87751498250000000000" + }, + "c1507ee435cf506fc5d8e4cb62515f2ea0f3a7ae": { + "balance": "4935384099000000000" + }, + "c150d185e2cf203054a6e328b72d8c35bfbbcc33": { + "balance": "21044148271000000000" + }, + "c163098f8b8f0736862274860b3842cf14bd2288": { + "balance": "119025568966000000000" + }, + "c1687fbbc7d504b73fe3e71af440b3dec0da88b2": { + "balance": "229520711528000000000" + }, + "c172bf224080d448261b3b66453074b28628daf7": { + "balance": "7903438287958000000000" + }, + "c18e9bc05dfee2a39fe2b6778a24a48d5bf0f141": { + "balance": "500000000000000000000000" + }, + "c198fec4069c95300d34b9c7109d7441b8e62745": { + "balance": "50000000000000000" + }, + "c1b4134f4757d19a687d05bd7087872b5625405f": { + "balance": "20000000000000000000000" + }, + "c1b43ca2af534ac6bcad8f23c30c07ba07e7e8fb": { + "balance": "194999622000000000000" + }, + "c1c2249507d2dcaf4a9103fcea2cfb47aa4957f7": { + "balance": "571416394325000000000" + }, + "c1e90af40fb64427aeb79a13607debbae9270b52": { + "balance": "50000000000000000000" + }, + "c1ffc8938f3412d19d428b8450f17fd394ae539a": { + "balance": "36000000000000000000" + }, + "c20013e25ae53d0d41bf365aa767822bbbe70936": { + "balance": "10000000000000000000000" + }, + "c20e9eadffa5529ce58a39f5898f39906dcd4b78": { + "balance": "757301065305000000000" + }, + "c211fc2623d51846d26952628d140643efa5156c": { + "balance": "865384323985000000000" + }, + "c2546c312570b30ad2ed05edb13b6469494c5b92": { + "balance": "5000000000000000000" + }, + "c25b2280ed0f835538f8ffd9dfc08a3b853f1ccf": { + "balance": "1000000000000000000" + }, + "c260e43b89a7a4e84bcc4c21dc43d4b5e6923f3a": { + "balance": "1000000000000000000" + }, + "c26aeef0e1f382c88bbdb1eb8c01afa7f58218ce": { + "balance": "79774757760000000000" + }, + "c27dd2645254bc30b6cf7bf418803b02ac808b5e": { + "balance": "4419594173874000000000" + }, + "c2b4f6cf92d6d63a20034e409a358df1803159b8": { + "balance": "1630820442000000000" + }, + "c2ba4a7ea6ca2d17231fb17ebd5dd2dfc0964de4": { + "balance": "221662324727000000000" + }, + "c2bc18f24b8097208a8b2418c444ea58beb94281": { + "balance": "1766754009521000000000" + }, + "c2c028dd17f8a89b9131b7daaeae9cb1dddf86e7": { + "balance": "10000000000000000000000" + }, + "c2ed78a0cb850c12ce8e6ff3873e8c18ffc9f4b9": { + "balance": "1017518755567000000000" + }, + "c2fd7296210b7013d476205d2517d51b21c9e76c": { + "balance": "500000000000000000000000" + }, + "c3041d3d650ff6ac3e35b60371b6798360727651": { + "balance": "1011071365226000000000" + }, + "c328ab9ce1fddd5623e0383828714a7e3ff12eff": { + "balance": "285042661579000000000" + }, + "c34ab008ddddf376dd866cccae4a4d6eb88403e2": { + "balance": "2798642711076000000000" + }, + "c3511391c4515cf8f27e9bc0f777a02a4125c8b1": { + "balance": "20000000000000000000000" + }, + "c36916a9fdf656bb1a8c2f7fb752a3489020f6ff": { + "balance": "689483152953000000000" + }, + "c37598a388d6f4e8e046923265ee9256456e40ab": { + "balance": "62865106394696000000000" + }, + "c38813db256eb221a7142d042b81ba2babab2c31": { + "balance": "98477603778000000000" + }, + "c3acd30f0bc3146fc2cab8d54904f98289021374": { + "balance": "17820000000000000000" + }, + "c3ede34dc1cd995fda1c5cb6e9ffd0c0da080587": { + "balance": "1080428143758000000000" + }, + "c3f04dffe2be55a1d6cdaa78e5c09a79d0477e7b": { + "balance": "59747493842929000000000" + }, + "c3f09f681cfb57d3cabc547dc32a71d2a6585c1a": { + "balance": "1757648436173000000000" + }, + "c3f3bb6444d853614f18c04a3c81f7d26e62e96a": { + "balance": "9022830778000000000" + }, + "c3fe4534327a2fc4144e2d3d3392f7b78d2aabc5": { + "balance": "1759225739027000000000" + }, + "c424f5be9490ec7f0f1e2debc3f72bd83e35f587": { + "balance": "1774372626989000000000" + }, + "c434f64eb937207f80e9a02d2f77ca34bfc63aa2": { + "balance": "960850858644000000000" + }, + "c438b6fa5801a4b8dea450530d975f174cdd47ef": { + "balance": "64000000000000000000" + }, + "c446effb984ff3e5ed92280e7b3dcdb1284230b3": { + "balance": "503490303680000000000" + }, + "c453ae9f94253ebdb871e9dac19056b13d1747a3": { + "balance": "1621494076559000000000" + }, + "c4a473b5e3a6bfb51f963d4dcf109bddedf4fb43": { + "balance": "104273242373000000000" + }, + "c4b8058e9e5416e526ea16e37f29dc221d28a003": { + "balance": "1833513486496000000000" + }, + "c4c09f4bbae0ee06f2a52ff0ef0de1978b5305e9": { + "balance": "20000000000000000000000" + }, + "c4c5981f5ac0a9a3701663b887c4aaac3a3a4d1d": { + "balance": "1411640000000000" + }, + "c4f7a493d16aab4d18e88e530e75e3095a3439ee": { + "balance": "191606419322000000000" + }, + "c5259c18bbd8b0485ca83d069d5ac235b28f24ea": { + "balance": "1276479076242000000000" + }, + "c526ef1124c7d0549b117e7b7463539a24209290": { + "balance": "9106523141000000000" + }, + "c5278b9eeff2221604f30f002c307ca2882fba97": { + "balance": "20875716591000000000" + }, + "c527ca73562846de9fca1649fe5144e5068a2f6e": { + "balance": "25000000000000000000" + }, + "c52a960c5df55169ed5d5cb0109a576321ab82fa": { + "balance": "1097338876493000000000" + }, + "c533ab799e5a04e0ba4e4780d632e0044262d216": { + "balance": "200529941482000000000" + }, + "c5389e3ee2f043ac2b6481f254440a97a9cf3bdb": { + "balance": "84047554571000000000" + }, + "c5594292b324c1d63f797c588a589c895c680ed0": { + "balance": "334298857161000000000" + }, + "c55d7ae4f29d857182d5f1ac2a78cbf35a694dc2": { + "balance": "500000000000000000000000" + }, + "c55ead0ece8fcfbecc573666c0170228e089aefb": { + "balance": "438775082956000000000" + }, + "c55f7d73491cdba391b631581029de32755a09b8": { + "balance": "1340000000000000000" + }, + "c56cb4e8308d6462eded0bbc74965ee135e23e11": { + "balance": "568187503785000000000" + }, + "c5b0c5f840f579536d5977a77262458d72ef1490": { + "balance": "5880686297881000000000" + }, + "c5b129c764daac8bfbf023646b9306d817a8ebdd": { + "balance": "10000000000000000000000" + }, + "c5bba43db949e2ed3de3036caf7a6e42558b1ef2": { + "balance": "763947031151000000000" + }, + "c5d57171e5b9cbafaba7d2c13cca3ec9d81bda49": { + "balance": "25000000000000000000" + }, + "c604e6c539c857ae9e60ca20d1906308ba431892": { + "balance": "100000000000000000000" + }, + "c607bdc5ad2f189e9356edb4d7975c7ba9300836": { + "balance": "55828814399000000000" + }, + "c60b0d2341ecada6c3faf1efcc9027125d99e17a": { + "balance": "121000000000000000000" + }, + "c61e1b993c3fd91a1023ba5b92d06a0aa539d92c": { + "balance": "23863993763643000000000" + }, + "c624656ee5298786cb3d0de045b0ac089c5341d6": { + "balance": "2210389938000000000" + }, + "c6573a023d6f4b5e151f266af4ec0045df0d1518": { + "balance": "52505006485983000000000" + }, + "c66b1d84c42018b16dbc4777409bf50a49febba9": { + "balance": "9078953000000000" + }, + "c69e4de93457f251b1e0879b5250b26e57839fec": { + "balance": "500000000000000000000000" + }, + "c6c51205c9f0bcaea05dce8e47e91d94a3f63c2a": { + "balance": "2720612321571000000000" + }, + "c6d237e0936c4714e701823aadb368fdc471451d": { + "balance": "541700595551000000000" + }, + "c6dcac15739872089cb3d23287e8cd546487ecf2": { + "balance": "1023857245227000000000" + }, + "c6f40b81a5860dece34305f53570be61cdf9a8fa": { + "balance": "20000000000000000000000" + }, + "c7147a95cc4f6bedce6292e8f95539caf550e9d6": { + "balance": "20000000000000000000000" + }, + "c7185b1a680d8b0893065d8213de54375d086420": { + "balance": "11564622085000000000" + }, + "c71b3876613c928197aadf3dd7888db3665f28f0": { + "balance": "112276274428000000000" + }, + "c72200bb380db62a3fd741713d332be77bc1a4ed": { + "balance": "6962060809000000000" + }, + "c7345cd5a7eafc9d7ebdc17d674f83e23336538c": { + "balance": "4425703195684000000000" + }, + "c734f9dc3ee2d857ac826b101129eb77a4a22256": { + "balance": "100000000000000000000" + }, + "c736fa9550b73f4a4ca0ac1cd94bf6f42ccbb11b": { + "balance": "449139000000000000" + }, + "c74128ea37f5d1ee016086a38e470bb332eb5270": { + "balance": "40479951869000000000" + }, + "c7647ec91e823cfe57e8a3433ddafd7b4f675b80": { + "balance": "307102062000000000000" + }, + "c76d49334ce25f5fc62841e5a87d4e03ab3edd9f": { + "balance": "109999979000000000000" + }, + "c771093ed5c4df518536b76e013e8142ecc3f9ed": { + "balance": "5247752820195000000000" + }, + "c780dfb4cdcba4dc89245a8be8a93de1a3e82d3c": { + "balance": "205580199482642000000000" + }, + "c79c6c3a0a46052f723a26b1f107a332474df3a1": { + "balance": "50370325181000000000" + }, + "c7a4e02d2c0f00fa56662cc9f323cabeff82759f": { + "balance": "1163435680762000000000" + }, + "c7c0632cff11812130c30163c83746839a625f95": { + "balance": "10000000000000000000000" + }, + "c82238664bedfa8ded51e91969a39f13a8262a37": { + "balance": "10000000000000000000000" + }, + "c877d228c350ec0d8d97802e7d874d3130171813": { + "balance": "199845203467946000000000" + }, + "c88b8a2e498fee366a1290a575a7f09da12ea8b2": { + "balance": "50895598476000000000" + }, + "c8bbd0e52b11ae6a20adc5f6bbe4d34d7440e8ca": { + "balance": "114566193776000000000" + }, + "c8ca2bd1bef02b505f0333996bcb6bf730648390": { + "balance": "1177250974576000000000" + }, + "c92c3358910418fdb3950e1a378af7246553ae38": { + "balance": "81000000000000000000" + }, + "c9325c9b6d2af226bc5ae1cc975e00cc11274cd1": { + "balance": "2927587698197000000000" + }, + "c95ae8dbc8bb075e7dcb2b2c6d9411bedf26244e": { + "balance": "931878010706000000000" + }, + "c98fc33c1d980052d75fee8b34d08796734b6a4d": { + "balance": "8671327034000000000" + }, + "c99fba8321d16cb19c55703b407c54ed106dcdc4": { + "balance": "20000000000000000000000" + }, + "c9a0da2a3be799e751738e61b9cc376eb06e2b00": { + "balance": "50000000000000000000000" + }, + "c9afc551058c32e89bc2d6704d0d00e92f5ef6d7": { + "balance": "11135553563900000000000" + }, + "c9bfa2ad4b3e9c624255c6ede116421b04487d65": { + "balance": "105514983171000000000" + }, + "c9e4b61d8ddeee339e31ba088efb5d608c3464a5": { + "balance": "20000000000000000000000" + }, + "c9e9090d9f95f401c87c7240f3bf88ca9b540f8b": { + "balance": "553735838243000000000" + }, + "c9fd40bb35284e3d7f0dd3b43a1d9e958f7c86e0": { + "balance": "50480449695128000000000" + }, + "ca038c7c9e66531ad79e4d67b42d7920b7f05c26": { + "balance": "64000000000000000000" + }, + "ca0d08f6019884f94f2b5b191ac9bb247150cd13": { + "balance": "25078089364984000000000" + }, + "ca2c6e6ed3d6a1d030807f91e1fd5c79d36af86f": { + "balance": "849454139892000000000" + }, + "ca7c7bbc24cac0f3aabfdccc77df21004672e634": { + "balance": "6952718700000000000" + }, + "ca998c74383b55c8dcddd46b49f95456fb056b7a": { + "balance": "2000000000000000000000" + }, + "caa989e6a1e934532aaae6cad282c18b1a0b9fd6": { + "balance": "2335540529729000000000" + }, + "cab32ee5cce74e0ee88bbd4b505aa587ef2e4bbf": { + "balance": "75914058971000000000" + }, + "cabe9f0d0a18de8d3495dd063b04c6a33584a8c1": { + "balance": "116083536145000000000" + }, + "cacde94daeafc06e46c86b1e20387a23d909ace8": { + "balance": "1521003430346000000000" + }, + "cafbad01b81ad6cc401883773994a9dd6e6ed913": { + "balance": "10000000000000000000" + }, + "cb343b882cfe866f73cd5f0f31fc68cebaddd882": { + "balance": "221801563082000000000" + }, + "cb3a7aa2e97517b6ea8d9ed0ac270a6a9cc6e079": { + "balance": "958830201738000000000" + }, + "cbd2c4916211ab2c234bc8a51e6f680b59aff782": { + "balance": "24279462419000000000" + }, + "cbea4ed5e8d2ffad442e482fa5f8d551ef2a58e6": { + "balance": "26730000000000000000" + }, + "cc001ce4f4417505116486bed9fdf04bf97ca246": { + "balance": "31740534557000000000" + }, + "cc0b53b26b6dee9f8226f25b834085bde13f5eb5": { + "balance": "132440104515963000000000" + }, + "cc174862456f02f349303d1b8328495de8ccd789": { + "balance": "155951512603000000000" + }, + "cc2af3921727d6d2de31d5f656f837a5475de6cf": { + "balance": "10000000000000000000000" + }, + "cc3201749f55f0d7b450110bc11f65b1ce165d2a": { + "balance": "123428947550000000000" + }, + "cc3f37ad6b449e39c544e26bbdf4d7be66b9dab0": { + "balance": "348574664284000000000" + }, + "cc5b36c9ecea12ebfd0721a58ac11b0c340a3f44": { + "balance": "384197170701000000000" + }, + "cc5b410c7797faa05ac4233eb31b468ee4bf279f": { + "balance": "10000000000000000" + }, + "cc60b223554cc6425374c5e2424df7007621368a": { + "balance": "1128118098000000000" + }, + "cc7027381d98c2e883c82bb9c2f85b985e1e7b4c": { + "balance": "1370000000000000000000" + }, + "cca378f16e07258b9c15921233110fb4729645d2": { + "balance": "151974946930000000000" + }, + "cca781d996c3ef985bf7d2b4d68d55f52efe1905": { + "balance": "2217463190039000000000" + }, + "ccd0b9f6ffb0383553c355c6a14be1200966d47d": { + "balance": "12917165349191000000000" + }, + "ccfa4594129bbb9d07cb4ae8dc2b1c8f3bf98508": { + "balance": "524845286088000000000" + }, + "cd19c879df458106d179bbb5b7f44609d68e6e5f": { + "balance": "8601633489844000000000" + }, + "cd1c55037a0570e8f9aaa95ef157ae81a1969250": { + "balance": "10000000000000000000" + }, + "cd1e47695b0fc93b82cffd0326852dc04d8441f0": { + "balance": "144000000000000000000" + }, + "cd1f90c388d76b3aeaf77850f2191f12a2311f51": { + "balance": "1728456799866000000000" + }, + "cd3aecd58de07f80b64044875fa6ad4f18f72789": { + "balance": "2648597880142000000000" + }, + "cd4f39123ece1e0ab52cfa2a5d059b49c4d63c3f": { + "balance": "1661718859439000000000" + }, + "cd6ed2f7ab49515f8fd70aeb4d72bfae8956b5f1": { + "balance": "183807926254000000000" + }, + "cd9d9d07fcf476a8ee7240324a602449606d75f4": { + "balance": "100000000000000000000000" + }, + "cda66d375a10a22f13dff8a9c40b63461daddab3": { + "balance": "1116940051064000000000" + }, + "cdb0832ee5b26da24b1775c4cf0dfd669b94ce00": { + "balance": "23919219542965000000000" + }, + "cdba5805f17df1f3e47647464de978944ed36b62": { + "balance": "4204539000000000" + }, + "cdd1df8bd54941e26ea26eebbd537e751f64f5f7": { + "balance": "5000000000000000000000" + }, + "cddf5b34342200c37ba96eb0dd662ca4c29f89f8": { + "balance": "10000000000000000000000" + }, + "cdf6c838980afd91a600e3fff755a4848d138568": { + "balance": "25000000000000000000" + }, + "cdf7f55a5a16572d2f2bbf7faeffe3c4d64f86ab": { + "balance": "3115969322502000000000" + }, + "ce0f1dbbfa3490a21ee4b28232db612f44bb7bf1": { + "balance": "9227310122000000000" + }, + "ce33184573c33dd859450304984fa63ea4f2b62d": { + "balance": "7055925237496000000000" + }, + "ce33a3db107f01c51d30b24a8db80faf05308bb7": { + "balance": "10996113113089000000000" + }, + "ce4922b3daef62914f0580a55c524e6a02e31d83": { + "balance": "5541295938315000000000" + }, + "ce4ce8a8540678dda16380c211482dd8c8b71092": { + "balance": "6224176337062000000000" + }, + "ce62cfd71abb9979a0acc398c17dbb5cb6da4721": { + "balance": "13448605175000000000" + }, + "ce724bb30c7821a9c847e0a3e9c12843c3471f9d": { + "balance": "252657175031000000000" + }, + "ce8af01494c2c5b4e74bb02dc6de982e7234fed2": { + "balance": "77349533545000000000" + }, + "ce8c774b7f92045faec43e9cc1711224a3b32435": { + "balance": "370287579971000000000" + }, + "ce8c9ed5018559f36ec72e5a9b0701724e498b51": { + "balance": "142866501748000000000" + }, + "ce995c13568a8b1521d4c9721cfc11da4891860b": { + "balance": "1000000000000000000" + }, + "ceab9dddc767a9651e98527fcf51f6e85c9ae402": { + "balance": "5251411770975000000000" + }, + "ceace25f8c7cf853500a461df007f9c9703ac4a5": { + "balance": "1428847332255000000000" + }, + "ceb0c49dad36f6169ec82a2f0d80da36c87e4209": { + "balance": "459821324064000000000" + }, + "cee8083233bcb4d50ddbf2121c90b5c2019ca58d": { + "balance": "557985245088000000000" + }, + "cf0c6bcc66eb75899bc7f8ed4b8d2b29437bfe85": { + "balance": "3252418478000000000" + }, + "cf32c5bf1d7ef0cb0f2f190f8468b01a4f2d93e2": { + "balance": "6593164924646000000000" + }, + "cf6e47463382153fcf0ec6738880925dbc08116a": { + "balance": "1091910654350000000000" + }, + "cf7539096fd0cd97cd316efcfe9d3c87a101a74c": { + "balance": "741847588809000000000" + }, + "cf9439bf2fbab65cecd783e135a37127f585f1e5": { + "balance": "50100000000000000000" + }, + "cf9bdc902604fab070c611ebf6a989ac4a785c82": { + "balance": "1501000000000000000000" + }, + "cfbbefc0e6013fa2caeabc54ac05f45dbf17ca13": { + "balance": "230809632301000000000" + }, + "cfd53f18ac7d94cadd032a0f4cdbdffaf4765d6e": { + "balance": "64000000000000000000" + }, + "cfe66dc4aa9ac9c9f87fdd05c1b2b95da5211703": { + "balance": "1656993051100000000000" + }, + "cff376eef4d69c4a47d6c7916583228fab3b5967": { + "balance": "5904462494391000000000" + }, + "cfffcb819302d05ed763026bdf84b48818938fb0": { + "balance": "289619807900000000000" + }, + "d000aa72a77d55911a5e66c2906da9206db86633": { + "balance": "3008989624945000000000" + }, + "d02d7b42213e873f91e789cbaffc734ffabd1087": { + "balance": "144960809826000000000" + }, + "d02db5279e918b3e93ff81d00d4025cc71dccaf6": { + "balance": "2386625717975000000000" + }, + "d0802cbcca2bb516f251b873eb20bb5e94af7f37": { + "balance": "9287997718210000000000" + }, + "d0c07380308972a36f57d1cd9081d7389d0421cb": { + "balance": "1280367167470000000000" + }, + "d0c131c1b60891b91e58fbed787ee4567e3f2038": { + "balance": "6360752089492000000000" + }, + "d0c71159d46c4d2af7699f682a055c79a1a68a0d": { + "balance": "1527974433762000000000" + }, + "d0d5d9f242f2613079b3b443c359c2e18ed5faab": { + "balance": "637334647476000000000" + }, + "d0dd208ce92da02eee3ee3de335e67f819581a33": { + "balance": "100000000000000000000" + }, + "d0e55ec0ad0f8986dd9fa9d738007c5bdc22f840": { + "balance": "53012893797000000000" + }, + "d0f222cec657ee444e284c07228d585155b82c0a": { + "balance": "7368748129592000000000" + }, + "d11efb07887d8b5b87a77d8fd388190614e8c077": { + "balance": "4703283503278000000000" + }, + "d129f1b89045ebfb4d1df1d9077e9359fd2990f7": { + "balance": "14496053137000000000" + }, + "d15a509424c4e04868bdcf59cbee09882ba04c8d": { + "balance": "65042393236903000000000" + }, + "d162416912b03fa65f3972a63e357ceaa3b621f7": { + "balance": "325650177224000000000" + }, + "d166183164b81bd049b2146a3ccfcc78cc6a0bdd": { + "balance": "1000000000000000000" + }, + "d173d759f0916e61400d56ca690cbf1743fe27b0": { + "balance": "53550838679000000000" + }, + "d18dc883e3881bf4c7db2afaa097bc2d33656724": { + "balance": "5000000000000000000" + }, + "d19dc9b5ae689dea1ccbfea8b44ec6034559e326": { + "balance": "135552499885000000000" + }, + "d1c79160d0b8c1a1546b86db5123e87645a45d13": { + "balance": "10000000000000000000000" + }, + "d1cccaa22259c547993df3c147d5b545f003adb8": { + "balance": "10000000000000000000000" + }, + "d209c9f32f3292ac4d15ef353fbe6f6efcd4e49d": { + "balance": "81000000000000000000" + }, + "d21ac89a20d67e309f96f64adf05fc48f55918a9": { + "balance": "500000000000000000000000" + }, + "d21f6e7adbf480600295af683091f9b9833f5330": { + "balance": "1229445878922000000000" + }, + "d22700a47a0edb137d2f0348aa0f8d4b6dbc5850": { + "balance": "21301422923000000000" + }, + "d258ddc9372e3b70ff53da171252239655ca9886": { + "balance": "16000000000000000000" + }, + "d274c69317dd836df48562455e8f5a7bd2e47d19": { + "balance": "156091832558000000000" + }, + "d286b68a358fcf8a6cec70b83467079664632ae9": { + "balance": "90377010699000000000" + }, + "d29284915d9b924ae5673e8a4a557478f68a7471": { + "balance": "324678197320000000000" + }, + "d297e64ac2bd8e98e6d276d6fe080679c398a26a": { + "balance": "3401930527000000000" + }, + "d2a1e7b51f6b5930a0d9e2ee55736f3d83a1b323": { + "balance": "44578900750000000000" + }, + "d2c9b0b0bbe61de504e4f210c168fa5999c9c23d": { + "balance": "76537483113000000000" + }, + "d2d49f650d222ec3e2cecba163ee92f0e934ca14": { + "balance": "3312486482635000000000" + }, + "d2d803bf10ba18adef5716b4056c1b1d61c45abf": { + "balance": "964679698000000000" + }, + "d2f673b589df7ef5cb32fdeef842d48d66130567": { + "balance": "1079010447581000000000" + }, + "d2ffaceef1af3f1c3e3f35e4062cd9f9abd1da59": { + "balance": "3041453068594000000000" + }, + "d30a74f5041ec6e73d066a375a105116699ce177": { + "balance": "21814020745000000000" + }, + "d30d849a2d8ff5041304014ecf6752dc769bf004": { + "balance": "1247532881540000000000" + }, + "d3113f558c6376321691931c9b21205e31f4a56e": { + "balance": "572224428451000000000" + }, + "d314bac1bf85eedeac0b359dd2106dbae8fc6947": { + "balance": "20000000000000000000000" + }, + "d3283e17112028b324327ef64a238183ba189207": { + "balance": "136000000000000000000" + }, + "d33ce3c3b64d1b3d399651432c15ecb943d16c70": { + "balance": "10000000000000000000000" + }, + "d33e1e4b10a98e82810f6d161df5d35e5677e35f": { + "balance": "10169656674000000000" + }, + "d34699fd152fe38caacd3c096f6abb1cd79e88b2": { + "balance": "25056644550000000000" + }, + "d369c0e01b9a9d519b3b099a98fead19867c019c": { + "balance": "100000000000000000000000" + }, + "d388dcfe55a9b710d05c686f033fdbdd7861ab71": { + "balance": "1439589263065000000000" + }, + "d391a7d45c7b454b743bd867f8f62f56894f9b65": { + "balance": "484904747488000000000" + }, + "d39a75b4831543e1bc99e7a5ca8875c4f69da45b": { + "balance": "10000000000000000000000" + }, + "d39ed6978b6a90fea29e735f8ea3f1d20e0fbd15": { + "balance": "144000000000000000000" + }, + "d3a0a1a00dcbd6bc44c9803ce351a4b36a69c929": { + "balance": "191222401916000000000" + }, + "d3bf1c0a6b0470c30fc49d995025af5e6b639e61": { + "balance": "10000000000000000000000" + }, + "d3cda762bafaf204469f85e6896ec64147a3452c": { + "balance": "468094119213000000000" + }, + "d3d04d78c1ab9e6887a9467b8b1e31b5c9910e5c": { + "balance": "81000000000000000000" + }, + "d3e1bfdd9396aba00d3e78646ddcdaf139a967c0": { + "balance": "833333174120000000000" + }, + "d3e502c42ff0274da12ba87ffd45fa593bba052a": { + "balance": "100409899947269000000000" + }, + "d3e76066c2e32d9a693161de07f2d3b7e6ea07eb": { + "balance": "10000000000000000000000" + }, + "d3e8d577323d97407246b198c4c61f7943c468cd": { + "balance": "10000000000000000000000" + }, + "d3fd4d1b0edbc314b103d350fff023ab75b7d7cd": { + "balance": "84129547428000000000" + }, + "d40087fca8feb72d130bbc9622575d4987f12895": { + "balance": "1000000000000000000" + }, + "d407d4126cbf3619a422c532ccf20c3da1495dbd": { + "balance": "99622000000000000" + }, + "d41a28761c8e5de8c803813667f1dc0918a105be": { + "balance": "157507410260000000000" + }, + "d46ed38228a3c3d78065b2d8b71b325bf0f0e685": { + "balance": "6787045850000000000" + }, + "d4a7463d202e804b39a93bccd77491d8791baf58": { + "balance": "171694163573000000000" + }, + "d4c20716ff7288d811d05fd6f0696a9f5627a11d": { + "balance": "100000000000000000000" + }, + "d4d95059c808cf41e64f7f353246ffae635419d4": { + "balance": "10000000000000000000000" + }, + "d4ef925157c6d0e2d649332f44416b85f8abe69e": { + "balance": "1392945162611000000000" + }, + "d4f0cb25801794f6d803306878763e08209d19f4": { + "balance": "64000000000000000000" + }, + "d55fbebc4dcf2de6341c2325448e9c198f0f06a3": { + "balance": "14206622892000000000" + }, + "d566968c40211fb25114105e36b5a7219cde9d5f": { + "balance": "4898442964000000000" + }, + "d5817b95c6b504a6d07f64faccc9aedf408b0ac4": { + "balance": "54387832478000000000" + }, + "d59679fc40a71897065bf1b3a73f331226cdae72": { + "balance": "20000000000000000000000" + }, + "d5a7deec4a5898f094e1600f9b15768d8aada258": { + "balance": "100000000000000000000000" + }, + "d5b91c29bf772ad3ba04033dfb86b672b245ad77": { + "balance": "100500000000000000000" + }, + "d5c1a9bcc5e68b7547354178fefb3d870572fd67": { + "balance": "2252066779089000000000" + }, + "d5da2a826f5909a221bfd8561dbd7dbf4aca4c35": { + "balance": "13839784966766000000000" + }, + "d5dcc82fa169b4677a3fc26d78f38e27dcc763f3": { + "balance": "10000000000000000000000" + }, + "d5f344ee8a1b954ae5fd8fc7ac702174749bc8a4": { + "balance": "1398836216771000000000" + }, + "d61cd03afbfc1bea186e5a3a51347c2c4ee3a2c3": { + "balance": "109879472702000000000" + }, + "d647fd7ca17203a0049c28ec6759612d767cfcce": { + "balance": "162681136487000000000" + }, + "d656d14acfb2f0fbde2ed2a137a52d852bb6288b": { + "balance": "20000000000000000000000" + }, + "d68130b421b19c193d03a9017b2dc687c7307d26": { + "balance": "128569735484000000000" + }, + "d69a41f7ca76b40ee94b0d04a3780a00c6c651ba": { + "balance": "2801054372864000000000" + }, + "d69af2a796a737a103f12d2f0bcc563a13900e6f": { + "balance": "7412286547000000000" + }, + "d6a5a7e149cbccb72a50b0a3ae00e6756b0a7eda": { + "balance": "1075352201657000000000" + }, + "d6aa9957f141f0dfed77e943c39aeed978834fdf": { + "balance": "20920740110000000000" + }, + "d6e99ccb72d24e8a60f24d47afd4074b1d1fd336": { + "balance": "15415994387186000000000" + }, + "d6ea4a9dda8d5bc832229c916fa45f05f99c093a": { + "balance": "27075799893190000000000" + }, + "d71de419d746ac277baa955761cced4b34c376ec": { + "balance": "1388473506822000000000" + }, + "d71ec6b5e5d4c604f741bafde0974eca49c56156": { + "balance": "61938809628000000000" + }, + "d72f90d9879f6d2d407b4fdf5d128b98d518f1a5": { + "balance": "10000000000000000000000" + }, + "d743d7925a0cfd08150814cce8cd5d3f7099e1c9": { + "balance": "25681376856000000000" + }, + "d7575a09e7498f21cda3e9e7266b7fde91dfe19b": { + "balance": "9841565066000000000" + }, + "d75c2eb5e0a2b2ee72ef4fa7249c1a1ce03f333d": { + "balance": "134491489751000000000" + }, + "d77088329ec1e280ea7a087ad20c5e965721ff4d": { + "balance": "3949070941222000000000" + }, + "d78d564bb79ea19e4a93975a38fe0882018f177c": { + "balance": "992717434142000000000" + }, + "d78efb176b252ce67b5648e04088d12c4668aad1": { + "balance": "10070463674000000000" + }, + "d7a25e43d7d4e23744f0b10e2b4f2911fd3b3bc1": { + "balance": "1000000000000000000" + }, + "d7a941cd82f8aa63c55baa81db44bcb347b8e529": { + "balance": "49000000000000000000" + }, + "d7b34387880daede6cbdad11bb3db67daf942975": { + "balance": "20000000000000000000000" + }, + "d7bca0770e2f890c1e93c3595641241454a31045": { + "balance": "2000000000000000000" + }, + "d7cb675cea1c0dafded44f611c9c344e2a5e053c": { + "balance": "25000000000000000000" + }, + "d7e53a2d8eaefd18e02bbadb7e64906ca8613151": { + "balance": "166599594268000000000" + }, + "d8076b9db0b7496efbd198b73c4bfcf51ac080fd": { + "balance": "210272077089000000000" + }, + "d81dcf5756da397ff1f783ffe5391d1ffd4ff227": { + "balance": "500000000000000000000000" + }, + "d833c6d08f5fff8f77628ab1e86584d052976d1f": { + "balance": "10000000000000000000000" + }, + "d835732e85953baf2af9e49f770bac1caa1dac23": { + "balance": "152211441541000000000" + }, + "d84005fea447e8c6aa0b5436ad79654a75348456": { + "balance": "22563694224690000000000" + }, + "d84d9c59a445911922e88c0f22cc6534f33ca3de": { + "balance": "3054115413381000000000" + }, + "d84e69926216065749e624d87783e90ce3015b82": { + "balance": "1420803164313000000000" + }, + "d884bdbdb7e13cc523e7f192310230c7bdbb4a07": { + "balance": "10000000000000000000000" + }, + "d88eedca1dd9249702f5ffc807c1e439eee1c5e5": { + "balance": "36000000000000000000" + }, + "d8a23fd234bada1c726622925ade62d3021e0037": { + "balance": "1567046607931000000000" + }, + "d8b1aee24264efebd1c677fcab6ada6e0f000cc5": { + "balance": "20000000000000000000000" + }, + "d8ba7afbb8bf2910b983a114aedec626eb7426c1": { + "balance": "275491152435000000000" + }, + "d8c8af55ebf116ba3c3904f8ac39d3a7d31aadc5": { + "balance": "1499999998278000000000000" + }, + "d8d97645f5f62aa89bf0046362dd0f45d40f821f": { + "balance": "25000000000000000000" + }, + "d8ea0e24a7e28285c4454f54181d581324da2583": { + "balance": "53039425000000000" + }, + "d8f5d258164747ccf790f5ed358162c756de49db": { + "balance": "323009990690000000000" + }, + "d9477bb62d3eb668a83a9679f3a7ef43f17c9e4d": { + "balance": "14045557127869000000000" + }, + "d9585e1b03fc86636dde1e64aed3cad77868549a": { + "balance": "1000000000000000000000" + }, + "d975f9ce3fe773fac3f8338a034a757c58f6e11f": { + "balance": "25000000000000000000" + }, + "d97e490faf19de612fb49c041d3f9e7877d3c0bb": { + "balance": "65766847746000000000" + }, + "d98117b74b2f2888d7078d3116d5758e2d09bfca": { + "balance": "1749157484422000000000" + }, + "d990b3f69ec700bdc095c184b3804551c832d612": { + "balance": "509385034698000000000" + }, + "d99b35298e709e5f54e6a5c612a326a83f4268c4": { + "balance": "71963571266000000000" + }, + "d99d9ec76005da26ccc721ec26be4ed9b3b1c586": { + "balance": "469607736824000000000" + }, + "d9bc61075c3201351584a026e5bdfb7cf9a7b6ab": { + "balance": "200000000000000000000" + }, + "d9d07b72f83491b6db26602f6b7039aeebfe6b61": { + "balance": "144000000000000000000" + }, + "d9f6f1ddf03e836b3744d008b62a6424544c67a5": { + "balance": "74347470143000000000" + }, + "d9fceff07ad69bf3b4aef54a7eee541368980cf6": { + "balance": "1143407707495000000000" + }, + "da0285fb7e37fd4be66fb862b248cea94ea8f6db": { + "balance": "80770216661309000000000" + }, + "da05c7aa330fcc5834e19deeb0a808e9ab7f3d99": { + "balance": "169000000000000000000" + }, + "da129e4481bd25450e6c7b42fe417c87ee2ce7a7": { + "balance": "256000000000000000000" + }, + "da32e3ec421993db088c71e256263158f7855b61": { + "balance": "18540215888567000000000" + }, + "da3c99669acd202ccbe6f80902c807588eca0880": { + "balance": "1000000000000000" + }, + "da72a7bec114d43aee6449db830d2d3f16e4d9b6": { + "balance": "744534872932000000000" + }, + "da72ec2cd7b8e3924f8baaea75d5ed23ef39394c": { + "balance": "38646377617204000000000" + }, + "da73078957f491827d62cb3ca0c484c2d1004ba7": { + "balance": "891774109242000000000" + }, + "da828e50c7c8580c6ce81718f11fbd43b2b0541f": { + "balance": "66094097819000000000" + }, + "da91483db6a6a034e068e69a6b46674838c5bc80": { + "balance": "4000000000000000000000" + }, + "da9551b635c3619f81641571e267755b89f7fe1e": { + "balance": "670841942250000000000" + }, + "da9b43a9c1c574580ec43da9f6acb687fc2f8c68": { + "balance": "761695404114000000000" + }, + "daa7f446923f7481115ad285ca468c865147e563": { + "balance": "10000000000000000000000" + }, + "dac6bfd15954efa4c9254e24e5831ab1884f8d67": { + "balance": "960042043423000000000" + }, + "dad85d0b8bb5ebf6ef811d0d35c89f9f343c833c": { + "balance": "37664599958479000000000" + }, + "dad9b01652de5d50bf30f9bcb0c6edc6315139e3": { + "balance": "21500996724000000000" + }, + "dae9c7d6bb0efe3f7ea20442b184f6d99b2a2c12": { + "balance": "937830189066000000000" + }, + "db0d6c28e9b913f611accaab15cc887f9b770f58": { + "balance": "20000000000000000000000" + }, + "db0e5341d64817885721c5abff04c30bd38df40f": { + "balance": "62600679700000000000" + }, + "db387dd404d14478babb60bad2391720d68b92ed": { + "balance": "115096708329000000000" + }, + "db3fb19e8a4a6ace4d8c6c02085d4cbba528b532": { + "balance": "1000000000000000000" + }, + "db4f05a66c0ccf0532ea1ecb931e05a400a6f4a7": { + "balance": "20000000000000000000000" + }, + "db571f1cdf8e83fbff6fb48cc0c81ef95ede12a0": { + "balance": "118317387393000000000" + }, + "db6a6a6db2aef3f43afbfe23027b670ebb3d33bf": { + "balance": "9960755220000000000" + }, + "db8bed34f8f34f45cb83ab19ed33fad76437d217": { + "balance": "21003651205000000000" + }, + "dbeba6a2a7f66c20c6db7b9270a5aee74de3f441": { + "balance": "4086905723945000000000" + }, + "dc04efeac13b2dab3d07833a7e7fa728fc23d18a": { + "balance": "1161834099120000000000" + }, + "dc092386c3a3e28b6b2d7d70db8f3d11e79ef5df": { + "balance": "124362293793000000000" + }, + "dc10be66aa11acbd42a2b1953714f09b5281681b": { + "balance": "20000000000000000000000" + }, + "dc2d58a383ce0bd40bed859ec2f25412b68eca0a": { + "balance": "104917823922000000000" + }, + "dc2e38183dceb2bc82b23e8ccf48dd96ea1c97b6": { + "balance": "2847787376064000000000" + }, + "dc5d9d94530d88451cf081fe7f2ac33667af9d8f": { + "balance": "65321904051000000000000" + }, + "dc993112a8d89136e0e73d67e2f26191583a50ec": { + "balance": "1000000000000000000" + }, + "dc9bb69b295945589a41feb794406558ce65dedc": { + "balance": "104077637254454000000000" + }, + "dcb0109d4fca2dace08ddca5d989a09d470161a0": { + "balance": "28897833222000000000" + }, + "dcce3a4ec516d833f5a9790c40ad0334b0d2dd01": { + "balance": "25000000000000000000" + }, + "dcdb21cc811ab733c2a80a2d5c8e5bb49cb2ddc4": { + "balance": "16000000000000000000" + }, + "dcdf8dd3ce03a2fe0d72835dbbd58725e1ed2c57": { + "balance": "113330414284000000000" + }, + "dd2165839ab95d6b24591307adcde9ee1819927a": { + "balance": "20260199589072000000000" + }, + "dd3015a5fdef66e749a000585d5574f975e3432d": { + "balance": "85465001652000000000" + }, + "dd37c478727f44943c5fd79ace30f21fae5a589a": { + "balance": "108577233510000000000" + }, + "dd3fb5810c31d37652bd17b92497ed479faf123d": { + "balance": "669996966072000000000" + }, + "ddc3bda30f7cf36bd535de4e20c9becb78d159f4": { + "balance": "99998278000000000000" + }, + "ddcce2d2431b67d4157c7ac4bd77f20c24831de6": { + "balance": "36160893899000000000" + }, + "dddcebe609f8b4354a1f27ab1915135e25800344": { + "balance": "1457846339959000000000" + }, + "dde223eb48f81748abde6cbc08cf1e6b0e8e4e5a": { + "balance": "1501921107087000000000" + }, + "ddf4ba402007060d9940a96f8e7c39f0a2c6108a": { + "balance": "377268151287000000000" + }, + "de05d9ada6626a8492acd137c7c7f7080a987cd1": { + "balance": "222144234923000000000" + }, + "de0fab89f79c4edf9766c3b7b1f508cb43c5495e": { + "balance": "8278000000000000" + }, + "de1070f3ff6c47237768fbdead88b2d5184fbe2f": { + "balance": "1000000000000000000" + }, + "de2b16d7f36f630329287822f550ec19415acb3a": { + "balance": "25000000000000000000" + }, + "de3faf6884337a99e54ac5d3f08b34be51b0755b": { + "balance": "51926806905184000000000" + }, + "de4614fd632ddac888d177de0858e62bbbf7dc11": { + "balance": "52506376589000000000" + }, + "de54cabb241dc5def530191f948f67db942a85b0": { + "balance": "9691177060000000000" + }, + "de81e488284acc4f8f6061d3a73bad112efa7a40": { + "balance": "14654060992000000000" + }, + "dea86ac3a661272691c877c1bad8355789382b69": { + "balance": "903877103000000000" + }, + "deadfc79f2a722dbf1c1a92f2824da8874189fea": { + "balance": "98905944986000000000" + }, + "decf1af47e153f6f3749a1b7abadefdcf1607a0f": { + "balance": "529000000000000000000" + }, + "dede5fa984f0def639d5b633f54c60fc5aaa272a": { + "balance": "8193771708654000000000" + }, + "df23607c63b3fd4b5fde6aab093c0c56d1188f95": { + "balance": "14687379916000000000" + }, + "df5b74bf02902e4c466821de798406b663d4d73e": { + "balance": "9000000000000000000" + }, + "df6402ee3f37389e7f65720561b54e26e5f1cbaf": { + "balance": "358266132937000000000" + }, + "df83ea5b770d5abeccac7f0cae803e8bd7b9831d": { + "balance": "25000000000000000000" + }, + "df92802ffe9892c7704875755bdec648914430e6": { + "balance": "20000000000000000000000" + }, + "dfa108bcd80e824a255679a38b2450d428e2f939": { + "balance": "489209553654000000000" + }, + "dfa9f18e859353796afe384d05353dc80b3ffc43": { + "balance": "121000000000000000000" + }, + "dfb0d6580f011e68a39d7727818b0890e70f3036": { + "balance": "537675412560000000000" + }, + "dfdf006abf2293aadc58feea6af6b35db428675e": { + "balance": "9000000000000000000" + }, + "dfdf2ba93bd47d7243b7419413458a947effcf67": { + "balance": "45080282196110000000000" + }, + "dff01277ac23a8cf93383595a80a7c070eafe5c6": { + "balance": "312778552103000000000" + }, + "e0450154c441e52c5e507e8316d4e9376c59c12b": { + "balance": "170163401434000000000" + }, + "e059374d6a7e6c63e609b65642272869fa3b2b3c": { + "balance": "300122497803000000000" + }, + "e0c0d8e739a2f274a43f019a07f7f61d7d8e11a7": { + "balance": "2630310240000000000" + }, + "e0e779e4e3573ea77096daec252ac2b3f1c0013a": { + "balance": "10000000000000000000000" + }, + "e1325eb586180a67873718a2016172afeb03c6a5": { + "balance": "531691399657000000000" + }, + "e13958af480da6443b9ec1067f0f33440634a282": { + "balance": "10000000000000000000000" + }, + "e142daac753b2c4d215372797999e9c88b65dfc9": { + "balance": "585813299366000000000" + }, + "e142ea343bc36ec49989fd43ad5c403c70a40dbe": { + "balance": "656734902975000000000" + }, + "e14d0a3d259db6bfec2fc4ef6e18729e4d93b007": { + "balance": "210234446279000000000" + }, + "e16a5316e3a113f27bafdf3d4fe44fe30ae9c210": { + "balance": "16000000000000000000" + }, + "e1770944aec145a96c9491497eacf7f3fb03c1b2": { + "balance": "335417250470000000000" + }, + "e199ac237661dcac0a4cfab404876abde72ee209": { + "balance": "340000000000000000000" + }, + "e1ad427471023f38cbdf07fdca3728ec343810c4": { + "balance": "343957267368000000000" + }, + "e1ae0223cecd738c8e530a0007ef05e8f3b33769": { + "balance": "950528515289000000000" + }, + "e1d2d4ef39f01a60c3bb5d671af91c5298d87711": { + "balance": "121000000000000000000" + }, + "e1d4a8888cbb383f3671ca96e7b55310b59a2541": { + "balance": "242387826125000000000" + }, + "e1da9039ddfe117e6a0b484fd3962426c112871c": { + "balance": "3710499693813000000000" + }, + "e1da9f16d57c601af8b6d102323c20408af8531a": { + "balance": "3135322588771000000000" + }, + "e1e1c163f391ffad2d0be68641253b0860485a95": { + "balance": "10000000000000000000000" + }, + "e1ec6361df67ad915df9e9661cd0932186db034a": { + "balance": "4279936304854000000000" + }, + "e224050bcd723e63f1fc0567a86942546aaf8d13": { + "balance": "12007628539000000000" + }, + "e2342c7f411d7ca3a86484af59a9c3f3180e2f0f": { + "balance": "16000000000000000000" + }, + "e26f2b026a258ce5801c90bb8fd6f7a152b8d267": { + "balance": "304593714834000000000" + }, + "e2717eb5fd0a1da51272b50ca8d12858009c7016": { + "balance": "506943817535000000000" + }, + "e27546d5620e6398829260e58e8cf4a3a03f4164": { + "balance": "3000000000000000000000" + }, + "e2762bb64e0606a5d635032e15164b01f612a74f": { + "balance": "884716158811000000000" + }, + "e2882066ed0a3c041d09c00c8532850fc42eac06": { + "balance": "42441412728970000000000" + }, + "e294c5d64daf7b7c0994aa9d03669c4b2658c9cf": { + "balance": "6996693830997000000000" + }, + "e2b179f0ed6870a6268aea64b0c7b39d98d97fcf": { + "balance": "334205318353000000000" + }, + "e2d1f6f7e3128340b789565b527bb91de96d54bf": { + "balance": "100000000000000000000" + }, + "e2f136d3693aa0b2346a968a22aca6707fc1d0e5": { + "balance": "10000000000000000000000" + }, + "e2f229054293e32cf3e83f9bb88d9cf1d6acd66b": { + "balance": "20000000000000000000000" + }, + "e33b8f4c9a49554c8b134861f88c8fffc399e456": { + "balance": "83552502198000000000" + }, + "e33cfc7727b1460324b34277dde14cc49bcb273d": { + "balance": "100000000000000000" + }, + "e36af9bfed4f912cae21f3d899f7354e1c902601": { + "balance": "31474316356000000000" + }, + "e36eff7c061dec48446d47675f176b4da3c2e950": { + "balance": "10000000000000000000000" + }, + "e383f3cf431f3cf645f26c7d5e5e2f77348ede6f": { + "balance": "776224304171000000000" + }, + "e398b9f004a4f891cf871a57d9124a97b56e89e9": { + "balance": "84846187740000000000" + }, + "e39ab2415144b46db522e92ed51b8089a5ec01fd": { + "balance": "4158925896363000000000" + }, + "e3aa7ac7e15e9a8a6f54565067234a9d4bf7b569": { + "balance": "1080385576951000000000" + }, + "e3ec5ebd3e822c972d802a0ee4e0ec080b8237ba": { + "balance": "2129139289000000000" + }, + "e3f1fbff8686af23ab95eeeee6a6a03782d72416": { + "balance": "401776848194000000000" + }, + "e4001b830fbd86df257ebab54aec0c66314ef9aa": { + "balance": "518220809325000000000" + }, + "e40790bff894f0b3e534942b5ad6f6592cd6e896": { + "balance": "25000000000000000000" + }, + "e409170a296e46fc96d85a2395e4324212a470ee": { + "balance": "1072528749756000000000" + }, + "e41546f68bbe1771febbdac2a4a5999eef50edf3": { + "balance": "1000000000000000000000000" + }, + "e425d63d711a9996c09d928ba8df94c88163aea9": { + "balance": "10000000000000000000000" + }, + "e4432ff1aee13f97f73a8407e4c7d6e768b8040b": { + "balance": "700508995102000000000" + }, + "e4690f5d024a395355a7cb5238fb7e0dc921b1e8": { + "balance": "1000000000000000000000000" + }, + "e4829684fb36f054766a61fb2a8f6ecdf27c9e87": { + "balance": "73885178137000000000" + }, + "e48a68e1ac007e14ac08c1b3b0df2b5602081ec2": { + "balance": "1389262869176000000000" + }, + "e4d699b3f4117eba7ed27b323048c9ffcb46ed42": { + "balance": "183131036697000000000" + }, + "e4db688c29fdf9a1c16114f99797d8409545955f": { + "balance": "16000000000000000000" + }, + "e535b94d370190d1e0955d3c0d12480e558f00dd": { + "balance": "20000000000000000000000" + }, + "e53966d4bb17fa9b50d29b44ddf3951c9ca67caa": { + "balance": "6400630678000000000" + }, + "e56f2656fdd1a5f7d3716e65dd89a37dd6e42dcc": { + "balance": "1000000000000000000" + }, + "e5a364113076273352e0c31bf505028e0b7edbaa": { + "balance": "10000000000000000000000" + }, + "e5a3c80518fab6a0a721ccbdc3e673680a65f6de": { + "balance": "171727917465000000000" + }, + "e5c71c7170e5c9b07e62cc307d81a4a3053ed64c": { + "balance": "10000000000000000000000" + }, + "e5fb6408db128c55cfb3e7fa1942d6347e34932c": { + "balance": "10000000000000000000" + }, + "e606883236f8b2045393c574153a100675cd4b90": { + "balance": "14005226900000000000" + }, + "e61869d1cf72f25e195898217f5bf5bcec9c9038": { + "balance": "50000000000000000000000" + }, + "e61e2e29c0719457ab1bf7d6d9fe442bd6107b07": { + "balance": "30943034333100000000000" + }, + "e61eb97093e9ee609647bd55f434a27bb30a9401": { + "balance": "200951434577471000000000" + }, + "e62812ad5834747f17c92435d863639e84d132fc": { + "balance": "3017271391299000000000" + }, + "e630b92aa8443eb077e1f6990a2e194d99cf53ec": { + "balance": "1000000000000000000000000" + }, + "e656fd1641c15e1a4b753be41bc4aa438b44b42c": { + "balance": "26972744083000000000" + }, + "e663f0257b98dfa80602a2af1bea1f901c4a7612": { + "balance": "97075813547000000000" + }, + "e66e411a8a9d019b53bf2e0a7e44703e1aa93ac1": { + "balance": "25000000000000000000" + }, + "e6712675d13fff27af43bb1cb3f2f283755bacf5": { + "balance": "227572496234000000000" + }, + "e68e8f04b2cff484da2d41dd639ae8880920f781": { + "balance": "20000000000000000000000" + }, + "e6972b5d7e0fe8c722dec9146b92f89291a0207a": { + "balance": "2115924954211000000000" + }, + "e698b491330cb55ecc4cc4b74015cd94eb927fc4": { + "balance": "1038111785278000000000" + }, + "e6c411e67b90109dbb0fa75f0f07ae8a504e9637": { + "balance": "123792105420000000000" + }, + "e6fb1dabc624edb45b040ad66f30dae010a6b634": { + "balance": "16076893670852000000000" + }, + "e71dac161206e7d3686d13b98fd922ab73587988": { + "balance": "500000000000000000000000" + }, + "e773f9be9b3f4b35ac149b4d759b9e47c8000bdb": { + "balance": "329623043336000000000" + }, + "e781cbbd2dccfdf68595d54fa44104a80d52dd22": { + "balance": "188679476509000000000" + }, + "e793666c7850a409b1d5494f576d122e85cfed9c": { + "balance": "1141845197779000000000" + }, + "e7a5527c6deb922e9f84309c502048f49f0c8f14": { + "balance": "81415566708000000000" + }, + "e7b0f75f9c69ae464b1b63cf295555d0815fc532": { + "balance": "10000000000000000000000" + }, + "e7b43cc673e321e607190a6fde996b71508f4d81": { + "balance": "103958781426000000000" + }, + "e7bfcf3125e37755e57804dfe4479657b212a8ca": { + "balance": "10000000000000000000000" + }, + "e7d33cbbd4eb38365c5be04ce32658a5ac741cfa": { + "balance": "1545192252109000000000" + }, + "e84cfbd7844f6aa3e830258a6b1069b6a7ff5b7e": { + "balance": "543989509107945000000000" + }, + "e8aa0cbc5c1f59fadf3ec122fa8a59ebfc60b5b6": { + "balance": "61271973066000000000" + }, + "e8adb5303c30a8ee044dc09c49818c02a16f4254": { + "balance": "737375689166000000000" + }, + "e8aeef5114e19d467c3064938c5965d04830f2ae": { + "balance": "51130466380000000000" + }, + "e8b5a83497198a513fb2e244bcf05f9d4cf09d62": { + "balance": "10000000000000000000000" + }, + "e8b6818cf0d24bd0e7ded854b3d368662a150dab": { + "balance": "63697741112000000000" + }, + "e8b68b9cb24169fd688db7a626d79d0363777c75": { + "balance": "427222669643000000000" + }, + "e8b8b57b23ea953943da3ef7efaefced9cdbb44c": { + "balance": "16000000000000000000" + }, + "e8f85dca364d26c2149b767904c6c06249c3d88a": { + "balance": "199342917246000000000" + }, + "e916c7801cdcf1b6cf640fcd9dcc1e3148c80105": { + "balance": "9000756000000000000" + }, + "e93cbef13277324caae7816c3d601e2f6bb42589": { + "balance": "121000000000000000000" + }, + "e9415fedcdf8939b551999900128530195a2a5f0": { + "balance": "85165078941891000000000" + }, + "e9a79ade714ce48a07fe88532a20d8f8ed27bac9": { + "balance": "30768493367842000000000" + }, + "e9b35c7ca775661bbd3a4844e2c6bc5effcdea58": { + "balance": "134719523000000000" + }, + "e9b819dffb600373bfd1b1608fc9744cc9167855": { + "balance": "1537634693002000000000" + }, + "e9c5ef50d4a194e53928659b4486a1c456df9e56": { + "balance": "50000000000000000000000" + }, + "e9e21f4523b11567516f6fc525e8967ac707f988": { + "balance": "2498740681000000000" + }, + "ea02821d6c730e061a9947b75188eb8bc0bbf9f1": { + "balance": "12822292582000000000" + }, + "ea3bca3a17c7e724ac0e15acab6442f222cd8688": { + "balance": "2789689549000000000" + }, + "ea4f7923d7045a148d50153f5f4620dbd31a74da": { + "balance": "113595858930000000000" + }, + "ea6d4cbae3cfe49ffd36653bb0d64c01b2bbc0b8": { + "balance": "49325017701000000000" + }, + "ea76cd4cff825301932a5c1d3a1de55a0ff00797": { + "balance": "1282028021000000000" + }, + "ea8e4c8c6500856777e2b41832ff00443db291ce": { + "balance": "553674550359000000000" + }, + "eab52191e5afc804b8685fe13d7ad6f5dc64fc12": { + "balance": "244412435341000000000" + }, + "eac1b0868b710e40d6d5c66a461dfc8f78abbaa9": { + "balance": "10000000000000000000000" + }, + "eacac2c75920b8f6e65f37ad81deb113d526d031": { + "balance": "53028042076000000000" + }, + "eacc9ef8b534143560f420031a8a7f030ff1a36e": { + "balance": "381111853842000000000" + }, + "eaf2cc9fdfe6272de269f32486b2d4c248a05afe": { + "balance": "2793234915237000000000" + }, + "eb0220406832a8a5d4f242538e82c80bd83d0ac6": { + "balance": "10000000000000000000000" + }, + "eb20efc0e0af48c8e6da4b21efa9c9f02d92d29f": { + "balance": "152958793764000000000" + }, + "eb41bce8e3aac2bcf662854a3151e3c83d98c6f3": { + "balance": "219455327737000000000" + }, + "eb44c591306972c29a7084079720d8ee5fb9b0a1": { + "balance": "49000000000000000000" + }, + "eb4b26ab55dc35df2e78d47a90fc43148a6de881": { + "balance": "12139574483030000000000" + }, + "eb4f53510db5edcaad6ea169e521bd094e8da4b1": { + "balance": "100000000000000000" + }, + "eb4fbfb7c0082aa0e7edaed934c5166fee955e5b": { + "balance": "299713748180000000000" + }, + "eb6067ab544af6289a73111e7693dc449d5c2134": { + "balance": "20000000000000000000" + }, + "eb86fea82d10d309b1365237e4855a48684e0e49": { + "balance": "81510415589000000000" + }, + "eb8abbcadeb6e19ab4392cded7a407c8d5df2d5c": { + "balance": "25000000000000000000" + }, + "eba44ca2d6f36df8221a2021bf0644cf6cb59452": { + "balance": "500000000000000000000000" + }, + "ebacbc0eace170f66415df48f74d98eb31828d15": { + "balance": "19046465915296000000000" + }, + "ebc72fb8a1029139d8abdc08da23dc559f87e1a8": { + "balance": "24177703742991000000000" + }, + "ebd561bb9001991cb6b02c8ff9e7ece8a3d73dde": { + "balance": "6684606759000000000" + }, + "ebe1dc3ee857ae4add6fa6636b678af8451d1701": { + "balance": "1485349608007000000000" + }, + "ebe68dc904c737be83aa2ee7f613dd51a6d436e4": { + "balance": "11206782120918000000000" + }, + "ebecf4db55a99f018bf136173ae823528f211380": { + "balance": "191817711082000000000" + }, + "ec15ad0aafe0c0f18089de50b2397509e15a20de": { + "balance": "20000000000000000000000" + }, + "ec2e56973a6cbd8b37d0294b16ef806ab5943ec7": { + "balance": "12031630315394000000000" + }, + "ec432a6a4685ebf6c1e872001d1de246140c8d98": { + "balance": "280056522277000000000" + }, + "ec866ba1bdadb91ca25f5ae035b0f69421ed4377": { + "balance": "431849961155000000000" + }, + "ec9be854224d3d371b79ffc1230fe704ba03be2b": { + "balance": "3692428502391000000000" + }, + "ecc2d6e129c7daa37a93f559c6d4f575171d8386": { + "balance": "20000000000000000000000" + }, + "ecc3aca2a21cb317c5b9debdcb2090f3931d5cd7": { + "balance": "100000000000000000000000" + }, + "eccc9a49ff40aa4b07aa0e1271cfb6713de683dd": { + "balance": "617207728367000000000" + }, + "ecccf24530629033fd6234ae32bde2052ebaa640": { + "balance": "16000000000000000000" + }, + "ed16770d5a56dced87224d4ff68a361a2285fef2": { + "balance": "10000000000000000000000" + }, + "ed23b8e782d5ddf203f9b80e5df83ec32e484fc6": { + "balance": "5000000000000000000" + }, + "ed3244e4168e669ae9d54175173c3f0f0e7c4c7a": { + "balance": "803397672115000000000" + }, + "ed48f39d3f022b321c0864d4955e1cdc8cf54834": { + "balance": "64000000000000000000" + }, + "ed4cb42fa6737cbbbf095f181e1425b3bc3ab4f6": { + "balance": "8974148344000000000" + }, + "ed560f7d83c27a26965f84dcface3930bc447fc5": { + "balance": "2092287996000000000" + }, + "ed6ace91369ec3b06cce474e67d1ce4aba6475a6": { + "balance": "1227081000000000000" + }, + "ed8249dd4a91f70176ffff310e5546e7e0c30b91": { + "balance": "813069034369000000000" + }, + "ed8987fa3d4d42bb8f009c99cda5868633d94f5a": { + "balance": "174952234860000000000" + }, + "ed99b72a58a519ca7aa8f46b8d254c3f1eeea0d6": { + "balance": "10000000000000000000000" + }, + "edb720c9bde4801e204e90282de2a6cf1c44c4ad": { + "balance": "10000000000000000000000" + }, + "edbea23cd0cfde3705d83aada88e78b9f4bb1a50": { + "balance": "4000000000000000000000" + }, + "edc1f174655205bb961ddf94a997cdfd24f1c2ed": { + "balance": "65211537189000000000" + }, + "edd1d2dcba881202bc546943194d64e59bf74bfd": { + "balance": "10000000000000000000000" + }, + "eded28fbd959f2351b4252abc71f0e809562fd4c": { + "balance": "1000000000000000000" + }, + "edfe4d4c83c7db76e5e8a9ccafa34d9841669dac": { + "balance": "2578239411258000000000" + }, + "ee1ef79de869b89334d883ba766e65150f3f6cf5": { + "balance": "779780646165000000000" + }, + "ee27b2da240e862f0848d31116a7b4ed91835c8d": { + "balance": "111637484977461000000000" + }, + "ee3195bdb69e97796911c63fdd3fcebad61ffe9b": { + "balance": "214483035823000000000" + }, + "ee43306530c21793c4fd6039b51cf54fbc912bf0": { + "balance": "374531713769000000000" + }, + "ee4515e30ee1b8dba4779ef213d89e8dfff26ea6": { + "balance": "1166743135013000000000" + }, + "ee591e9ca7948b8485eb210e2a3f706b97e6f9e2": { + "balance": "27793157052774000000000" + }, + "ee5ba6c854d633a04f7656d311817e5104c6de14": { + "balance": "289361919166000000000" + }, + "ee909db4ee48bff3adb9e43db940245a8e5e094d": { + "balance": "582143490064000000000" + }, + "ee94d1afa82de70eb65aad0662f48ef3170495cb": { + "balance": "242490158636000000000" + }, + "ee97e18e09bbb16137a7b4aaae464e97d70e6606": { + "balance": "442709862861000000000" + }, + "eebe957af00050c2841f3ef8768c6a77a5394012": { + "balance": "9000000000000000000" + }, + "eec052f4e2902f7cc496162ca6525997d2b3ede4": { + "balance": "69349303517000000000" + }, + "eed30e1a939d5f0b4a39598967a5f149a7b7cb8c": { + "balance": "1637195595000000000" + }, + "eed7bf1ba39bfdad0ce1b6b8d4c9bb31dc1a9843": { + "balance": "203331701702000000000" + }, + "eee276140ea24e36eccb4fd748f675df1acd3b73": { + "balance": "1000000000000000000000000" + }, + "eefb33b290741c4cded862cea777efe4b14a76da": { + "balance": "64000000000000000000" + }, + "ef17a60d15ecf68a62b4bfd5e3acd6201e1931af": { + "balance": "113292502078000000000" + }, + "ef3f4df42127d3e94b4b5883ca97ee63f90b68b5": { + "balance": "17819622000000000000" + }, + "ef4aa6833a69cf72fbf3eaac57da236970aa4241": { + "balance": "1638520372091000000000" + }, + "ef958a1db06e5b8e12547148f3b01da9a8841aad": { + "balance": "12847752197000000000" + }, + "ef9fa861eefe12a3b4c161a47db5d94b1fa873a9": { + "balance": "49000000000000000000" + }, + "efd9b1ce6bc3932961e41e875edaaa367d318b36": { + "balance": "1626378762077000000000" + }, + "efdce7f577c77f0dac6afc78dcbf5ebadc1c3a73": { + "balance": "627500067619000000000" + }, + "eff3f26bc45638d89f28b3ea7a5471af0b680b72": { + "balance": "1650959950189000000000" + }, + "eff6d78814ddae79d6d09d830dd44de55f3f919d": { + "balance": "44409266093000000000" + }, + "eff739e22b9aeb3781dc301da70761fdd178f08f": { + "balance": "574842224234000000000" + }, + "f0059b3c8a32d3d012b4fcb993431a484b67762f": { + "balance": "516933429840000000000" + }, + "f06747d8e2c76b8827bbd0bf4ea3a68d390ee8f3": { + "balance": "8124594790100000000000" + }, + "f0e29fc0aecc36d1bdd818148878ea7d01957476": { + "balance": "79821431871000000000" + }, + "f0e42acf4e027aa61ac2f56e3d2c171ec0fd6ebf": { + "balance": "672499252575000000000" + }, + "f14338307bc5e6ab71fa202447ce240947568b3c": { + "balance": "13990001528784000000000" + }, + "f14f9a1206eb436a3d2e4ba9b3976137f67a6596": { + "balance": "1086707451000000000" + }, + "f15fcf1772fa5b2a578ce4f9270996430d533000": { + "balance": "496026996898000000000" + }, + "f18c691a5827ff1fdc44b54bd9a64fabd53c1cf4": { + "balance": "3112912699000000000000" + }, + "f1960640b52af75fc71101aec2611499c17cd9c6": { + "balance": "195957678178000000000" + }, + "f1abf01ddd474949713bd7fa67ec81d6b56c87b7": { + "balance": "121000000000000000000" + }, + "f1b93a6cfd4b1c7e0e89ebed119c5fe55af2035e": { + "balance": "1000000000000000000000000" + }, + "f1d14c7659a10ff38f4ea74ff5b07ac035984b6a": { + "balance": "9986323720000000000" + }, + "f1dbf37470a2c4fef98b1023026870ae8f7df2c0": { + "balance": "132757602000000000000" + }, + "f220b958b619d5d848597dd00824ab8b1401ebd2": { + "balance": "1461699635849000000000" + }, + "f2484911e0aa707f88d9dd970db21e8f24b9de2f": { + "balance": "20000000000000000000000" + }, + "f264c15790fd7a36d9ce7a454f6bfbe878708a50": { + "balance": "64000000000000000000" + }, + "f2662356cb3ae7b82efd6c82c3591ee40854892b": { + "balance": "50000000000000000000000" + }, + "f27ae5783b96ef637bde4179080a8f5af63ae692": { + "balance": "784985848611000000000" + }, + "f2a62fc212717e411f72f9a694e30b8da21bb31b": { + "balance": "614971541702000000000" + }, + "f2d0a9594231efb87ac833c365b80944251f29d7": { + "balance": "478622654587000000000" + }, + "f2df99a3df0b9b448d0ea48b9fd5cb1ce9ce50cf": { + "balance": "851116673037000000000" + }, + "f2dff0ae1f5f74808624e4f26fa814e4e19c216a": { + "balance": "404457730686000000000" + }, + "f2ea1ac6282364ad5904c6f058827a4382111d94": { + "balance": "5502482915000000000" + }, + "f2fafdcdb2d887eb13b5362eb76be2a682868643": { + "balance": "6174264174000000000" + }, + "f314adfc2fbf632a6e5d8a261385b6054aca31b6": { + "balance": "1267558242119000000000" + }, + "f31a66a88394ed7dd6609aff07dd26a60a219bd8": { + "balance": "346102834465000000000" + }, + "f3535f2b42d8613363e6d9717cc21a8ec3a74fe0": { + "balance": "35723093185103000000000" + }, + "f36a149466982c030ce3b9717f34b593613804d5": { + "balance": "10000000000000000000000" + }, + "f3828b0eaba4acfbbcf3c58277ceb4616a34b630": { + "balance": "633998941064000000000" + }, + "f38f767eeb8002ef051b32fe2f40193bf0751d92": { + "balance": "50000000000000000000000" + }, + "f39bce177817a7338b1adaf713222e515c0d762b": { + "balance": "1128231726329000000000" + }, + "f3ac7ea27a1cefc7787e5ba54dacfd8385ee4afc": { + "balance": "11364602682758000000000" + }, + "f3d9ea511335ed418b1837766da11832aedf5578": { + "balance": "29188596603509000000000" + }, + "f3ef05ccd19df167e06797d962f6afe16037e134": { + "balance": "144000000000000000000" + }, + "f3f630148eccea0ad7bd67bb806bd5676a4ea4cb": { + "balance": "87187208643000000000" + }, + "f3ff31784e0b8c3cd2f7e18cfd07c682a42d1c8d": { + "balance": "10515373125000000000" + }, + "f40b976e8519a2c97f64783bca495ed3f2e4a7c0": { + "balance": "780184503985000000000" + }, + "f416a3af7f3181ad9c8a916989949d35b0b636ec": { + "balance": "16114504005275000000000" + }, + "f419759927eea6afe77701c4cf4a98791a709ad1": { + "balance": "1032589347112000000000" + }, + "f4368f9c9ad8236b56413f174562d6b6fef21d1c": { + "balance": "5447645343000000000" + }, + "f43c57f984b0e2b7ce4d703e82f41195585504a4": { + "balance": "1135809111749000000000" + }, + "f4449f52895de96a4638c927dc389f010bbd530c": { + "balance": "693196063498000000000" + }, + "f449bd417a674c8bfa1db3a3e09c2b03da0f0c04": { + "balance": "106343287319000000000" + }, + "f44dec8340986c06d64dc98d78772a8a9cdc41ec": { + "balance": "1379381904815000000000" + }, + "f4642be1a7685aea0dc7b362d36f58f15d806b72": { + "balance": "4717509847323000000000" + }, + "f4712925f57391043e0cc2e671f33124a0bc8613": { + "balance": "419736833200000000000" + }, + "f47317fba5927dd8dffc4049d4f3277fcef503d6": { + "balance": "149279442682000000000" + }, + "f47ce4c5aaef82692e47f7a810ba38d1faec0eea": { + "balance": "10000000000000000000000" + }, + "f491ffc412bf142788bb82d48bd4eccbe9e0a286": { + "balance": "77276422315000000000" + }, + "f4a1e27e669c29f15b9f89ac15f702340a135743": { + "balance": "324000000000000000000" + }, + "f4b5cbfa50a6c4f5f7db7a93fa565362cc7aceac": { + "balance": "195951823248000000000" + }, + "f4b949c6e10615b651675016f0d7d6ff64e31aee": { + "balance": "35516207325223000000000" + }, + "f4c5e2f043ef3548a2c1c27d968087bec65e2f7d": { + "balance": "100000000000000000000000" + }, + "f4c79ea9c6f7297e016c39296d86f0304070c31d": { + "balance": "71036374423000000000" + }, + "f4dde3733a72872a7efc095cb412672c50928f1b": { + "balance": "129914864759880000000000" + }, + "f4ed736a413464eb93f8a430e093a64f0bd4222d": { + "balance": "10000000000000000000000" + }, + "f4f07e45560fb63d5207ed7e8d7cf4fe29e06d18": { + "balance": "293103814503448000000000" + }, + "f50eac35eef0a1bfa23ba31020ef60e89bf8e9df": { + "balance": "10000000000000000000000" + }, + "f51236dfd888929ccb2fe1f1fc5554abc5df4ce2": { + "balance": "25000000000000000000" + }, + "f521eb42e9092350f2ad4391ddb42bfe7abb4db9": { + "balance": "217462745186000000000" + }, + "f54e7062b6a9a8b283acf00fcbad58aca0737676": { + "balance": "7327357122437000000000" + }, + "f553301efd81629d0856d9c95c70f4a962e602ed": { + "balance": "1500355826530000000000" + }, + "f55c555b0991b2413f2f2764d8ed6a0d77825965": { + "balance": "1174679810163000000000" + }, + "f56ff110d521ceaec29dbf2842f1e78b24463cea": { + "balance": "20000000000000000000000" + }, + "f573fec366236ab87ba041f7dc6a88d92b1fc9b7": { + "balance": "4659857040000000000" + }, + "f59987743b239379aac9353e17e0e4442aa2c684": { + "balance": "25000000000000000000" + }, + "f5a9ca298e88c5492dd44a66d815b649c2f01d39": { + "balance": "95879585325000000000" + }, + "f5b4933164c55b5ba99db906ecaa52bba4f95164": { + "balance": "25663623936000000000" + }, + "f5d20af68c6fed98144718b6beab82fde00dfedc": { + "balance": "16000000000000000000" + }, + "f5e49ce72be9b17ff39688860e5cf6fd500a886c": { + "balance": "106142276914000000000" + }, + "f5f472405a4530075805fbc11928544770fd61fe": { + "balance": "64000000000000000000" + }, + "f62096c7305eb97b221bb637f4269246fe59262b": { + "balance": "855993602798000000000" + }, + "f622bf9b8f7be2f75d5ed73d318a0e7fa62a587f": { + "balance": "20000000000000000000000" + }, + "f6231f31d524ccc444bd046123ba33bc224bdd52": { + "balance": "97550810879000000000" + }, + "f641b4a721dcefa497274fd06888eb998b9bc038": { + "balance": "39401014566340000000000" + }, + "f64f0c5172c99d74b2450a4685c3ec715b379922": { + "balance": "28337413668000000000" + }, + "f65841061cd55cbf20843d9594bce9ee133aa644": { + "balance": "9064540188290000000000" + }, + "f65f0106f3d148d0660547f0683ded4dffc12fe9": { + "balance": "87334071785367000000000" + }, + "f677961296ed933db9e1dd887711387540c0436d": { + "balance": "3982789899000000000" + }, + "f68ba7530f423b8df1625cee36f8df2363a57c49": { + "balance": "5000000000000000000000" + }, + "f69c6eaf077b795f19a9590ee8b578543558e4c4": { + "balance": "10000000000000000000000" + }, + "f69dfe3f0f76e50e2850e44e9e36b6966e277eaa": { + "balance": "288231750575462000000000" + }, + "f6a73c4b958b4d6044f3f4da7147d0fa80e2ea31": { + "balance": "50000000000000000000000" + }, + "f6b0864be5f7bbc4210a3420aa3ead614a8fe7e2": { + "balance": "880968828000000000" + }, + "f6f43a6d9517471436d2ce5047a2b707580e7149": { + "balance": "20000000000000000000000" + }, + "f6fb414d1ca7c29be35b5f97096c817bbf70b070": { + "balance": "15156317416682000000000" + }, + "f707b491ac27b2d2e5e1f9d4123635ee0af92c5c": { + "balance": "500000000000000000000000" + }, + "f71179583a471767a1b399842d7d29caefe57a5e": { + "balance": "429648186876000000000" + }, + "f71ed909eca6bfd574cd670389bc9250493d686d": { + "balance": "38189267531000000000" + }, + "f72ccdc70b7878cdb94f42ee72ca5b4b35a46238": { + "balance": "86065647347000000000" + }, + "f74035e85dbfdb961037bf689ee7dfdcfaf32d64": { + "balance": "398451682882000000000" + }, + "f77668db085a87b0a0405a275e1c2516d3e02b66": { + "balance": "10000000000000000000000" + }, + "f78990d9e50876b49f933e9d74bda44197e9aa7d": { + "balance": "51984216556000000000" + }, + "f79b9df28b7d94d1b4491fca1cbe50bd36aedb3a": { + "balance": "11546152485156000000000" + }, + "f7c773b89be413848dc4a96f064693a0c3a2eab0": { + "balance": "7084247258755000000000" + }, + "f7e29c20bb0023e9ae079da589346fdfd960dae3": { + "balance": "93132014782000000000" + }, + "f8124428ea619d30a335ecc4c2f64e36500abdcb": { + "balance": "8838170798391000000000" + }, + "f843c9d70226e6c2c8cd4cef78e2db66a8eac027": { + "balance": "498377670361000000000" + }, + "f84bb3c0d872dcdbe99d6abcc57c6b5c2b2e35ad": { + "balance": "1405105232436000000000" + }, + "f8679b915ae94e4668f2e27d1094cbb2d97cf428": { + "balance": "1000000000000000000" + }, + "f86dbb82c634cdfa818e4d0dbcfcc9a5c47a9ddb": { + "balance": "196000000000000000000" + }, + "f88bad7726aa66bc1d0ca5824044072f3551fd15": { + "balance": "37432374800000000000" + }, + "f8ab07d0751a2c283ebe2a7e28c5b6e57867e1d1": { + "balance": "25000000000000000000" + }, + "f8afb4f5684c56ff7ce71b4e4cf7e42062470e08": { + "balance": "10000000000000000000000" + }, + "f8c28df0d1a0982289ddfa2a6d562e5c75a5dd01": { + "balance": "1447386977682000000000" + }, + "f8cca137f9c12b48eafd43f038e55e2d3c481919": { + "balance": "35370515421000000000" + }, + "f8e50d1816a5e5c649756ae208209b03b1ece0c3": { + "balance": "48449640035000000000" + }, + "f8fb33ba1d93112d9c3672806e0939083f09a88e": { + "balance": "419743187776000000000" + }, + "f903bebfcc6a7050fc2c5bd14248af9b300f1600": { + "balance": "473363252199000000000" + }, + "f90ab9078f26dd881fb054b4b6e3b3e17fa94718": { + "balance": "156449634345000000000" + }, + "f93e3f392efc057f0af3a91416858a515c1ed996": { + "balance": "1147663044625000000000" + }, + "f94eac538ca66931869c312acb67721c4337842f": { + "balance": "368103335377000000000" + }, + "f94fda503c3f792491fa77b3702fd465f028810d": { + "balance": "317241487661000000000" + }, + "f95dcedbefee8ed01086c91d91a4c115ad8fc947": { + "balance": "147059838786000000000" + }, + "f961a293bbce366a6fcc98d2ba0342e2ef3c5519": { + "balance": "10000000000000000000000" + }, + "f966fdbc4a42f055f8f52d31c23ad7b6a07a5e22": { + "balance": "10000000000000000000000" + }, + "f9a3a61a2f1469835240bb0641eae40c07451e30": { + "balance": "218000000000000" + }, + "f9adcf232180378b08a46d6c8d9d97f01802e01b": { + "balance": "15658216517944000000000" + }, + "f9c68991ff7ac307e41ea1c673f8ebb1a6afbd99": { + "balance": "10000000000000000000000" + }, + "f9cc0c60431d7bdb0c7581a9ae7f011b0abefeb1": { + "balance": "16000000000000000000" + }, + "f9d43c329b61ca2169600e45c8fad3c94226adb8": { + "balance": "120128558137000000000" + }, + "f9ef5d4e2ca8888216b939d3d938438a34dd9da2": { + "balance": "144000000000000000000" + }, + "f9f3d14cd3bd09e2c4c89035b4f50e93f6175cef": { + "balance": "725000000000000000000" + }, + "fa0f5a03601bd1fc76865cdd69d9671ba6073592": { + "balance": "225298289139000000000" + }, + "fa12f10db0eb552b719194becef20af9f45de8db": { + "balance": "1012484659496000000000" + }, + "fa146c58a0709951bc2e9bccddcd002c5a0bb7dd": { + "balance": "199563276701000000000" + }, + "fa159185c156f35fa450b77c48846c2dab6349b7": { + "balance": "100660066567000000000" + }, + "fa193312655f79c7b0ee7d7ef904486836180026": { + "balance": "48141690266000000000" + }, + "fa2484de744918bd8c91350fbabc0dab8b8a44f0": { + "balance": "36000000000000000000" + }, + "fa36dc463b026d8edfeb8ac4acac43a51d643457": { + "balance": "9608761064478000000000" + }, + "fa84199010be2bf53e803c23771e0d15fd025386": { + "balance": "1474902394742000000000" + }, + "fa958bbfa367a745bcd0904db2c4e30445edaefb": { + "balance": "175679888121000000000" + }, + "fa98bcaeb55285ad7ead12ccaa15cf488f567ede": { + "balance": "136105143781000000000" + }, + "faa1be631da42b41a026774f4166c1b831ef41e9": { + "balance": "86358861589000000000" + }, + "faaa857e7f149968434f313ab8db596e1b0ae75d": { + "balance": "36000000000000000000" + }, + "fac2b85ab274055cf1415d57394e8aca4541857d": { + "balance": "289000000000000000000" + }, + "fb23a508ccdb4e91b252f5c06c465c55ed59b1db": { + "balance": "14698710175236000000000" + }, + "fb24d4e47ba70aa4b984372b4852ad3d082daa24": { + "balance": "4526648424830000000000" + }, + "fb27a7e8b8b4ae43c69ce025b46187e538608769": { + "balance": "121000000000000000000" + }, + "fb2cdb5e85872f52c99985f219b8fb4125c6a8b7": { + "balance": "8568367153000000000" + }, + "fb3d76c8165bcb3c93fd3b2b10c20588d0fa97aa": { + "balance": "500000000000000000000000" + }, + "fb5161b2cc9d48a53f47d66002905f0458e3cd9e": { + "balance": "225000000000000000000" + }, + "fb72756c4845f18ab35d29f632b662c0c0d4b94f": { + "balance": "883095068524000000000" + }, + "fb8b7efb02ea5292304c0f0abc8c555684653587": { + "balance": "10000000000000000000000" + }, + "fb9ee61e337a5c7b57c5140e84919101570e2cb7": { + "balance": "16000000000000000000" + }, + "fbae69f44b116c186a86cb0de79323ca3d6b99eb": { + "balance": "1359504686067000000000" + }, + "fbbd399eb9e5d3dd67efc48927973601dcd84321": { + "balance": "2049018637367000000000" + }, + "fbc9a3c3c429990cc306710b3dd44174dcc72ad4": { + "balance": "55507457947000000000" + }, + "fbce66a6898ecd70893db6b4b8c3d00afef8e20b": { + "balance": "20857164902458000000000" + }, + "fbe8fe04084fc93dff8228861fe100bfeeb057b6": { + "balance": "10000000000000000000000" + }, + "fbfb717f902ad79ef63565f9ab57f041ff5f7626": { + "balance": "16000000000000000000" + }, + "fc0b6c8c6be79bf0c9554f7855dc8c4a617d02c9": { + "balance": "17347593956000000000" + }, + "fc17518d05e605807847bbf6f407da89037bca00": { + "balance": "1796383702108000000000" + }, + "fc2793424c809cc80938a1be1292813adbc8ac8c": { + "balance": "10000000000000000000" + }, + "fc35930abb108ae6cae33fd065dfb799808ea326": { + "balance": "912737460000000000000" + }, + "fc5a9209799e563ae8d958774dc86345a3bc7ed2": { + "balance": "29049176573000000000" + }, + "fc8011850c09c9288e737ea58ca5c15cded6dc8d": { + "balance": "10000000000000000000000" + }, + "fc9183ed137be071ad183d025395a0ebe2674654": { + "balance": "500000000000000000000000" + }, + "fc98c9d88b1fbbb68dbdd6448aa6a32e8282800d": { + "balance": "900000000000000000000" + }, + "fc9f4b9da7a46c2bfcd50cafe1f892b9984be0ee": { + "balance": "21577116424370000000000" + }, + "fca525b732a673b953f1c23083c276cc8cbcb86c": { + "balance": "77653618624000000000" + }, + "fca57b6a4798f33478b6e23622173cda3fe1b9a0": { + "balance": "793368066098000000000" + }, + "fca79b446c513a7bed643603c42f35ff0fa89f49": { + "balance": "998082799053000000000" + }, + "fcab42f7f07735a7b09074c1f1769287069c88c8": { + "balance": "94824830574000000000" + }, + "fcacbbc6810c586522012ad32c3dfac80eb563b4": { + "balance": "10000000000000000000000" + }, + "fcb38809b63810b6673dcb4c947e01f7b49fb1b3": { + "balance": "725937240372000000000" + }, + "fcc0e531d9f6265672aa885af361534464a11015": { + "balance": "22121462657000000000" + }, + "fcc49c62d7738fa1b92aa6a69a12b671e4c7c8d9": { + "balance": "50000000000000000000000" + }, + "fcc95394fd796ca5bd8f3814883b1150d74dd9a5": { + "balance": "144000000000000000000" + }, + "fccdb068dfd599d7d5c290a6ae65eba9151d5b29": { + "balance": "5369426564000000000" + }, + "fcde41ae28bdf9084a28f47a9348d8aac5b3dd43": { + "balance": "409599263197000000000" + }, + "fce5816f066ca32d1fa02e9e8b5eb8a7fa3e4dea": { + "balance": "1193272309645000000000" + }, + "fcf9fb8996d6d9175ade6d6063be0742de20ea1f": { + "balance": "16852526239339000000000" + }, + "fd10488d55e6861cb67f7f50950d78892e7032ad": { + "balance": "165069902909000000000" + }, + "fd23e8263d89256add0dfe93da153d305ad917c7": { + "balance": "26633825496000000000" + }, + "fd3a98cc3b3f1439af35f806de2fb05fef98f279": { + "balance": "1043321187464000000000" + }, + "fd3d79185a91984a117ee6f9fd304725875094e2": { + "balance": "2349991833898000000000" + }, + "fd5e6ac22634f04ec4ace5da8996c2b7b70b22f4": { + "balance": "10000000000000000" + }, + "fd62ed1cf7a535c989fbd742b1660205a2f69dd0": { + "balance": "49000000000000000000" + }, + "fd645043bd4d7b71e63e30409b91e9fdda3a86c0": { + "balance": "362957768837969000000000" + }, + "fd7014fc1c70af482115247ff94ff6bdbd3d364d": { + "balance": "743383172317000000000" + }, + "fda0cfe95df9021497752b04863c3ec44d13e853": { + "balance": "15586809617955000000000" + }, + "fdb5b964808bcb974d3e888cbb45bcd57e57c907": { + "balance": "5549247772273000000000" + }, + "fdbaaa865ec38da13e80554b6d0abc437f60d8a5": { + "balance": "3736861227131000000000" + }, + "fdbb8693b3c20c0eac5fb585e2347d41debbffce": { + "balance": "100000000000000000" + }, + "fdbdaec57829f25ad48e18d94e0b8533f2801818": { + "balance": "6934630922926000000000" + }, + "fdc318ba5b1f8ad33e00528828b93a840592e2fb": { + "balance": "10000000000000000000000" + }, + "fdcf6a997bb10806e4d87eb4222e9f93b4202179": { + "balance": "1000000000000000000" + }, + "fde5a9911a10770d733db4d32ca9a5493478399c": { + "balance": "20000000000000000000000" + }, + "fe39185a6b84378820ee215f630533e658731ca9": { + "balance": "17022202932000000000" + }, + "fe3b1032e524674cba5f329f940c837850fa53ed": { + "balance": "50000000000000000000000" + }, + "fe3bc4ff2c3b66bc582558314b80030407e7de96": { + "balance": "1669870860988000000000" + }, + "fe668dbb1f3de744d16e13e0ed6f5708c2c15d1f": { + "balance": "39974355655263000000000" + }, + "fe95bfb97fa60341f8af2ad621e606b85e3c2e57": { + "balance": "528601649597478000000000" + }, + "fe99cf2a1fbbe7c46e4235b2d135a3a093fcf16c": { + "balance": "7271022106877000000000" + }, + "fec1f6ed4b3ff01e7ebe13fb53f60ee5a3b9e191": { + "balance": "1316316072034000000000" + }, + "fed9bec1b2145452ed5535e4ba29fafac6c35fbb": { + "balance": "10799354586000000000" + }, + "fedced7aa1cf3f3a7eec321cc0274759b154ea8e": { + "balance": "11740927210323000000000" + }, + "fef5063701a93ad02676fe0b99d0f4d2da0ccd67": { + "balance": "10178531012000000000" + }, + "fefd5627a408ca099587892ee2a46fa8cc89be19": { + "balance": "458504035686000000000" + }, + "ff1fc0f6f26188cbe18cf65d8a344d3775aecc6d": { + "balance": "81000000000000000000" + }, + "ff4fe483b3c04ebc8d6705c699ecee3e92071715": { + "balance": "1000000000000000000" + }, + "ff51bfe823394b2bce05947a6068bd5158d4af0e": { + "balance": "692533626783000000000" + }, + "ff6652e4e45f6b0f95ad4c9ec2bc80476e3f7fc6": { + "balance": "46457898024000000000" + }, + "ff68246ac7640091e5e58345736b249e036364fc": { + "balance": "2626125272000000000" + }, + "ff6d4b8a8393a503047ff829dbf2bf8e9172dc6d": { + "balance": "2865001878255000000000" + }, + "ff6fe19e056a7211b7e484c2c540d5aa5f1d83e5": { + "balance": "36000000000000000000" + }, + "ff7fa33529e1781c1b2951e57581780b229e3fda": { + "balance": "10000000000000000000" + }, + "ff82d1052538539d07cf3955476cc9a5027d8e4e": { + "balance": "83572023121000000000" + }, + "ff8acfe75afcc1efb1bc44be9f9bb242a94f73f7": { + "balance": "7556034521000000000" + }, + "ffa2b5f1685de9fcf1af4653cd3a584db1beed64": { + "balance": "114892199805000000000" + }, + "ffb1e9be68ae8be8d7d066c473589921e68825a2": { + "balance": "484660652980000000000" + }, + "ffbf91a9d1a6377b7435e3e734132e7b34188dac": { + "balance": "20000000000000000000000" + }, + "ffbff1fab9f2bc2f387d0cc9cc28f6aac533c813": { + "balance": "10000000000000000000000" + }, + "ffc4ff6433ea35544e7a07fda170e62c451301df": { + "balance": "29238210920000000000" + }, + "ffc7534b64a8fe8760e931a710883119d28ae106": { + "balance": "500000000000000000000000" + }, + "ffda6b8e3de72d7f7c18b892e6a8b80b886d5fa5": { + "balance": "214366938289000000000" + }, + "ffddb1fb7521c9772ea4886aaf022c4375ef904d": { + "balance": "554864446437000000000" + } + } +} diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 1bdcb01e14..71cf2e86af 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -76,6 +76,11 @@ pub fn new_easthub<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/easthub.json")) } +/// Create a new Ethereum Social mainnet chain spec ¯\_(ツ)_/¯ . +pub fn new_social<'a, T: Into>>(params: T) -> Spec { + load(params.into(), include_bytes!("../../res/ethereum/social.json")) +} + /// Create a new Kovan testnet chain spec. pub fn new_kovan<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/kovan.json")) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index a160661b91..cb6470e9b8 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -294,7 +294,7 @@ usage! { ARG arg_chain: (String) = "foundation", or |c: &Config| c.parity.as_ref()?.chain.clone(), "--chain=[CHAIN]", - "Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, musicoin, ellaism, easthub, testnet, kovan or dev.", + "Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, musicoin, ellaism, easthub, social, testnet, kovan or dev.", ARG arg_keys_path: (String) = "$BASE/keys", or |c: &Config| c.parity.as_ref()?.keys_path.clone(), "--keys-path=[PATH]", diff --git a/parity/params.rs b/parity/params.rs index ef58bc37b6..59676108ed 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -39,6 +39,7 @@ pub enum SpecType { Musicoin, Ellaism, Easthub, + Social, Dev, Custom(String), } @@ -64,6 +65,7 @@ impl str::FromStr for SpecType { "musicoin" => SpecType::Musicoin, "ellaism" => SpecType::Ellaism, "easthub" => SpecType::Easthub, + "social" => SpecType::Social, "dev" => SpecType::Dev, other => SpecType::Custom(other.into()), }; @@ -83,6 +85,7 @@ impl fmt::Display for SpecType { SpecType::Musicoin => "musicoin", SpecType::Ellaism => "ellaism", SpecType::Easthub => "easthub", + SpecType::Social => "social", SpecType::Kovan => "kovan", SpecType::Dev => "dev", SpecType::Custom(ref custom) => custom, @@ -103,6 +106,7 @@ impl SpecType { SpecType::Musicoin => Ok(ethereum::new_musicoin(params)), SpecType::Ellaism => Ok(ethereum::new_ellaism(params)), SpecType::Easthub => Ok(ethereum::new_easthub(params)), + SpecType::Social => Ok(ethereum::new_social(params)), SpecType::Kovan => Ok(ethereum::new_kovan(params)), SpecType::Dev => Ok(Spec::new_instant()), SpecType::Custom(ref filename) => { -- GitLab From 431b27d3e19fb70eee309aaa723e910070506867 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 9 Apr 2018 22:34:47 +0800 Subject: [PATCH 049/263] replace_home for password_files, reserved_peers and log_file (#8324) * replace_home for password_files, reserved_peers and log_file * typo: arg_log_file is Option --- parity/configuration.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/parity/configuration.rs b/parity/configuration.rs index 7ce3db1240..7760fe470a 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -149,7 +149,7 @@ impl Configuration { if self.args.cmd_signer_new_token { Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone()) } else if self.args.cmd_signer_sign { - let pwfile = self.args.arg_password.first().map(|pwfile| { + let pwfile = self.accounts_config()?.password_files.first().map(|pwfile| { PathBuf::from(pwfile) }); Cmd::SignerSign { @@ -186,7 +186,7 @@ impl Configuration { iterations: self.args.arg_keys_iterations, path: dirs.keys, spec: spec, - password_file: self.args.arg_password.first().map(|x| x.to_owned()), + password_file: self.accounts_config()?.password_files.first().map(|x| x.to_owned()), }; AccountCmd::New(new_acc) } else if self.args.cmd_account_list { @@ -220,8 +220,8 @@ impl Configuration { iterations: self.args.arg_keys_iterations, path: dirs.keys, spec: spec, - wallet_path: self.args.arg_wallet_import_path.unwrap().clone(), - password_file: self.args.arg_password.first().map(|x| x.to_owned()), + wallet_path: self.args.arg_wallet_import_path.clone().unwrap(), + password_file: self.accounts_config()?.password_files.first().map(|x| x.to_owned()), }; Cmd::ImportPresaleWallet(presale_cmd) } else if self.args.cmd_import { @@ -456,7 +456,7 @@ impl Configuration { LogConfig { mode: self.args.arg_logging.clone(), color: !self.args.flag_no_color && !cfg!(windows), - file: self.args.arg_log_file.clone(), + file: self.args.arg_log_file.as_ref().map(|log_file| replace_home(&self.directories().base, log_file)), } } @@ -508,7 +508,7 @@ impl Configuration { iterations: self.args.arg_keys_iterations, refresh_time: self.args.arg_accounts_refresh, testnet: self.args.flag_testnet, - password_files: self.args.arg_password.clone(), + password_files: self.args.arg_password.iter().map(|s| replace_home(&self.directories().base, s)).collect(), unlocked_accounts: to_addresses(&self.args.arg_unlock)?, enable_hardware_wallets: !self.args.flag_no_hardware_wallets, enable_fast_unlock: self.args.flag_fast_unlock, @@ -728,8 +728,10 @@ impl Configuration { match self.args.arg_reserved_peers { Some(ref path) => { + let path = replace_home(&self.directories().base, path); + 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))?; node_file.read_to_string(&mut buffer).map_err(|_| "Error reading reserved node file")?; let lines = buffer.lines().map(|s| s.trim().to_owned()).filter(|s| !s.is_empty() && !s.starts_with("#")).collect::>(); -- GitLab From 1c75e8eb479924f1a596635c9537acdfd12031a6 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 9 Apr 2018 16:35:45 +0200 Subject: [PATCH 050/263] Whisper cli (#8201) * getting started * wip wip * add parsing of pool-size and enable panic-hook * more cli options * remove explicit unwrapping * bump dependencies to parity-jsonrpc * add tests * remove tests * bump jsonrpc * Remove unused dependencies * add logging to the cli * Fix so `FilterManager` drops its resources * Introduced an AtomicBool flag in FilterManager to cancel the `Decryption Worker Thread` * Added some very basic test to faulty arguments * ignore privileged port test --- Cargo.lock | 18 +++ Cargo.toml | 3 +- whisper/cli/Cargo.toml | 22 +++ whisper/cli/src/main.rs | 300 ++++++++++++++++++++++++++++++++++++++ whisper/src/rpc/filter.rs | 28 +++- 5 files changed, 364 insertions(+), 7 deletions(-) create mode 100644 whisper/cli/Cargo.toml create mode 100644 whisper/cli/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 28a4b8a7af..80bdcf3497 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3697,6 +3697,24 @@ dependencies = [ "webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "whisper-cli" +version = "0.1.0" +dependencies = [ + "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-logger 1.11.0", + "ethcore-network 1.11.0", + "ethcore-network-devp2p 1.11.0", + "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", + "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", + "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "panic_hook 0.1.0", + "parity-whisper 0.1.0", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index 202215ab34..bb92fff358 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,7 +132,8 @@ members = [ "evmbin", "miner", "transaction-pool", - "whisper" + "whisper", + "whisper/cli", ] [patch.crates-io] diff --git a/whisper/cli/Cargo.toml b/whisper/cli/Cargo.toml new file mode 100644 index 0000000000..363471a1a3 --- /dev/null +++ b/whisper/cli/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "whisper-cli" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +ethcore-network-devp2p = { path = "../../util/network-devp2p" } +ethcore-network = { path = "../../util/network" } +ethcore-logger = { path = "../../logger" } +parity-whisper = { path = "../" } +docopt = "0.8" +serde = "1.0" +serde_derive = "1.0" +panic_hook = { path = "../../util/panic_hook" } +jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } +jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } +jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } +log = "0.3" + +[[bin]] +name = "whisper-cli" +path = "src/main.rs" diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs new file mode 100644 index 0000000000..d0866cd66a --- /dev/null +++ b/whisper/cli/src/main.rs @@ -0,0 +1,300 @@ +// Copyright 2015-2018 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 . + +//! Whisper command line interface +//! +//! Spawns an Ethereum network instance and attaches the Whisper protocol RPCs to it. +//! + +extern crate docopt; +extern crate ethcore_network_devp2p as devp2p; +extern crate ethcore_network as net; +extern crate parity_whisper as whisper; +extern crate serde; +extern crate panic_hook; + +extern crate jsonrpc_core; +extern crate jsonrpc_pubsub; +extern crate jsonrpc_http_server; +extern crate ethcore_logger as log; + +#[macro_use] +extern crate log as rlog; + +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use std::{fmt, io, process, env, sync::Arc}; +use jsonrpc_core::{Metadata, MetaIoHandler}; +use jsonrpc_pubsub::{PubSubMetadata, Session}; +use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation}; + +const POOL_UNIT: usize = 1024 * 1024; +const USAGE: &'static str = r#" +Whisper CLI. + Copyright 2017 Parity Technologies (UK) Ltd + +Usage: + whisper [options] + whisper [-h | --help] + +Options: + --whisper-pool-size SIZE Specify Whisper pool size [default: 10]. + -p, --port PORT Specify which RPC port to use [default: 8545]. + -a, --address ADDRESS Specify which address to use [default: 127.0.0.1]. + -l, --log LEVEL Specify the logging level. Must conform to the same format as RUST_LOG [default: Error]. + -h, --help Display this message and exit. +"#; + +#[derive(Clone, Default)] +struct Meta; + +impl Metadata for Meta {} + +impl PubSubMetadata for Meta { + fn session(&self) -> Option> { + None + } +} + +#[derive(Debug, Deserialize)] +struct Args { + flag_whisper_pool_size: usize, + flag_port: String, + flag_address: String, + flag_log: String, +} + +struct WhisperPoolHandle { + /// Pool handle. + handle: Arc>>, + /// Network manager. + net: Arc, +} + +impl whisper::rpc::PoolHandle for WhisperPoolHandle { + fn relay(&self, message: whisper::message::Message) -> bool { + let mut res = false; + let mut message = Some(message); + self.with_proto_context(whisper::net::PROTOCOL_ID, &mut |ctx| { + if let Some(message) = message.take() { + res = self.handle.post_message(message, ctx); + } + }); + res + } + + fn pool_status(&self) -> whisper::net::PoolStatus { + self.handle.pool_status() + } +} + +impl WhisperPoolHandle { + fn with_proto_context(&self, proto: net::ProtocolId, f: &mut FnMut(&net::NetworkContext)) { + self.net.with_context_eval(proto, f); + } +} + +struct RpcFactory { + handle: Arc>>, + manager: Arc, +} + +impl RpcFactory { + fn make_handler(&self, net: Arc) -> whisper::rpc::WhisperClient { + let whisper_pool_handle = WhisperPoolHandle { handle: self.handle.clone(), net: net }; + whisper::rpc::WhisperClient::new(whisper_pool_handle, self.manager.clone()) + } +} + +#[derive(Debug)] +enum Error { + Docopt(docopt::Error), + Io(io::Error), + JsonRpc(jsonrpc_core::Error), + Network(net::Error), + SockAddr(std::net::AddrParseError), + Logger(String), +} + +impl From for Error { + fn from(err: std::net::AddrParseError) -> Self { + Error::SockAddr(err) + } +} + +impl From for Error { + fn from(err: net::Error) -> Self { + Error::Network(err) + } +} + +impl From for Error { + fn from(err: docopt::Error) -> Self { + Error::Docopt(err) + } +} + +impl From for Error { + fn from(err: io::Error) -> Self { + Error::Io(err) + } +} + +impl From for Error { + fn from(err: jsonrpc_core::Error) -> Self { + Error::JsonRpc(err) + } +} + +impl From for Error { + fn from(err: String) -> Self { + Error::Logger(err) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::SockAddr(ref e) => write!(f, "SockAddrError: {}", e), + Error::Docopt(ref e) => write!(f, "DocoptError: {}", e), + Error::Io(ref e) => write!(f, "IoError: {}", e), + Error::JsonRpc(ref e) => write!(f, "JsonRpcError: {:?}", e), + Error::Network(ref e) => write!(f, "NetworkError: {}", e), + Error::Logger(ref e) => write!(f, "LoggerError: {}", e), + } + } +} + +fn main() { + panic_hook::set(); + + match execute(env::args()) { + Ok(_) => { + println!("whisper-cli terminated"); + process::exit(1); + } + Err(err) => { + println!("{}", err); + process::exit(1); + }, + } +} + +fn execute(command: I) -> Result<(), Error> where I: IntoIterator, S: AsRef { + + // Parse arguments + let args: Args = Docopt::new(USAGE).and_then(|d| d.argv(command).deserialize())?; + let pool_size = args.flag_whisper_pool_size * POOL_UNIT; + let url = format!("{}:{}", args.flag_address, args.flag_port); + + initialize_logger(args.flag_log)?; + info!(target: "whisper-cli", "start"); + + // Filter manager that will dispatch `decryption tasks` + let manager = Arc::new(whisper::rpc::FilterManager::new()?); + + // Whisper protocol network handler + let whisper_network_handler = Arc::new(whisper::net::Network::new(pool_size, manager.clone())); + + // Create network service + let network = devp2p::NetworkService::new(net::NetworkConfiguration::new_local(), None)?; + + // Start network service + network.start()?; + + // Attach whisper protocol to the network service + network.register_protocol(whisper_network_handler.clone(), whisper::net::PROTOCOL_ID, whisper::net::PACKET_COUNT, + whisper::net::SUPPORTED_VERSIONS)?; + network.register_protocol(Arc::new(whisper::net::ParityExtensions), whisper::net::PARITY_PROTOCOL_ID, + whisper::net::PACKET_COUNT, whisper::net::SUPPORTED_VERSIONS)?; + + // Request handler + let mut io = MetaIoHandler::default(); + + // Shared network service + let shared_network = Arc::new(network); + + // Pool handler + let whisper_factory = RpcFactory { handle: whisper_network_handler, manager: manager }; + + io.extend_with(whisper::rpc::Whisper::to_delegate(whisper_factory.make_handler(shared_network.clone()))); + io.extend_with(whisper::rpc::WhisperPubSub::to_delegate(whisper_factory.make_handler(shared_network.clone()))); + + let server = jsonrpc_http_server::ServerBuilder::new(io) + .cors(DomainsValidation::AllowOnly(vec![AccessControlAllowOrigin::Null])) + .start_http(&url.parse()?)?; + + server.wait(); + + // This will never return if the http server runs without errors + Ok(()) +} + +fn initialize_logger(log_level: String) -> Result<(), String> { + let mut l = log::Config::default(); + l.mode = Some(log_level); + log::setup_log(&l)?; + Ok(()) +} + + +#[cfg(test)] +mod tests { + use super::execute; + + #[test] + fn invalid_argument() { + let command = vec!["whisper-cli", "--foo=12"] + .into_iter() + .map(Into::into) + .collect::>(); + + assert!(execute(command).is_err()); + } + + #[test] + #[ignore] + fn privileged_port() { + let command = vec!["whisper-cli", "--port=3"] + .into_iter() + .map(Into::into) + .collect::>(); + + assert!(execute(command).is_err()); + } + + #[test] + fn invalid_ip_address() { + let command = vec!["whisper-cli", "--address=x.x.x.x"] + .into_iter() + .map(Into::into) + .collect::>(); + + assert!(execute(command).is_err()); + } + + #[test] + fn invalid_whisper_pool_size() { + let command = vec!["whisper-cli", "--whisper-pool-size=-100000000000000000000000000000000000000"] + .into_iter() + .map(Into::into) + .collect::>(); + + assert!(execute(command).is_err()); + } +} diff --git a/whisper/src/rpc/filter.rs b/whisper/src/rpc/filter.rs index 663c6a6bf7..5a192ac04c 100644 --- a/whisper/src/rpc/filter.rs +++ b/whisper/src/rpc/filter.rs @@ -17,8 +17,7 @@ //! Abstraction over filters which works with polling and subscription. use std::collections::HashMap; -use std::sync::{mpsc, Arc}; -use std::thread; +use std::{sync::{Arc, atomic, atomic::AtomicBool, mpsc}, thread}; use ethereum_types::{H256, H512}; use ethkey::Public; @@ -27,8 +26,7 @@ use parking_lot::{Mutex, RwLock}; use rand::{Rng, OsRng}; use message::{Message, Topic}; -use super::key_store::KeyStore; -use super::types::{self, FilterItem, HexEncode}; +use super::{key_store::KeyStore, types::{self, FilterItem, HexEncode}}; /// Kinds of filters, #[derive(PartialEq, Eq, Clone, Copy)] @@ -53,6 +51,7 @@ pub struct Manager { filters: RwLock>, tx: Mutex>>, join: Option>, + exit: Arc, } impl Manager { @@ -60,15 +59,29 @@ impl Manager { /// the given thread pool. pub fn new() -> ::std::io::Result { let (tx, rx) = mpsc::channel::>(); + let exit = Arc::new(AtomicBool::new(false)); + let e = exit.clone(); + let join_handle = thread::Builder::new() .name("Whisper Decryption Worker".to_string()) - .spawn(move || for item in rx { (item)() })?; + .spawn(move || { + trace!(target: "parity_whisper", "Start decryption worker"); + loop { + if exit.load(atomic::Ordering::Acquire) { + break; + } + if let Ok(item) = rx.try_recv() { + item(); + } + } + })?; Ok(Manager { key_store: Arc::new(RwLock::new(KeyStore::new()?)), filters: RwLock::new(HashMap::new()), tx: Mutex::new(tx), join: Some(join_handle), + exit: e, }) } @@ -103,7 +116,7 @@ impl Manager { } /// Insert new subscription filter. Generates a secure ID and sends it to - /// the + /// the subscriber pub fn insert_subscription(&self, filter: Filter, sub: Subscriber) -> Result<(), &'static str> { @@ -180,9 +193,12 @@ impl ::net::MessageHandler for Arc { impl Drop for Manager { fn drop(&mut self) { + trace!(target: "parity_whisper", "waiting to drop FilterManager"); + self.exit.store(true, atomic::Ordering::Release); if let Some(guard) = self.join.take() { let _ = guard.join(); } + trace!(target: "parity_whisper", "FilterManager dropped"); } } -- GitLab From 0d75d01c84ace637b903259c32d71699e8e1ef46 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 9 Apr 2018 17:38:59 +0300 Subject: [PATCH 051/263] SecretStore: get rid of engine.signer dependency (#8173) * SecretStore: get rid of engine.signer dependency * SecretStore: fixed self for transact_contract * SecretStore: fixed pending requests + 1-of-1 sessions completion * SecretStore: fixed completion signal in 1-of-1 case * fixed test(s) * removed obsolete TODO && redundant statement * ok_or -> ok_or_else --- Cargo.lock | 1 + parity/run.rs | 1 + parity/secretstore.rs | 5 +- secret_store/Cargo.toml | 1 + secret_store/src/acl_storage.rs | 2 +- .../client_sessions/generation_session.rs | 7 +- .../signing_session_schnorr.rs | 2 +- .../src/key_server_cluster/cluster.rs | 79 ++++++++----------- secret_store/src/key_server_set.rs | 8 +- secret_store/src/lib.rs | 6 +- secret_store/src/listener/service_contract.rs | 2 +- .../src/listener/service_contract_listener.rs | 4 +- secret_store/src/trusted_client.rs | 36 ++++++++- 13 files changed, 94 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80bdcf3497..d6f38caa40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -766,6 +766,7 @@ dependencies = [ "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", + "ethcore-transaction 0.1.0", "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", diff --git a/parity/run.rs b/parity/run.rs index fbc24a90d7..9d43801ac0 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -843,6 +843,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let secretstore_deps = secretstore::Dependencies { client: client.clone(), sync: sync_provider.clone(), + miner: miner, account_provider: account_provider, accounts_passwords: &passwords, }; diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 797f8673b1..8e9f5fef5a 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -20,6 +20,7 @@ use dir::default_data_path; use dir::helpers::replace_home; use ethcore::account_provider::AccountProvider; use ethcore::client::Client; +use ethcore::miner::Miner; use ethkey::{Secret, Public}; use ethsync::SyncProvider; use ethereum_types::Address; @@ -87,6 +88,8 @@ pub struct Dependencies<'a> { pub client: Arc, /// Sync provider. pub sync: Arc, + /// Miner service. + pub miner: Arc, /// Account provider. pub account_provider: Arc, /// Passed accounts passwords. @@ -190,7 +193,7 @@ mod server { cconf.cluster_config.nodes.insert(self_secret.public().clone(), cconf.cluster_config.listener_address.clone()); - let key_server = ethcore_secretstore::start(deps.client, deps.sync, self_secret, cconf) + let key_server = ethcore_secretstore::start(deps.client, deps.sync, deps.miner, self_secret, cconf) .map_err(|e| format!("Error starting KeyServer {}: {}", key_server_name, e))?; Ok(KeyServer { diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index 3b60a3c6c5..d894bb4efd 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -24,6 +24,7 @@ tokio-proto = "0.1" url = "1.0" ethcore = { path = "../ethcore" } ethcore-bytes = { path = "../util/bytes" } +ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" ethsync = { path = "../sync" } kvdb = { path = "../util/kvdb" } diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 0ff8a2f307..58d9bc4775 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -62,7 +62,7 @@ impl OnChainAclStorage { contract: Mutex::new(CachedContract::new(trusted_client)), }); client - .ok_or(Error::Internal("Constructing OnChainAclStorage without active Client".into()))? + .ok_or_else(|| Error::Internal("Constructing OnChainAclStorage without active Client".into()))? .add_notify(acl_storage.clone()); Ok(acl_storage) } diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs index 2c0cbe2b1e..0afe618246 100644 --- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs @@ -326,7 +326,12 @@ impl SessionImpl { self.complete_initialization(derived_point)?; self.disseminate_keys()?; self.verify_keys()?; - self.complete_generation() + self.complete_generation()?; + + self.data.lock().state = SessionState::Finished; + self.completed.notify_all(); + + Ok(()) } } } diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs index b4041da53f..ed7164ca3a 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs @@ -280,7 +280,7 @@ impl SessionImpl { }); generation_session.initialize(Default::default(), Default::default(), false, 0, vec![self.core.meta.self_node_id.clone()].into_iter().collect::>().into())?; - debug_assert_eq!(generation_session.state(), GenerationSessionState::WaitingForGenerationConfirmation); + debug_assert_eq!(generation_session.state(), GenerationSessionState::Finished); let joint_public_and_secret = generation_session .joint_public_and_secret() .expect("session key is generated before signature is computed; we are in SignatureComputing state; qed")?; diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs index c90474fa63..26f0e7ef1f 100644 --- a/secret_store/src/key_server_cluster/cluster.rs +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -896,6 +896,20 @@ impl ClusterClientImpl { } } } + + fn process_initialization_result, D>(result: Result<(), Error>, session: Arc, sessions: &ClusterSessionsContainer) -> Result, Error> { + match result { + Ok(()) if session.is_finished() => { + sessions.remove(&session.id()); + Ok(session) + }, + Ok(()) => Ok(session), + Err(error) => { + sessions.remove(&session.id()); + Err(error) + }, + } + } } impl ClusterClient for ClusterClientImpl { @@ -909,13 +923,9 @@ impl ClusterClient for ClusterClientImpl { let cluster = create_cluster_view(&self.data, true)?; let session = self.data.sessions.generation_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id, None, false, None)?; - match session.initialize(origin, author, false, threshold, connected_nodes.into()) { - Ok(()) => Ok(session), - Err(error) => { - self.data.sessions.generation_sessions.remove(&session.id()); - Err(error) - }, - } + Self::process_initialization_result( + session.initialize(origin, author, false, threshold, connected_nodes.into()), + session, &self.data.sessions.generation_sessions) } fn new_encryption_session(&self, session_id: SessionId, requester: Requester, common_point: Public, encrypted_point: Public) -> Result, Error> { @@ -924,13 +934,9 @@ impl ClusterClient for ClusterClientImpl { let cluster = create_cluster_view(&self.data, true)?; let session = self.data.sessions.encryption_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id, None, false, None)?; - match session.initialize(requester, common_point, encrypted_point) { - Ok(()) => Ok(session), - Err(error) => { - self.data.sessions.encryption_sessions.remove(&session.id()); - Err(error) - }, - } + Self::process_initialization_result( + session.initialize(requester, common_point, encrypted_point), + session, &self.data.sessions.encryption_sessions) } fn new_decryption_session(&self, session_id: SessionId, origin: Option

, requester: Requester, version: Option, is_shadow_decryption: bool, is_broadcast_decryption: bool) -> Result, Error> { @@ -954,13 +960,9 @@ impl ClusterClient for ClusterClientImpl { }, }; - match initialization_result { - Ok(()) => Ok(session), - Err(error) => { - self.data.sessions.decryption_sessions.remove(&session.id()); - Err(error) - }, - } + Self::process_initialization_result( + initialization_result, + session, &self.data.sessions.decryption_sessions) } fn new_schnorr_signing_session(&self, session_id: SessionId, requester: Requester, version: Option, message_hash: H256) -> Result, Error> { @@ -983,13 +985,9 @@ impl ClusterClient for ClusterClientImpl { }, }; - match initialization_result { - Ok(()) => Ok(session), - Err(error) => { - self.data.sessions.schnorr_signing_sessions.remove(&session.id()); - Err(error) - }, - } + Self::process_initialization_result( + initialization_result, + session, &self.data.sessions.schnorr_signing_sessions) } fn new_ecdsa_signing_session(&self, session_id: SessionId, requester: Requester, version: Option, message_hash: H256) -> Result, Error> { @@ -1012,13 +1010,9 @@ impl ClusterClient for ClusterClientImpl { }, }; - match initialization_result { - Ok(()) => Ok(session), - Err(error) => { - self.data.sessions.ecdsa_signing_sessions.remove(&session.id()); - Err(error) - }, - } + Self::process_initialization_result( + initialization_result, + session, &self.data.sessions.ecdsa_signing_sessions) } fn new_key_version_negotiation_session(&self, session_id: SessionId) -> Result>, Error> { @@ -1042,16 +1036,13 @@ impl ClusterClient for ClusterClientImpl { let initialization_result = session.as_servers_set_change().expect("servers set change session is created; qed") .initialize(new_nodes_set, old_set_signature, new_set_signature); - match initialization_result { - Ok(()) => { - self.data.connections.servers_set_change_creator_connector().set_key_servers_set_change_session(session.clone()); - Ok(session) - }, - Err(error) => { - self.data.sessions.admin_sessions.remove(&session.id()); - Err(error) - }, + if initialization_result.is_ok() { + self.data.connections.servers_set_change_creator_connector().set_key_servers_set_change_session(session.clone()); } + + Self::process_initialization_result( + initialization_result, + session, &self.data.sessions.admin_sessions) } fn add_generation_listener(&self, listener: Arc>) { diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index 899709a7d5..7697408557 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -141,7 +141,7 @@ impl OnChainKeyServerSet { contract: Mutex::new(CachedContract::new(trusted_client, self_key_pair, auto_migrate_enabled, key_servers)?), }); client - .ok_or(Error::Internal("Constructing OnChainKeyServerSet without active Client".into()))? + .ok_or_else(|| Error::Internal("Constructing OnChainKeyServerSet without active Client".into()))? .add_notify(key_server_set.clone()); Ok(key_server_set) } @@ -292,7 +292,7 @@ impl CachedContract { let transaction_data = self.contract.functions().start_migration().input(migration_id); // send transaction - if let Err(error) = client.transact_contract(*contract_address, transaction_data) { + if let Err(error) = self.client.transact_contract(*contract_address, transaction_data) { warn!(target: "secretstore_net", "{}: failed to submit auto-migration start transaction: {}", self.self_key_pair.public(), error); } else { @@ -314,7 +314,7 @@ impl CachedContract { let transaction_data = self.contract.functions().confirm_migration().input(migration_id); // send transaction - if let Err(error) = client.transact_contract(contract_address, transaction_data) { + if let Err(error) = self.client.transact_contract(contract_address, transaction_data) { warn!(target: "secretstore_net", "{}: failed to submit auto-migration confirmation transaction: {}", self.self_key_pair.public(), error); } else { @@ -551,7 +551,6 @@ fn update_number_of_confirmations H256, F2: Fn(H256) -> Option> } fn update_last_transaction_block(client: &Client, migration_id: &H256, previous_transaction: &mut Option) -> bool { - // TODO [Reliability]: add the same mechanism to the contract listener, if accepted let last_block = client.block_number(BlockId::Latest).unwrap_or_default(); match previous_transaction.as_ref() { // no previous transaction => send immideately @@ -565,7 +564,6 @@ fn update_last_transaction_block(client: &Client, migration_id: &H256, previous_ // or the transaction has been removed from the queue (and never reached any miner node) // if we have restarted after sending tx => assume we have never sent it Some(tx) => { - let last_block = client.block_number(BlockId::Latest).unwrap_or_default(); if tx.block > last_block || last_block - tx.block < TRANSACTION_RETRY_INTERVAL_BLOCKS { return false; } diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index f08a26a907..d58e37ffe7 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -19,6 +19,7 @@ extern crate ethabi; extern crate ethcore; extern crate ethcore_bytes as bytes; extern crate ethcore_logger as logger; +extern crate ethcore_transaction as transaction; extern crate ethcrypto; extern crate ethereum_types; extern crate ethkey; @@ -68,6 +69,7 @@ mod trusted_client; use std::sync::Arc; use ethcore::client::Client; +use ethcore::miner::Miner; use ethsync::SyncProvider; pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, @@ -76,8 +78,8 @@ pub use traits::{NodeKeyPair, KeyServer}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; /// Start new key server instance -pub fn start(client: Arc, sync: Arc, self_key_pair: Arc, config: ServiceConfiguration) -> Result, Error> { - let trusted_client = trusted_client::TrustedClient::new(client.clone(), sync); +pub fn start(client: Arc, sync: Arc, miner: Arc, self_key_pair: Arc, config: ServiceConfiguration) -> Result, Error> { + let trusted_client = trusted_client::TrustedClient::new(self_key_pair.clone(), client.clone(), sync, miner); let acl_storage: Arc = if config.acl_check_enabled { acl_storage::OnChainAclStorage::new(trusted_client.clone())? } else { diff --git a/secret_store/src/listener/service_contract.rs b/secret_store/src/listener/service_contract.rs index 4d6ac14c81..eac3cfa9da 100644 --- a/secret_store/src/listener/service_contract.rs +++ b/secret_store/src/listener/service_contract.rs @@ -188,7 +188,7 @@ impl OnChainServiceContract { let transaction_data = prepare_tx(&*client, origin, &self.contract)?; // send transaction - client.transact_contract( + self.client.transact_contract( origin.clone(), transaction_data ).map_err(|e| format!("{}", e))?; diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 8776dc218e..2975eaa134 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -268,9 +268,9 @@ impl ServiceContractListener { let pending_tasks = data.contract.read_pending_requests() .filter_map(|(is_confirmed, task)| Self::filter_task(data, task) .map(|t| (is_confirmed, t))); - for (is_confirmed, task) in pending_tasks { + for (is_response_required, task) in pending_tasks { // only process requests, which we haven't confirmed yet - if is_confirmed { + if !is_response_required { continue; } diff --git a/secret_store/src/trusted_client.rs b/secret_store/src/trusted_client.rs index 8a0f83d44f..e40961e044 100644 --- a/secret_store/src/trusted_client.rs +++ b/secret_store/src/trusted_client.rs @@ -15,24 +15,35 @@ // along with Parity. If not, see . use std::sync::{Arc, Weak}; -use ethcore::client::{Client, BlockChainClient, ChainInfo}; +use bytes::Bytes; +use ethereum_types::Address; +use ethcore::client::{Client, BlockChainClient, ChainInfo, Nonce}; +use ethcore::miner::{Miner, MinerService}; use ethsync::SyncProvider; +use transaction::{Transaction, SignedTransaction, Action}; +use {Error, NodeKeyPair}; #[derive(Clone)] /// 'Trusted' client weak reference. pub struct TrustedClient { + /// This key server node key pair. + self_key_pair: Arc, /// Blockchain client. client: Weak, /// Sync provider. sync: Weak, + /// Miner service. + miner: Weak, } impl TrustedClient { /// Create new trusted client. - pub fn new(client: Arc, sync: Arc) -> Self { + pub fn new(self_key_pair: Arc, client: Arc, sync: Arc, miner: Arc) -> Self { TrustedClient { + self_key_pair: self_key_pair, client: Arc::downgrade(&client), sync: Arc::downgrade(&sync), + miner: Arc::downgrade(&miner), } } @@ -54,4 +65,25 @@ impl TrustedClient { pub fn get_untrusted(&self) -> Option> { self.client.upgrade() } + + /// Transact contract. + pub fn transact_contract(&self, contract: Address, tx_data: Bytes) -> Result<(), Error> { + let client = self.client.upgrade().ok_or_else(|| Error::Internal("cannot submit tx when client is offline".into()))?; + let miner = self.miner.upgrade().ok_or_else(|| Error::Internal("cannot submit tx when miner is offline".into()))?; + let engine = client.engine(); + let transaction = Transaction { + nonce: client.latest_nonce(&self.self_key_pair.address()), + action: Action::Call(contract), + gas: miner.gas_floor_target(), + gas_price: miner.sensible_gas_price(), + value: Default::default(), + data: tx_data, + }; + let chain_id = engine.signing_chain_id(&client.latest_env_info()); + let signature = self.self_key_pair.sign(&transaction.hash(chain_id))?; + let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?; + miner.import_own_transaction(&*client, signed.into()) + .map_err(|e| Error::Internal(format!("failed to import tx: {}", e))) + .map(|_| ()) + } } -- GitLab From 8e7a08f865715c964dc3dd83d211c2beddb3539f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 10 Apr 2018 10:13:42 +0200 Subject: [PATCH 052/263] ethcore-stratum crate moved to ethcore directory (#8338) --- Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- {stratum => ethcore/stratum}/Cargo.toml | 5 ++--- {stratum => ethcore/stratum}/src/lib.rs | 17 ++++++++--------- {stratum => ethcore/stratum}/src/traits.rs | 0 5 files changed, 12 insertions(+), 14 deletions(-) rename {stratum => ethcore/stratum}/Cargo.toml (83%) rename {stratum => ethcore/stratum}/src/lib.rs (96%) rename {stratum => ethcore/stratum}/src/traits.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index bb92fff358..34d347d453 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ ethcore-miner = { path = "miner" } ethcore-network = { path = "util/network" } ethcore-private-tx = { path = "ethcore/private-tx" } ethcore-service = { path = "ethcore/service" } -ethcore-stratum = { path = "stratum" } +ethcore-stratum = { path = "ethcore/stratum" } ethcore-transaction = { path = "ethcore/transaction" } ethereum-types = "0.3" node-filter = { path = "ethcore/node_filter" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index c028f8e6b0..0ffb7034a3 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -23,7 +23,7 @@ patricia-trie = { path = "../util/patricia_trie" } ethcore-io = { path = "../util/io" } ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } -ethcore-stratum = { path = "../stratum" } +ethcore-stratum = { path = "./stratum" } ethcore-transaction = { path = "./transaction" } ethereum-types = "0.3" memory-cache = { path = "../util/memory_cache" } diff --git a/stratum/Cargo.toml b/ethcore/stratum/Cargo.toml similarity index 83% rename from stratum/Cargo.toml rename to ethcore/stratum/Cargo.toml index 5f66cfd49c..de65a470c6 100644 --- a/stratum/Cargo.toml +++ b/ethcore/stratum/Cargo.toml @@ -6,9 +6,8 @@ license = "GPL-3.0" authors = ["Parity Technologies "] [dependencies] -ethcore-logger = { path = "../logger" } ethereum-types = "0.3" -keccak-hash = { path = "../util/hash" } +keccak-hash = { path = "../../util/hash" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-tcp-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } @@ -19,4 +18,4 @@ parking_lot = "0.5" env_logger = "0.4" tokio-core = "0.1" tokio-io = "0.1" -ethcore-logger = { path = "../logger" } +ethcore-logger = { path = "../../logger" } diff --git a/stratum/src/lib.rs b/ethcore/stratum/src/lib.rs similarity index 96% rename from stratum/src/lib.rs rename to ethcore/stratum/src/lib.rs index d43bcc5569..a4abeffd73 100644 --- a/stratum/src/lib.rs +++ b/ethcore/stratum/src/lib.rs @@ -77,10 +77,10 @@ impl Stratum { ) -> Result, Error> { let implementation = Arc::new(StratumImpl { - subscribers: RwLock::new(Vec::new()), - job_que: RwLock::new(HashSet::new()), + subscribers: RwLock::default(), + job_que: RwLock::default(), dispatcher, - workers: Arc::new(RwLock::new(HashMap::new())), + workers: Arc::new(RwLock::default()), secret, notify_counter: RwLock::new(NOTIFY_COUNTER_INITIAL), }); @@ -323,7 +323,6 @@ impl MetaExtractor for PeerMetaExtractor { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; use std::net::SocketAddr; use std::sync::Arc; @@ -366,7 +365,7 @@ mod tests { #[test] fn can_be_started() { - let stratum = Stratum::start(&SocketAddr::from_str("127.0.0.1:19980").unwrap(), Arc::new(VoidManager), None); + let stratum = Stratum::start(&"127.0.0.1:19980".parse().unwrap(), Arc::new(VoidManager), None); assert!(stratum.is_ok()); } @@ -374,7 +373,7 @@ mod tests { fn records_subscriber() { init_log(); - let addr = SocketAddr::from_str("127.0.0.1:19985").unwrap(); + let addr = "127.0.0.1:19985".parse().unwrap(); let stratum = Stratum::start(&addr, Arc::new(VoidManager), None).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "mining.subscribe", "params": [], "id": 1}"#; dummy_request(&addr, request); @@ -419,7 +418,7 @@ mod tests { #[test] fn receives_initial_paylaod() { - let addr = SocketAddr::from_str("127.0.0.1:19975").unwrap(); + let addr = "127.0.0.1:19975".parse().unwrap(); let _stratum = Stratum::start(&addr, DummyManager::new(), None).expect("There should be no error starting stratum"); let request = r#"{"jsonrpc": "2.0", "method": "mining.subscribe", "params": [], "id": 2}"#; @@ -430,7 +429,7 @@ mod tests { #[test] fn can_authorize() { - let addr = SocketAddr::from_str("127.0.0.1:19970").unwrap(); + let addr = "127.0.0.1:19970".parse().unwrap(); let stratum = Stratum::start( &addr, Arc::new(DummyManager::build().of_initial(r#"["dummy autorize payload"]"#)), @@ -448,7 +447,7 @@ mod tests { fn can_push_work() { init_log(); - let addr = SocketAddr::from_str("127.0.0.1:19995").unwrap(); + let addr = "127.0.0.1:19995".parse().unwrap(); let stratum = Stratum::start( &addr, Arc::new(DummyManager::build().of_initial(r#"["dummy autorize payload"]"#)), diff --git a/stratum/src/traits.rs b/ethcore/stratum/src/traits.rs similarity index 100% rename from stratum/src/traits.rs rename to ethcore/stratum/src/traits.rs -- GitLab From d1487b31770fdd511bb5d9a539f014ff41d8ea85 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 10 Apr 2018 16:36:14 +0800 Subject: [PATCH 053/263] rpc, eth_filter: return error if the filter id does not exist (#8341) --- rpc/src/v1/helpers/errors.rs | 8 ++++++++ rpc/src/v1/impls/eth_filter.rs | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index e86ab630f5..6e8836c20d 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -399,6 +399,14 @@ pub fn deprecated>>(message: T) -> Error { } } +pub fn filter_not_found() -> Error { + Error { + code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), + message: "Filter not found".into(), + data: None, + } +} + // on-demand sender cancelled. pub fn on_demand_cancel(_cancel: futures::sync::oneshot::Canceled) -> Error { internal("on-demand sender cancelled", "") diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 6c3d6837eb..9e2f2f8887 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -30,7 +30,7 @@ use jsonrpc_core::futures::{future, Future}; use jsonrpc_core::futures::future::Either; use v1::traits::EthFilter; use v1::types::{BlockNumber, Index, Filter, FilterChanges, Log, H256 as RpcH256, U256 as RpcU256}; -use v1::helpers::{PollFilter, PollManager, limit_logs}; +use v1::helpers::{errors, PollFilter, PollManager, limit_logs}; use v1::impls::eth::pending_logs; /// Something which provides data that can be filtered over. @@ -127,7 +127,7 @@ impl EthFilter for T { fn filter_changes(&self, index: Index) -> BoxFuture { let mut polls = self.polls().lock(); Box::new(match polls.poll_mut(&index.value()) { - None => Either::A(future::ok(FilterChanges::Empty)), + None => Either::A(future::err(errors::filter_not_found())), Some(filter) => match *filter { PollFilter::Block(ref mut block_number) => { // +1, cause we want to return hashes including current block hash. @@ -217,7 +217,8 @@ impl EthFilter for T { match polls.poll(&index.value()) { Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => filter.clone(), // just empty array - _ => return Box::new(future::ok(Vec::new())), + Some(_) => return Box::new(future::ok(Vec::new())), + None => return Box::new(future::err(errors::filter_not_found())), } }; -- GitLab From 86446d713a9b379e0eddf32402182c387ddc3748 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 10 Apr 2018 12:13:49 +0200 Subject: [PATCH 054/263] ethcore-sync (#8347) --- Cargo.lock | 72 +++++++++---------- Cargo.toml | 2 +- ethcore/service/Cargo.toml | 2 +- ethcore/service/src/lib.rs | 4 +- ethcore/service/src/service.rs | 2 +- ethcore/sync/Cargo.toml | 37 ++++++++++ {sync => ethcore/sync}/src/api.rs | 0 {sync => ethcore/sync}/src/block_sync.rs | 0 {sync => ethcore/sync}/src/blocks.rs | 0 {sync => ethcore/sync}/src/chain.rs | 0 {sync => ethcore/sync}/src/lib.rs | 0 {sync => ethcore/sync}/src/light_sync/mod.rs | 0 .../sync}/src/light_sync/response.rs | 0 .../sync}/src/light_sync/sync_round.rs | 0 .../sync}/src/light_sync/tests/mod.rs | 0 .../sync}/src/light_sync/tests/test_net.rs | 0 {sync => ethcore/sync}/src/private_tx.rs | 0 {sync => ethcore/sync}/src/snapshot.rs | 0 {sync => ethcore/sync}/src/sync_io.rs | 0 {sync => ethcore/sync}/src/tests/chain.rs | 0 {sync => ethcore/sync}/src/tests/consensus.rs | 0 {sync => ethcore/sync}/src/tests/helpers.rs | 0 {sync => ethcore/sync}/src/tests/mod.rs | 0 {sync => ethcore/sync}/src/tests/rpc.rs | 0 {sync => ethcore/sync}/src/tests/snapshot.rs | 0 .../sync}/src/transactions_stats.rs | 0 parity/configuration.rs | 4 +- parity/dapps.rs | 2 +- parity/helpers.rs | 8 +-- parity/informant.rs | 2 +- parity/light_helpers/epoch_fetch.rs | 2 +- parity/light_helpers/queue_cull.rs | 2 +- parity/main.rs | 2 +- parity/modules.rs | 6 +- parity/rpc_apis.rs | 2 +- parity/run.rs | 20 +++--- parity/secretstore.rs | 2 +- parity/whisper.rs | 2 +- rpc/Cargo.toml | 2 +- rpc/src/lib.rs | 6 +- rpc/src/v1/helpers/block_import.rs | 4 +- rpc/src/v1/helpers/dispatch.rs | 2 +- rpc/src/v1/helpers/light_fetch.rs | 2 +- rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/impls/eth_pubsub.rs | 2 +- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/net.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 2 +- rpc/src/v1/impls/light/parity_set.rs | 2 +- rpc/src/v1/impls/net.rs | 2 +- rpc/src/v1/impls/parity.rs | 2 +- rpc/src/v1/impls/parity_set.rs | 2 +- rpc/src/v1/tests/helpers/sync_provider.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/tests/mocked/manage_network.rs | 2 +- rpc/src/v1/tests/mocked/parity.rs | 2 +- rpc/src/v1/tests/mocked/parity_set.rs | 2 +- rpc/src/v1/types/sync.rs | 10 +-- secret_store/Cargo.toml | 2 +- secret_store/src/lib.rs | 4 +- secret_store/src/trusted_client.rs | 2 +- sync/Cargo.toml | 37 ---------- updater/Cargo.toml | 2 +- updater/src/lib.rs | 2 +- updater/src/updater.rs | 2 +- 65 files changed, 139 insertions(+), 139 deletions(-) create mode 100644 ethcore/sync/Cargo.toml rename {sync => ethcore/sync}/src/api.rs (100%) rename {sync => ethcore/sync}/src/block_sync.rs (100%) rename {sync => ethcore/sync}/src/blocks.rs (100%) rename {sync => ethcore/sync}/src/chain.rs (100%) rename {sync => ethcore/sync}/src/lib.rs (100%) rename {sync => ethcore/sync}/src/light_sync/mod.rs (100%) rename {sync => ethcore/sync}/src/light_sync/response.rs (100%) rename {sync => ethcore/sync}/src/light_sync/sync_round.rs (100%) rename {sync => ethcore/sync}/src/light_sync/tests/mod.rs (100%) rename {sync => ethcore/sync}/src/light_sync/tests/test_net.rs (100%) rename {sync => ethcore/sync}/src/private_tx.rs (100%) rename {sync => ethcore/sync}/src/snapshot.rs (100%) rename {sync => ethcore/sync}/src/sync_io.rs (100%) rename {sync => ethcore/sync}/src/tests/chain.rs (100%) rename {sync => ethcore/sync}/src/tests/consensus.rs (100%) rename {sync => ethcore/sync}/src/tests/helpers.rs (100%) rename {sync => ethcore/sync}/src/tests/mod.rs (100%) rename {sync => ethcore/sync}/src/tests/rpc.rs (100%) rename {sync => ethcore/sync}/src/tests/snapshot.rs (100%) rename {sync => ethcore/sync}/src/transactions_stats.rs (100%) delete mode 100644 sync/Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index d6f38caa40..275c224f36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -766,11 +766,11 @@ dependencies = [ "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", + "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", - "ethsync 1.11.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -802,7 +802,7 @@ dependencies = [ "ethcore 1.11.0", "ethcore-io 1.11.0", "ethcore-private-tx 1.0.0", - "ethsync 1.11.0", + "ethcore-sync 1.11.0", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -827,6 +827,37 @@ dependencies = [ "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-sync" +version = "1.11.0" +dependencies = [ + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore 1.11.0", + "ethcore-bytes 0.1.0", + "ethcore-io 1.11.0", + "ethcore-light 1.11.0", + "ethcore-network 1.11.0", + "ethcore-network-devp2p 1.11.0", + "ethcore-transaction 0.1.0", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethkey 0.3.0", + "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hash 0.1.0", + "kvdb 0.1.0", + "kvdb-memorydb 0.1.0", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "macros 0.1.0", + "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "plain_hasher 0.1.0", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.1", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "triehash 0.1.0", +] + [[package]] name = "ethcore-transaction" version = "0.1.0" @@ -962,37 +993,6 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethsync" -version = "1.11.0" -dependencies = [ - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", - "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-light 1.11.0", - "ethcore-network 1.11.0", - "ethcore-network-devp2p 1.11.0", - "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethkey 0.3.0", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", - "kvdb 0.1.0", - "kvdb-memorydb 0.1.0", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "macros 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "plain_hasher 0.1.0", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", - "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "triehash 0.1.0", -] - [[package]] name = "evm" version = "0.1.0" @@ -1983,10 +1983,10 @@ dependencies = [ "ethcore-secretstore 1.0.0", "ethcore-service 0.1.0", "ethcore-stratum 1.11.0", + "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", - "ethsync 1.11.0", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2187,13 +2187,13 @@ dependencies = [ "ethcore-miner 1.11.0", "ethcore-network 1.11.0", "ethcore-private-tx 1.0.0", + "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", - "ethsync 1.11.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2320,8 +2320,8 @@ dependencies = [ "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", + "ethcore-sync 1.11.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethsync 1.11.0", "keccak-hash 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 34d347d453..09c00b3386 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,6 @@ fdlimit = "0.1" ws2_32-sys = "0.2" ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } -ethsync = { path = "sync" } ethcore = { path = "ethcore" } ethcore-bytes = { path = "util/bytes" } ethcore-io = { path = "util/io" } @@ -45,6 +44,7 @@ ethcore-network = { path = "util/network" } ethcore-private-tx = { path = "ethcore/private-tx" } ethcore-service = { path = "ethcore/service" } ethcore-stratum = { path = "ethcore/stratum" } +ethcore-sync = { path = "ethcore/sync" } ethcore-transaction = { path = "ethcore/transaction" } ethereum-types = "0.3" node-filter = { path = "ethcore/node_filter" } diff --git a/ethcore/service/Cargo.toml b/ethcore/service/Cargo.toml index 608d591e09..b612baf566 100644 --- a/ethcore/service/Cargo.toml +++ b/ethcore/service/Cargo.toml @@ -9,7 +9,7 @@ error-chain = { version = "0.11", default-features = false } ethcore = { path = ".." } ethcore-io = { path = "../../util/io" } ethcore-private-tx = { path = "../private-tx" } -ethsync = { path = "../../sync" } +ethcore-sync = { path = "../sync" } kvdb = { path = "../../util/kvdb" } log = "0.3" stop-guard = { path = "../../util/stop-guard" } diff --git a/ethcore/service/src/lib.rs b/ethcore/service/src/lib.rs index 5bd1c39de5..1604e84b10 100644 --- a/ethcore/service/src/lib.rs +++ b/ethcore/service/src/lib.rs @@ -17,9 +17,9 @@ extern crate ansi_term; extern crate ethcore; extern crate ethcore_io as io; -extern crate ethsync; -extern crate kvdb; extern crate ethcore_private_tx; +extern crate ethcore_sync as sync; +extern crate kvdb; extern crate stop_guard; #[macro_use] diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 27f58b4215..8fab545574 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -24,7 +24,7 @@ use io::{IoContext, TimerToken, IoHandler, IoService, IoError}; use kvdb::{KeyValueDB, KeyValueDBHandler}; use stop_guard::StopGuard; -use ethsync::PrivateTxHandler; +use sync::PrivateTxHandler; use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage}; use ethcore::miner::Miner; use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams}; diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml new file mode 100644 index 0000000000..a09f161e2a --- /dev/null +++ b/ethcore/sync/Cargo.toml @@ -0,0 +1,37 @@ +[package] +description = "Ethcore blockchain sync" +name = "ethcore-sync" +version = "1.11.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[lib] + +[dependencies] +ethcore-bytes = { path = "../../util/bytes" } +ethcore-network = { path = "../../util/network" } +ethcore-network-devp2p = { path = "../../util/network-devp2p" } +ethcore-io = { path = "../../util/io" } +ethcore-light = { path = "../light" } +ethcore-transaction = { path = "../transaction" } +ethcore = { path = ".." } +ethereum-types = "0.3" +plain_hasher = { path = "../../util/plain_hasher" } +rlp = { path = "../../util/rlp" } +rustc-hex = "1.0" +keccak-hash = { path = "../../util/hash" } +triehash = { path = "../../util/triehash" } +kvdb = { path = "../../util/kvdb" } +macros = { path = "../../util/macros" } +log = "0.3" +env_logger = "0.4" +rand = "0.4" +heapsize = "0.4" +semver = "0.9" +smallvec = { version = "0.4", features = ["heapsizeof"] } +parking_lot = "0.5" +ipnetwork = "0.12.6" + +[dev-dependencies] +ethkey = { path = "../../ethkey" } +kvdb-memorydb = { path = "../../util/kvdb-memorydb" } diff --git a/sync/src/api.rs b/ethcore/sync/src/api.rs similarity index 100% rename from sync/src/api.rs rename to ethcore/sync/src/api.rs diff --git a/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs similarity index 100% rename from sync/src/block_sync.rs rename to ethcore/sync/src/block_sync.rs diff --git a/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs similarity index 100% rename from sync/src/blocks.rs rename to ethcore/sync/src/blocks.rs diff --git a/sync/src/chain.rs b/ethcore/sync/src/chain.rs similarity index 100% rename from sync/src/chain.rs rename to ethcore/sync/src/chain.rs diff --git a/sync/src/lib.rs b/ethcore/sync/src/lib.rs similarity index 100% rename from sync/src/lib.rs rename to ethcore/sync/src/lib.rs diff --git a/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs similarity index 100% rename from sync/src/light_sync/mod.rs rename to ethcore/sync/src/light_sync/mod.rs diff --git a/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs similarity index 100% rename from sync/src/light_sync/response.rs rename to ethcore/sync/src/light_sync/response.rs diff --git a/sync/src/light_sync/sync_round.rs b/ethcore/sync/src/light_sync/sync_round.rs similarity index 100% rename from sync/src/light_sync/sync_round.rs rename to ethcore/sync/src/light_sync/sync_round.rs diff --git a/sync/src/light_sync/tests/mod.rs b/ethcore/sync/src/light_sync/tests/mod.rs similarity index 100% rename from sync/src/light_sync/tests/mod.rs rename to ethcore/sync/src/light_sync/tests/mod.rs diff --git a/sync/src/light_sync/tests/test_net.rs b/ethcore/sync/src/light_sync/tests/test_net.rs similarity index 100% rename from sync/src/light_sync/tests/test_net.rs rename to ethcore/sync/src/light_sync/tests/test_net.rs diff --git a/sync/src/private_tx.rs b/ethcore/sync/src/private_tx.rs similarity index 100% rename from sync/src/private_tx.rs rename to ethcore/sync/src/private_tx.rs diff --git a/sync/src/snapshot.rs b/ethcore/sync/src/snapshot.rs similarity index 100% rename from sync/src/snapshot.rs rename to ethcore/sync/src/snapshot.rs diff --git a/sync/src/sync_io.rs b/ethcore/sync/src/sync_io.rs similarity index 100% rename from sync/src/sync_io.rs rename to ethcore/sync/src/sync_io.rs diff --git a/sync/src/tests/chain.rs b/ethcore/sync/src/tests/chain.rs similarity index 100% rename from sync/src/tests/chain.rs rename to ethcore/sync/src/tests/chain.rs diff --git a/sync/src/tests/consensus.rs b/ethcore/sync/src/tests/consensus.rs similarity index 100% rename from sync/src/tests/consensus.rs rename to ethcore/sync/src/tests/consensus.rs diff --git a/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs similarity index 100% rename from sync/src/tests/helpers.rs rename to ethcore/sync/src/tests/helpers.rs diff --git a/sync/src/tests/mod.rs b/ethcore/sync/src/tests/mod.rs similarity index 100% rename from sync/src/tests/mod.rs rename to ethcore/sync/src/tests/mod.rs diff --git a/sync/src/tests/rpc.rs b/ethcore/sync/src/tests/rpc.rs similarity index 100% rename from sync/src/tests/rpc.rs rename to ethcore/sync/src/tests/rpc.rs diff --git a/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs similarity index 100% rename from sync/src/tests/snapshot.rs rename to ethcore/sync/src/tests/snapshot.rs diff --git a/sync/src/transactions_stats.rs b/ethcore/sync/src/transactions_stats.rs similarity index 100% rename from sync/src/transactions_stats.rs rename to ethcore/sync/src/transactions_stats.rs diff --git a/parity/configuration.rs b/parity/configuration.rs index 7760fe470a..3e8f58b6fa 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -27,7 +27,7 @@ use ethereum_types::{U256, H256, Address}; use parity_version::{version_data, version}; use bytes::Bytes; use ansi_term::Colour; -use ethsync::{NetworkConfiguration, validate_node_url, self}; +use sync::{NetworkConfiguration, validate_node_url, self}; use ethcore::ethstore::ethkey::{Secret, Public}; use ethcore::client::{VMType}; use ethcore::miner::{MinerOptions, Banning, StratumOptions}; @@ -738,7 +738,7 @@ impl Configuration { for line in &lines { match validate_node_url(line).map(Into::into) { None => continue, - Some(ethsync::ErrorKind::AddressResolve(_)) => return Err(format!("Failed to resolve hostname of a boot node: {}", line)), + Some(sync::ErrorKind::AddressResolve(_)) => return Err(format!("Failed to resolve hostname of a boot node: {}", line)), Some(_) => return Err(format!("Invalid node address format given for a boot node: {}", line)), } } diff --git a/parity/dapps.rs b/parity/dapps.rs index d93ae2db7c..42ff21b58f 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -21,7 +21,7 @@ use bytes::Bytes; use dir::default_data_path; use dir::helpers::replace_home; use ethcore::client::{Client, BlockChainClient, BlockId, CallContract}; -use ethsync::LightSync; +use sync::LightSync; use futures::{Future, future, IntoFuture}; use futures_cpupool::CpuPool; use hash_fetch::fetch::Client as FetchClient; diff --git a/parity/helpers.rs b/parity/helpers.rs index 1c6c70cdae..0494be40d8 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -31,7 +31,7 @@ use dir::DatabaseDirectories; use dir::helpers::replace_home; use upgrade::{upgrade, upgrade_data_paths}; use migration::migrate; -use ethsync::{validate_node_url, self}; +use sync::{validate_node_url, self}; use kvdb::{KeyValueDB, KeyValueDBHandler}; use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile}; use path; @@ -174,7 +174,7 @@ pub fn to_bootnodes(bootnodes: &Option) -> Result, String> { Some(ref x) if !x.is_empty() => x.split(',').map(|s| { match validate_node_url(s).map(Into::into) { None => Ok(s.to_owned()), - Some(ethsync::ErrorKind::AddressResolve(_)) => Err(format!("Failed to resolve hostname of a boot node: {}", s)), + Some(sync::ErrorKind::AddressResolve(_)) => Err(format!("Failed to resolve hostname of a boot node: {}", s)), Some(_) => Err(format!("Invalid node address format given for a boot node: {}", s)), } }).collect(), @@ -184,8 +184,8 @@ pub fn to_bootnodes(bootnodes: &Option) -> Result, String> { } #[cfg(test)] -pub fn default_network_config() -> ::ethsync::NetworkConfiguration { - use ethsync::{NetworkConfiguration}; +pub fn default_network_config() -> ::sync::NetworkConfiguration { + use sync::{NetworkConfiguration}; use super::network::IpFilter; NetworkConfiguration { config_path: Some(replace_home(&::dir::default_data_path(), "$BASE/network")), diff --git a/parity/informant.rs b/parity/informant.rs index b834b018d6..2ccc622a70 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -29,7 +29,7 @@ use ethcore::client::{ use ethcore::header::BlockNumber; use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; use ethcore::snapshot::service::Service as SnapshotService; -use ethsync::{LightSyncProvider, LightSync, SyncProvider, ManageNetwork}; +use sync::{LightSyncProvider, LightSync, SyncProvider, ManageNetwork}; use io::{TimerToken, IoContext, IoHandler}; use isatty::{stdout_isatty}; use light::Cache as LightDataCache; diff --git a/parity/light_helpers/epoch_fetch.rs b/parity/light_helpers/epoch_fetch.rs index ff384c1310..1b9ae86484 100644 --- a/parity/light_helpers/epoch_fetch.rs +++ b/parity/light_helpers/epoch_fetch.rs @@ -21,7 +21,7 @@ use ethcore::engines::{EthEngine, StateDependentProof}; use ethcore::header::Header; use ethcore::machine::EthereumMachine; use ethcore::receipt::Receipt; -use ethsync::LightSync; +use sync::LightSync; use futures::{future, Future}; use futures::future::Either; diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index 9acf2bf1f9..0d0ff6d450 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -20,7 +20,7 @@ use std::sync::Arc; use std::time::Duration; use ethcore::client::ClientIoMessage; -use ethsync::LightSync; +use sync::LightSync; use io::{IoContext, IoHandler, TimerToken}; use light::client::LightChainClient; diff --git a/parity/main.rs b/parity/main.rs index 9ff3d97ab3..7179996bf5 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -55,10 +55,10 @@ extern crate ethcore_miner as miner; extern crate ethcore_network as network; extern crate ethcore_private_tx; extern crate ethcore_service; +extern crate ethcore_sync as sync; extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethkey; -extern crate ethsync; extern crate kvdb; extern crate kvdb_rocksdb; extern crate migration as migr; diff --git a/parity/modules.rs b/parity/modules.rs index 22f8afe9f1..cf46149b8e 100644 --- a/parity/modules.rs +++ b/parity/modules.rs @@ -17,11 +17,11 @@ use std::sync::Arc; use ethcore::client::BlockChainClient; -use ethsync::{self, AttachedProtocol, SyncConfig, NetworkConfiguration, Params, ConnectionFilter}; +use sync::{self, AttachedProtocol, SyncConfig, NetworkConfiguration, Params, ConnectionFilter}; use ethcore::snapshot::SnapshotService; use light::Provider; -pub use ethsync::{EthSync, SyncProvider, ManageNetwork, PrivateTxHandler}; +pub use sync::{EthSync, SyncProvider, ManageNetwork, PrivateTxHandler}; pub use ethcore::client::ChainNotify; use ethcore_logger::Config as LogConfig; @@ -37,7 +37,7 @@ pub fn sync( _log_settings: &LogConfig, attached_protos: Vec, connection_filter: Option>, -) -> Result { +) -> Result { let eth_sync = EthSync::new(Params { config: sync_cfg, chain: client, diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 23a69755ff..7b914f2860 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -28,7 +28,7 @@ use ethcore::client::Client; use ethcore::miner::Miner; use ethcore::snapshot::SnapshotService; use ethcore_logger::RotatingLogger; -use ethsync::{ManageNetwork, SyncProvider, LightSync}; +use sync::{ManageNetwork, SyncProvider, LightSync}; use futures_cpupool::CpuPool; use hash_fetch::fetch::Client as FetchClient; use jsonrpc_core::{self as core, MetaIoHandler}; diff --git a/parity/run.rs b/parity/run.rs index 9d43801ac0..9db2f1ca4c 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -34,7 +34,7 @@ use ethcore::spec::{SpecParams, OptimizeFor}; use ethcore::verification::queue::VerifierSettings; use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_service::ClientService; -use ethsync::{self, SyncConfig}; +use sync::{self, SyncConfig}; use fdlimit::raise_fd_limit; use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; @@ -99,7 +99,7 @@ pub struct RunCmd { pub ws_conf: rpc::WsConfiguration, pub http_conf: rpc::HttpConfiguration, pub ipc_conf: rpc::IpcConfiguration, - pub net_conf: ethsync::NetworkConfiguration, + pub net_conf: sync::NetworkConfiguration, pub network_id: Option, pub warp_sync: bool, pub warp_barrier: Option, @@ -188,7 +188,7 @@ type LightClient = ::light::client::Client<::light_helpers::EpochFetch>; // helper for light execution. fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result { use light::client as light_client; - use ethsync::{LightSyncParams, LightSync, ManageNetwork}; + use sync::{LightSyncParams, LightSync, ManageNetwork}; use parking_lot::{Mutex, RwLock}; // load spec @@ -290,7 +290,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result bool { self.0.is_major_importing() } fn peers(&self) -> (usize, usize) { - let peers = ethsync::LightSyncProvider::peer_numbers(&*self.0); + let peers = sync::LightSyncProvider::peer_numbers(&*self.0); (peers.connected, peers.max) } } @@ -535,9 +535,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: } } sync_config.warp_sync = match (warp_sync, cmd.warp_barrier) { - (true, Some(block)) => ethsync::WarpSync::OnlyAndAfter(block), - (true, _) => ethsync::WarpSync::Enabled, - _ => ethsync::WarpSync::Disabled, + (true, Some(block)) => sync::WarpSync::OnlyAndAfter(block), + (true, _) => sync::WarpSync::Enabled, + _ => sync::WarpSync::Disabled, }; sync_config.download_old_blocks = cmd.download_old_blocks; sync_config.serve_light = cmd.serve_light; @@ -711,7 +711,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: client.clone(), &cmd.logger_config, attached_protos, - connection_filter.clone().map(|f| f as Arc<::ethsync::ConnectionFilter + 'static>), + connection_filter.clone().map(|f| f as Arc<::sync::ConnectionFilter + 'static>), ).map_err(|e| format!("Sync error: {}", e))?; service.add_notify(chain_notify.clone()); @@ -758,7 +758,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let (node_health, dapps_deps) = { let (sync, client) = (sync_provider.clone(), client.clone()); - struct SyncStatus(Arc, Arc, ethsync::NetworkConfiguration); + struct SyncStatus(Arc, Arc, sync::NetworkConfiguration); impl fmt::Debug for SyncStatus { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "Dapps Sync Status") diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 8e9f5fef5a..9c130a59a9 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -22,7 +22,7 @@ use ethcore::account_provider::AccountProvider; use ethcore::client::Client; use ethcore::miner::Miner; use ethkey::{Secret, Public}; -use ethsync::SyncProvider; +use sync::SyncProvider; use ethereum_types::Address; /// This node secret key. diff --git a/parity/whisper.rs b/parity/whisper.rs index ed4812063d..c7acd8f9d6 100644 --- a/parity/whisper.rs +++ b/parity/whisper.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use std::io; -use ethsync::{AttachedProtocol, ManageNetwork}; +use sync::{AttachedProtocol, ManageNetwork}; use parity_rpc::Metadata; use parity_whisper::message::Message; use parity_whisper::net::{self as whisper_net, Network as WhisperNetwork}; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index ed59a91e8d..7f975ca9dd 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -45,6 +45,7 @@ ethcore-light = { path = "../ethcore/light" } ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } ethcore-private-tx = { path = "../ethcore/private-tx" } +ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" @@ -52,7 +53,6 @@ ethcrypto = { path = "../ethcrypto" } ethjson = { path = "../json" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } -ethsync = { path = "../sync" } fetch = { path = "../util/fetch" } hardware-wallet = { path = "../hw" } keccak-hash = { path = "../util/hash" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 79911938b8..13e700375e 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -49,14 +49,15 @@ extern crate ethcore_bytes as bytes; extern crate ethcore_devtools as devtools; extern crate ethcore_io as io; extern crate ethcore_light as light; +extern crate ethcore_logger; extern crate ethcore_miner as miner; +extern crate ethcore_private_tx; +extern crate ethcore_sync as sync; extern crate ethcore_transaction as transaction; extern crate ethcrypto as crypto; extern crate ethereum_types; extern crate ethkey; extern crate ethstore; -extern crate ethsync; -extern crate ethcore_logger; extern crate vm; extern crate fetch; extern crate node_health; @@ -67,7 +68,6 @@ extern crate rlp; extern crate stats; extern crate keccak_hash as hash; extern crate hardware_wallet; -extern crate ethcore_private_tx; extern crate patricia_trie as trie; #[macro_use] diff --git a/rpc/src/v1/helpers/block_import.rs b/rpc/src/v1/helpers/block_import.rs index 3c3f84635d..1246faa658 100644 --- a/rpc/src/v1/helpers/block_import.rs +++ b/rpc/src/v1/helpers/block_import.rs @@ -17,7 +17,7 @@ //! Block import analysis functions. use ethcore::client::BlockQueueInfo; -use ethsync::SyncState; +use sync::SyncState; /// Check if client is during major sync or during block import. pub fn is_major_importing(sync_state: Option, queue_info: BlockQueueInfo) -> bool { @@ -32,7 +32,7 @@ pub fn is_major_importing(sync_state: Option, queue_info: BlockQueueI #[cfg(test)] mod tests { use ethcore::client::BlockQueueInfo; - use ethsync::SyncState; + use sync::SyncState; use super::is_major_importing; diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index b082320d57..b1fc07a22d 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -32,7 +32,7 @@ use parking_lot::{Mutex, RwLock}; use stats::Corpus; use ethkey::Signature; -use ethsync::LightSync; +use sync::LightSync; use ethcore::ids::BlockId; use ethcore::miner::MinerService; use ethcore::client::MiningBlockChainClient; diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index f0c389d577..d8a157da21 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -36,7 +36,7 @@ use light::cht; use light::on_demand::{request, OnDemand, HeaderRef, Request as OnDemandRequest, Response as OnDemandResponse}; use light::request::Field; -use ethsync::LightSync; +use sync::LightSync; use ethereum_types::{U256, Address}; use hash::H256; use parking_lot::Mutex; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 4c48ccb616..c833e3ee7f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -35,7 +35,7 @@ use ethcore::log_entry::LogEntry; use ethcore::miner::MinerService; use ethcore::snapshot::SnapshotService; use ethcore::encoded; -use ethsync::{SyncProvider}; +use sync::{SyncProvider}; use miner::external::ExternalMinerService; use transaction::{SignedTransaction, LocalizedTransaction}; diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index 315fc2f4f8..d7e6112a93 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -34,7 +34,7 @@ use v1::types::{pubsub, RichHeader, Log}; use ethcore::encoded; use ethcore::filter::Filter as EthFilter; use ethcore::client::{BlockChainClient, ChainNotify, BlockId}; -use ethsync::LightSync; +use sync::LightSync; use light::cache::Cache; use light::on_demand::OnDemand; use light::client::{LightChainClient, LightChainNotify}; diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index b449a2a227..c617c03b1d 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -32,7 +32,7 @@ use ethcore::account_provider::{AccountProvider, DappId}; use ethcore::encoded; use ethcore::filter::Filter as EthcoreFilter; use ethcore::ids::BlockId; -use ethsync::LightSync; +use sync::LightSync; use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; use ethereum_types::U256; use parking_lot::{RwLock, Mutex}; diff --git a/rpc/src/v1/impls/light/net.rs b/rpc/src/v1/impls/light/net.rs index 3491b35ba7..1b374247a3 100644 --- a/rpc/src/v1/impls/light/net.rs +++ b/rpc/src/v1/impls/light/net.rs @@ -17,7 +17,7 @@ //! Net rpc implementation. use std::sync::Arc; use jsonrpc_core::Result; -use ethsync::LightSyncProvider; +use sync::LightSyncProvider; use v1::traits::Net; /// Net rpc implementation. diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 3b2fab9a3c..e1dc8d4d3d 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -23,7 +23,7 @@ use version::version_data; use crypto::{ecies, DEFAULT_MAC}; use ethkey::{Brain, Generator}; use ethstore::random_phrase; -use ethsync::LightSyncProvider; +use sync::LightSyncProvider; use ethcore::account_provider::AccountProvider; use ethcore_logger::RotatingLogger; use node_health::{NodeHealth, Health}; diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index 0a6c2c5a57..76c33cf458 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -20,7 +20,7 @@ use std::io; use std::sync::Arc; -use ethsync::ManageNetwork; +use sync::ManageNetwork; use fetch::{self, Fetch}; use futures_cpupool::CpuPool; use hash::keccak_buffer; diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 50dbffdc79..3f42f01b94 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -17,7 +17,7 @@ //! Net rpc implementation. use std::sync::Arc; use jsonrpc_core::Result; -use ethsync::SyncProvider; +use sync::SyncProvider; use v1::traits::Net; /// Net rpc implementation. diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 95c810aa1a..451556e856 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -25,7 +25,7 @@ use version::version_data; use crypto::{DEFAULT_MAC, ecies}; use ethkey::{Brain, Generator}; use ethstore::random_phrase; -use ethsync::{SyncProvider, ManageNetwork}; +use sync::{SyncProvider, ManageNetwork}; use ethcore::account_provider::AccountProvider; use ethcore::client::{MiningBlockChainClient, StateClient, Call}; use ethcore::ids::BlockId; diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 1be136e1de..475f5e0195 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use ethcore::miner::MinerService; use ethcore::client::MiningBlockChainClient; use ethcore::mode::Mode; -use ethsync::ManageNetwork; +use sync::ManageNetwork; use fetch::{self, Fetch}; use futures_cpupool::CpuPool; use hash::keccak_buffer; diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index cbe6654235..a5ca4a4b36 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -19,7 +19,7 @@ use std::collections::BTreeMap; use ethereum_types::H256; use parking_lot::RwLock; -use ethsync::{SyncProvider, EthProtocolInfo, SyncStatus, SyncState, PeerInfo, TransactionStats}; +use sync::{SyncProvider, EthProtocolInfo, SyncStatus, SyncState, PeerInfo, TransactionStats}; /// TestSyncProvider config. pub struct Config { diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 99c67286eb..e79411f705 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -27,7 +27,7 @@ use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::miner::MinerService; use ethcore::receipt::{LocalizedReceipt, TransactionOutcome}; use ethkey::Secret; -use ethsync::SyncState; +use sync::SyncState; use miner::external::ExternalMiner; use rlp; use rustc_hex::{FromHex, ToHex}; diff --git a/rpc/src/v1/tests/mocked/manage_network.rs b/rpc/src/v1/tests/mocked/manage_network.rs index 9438429cdb..3a901c8e9f 100644 --- a/rpc/src/v1/tests/mocked/manage_network.rs +++ b/rpc/src/v1/tests/mocked/manage_network.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethsync::{ManageNetwork, NetworkConfiguration}; +use sync::{ManageNetwork, NetworkConfiguration}; use self::ethcore_network::{ProtocolId, NetworkContext}; extern crate ethcore_network; diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 332221b081..18f76c6719 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -20,7 +20,7 @@ use ethcore::client::{TestBlockChainClient, Executed}; use ethcore::miner::LocalTransactionStatus; use ethcore_logger::RotatingLogger; use ethstore::ethkey::{Generator, Random}; -use ethsync::ManageNetwork; +use sync::ManageNetwork; use node_health::{self, NodeHealth}; use parity_reactor; use ethereum_types::{Address, U256, H256}; diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index 549811bd58..2ae8ab5b2b 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -21,7 +21,7 @@ use ethereum_types::{U256, Address}; use ethcore::miner::MinerService; use ethcore::client::TestBlockChainClient; -use ethsync::ManageNetwork; +use sync::ManageNetwork; use futures_cpupool::CpuPool; use jsonrpc_core::IoHandler; diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index ae421ed404..cbac3e1bbb 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::collections::BTreeMap; -use ethsync::{self, PeerInfo as SyncPeerInfo, TransactionStats as SyncTransactionStats}; +use sync::{self, PeerInfo as SyncPeerInfo, TransactionStats as SyncTransactionStats}; use serde::{Serialize, Serializer}; use v1::types::{U256, H512}; @@ -98,8 +98,8 @@ pub struct EthProtocolInfo { pub head: String, } -impl From for EthProtocolInfo { - fn from(info: ethsync::EthProtocolInfo) -> Self { +impl From for EthProtocolInfo { + fn from(info: sync::EthProtocolInfo) -> Self { EthProtocolInfo { version: info.version, difficulty: info.difficulty.map(Into::into), @@ -119,8 +119,8 @@ pub struct PipProtocolInfo { pub head: String, } -impl From for PipProtocolInfo { - fn from(info: ethsync::PipProtocolInfo) -> Self { +impl From for PipProtocolInfo { + fn from(info: sync::PipProtocolInfo) -> Self { PipProtocolInfo { version: info.version, difficulty: info.difficulty.into(), diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index d894bb4efd..b9dee7303b 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -24,9 +24,9 @@ tokio-proto = "0.1" url = "1.0" ethcore = { path = "../ethcore" } ethcore-bytes = { path = "../util/bytes" } +ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" -ethsync = { path = "../sync" } kvdb = { path = "../util/kvdb" } kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } keccak-hash = { path = "../util/hash" } diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index d58e37ffe7..c087d66511 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -19,11 +19,11 @@ extern crate ethabi; extern crate ethcore; extern crate ethcore_bytes as bytes; extern crate ethcore_logger as logger; +extern crate ethcore_sync as sync; extern crate ethcore_transaction as transaction; extern crate ethcrypto; extern crate ethereum_types; extern crate ethkey; -extern crate ethsync; extern crate futures_cpupool; extern crate hyper; extern crate keccak_hash as hash; @@ -70,7 +70,7 @@ mod trusted_client; use std::sync::Arc; use ethcore::client::Client; use ethcore::miner::Miner; -use ethsync::SyncProvider; +use sync::SyncProvider; pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, Error, NodeAddress, ContractAddress, ServiceConfiguration, ClusterConfiguration}; diff --git a/secret_store/src/trusted_client.rs b/secret_store/src/trusted_client.rs index e40961e044..5a9efe4b68 100644 --- a/secret_store/src/trusted_client.rs +++ b/secret_store/src/trusted_client.rs @@ -19,7 +19,7 @@ use bytes::Bytes; use ethereum_types::Address; use ethcore::client::{Client, BlockChainClient, ChainInfo, Nonce}; use ethcore::miner::{Miner, MinerService}; -use ethsync::SyncProvider; +use sync::SyncProvider; use transaction::{Transaction, SignedTransaction, Action}; use {Error, NodeKeyPair}; diff --git a/sync/Cargo.toml b/sync/Cargo.toml deleted file mode 100644 index 23cbbcf341..0000000000 --- a/sync/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -description = "Ethcore blockchain sync" -name = "ethsync" -version = "1.11.0" -license = "GPL-3.0" -authors = ["Parity Technologies "] - -[lib] - -[dependencies] -ethcore-bytes = { path = "../util/bytes" } -ethcore-network = { path = "../util/network" } -ethcore-network-devp2p = { path = "../util/network-devp2p" } -ethcore-io = { path = "../util/io" } -ethcore-light = { path = "../ethcore/light" } -ethcore-transaction = { path = "../ethcore/transaction" } -ethcore = { path = "../ethcore" } -ethereum-types = "0.3" -plain_hasher = { path = "../util/plain_hasher" } -rlp = { path = "../util/rlp" } -rustc-hex = "1.0" -keccak-hash = { path = "../util/hash" } -triehash = { path = "../util/triehash" } -kvdb = { path = "../util/kvdb" } -macros = { path = "../util/macros" } -log = "0.3" -env_logger = "0.4" -rand = "0.4" -heapsize = "0.4" -semver = "0.9" -smallvec = { version = "0.4", features = ["heapsizeof"] } -parking_lot = "0.5" -ipnetwork = "0.12.6" - -[dev-dependencies] -ethkey = { path = "../ethkey" } -kvdb-memorydb = { path = "../util/kvdb-memorydb" } diff --git a/updater/Cargo.toml b/updater/Cargo.toml index 4afe802c61..9e7733bc46 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -15,8 +15,8 @@ ethabi-contract = "5.0" target_info = "0.1" semver = "0.9" ethcore = { path = "../ethcore" } -ethsync = { path = "../sync" } ethcore-bytes = { path = "../util/bytes" } +ethcore-sync = { path = "../ethcore/sync" } ethereum-types = "0.3" parking_lot = "0.5" parity-hash-fetch = { path = "../hash-fetch" } diff --git a/updater/src/lib.rs b/updater/src/lib.rs index 91c66d7680..67525aa4b2 100644 --- a/updater/src/lib.rs +++ b/updater/src/lib.rs @@ -19,8 +19,8 @@ extern crate ethabi; extern crate ethcore; extern crate ethcore_bytes as bytes; +extern crate ethcore_sync as sync; extern crate ethereum_types; -extern crate ethsync; extern crate keccak_hash as hash; extern crate parity_hash_fetch as hash_fetch; extern crate parity_version as version; diff --git a/updater/src/updater.rs b/updater/src/updater.rs index 60984e10f1..3b5ce01a93 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -30,7 +30,7 @@ use ethcore::BlockNumber; use ethcore::filter::Filter; use ethcore::client::{BlockId, BlockChainClient, ChainNotify}; use ethereum_types::H256; -use ethsync::{SyncProvider}; +use sync::{SyncProvider}; use hash_fetch::{self as fetch, HashFetch}; use path::restrict_permissions_owner; use service::Service; -- GitLab From 692cd10d4af2aaf1125d79808c0a510127f3ed7c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 10 Apr 2018 19:51:29 +0800 Subject: [PATCH 055/263] Use hyper 0.11 in ethcore-miner and improvements in parity-reactor (#8335) * parity-reactor: Pass over Handle in spawning fn to allow normal tokio ops * Allow fetch to work with arbitrary requests * typo: Fix missing handler closure * miner, work_notify: use fetch and parity-reactor * Fix work_notify pushing in parity CLI --- Cargo.lock | 72 +---------- dapps/node-health/src/health.rs | 2 +- dapps/src/tests/helpers/fetch.rs | 26 +++- ethcore/private-tx/Cargo.toml | 1 + ethcore/private-tx/src/encryptor.rs | 7 +- ethcore/private-tx/src/lib.rs | 2 +- ethcore/src/miner/miner.rs | 12 +- hash-fetch/src/client.rs | 25 +++- miner/Cargo.toml | 7 +- miner/src/work_notify.rs | 82 ++++--------- parity/configuration.rs | 3 +- parity/light_helpers/queue_cull.rs | 2 +- parity/run.rs | 11 +- price-info/src/lib.rs | 24 +++- rpc/src/v1/tests/eth.rs | 1 - rpc/src/v1/tests/helpers/fetch.rs | 24 +++- util/fetch/Cargo.toml | 1 + util/fetch/src/client.rs | 181 +++++++++++++++++++++------- util/fetch/src/lib.rs | 4 +- util/reactor/src/lib.rs | 36 ++++-- 20 files changed, 302 insertions(+), 221 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 275c224f36..f802b863e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,15 +250,6 @@ dependencies = [ "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cookie" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam" version = "0.3.2" @@ -660,16 +651,19 @@ dependencies = [ "ethcore-transaction 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", + "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", + "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-reactor 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "table 0.1.0", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -753,6 +747,7 @@ dependencies = [ "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1041,6 +1036,7 @@ dependencies = [ name = "fetch" version = "0.1.0" dependencies = [ + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1204,25 +1200,6 @@ name = "httparse" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "hyper" -version = "0.10.0-a.0" -source = "git+https://github.com/paritytech/hyper#da10f69a4924cd44e98a8d1f9562bd7534d13dcc" -dependencies = [ - "cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rotor 0.6.3 (git+https://github.com/tailhook/rotor)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "spmc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hyper" version = "0.10.13" @@ -2634,11 +2611,6 @@ dependencies = [ "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quick-error" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "quote" version = "0.5.1" @@ -2807,18 +2779,6 @@ dependencies = [ "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", ] -[[package]] -name = "rotor" -version = "0.6.3" -source = "git+https://github.com/tailhook/rotor#80ce2e4cd82fdc7f88bb2d737407fa5106799790" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rpassword" version = "1.0.2" @@ -3054,11 +3014,6 @@ dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "spmc" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "stable_deref_trait" version = "1.0.0" @@ -3612,15 +3567,6 @@ name = "vec_map" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "vecio" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "vergen" version = "0.1.1" @@ -3831,7 +3777,6 @@ dependencies = [ "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" @@ -3878,7 +3823,6 @@ dependencies = [ "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)" = "" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)" = "" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)" = "df4dd5dae401458087396b6db7fabc4d6760aa456a5fa8e92bda549f39cae661" "checksum hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6cdc1751771a14b8175764394f025e309a28c825ed9eaf97fa62bb831dc8c5" @@ -3973,7 +3917,6 @@ dependencies = [ "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" -"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" @@ -3988,7 +3931,6 @@ dependencies = [ "checksum ring 0.12.1 (git+https://github.com/paritytech/ring)" = "" "checksum rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)" = "" "checksum rocksdb-sys 0.3.0 (git+https://github.com/paritytech/rust-rocksdb)" = "" -"checksum rotor 0.6.3 (git+https://github.com/tailhook/rotor)" = "" "checksum rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b273c91bd242ca03ad6d71c143b6f17a48790e61f21a6c78568fa2b6774a24a4" "checksum rprompt 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1601f32bc5858aae3cbfa1c645c96c4d820cc5c16be0194f089560c00b6eb625" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" @@ -4020,7 +3962,6 @@ dependencies = [ "checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d" "checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" -"checksum spmc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cd1f11d1fb5fd41834e55ce0b85a186efbf2f2afd9fdb09e2c8d72f9bff1ad1a" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb" @@ -4075,7 +4016,6 @@ dependencies = [ "checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" -"checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24" "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/dapps/node-health/src/health.rs b/dapps/node-health/src/health.rs index ab52b22330..ab300a4a77 100644 --- a/dapps/node-health/src/health.rs +++ b/dapps/node-health/src/health.rs @@ -53,7 +53,7 @@ impl NodeHealth { let tx = Arc::new(Mutex::new(Some(tx))); let tx2 = tx.clone(); self.remote.spawn_with_timeout( - move || time.then(move |result| { + move |_| time.then(move |result| { let _ = tx.lock().take().expect(PROOF).send(Ok(result)); Ok(()) }), diff --git a/dapps/src/tests/helpers/fetch.rs b/dapps/src/tests/helpers/fetch.rs index d65d9d09b0..146163a77f 100644 --- a/dapps/src/tests/helpers/fetch.rs +++ b/dapps/src/tests/helpers/fetch.rs @@ -19,8 +19,8 @@ use std::sync::{atomic, mpsc, Arc}; use parking_lot::Mutex; use hyper; -use futures::{self, Future}; -use fetch::{self, Fetch, Url, Method}; +use futures::{self, future, Future}; +use fetch::{self, Fetch, Url, Request, Abort}; pub struct FetchControl { sender: mpsc::Sender<()>, @@ -97,9 +97,9 @@ impl FakeFetch { impl Fetch for FakeFetch { type Result = Box + Send>; - fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { - let u = Url::parse(url).unwrap(); - self.requested.lock().push(url.into()); + fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { + let u = request.url().clone(); + self.requested.lock().push(u.as_str().into()); let manual = self.manual.clone(); let response = self.response.clone(); @@ -115,4 +115,20 @@ impl Fetch for FakeFetch { Box::new(rx.map_err(|_| fetch::Error::Aborted)) } + + fn get(&self, url: &str, abort: Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return Box::new(future::err(e.into())) + }; + self.fetch(Request::get(url), abort) + } + + fn post(&self, url: &str, abort: Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return Box::new(future::err(e.into())) + }; + self.fetch(Request::post(url), abort) + } } diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index 6ecfdb5464..ff37f20ab2 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -34,3 +34,4 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" tiny-keccak = "1.3" +url = "1" diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs index 385356227f..fd7eaa680f 100644 --- a/ethcore/private-tx/src/encryptor.rs +++ b/ethcore/private-tx/src/encryptor.rs @@ -17,6 +17,7 @@ //! Encryption providers. use std::io::Read; +use std::str::FromStr; use std::iter::repeat; use std::time::{Instant, Duration}; use std::collections::HashMap; @@ -28,9 +29,10 @@ use ethjson; use ethkey::{Signature, Public}; use ethcrypto; use futures::Future; -use fetch::{Fetch, Client as FetchClient, Method, BodyReader}; +use fetch::{Fetch, Client as FetchClient, Method, BodyReader, Request}; use bytes::{Bytes, ToPretty}; use error::{Error, ErrorKind}; +use url::Url; use super::find_account_password; /// Initialization vector length. @@ -128,7 +130,8 @@ impl SecretStoreEncryptor { Method::Get }; - let response = self.client.fetch(&url, method, Default::default()).wait() + let url = Url::from_str(&url).map_err(|e| ErrorKind::Encrypt(e.to_string()))?; + let response = self.client.fetch(Request::new(url, method), Default::default()).wait() .map_err(|e| ErrorKind::Encrypt(e.to_string()))?; if response.is_not_found() { diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 4fa1f8789c..5b7a62b7cd 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -41,6 +41,7 @@ extern crate keccak_hash as hash; extern crate parking_lot; extern crate patricia_trie as trie; extern crate rlp; +extern crate url; extern crate rustc_hex; #[macro_use] extern crate log; @@ -673,4 +674,3 @@ impl ChainNotify for Provider { } } } - diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 96094dce41..755294637b 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -36,7 +36,7 @@ use ethcore_miner::transaction_queue::{ TransactionOrigin, }; use futures_cpupool::CpuPool; -use ethcore_miner::work_notify::{WorkPoster, NotifyWork}; +use ethcore_miner::work_notify::NotifyWork; use miner::service_transaction_checker::ServiceTransactionChecker; use miner::{MinerService, MinerStatus}; use price_info::fetch::Client as FetchClient; @@ -104,8 +104,6 @@ pub enum Banning { /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] pub struct MinerOptions { - /// URLs to notify when there is new work. - pub new_work_notify: Vec, /// Force the miner to reseal, even when nobody has asked for work. pub force_sealing: bool, /// Reseal on receipt of new external transactions. @@ -147,7 +145,6 @@ pub struct MinerOptions { impl Default for MinerOptions { fn default() -> Self { MinerOptions { - new_work_notify: vec![], force_sealing: false, reseal_on_external_tx: false, reseal_on_own_tx: true, @@ -305,10 +302,7 @@ impl Miner { ), }; - let notifiers: Vec> = match options.new_work_notify.is_empty() { - true => Vec::new(), - false => vec![Box::new(WorkPoster::new(&options.new_work_notify))], - }; + let notifiers: Vec> = Vec::new(); let service_transaction_action = match options.refuse_service_transactions { true => ServiceTransactionAction::Refuse, @@ -324,7 +318,6 @@ impl Miner { sealing_work: Mutex::new(SealingWork{ queue: UsingQueue::new(options.work_queue_size), enabled: options.force_sealing - || !options.new_work_notify.is_empty() || spec.engine.seals_internally().is_some() }), gas_range_target: RwLock::new((U256::zero(), U256::zero())), @@ -1364,7 +1357,6 @@ mod tests { fn miner() -> Miner { Arc::try_unwrap(Miner::new( MinerOptions { - new_work_notify: Vec::new(), force_sealing: false, reseal_on_external_tx: false, reseal_on_own_tx: true, diff --git a/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index ce2e44054e..201d65ba79 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -199,7 +199,7 @@ mod tests { use parking_lot::Mutex; use futures::future; use futures_cpupool::CpuPool; - use fetch::{self, Fetch, Url, Method}; + use fetch::{self, Fetch, Url, Request}; use parity_reactor::Remote; use urlhint::tests::{FakeRegistrar, URLHINT}; use super::{Error, Client, HashFetch, random_temp_path}; @@ -214,15 +214,31 @@ mod tests { impl Fetch for FakeFetch { type Result = future::Ok; - fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { - assert_eq!(url, "https://parity.io/assets/images/ethcore-black-horizontal.png"); - let u = Url::parse(url).unwrap(); + fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { + assert_eq!(request.url().as_str(), "https://parity.io/assets/images/ethcore-black-horizontal.png"); + let u = request.url().clone(); future::ok(if self.return_success { fetch::client::Response::new(u, hyper::Response::new().with_body(&b"result"[..]), abort) } else { fetch::client::Response::new(u, hyper::Response::new().with_status(StatusCode::NotFound), abort) }) } + + fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return future::err(e.into()) + }; + self.fetch(Request::get(url), abort) + } + + fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return future::err(e.into()) + }; + self.fetch(Request::post(url), abort) + } } fn registrar() -> FakeRegistrar { @@ -311,4 +327,3 @@ mod tests { assert!(result.is_ok(), "Should return path, got: {:?}", result); } } - diff --git a/miner/Cargo.toml b/miner/Cargo.toml index a3464cf7d0..4ee8d74c0f 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -7,9 +7,6 @@ version = "1.11.0" authors = ["Parity Technologies "] [dependencies] -# TODO [ToDr] Rewrite using reqwest -hyper = { git = "https://github.com/paritytech/hyper", default-features = false } - common-types = { path = "../ethcore/types" } ethabi = "5.1" ethabi-contract = "5.0" @@ -27,3 +24,7 @@ parking_lot = "0.5" rustc-hex = "1.0" table = { path = "../util/table" } transient-hashmap = "0.4" +fetch = { path = "../util/fetch" } +parity-reactor = { path = "../util/reactor" } +url = "1" +hyper = "0.11" diff --git a/miner/src/work_notify.rs b/miner/src/work_notify.rs index 8ab65ed832..3436938097 100644 --- a/miner/src/work_notify.rs +++ b/miner/src/work_notify.rs @@ -17,19 +17,20 @@ //! Sends HTTP notifications to a list of URLs every time new work is available. extern crate ethash; +extern crate fetch; +extern crate parity_reactor; +extern crate url; extern crate hyper; -use self::hyper::header::ContentType; -use self::hyper::method::Method; -use self::hyper::client::{Request, Response, Client}; -use self::hyper::{Next, Url}; -use self::hyper::net::HttpStream; - +use self::fetch::{Fetch, Request, Client as FetchClient, Method}; +use self::parity_reactor::Remote; use self::ethash::SeedHashCompute; +use self::url::Url; +use self::hyper::header::ContentType; -use std::io::Write; use ethereum_types::{H256, U256}; use parking_lot::Mutex; +use futures::Future; /// Trait for notifying about new mining work pub trait NotifyWork : Send + Sync { @@ -40,13 +41,14 @@ pub trait NotifyWork : Send + Sync { /// POSTs info about new work to given urls. pub struct WorkPoster { urls: Vec, - client: Mutex>, + client: FetchClient, + remote: Remote, seed_compute: Mutex, } impl WorkPoster { /// Create new `WorkPoster`. - pub fn new(urls: &[String]) -> Self { + pub fn new(urls: &[String], fetch: FetchClient, remote: Remote) -> Self { let urls = urls.into_iter().filter_map(|u| { match Url::parse(u) { Ok(url) => Some(url), @@ -56,20 +58,13 @@ impl WorkPoster { } } }).collect(); - let client = WorkPoster::create_client(); WorkPoster { - client: Mutex::new(client), + client: fetch, + remote: remote, urls: urls, seed_compute: Mutex::new(SeedHashCompute::new()), } } - - fn create_client() -> Client { - Client::::configure() - .keep_alive(true) - .build() - .expect("Error creating HTTP client") - } } /// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`. @@ -91,51 +86,16 @@ impl NotifyWork for WorkPoster { r#"{{ "result": ["0x{:x}","0x{:x}","0x{:x}","0x{:x}"] }}"#, pow_hash, seed_hash, target, number ); - let mut client = self.client.lock(); + for u in &self.urls { - if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) { + let u = u.clone(); + self.remote.spawn(self.client.fetch( + Request::new(u.clone(), Method::Post) + .with_header(ContentType::json()) + .with_body(body.clone()), Default::default() + ).map_err(move |e| { warn!("Error sending HTTP notification to {} : {}, retrying", u, e); - // TODO: remove this once https://github.com/hyperium/hyper/issues/848 is fixed - *client = WorkPoster::create_client(); - if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) { - warn!("Error sending HTTP notification to {} : {}", u, e); - } - } - } - } -} - -struct PostHandler { - body: String, -} - -impl hyper::client::Handler for PostHandler { - fn on_request(&mut self, request: &mut Request) -> Next { - request.set_method(Method::Post); - request.headers_mut().set(ContentType::json()); - Next::write() - } - - fn on_request_writable(&mut self, encoder: &mut hyper::Encoder) -> Next { - if let Err(e) = encoder.write_all(self.body.as_bytes()) { - trace!("Error posting work data: {}", e); + }).map(|_| ())); } - encoder.close(); - Next::read() - - } - - fn on_response(&mut self, _response: Response) -> Next { - Next::end() - } - - fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder) -> Next { - Next::end() - } - - fn on_error(&mut self, err: hyper::Error) -> Next { - trace!("Error posting work data: {}", err); - Next::end() } } - diff --git a/parity/configuration.rs b/parity/configuration.rs index 3e8f58b6fa..d1c02d5bc7 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -354,6 +354,7 @@ impl Configuration { daemon: daemon, logger_config: logger_config.clone(), miner_options: self.miner_options()?, + work_notify: self.work_notify(), gas_price_percentile: self.args.arg_gas_price_percentile, ntp_servers: self.ntp_servers(), ws_conf: ws_conf, @@ -537,7 +538,6 @@ impl Configuration { let reseal = self.args.arg_reseal_on_txs.parse::()?; let options = MinerOptions { - new_work_notify: self.work_notify(), force_sealing: self.args.flag_force_sealing, reseal_on_external_tx: reseal.external, reseal_on_own_tx: reseal.own, @@ -1516,6 +1516,7 @@ mod tests { no_hardcoded_sync: false, no_persistent_txqueue: false, whisper: Default::default(), + work_notify: Vec::new(), }; expected.secretstore_conf.enabled = cfg!(feature = "secretstore"); expected.secretstore_conf.http_enabled = cfg!(feature = "secretstore"); diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index 0d0ff6d450..e072540619 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -70,7 +70,7 @@ impl IoHandler for QueueCull let start_nonce = self.client.engine().account_start_nonce(best_header.number()); info!(target: "cull", "Attempting to cull queued transactions from {} senders.", senders.len()); - self.remote.spawn_with_timeout(move || { + self.remote.spawn_with_timeout(move |_| { let maybe_fetching = sync.with_context(move |ctx| { // fetch the nonce of each sender in the queue. let nonce_reqs = senders.iter() diff --git a/parity/run.rs b/parity/run.rs index 9db2f1ca4c..8fa76693b8 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -35,6 +35,7 @@ use ethcore::verification::queue::VerifierSettings; use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_service::ClientService; use sync::{self, SyncConfig}; +use miner::work_notify::WorkPoster; use fdlimit::raise_fd_limit; use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; @@ -137,6 +138,7 @@ pub struct RunCmd { pub no_persistent_txqueue: bool, pub whisper: ::whisper::Config, pub no_hardcoded_sync: bool, + pub work_notify: Vec, } pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { @@ -549,6 +551,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let cpu_pool = CpuPool::new(4); + // spin up event loop + let event_loop = EventLoop::spawn(); + // fetch service let fetch = fetch::Client::new().map_err(|e| format!("Error starting fetch client: {:?}", e))?; @@ -561,6 +566,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: miner.set_extra_data(cmd.miner_extras.extra_data); miner.set_minimal_gas_price(initial_min_gas_price); miner.recalibrate_minimal_gas_price(); + if !cmd.work_notify.is_empty() { + miner.push_notifier(Box::new(WorkPoster::new(&cmd.work_notify, fetch.clone(), event_loop.remote()))); + } let engine_signer = cmd.miner_extras.engine_signer; if engine_signer != Default::default() { @@ -730,9 +738,6 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: chain_notify.start(); } - // spin up event loop - let event_loop = EventLoop::spawn(); - let contract_client = Arc::new(::dapps::FullRegistrar::new(client.clone())); // the updater service diff --git a/price-info/src/lib.rs b/price-info/src/lib.rs index 9be27a1319..8b87f0c11d 100644 --- a/price-info/src/lib.rs +++ b/price-info/src/lib.rs @@ -140,7 +140,7 @@ mod test { use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use fetch; - use fetch::{Fetch, Url, Method}; + use fetch::{Fetch, Url, Request}; use futures_cpupool::CpuPool; use futures::future::{self, FutureResult}; use Client; @@ -158,9 +158,9 @@ mod test { impl Fetch for FakeFetch { type Result = FutureResult; - fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { - assert_eq!(url, "https://api.etherscan.io/api?module=stats&action=ethprice"); - let u = Url::parse(url).unwrap(); + fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { + assert_eq!(request.url().as_str(), "https://api.etherscan.io/api?module=stats&action=ethprice"); + let u = request.url().clone(); let mut val = self.1.lock(); *val = *val + 1; if let Some(ref response) = self.0 { @@ -171,6 +171,22 @@ mod test { future::ok(fetch::client::Response::new(u, r, abort)) } } + + fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return future::err(e.into()) + }; + self.fetch(Request::get(url), abort) + } + + fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return future::err(e.into()) + }; + self.fetch(Request::post(url), abort) + } } fn price_info_ok(response: &str) -> Client { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index bb03808c58..747c10200d 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -60,7 +60,6 @@ fn sync_provider() -> Arc { fn miner_service(spec: &Spec, accounts: Arc) -> Arc { Miner::new( MinerOptions { - new_work_notify: vec![], force_sealing: true, reseal_on_external_tx: true, reseal_on_own_tx: true, diff --git a/rpc/src/v1/tests/helpers/fetch.rs b/rpc/src/v1/tests/helpers/fetch.rs index f3b7543f70..7de3949c4b 100644 --- a/rpc/src/v1/tests/helpers/fetch.rs +++ b/rpc/src/v1/tests/helpers/fetch.rs @@ -17,8 +17,10 @@ //! Test implementation of fetch client. use std::thread; +use std::boxed::Box; use jsonrpc_core::futures::{self, Future}; -use fetch::{self, Fetch, Url, Method}; +use fetch::{self, Fetch, Url, Request}; +use futures::future; use hyper; /// Test implementation of fetcher. Will always return the same file. @@ -28,8 +30,8 @@ pub struct TestFetch; impl Fetch for TestFetch { type Result = Box + Send + 'static>; - fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result { - let u = Url::parse(url).unwrap(); + fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { + let u = request.url().clone(); let (tx, rx) = futures::oneshot(); thread::spawn(move || { let r = hyper::Response::new().with_body(&b"Some content"[..]); @@ -38,4 +40,20 @@ impl Fetch for TestFetch { Box::new(rx.map_err(|_| fetch::Error::Aborted)) } + + fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return Box::new(future::err(e.into())) + }; + self.fetch(Request::get(url), abort) + } + + fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return Box::new(future::err(e.into())) + }; + self.fetch(Request::post(url), abort) + } } diff --git a/util/fetch/Cargo.toml b/util/fetch/Cargo.toml index 61925e189d..98b1fc5823 100644 --- a/util/fetch/Cargo.toml +++ b/util/fetch/Cargo.toml @@ -14,6 +14,7 @@ hyper-rustls = "0.11" log = "0.4" tokio-core = "0.1" url = "1" +bytes = "0.4" [features] default = [] diff --git a/util/fetch/src/client.rs b/util/fetch/src/client.rs index b3274ca4f7..9bb55aad0e 100644 --- a/util/fetch/src/client.rs +++ b/util/fetch/src/client.rs @@ -20,7 +20,7 @@ use futures::{self, Future, Async, Sink, Stream}; use futures_timer::FutureExt; use hyper::header::{UserAgent, Location, ContentLength, ContentType}; use hyper::mime::Mime; -use hyper::{self, Request, Method, StatusCode}; +use hyper::{self, Method, StatusCode}; use hyper_rustls; use std; use std::cmp::min; @@ -32,6 +32,7 @@ use std::time::Duration; use std::{io, fmt}; use tokio_core::reactor; use url::{self, Url}; +use bytes::Bytes; const MAX_SIZE: usize = 64 * 1024 * 1024; const MAX_SECS: Duration = Duration::from_secs(5); @@ -120,22 +121,18 @@ pub trait Fetch: Clone + Send + Sync + 'static { type Result: Future + Send + 'static; /// Make a request to given URL - fn fetch(&self, url: &str, method: Method, abort: Abort) -> Self::Result; + fn fetch(&self, request: Request, abort: Abort) -> Self::Result; /// Get content from some URL. - fn get(&self, url: &str, abort: Abort) -> Self::Result { - self.fetch(url, Method::Get, abort) - } + fn get(&self, url: &str, abort: Abort) -> Self::Result; /// Post content to some URL. - fn post(&self, url: &str, abort: Abort) -> Self::Result { - self.fetch(url, Method::Post, abort) - } + fn post(&self, url: &str, abort: Abort) -> Self::Result; } type TxResponse = oneshot::Sender>; type TxStartup = std::sync::mpsc::SyncSender>; -type ChanItem = Option<(Url, Method, Abort, TxResponse)>; +type ChanItem = Option<(Request, Abort, TxResponse)>; /// An implementation of `Fetch` using a `hyper` client. // Due to the `Send` bound of `Fetch` we spawn a background thread for @@ -213,29 +210,37 @@ impl Client { let future = rx_proto.take_while(|item| Ok(item.is_some())) .map(|item| item.expect("`take_while` is only passing on channel items != None; qed")) - .for_each(|(url, method, abort, sender)| + .for_each(|(request, abort, sender)| { - trace!(target: "fetch", "new request to {}", url); + trace!(target: "fetch", "new request to {}", request.url()); if abort.is_aborted() { return future::ok(sender.send(Err(Error::Aborted)).unwrap_or(())) } - let ini = (hyper.clone(), url, method, abort, 0); - let fut = future::loop_fn(ini, |(client, url, method, abort, redirects)| { - let url2 = url.clone(); + let ini = (hyper.clone(), request, abort, 0); + let fut = future::loop_fn(ini, |(client, request, abort, redirects)| { + let request2 = request.clone(); + let url2 = request2.url().clone(); let abort2 = abort.clone(); - client.request(build_request(&url, method.clone())) + client.request(request.into()) .map(move |resp| Response::new(url2, resp, abort2)) .from_err() .and_then(move |resp| { if abort.is_aborted() { - debug!(target: "fetch", "fetch of {} aborted", url); + debug!(target: "fetch", "fetch of {} aborted", request2.url()); return Err(Error::Aborted) } - if let Some(next_url) = redirect_location(url, &resp) { + if let Some((next_url, preserve_method)) = redirect_location(request2.url().clone(), &resp) { if redirects >= abort.max_redirects() { return Err(Error::TooManyRedirects) } - Ok(Loop::Continue((client, next_url, method, abort, redirects + 1))) + let request = if preserve_method { + let mut request2 = request2.clone(); + request2.set_url(next_url); + request2 + } else { + Request::new(next_url, Method::Get) + }; + Ok(Loop::Continue((client, request, abort, redirects + 1))) } else { let content_len = resp.headers.get::().cloned(); if content_len.map(|n| *n > abort.max_size() as u64).unwrap_or(false) { @@ -267,19 +272,15 @@ impl Client { impl Fetch for Client { type Result = Box + Send>; - fn fetch(&self, url: &str, method: Method, abort: Abort) -> Self::Result { - debug!(target: "fetch", "fetching: {:?}", url); + fn fetch(&self, request: Request, abort: Abort) -> Self::Result { + debug!(target: "fetch", "fetching: {:?}", request.url()); if abort.is_aborted() { return Box::new(future::err(Error::Aborted)) } - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return Box::new(future::err(e.into())) - }; let (tx_res, rx_res) = oneshot::channel(); let maxdur = abort.max_duration(); let sender = self.core.clone(); - let future = sender.send(Some((url.clone(), method, abort, tx_res))) + let future = sender.send(Some((request, abort, tx_res))) .map_err(|e| { error!(target: "fetch", "failed to schedule request: {}", e); Error::BackgroundThreadDead @@ -297,11 +298,33 @@ impl Fetch for Client { }); Box::new(future) } + + /// Get content from some URL. + fn get(&self, url: &str, abort: Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return Box::new(future::err(e.into())) + }; + self.fetch(Request::get(url), abort) + } + + /// Post content to some URL. + fn post(&self, url: &str, abort: Abort) -> Self::Result { + let url: Url = match url.parse() { + Ok(u) => u, + Err(e) => return Box::new(future::err(e.into())) + }; + self.fetch(Request::post(url), abort) + } } -// Extract redirect location from response. -fn redirect_location(u: Url, r: &Response) -> Option { +// Extract redirect location from response. The second return value indicate whether the original method should be preserved. +fn redirect_location(u: Url, r: &Response) -> Option<(Url, bool)> { use hyper::StatusCode::*; + let preserve_method = match r.status() { + TemporaryRedirect | PermanentRedirect => true, + _ => false, + }; match r.status() { MovedPermanently | PermanentRedirect @@ -309,7 +332,7 @@ fn redirect_location(u: Url, r: &Response) -> Option { | Found | SeeOther => { if let Some(loc) = r.headers.get::() { - u.join(loc).ok() + u.join(loc).ok().map(|url| (url, preserve_method)) } else { None } @@ -318,12 +341,84 @@ fn redirect_location(u: Url, r: &Response) -> Option { } } -// Build a simple request for the given Url and method -fn build_request(u: &Url, method: Method) -> hyper::Request { - let uri = u.as_ref().parse().expect("Every valid URL is aso a URI."); - let mut rq = Request::new(method, uri); - rq.headers_mut().set(UserAgent::new("Parity Fetch Neo")); - rq +/// A wrapper for hyper::Request using Url and with methods. +#[derive(Debug, Clone)] +pub struct Request { + url: Url, + method: Method, + headers: hyper::Headers, + body: Bytes, +} + +impl Request { + /// Create a new request, with given url and method. + pub fn new(url: Url, method: Method) -> Request { + Request { + url, method, + headers: hyper::Headers::new(), + body: Default::default(), + } + } + + /// Create a new GET request. + pub fn get(url: Url) -> Request { + Request::new(url, Method::Get) + } + + /// Create a new empty POST request. + pub fn post(url: Url) -> Request { + Request::new(url, Method::Post) + } + + /// Read the url. + pub fn url(&self) -> &Url { + &self.url + } + + /// Read the request headers. + pub fn headers(&self) -> &hyper::Headers { + &self.headers + } + + /// Get a mutable reference to the headers. + pub fn headers_mut(&mut self) -> &mut hyper::Headers { + &mut self.headers + } + + /// Set the body of the request. + pub fn set_body>(&mut self, body: T) { + self.body = body.into(); + } + + /// Set the url of the request. + pub fn set_url(&mut self, url: Url) { + self.url = url; + } + + /// Consume self, and return it with the added given header. + pub fn with_header(mut self, value: H) -> Self { + self.headers_mut().set(value); + self + } + + /// Consume self, and return it with the body. + pub fn with_body>(mut self, body: T) -> Self { + self.set_body(body); + self + } +} + +impl Into for Request { + fn into(mut self) -> hyper::Request { + let uri = self.url.as_ref().parse().expect("Every valid URLis also a URI."); + let mut req = hyper::Request::new(self.method, uri); + + self.headers.set(UserAgent::new("Parity Fetch Neo")); + *req.headers_mut() = self.headers; + req.set_body(self.body); + + req + } } /// An HTTP response. @@ -527,7 +622,7 @@ mod test { use futures::future; use futures::sync::mpsc; use futures_timer::Delay; - use hyper::{StatusCode, Method}; + use hyper::StatusCode; use hyper::server::{Http, Request, Response, Service}; use std; use std::io::Read; @@ -539,7 +634,7 @@ mod test { fn it_should_fetch() { let server = TestServer::run(); let client = Client::new().unwrap(); - let future = client.fetch(&format!("http://{}?123", server.addr()), Method::Get, Default::default()); + let future = client.get(&format!("http://{}?123", server.addr()), Default::default()); let resp = future.wait().unwrap(); assert!(resp.is_success()); let body = resp.concat2().wait().unwrap(); @@ -551,7 +646,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_duration(Duration::from_secs(1)); - match client.fetch(&format!("http://{}/delay?3", server.addr()), Method::Get, abort).wait() { + match client.get(&format!("http://{}/delay?3", server.addr()), abort).wait() { Err(Error::Timeout) => {} other => panic!("expected timeout, got {:?}", other) } @@ -562,7 +657,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default(); - let future = client.fetch(&format!("http://{}/redirect?http://{}/", server.addr(), server.addr()), Method::Get, abort); + let future = client.get(&format!("http://{}/redirect?http://{}/", server.addr(), server.addr()), abort); assert!(future.wait().unwrap().is_success()) } @@ -571,7 +666,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_redirects(4); - let future = client.fetch(&format!("http://{}/redirect?/", server.addr()), Method::Get, abort); + let future = client.get(&format!("http://{}/redirect?/", server.addr()), abort); assert!(future.wait().unwrap().is_success()) } @@ -580,7 +675,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_redirects(3); - match client.fetch(&format!("http://{}/loop", server.addr()), Method::Get, abort).wait() { + match client.get(&format!("http://{}/loop", server.addr()), abort).wait() { Err(Error::TooManyRedirects) => {} other => panic!("expected too many redirects error, got {:?}", other) } @@ -591,7 +686,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default(); - let future = client.fetch(&format!("http://{}?abcdefghijklmnopqrstuvwxyz", server.addr()), Method::Get, abort); + let future = client.get(&format!("http://{}?abcdefghijklmnopqrstuvwxyz", server.addr()), abort); let resp = future.wait().unwrap(); assert!(resp.is_success()); assert_eq!(&resp.concat2().wait().unwrap()[..], b"abcdefghijklmnopqrstuvwxyz") @@ -602,7 +697,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_size(3); - let resp = client.fetch(&format!("http://{}/?1234", server.addr()), Method::Get, abort).wait().unwrap(); + let resp = client.get(&format!("http://{}/?1234", server.addr()), abort).wait().unwrap(); assert!(resp.is_success()); match resp.concat2().wait() { Err(Error::SizeLimit) => {} @@ -615,7 +710,7 @@ mod test { let server = TestServer::run(); let client = Client::new().unwrap(); let abort = Abort::default().with_max_size(3); - let resp = client.fetch(&format!("http://{}/?1234", server.addr()), Method::Get, abort).wait().unwrap(); + let resp = client.get(&format!("http://{}/?1234", server.addr()), abort).wait().unwrap(); assert!(resp.is_success()); let mut buffer = Vec::new(); let mut reader = BodyReader::new(resp); diff --git a/util/fetch/src/lib.rs b/util/fetch/src/lib.rs index 55785633f5..f42aacec5b 100644 --- a/util/fetch/src/lib.rs +++ b/util/fetch/src/lib.rs @@ -30,11 +30,11 @@ extern crate hyper_rustls; extern crate tokio_core; extern crate url; +extern crate bytes; /// Fetch client implementation. pub mod client; pub use url::Url; -pub use self::client::{Client, Fetch, Error, Response, Abort, BodyReader}; +pub use self::client::{Client, Fetch, Error, Response, Request, Abort, BodyReader}; pub use hyper::Method; - diff --git a/util/reactor/src/lib.rs b/util/reactor/src/lib.rs index f5a37fb0fc..9c049b8f75 100644 --- a/util/reactor/src/lib.rs +++ b/util/reactor/src/lib.rs @@ -24,7 +24,7 @@ use std::{fmt, thread}; use std::sync::mpsc; use std::time::Duration; use futures::{Future, IntoFuture}; -pub use tokio_core::reactor::{Remote as TokioRemote, Timeout}; +pub use tokio_core::reactor::{Remote as TokioRemote, Handle, Timeout}; /// Event Loop for futures. /// Wrapper around `tokio::reactor::Core`. @@ -143,18 +143,22 @@ impl Remote { /// Spawn a new future returned by given closure. pub fn spawn_fn(&self, f: F) where - F: FnOnce() -> R + Send + 'static, + F: FnOnce(&Handle) -> R + Send + 'static, R: IntoFuture, R::Future: 'static, { match self.inner { - Mode::Tokio(ref remote) => remote.spawn(move |_| f()), + Mode::Tokio(ref remote) => remote.spawn(move |handle| f(handle)), Mode::Sync => { - let _ = f().into_future().wait(); + let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail."); + let handle = core.handle(); + let _ = core.run(f(&handle).into_future()); }, Mode::ThreadPerFuture => { thread::spawn(move || { - let _= f().into_future().wait(); + let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail."); + let handle = core.handle(); + let _ = core.run(f(&handle).into_future()); }); }, } @@ -163,13 +167,13 @@ impl Remote { /// Spawn a new future and wait for it or for a timeout to occur. pub fn spawn_with_timeout(&self, f: F, duration: Duration, on_timeout: T) where T: FnOnce() -> () + Send + 'static, - F: FnOnce() -> R + Send + 'static, + F: FnOnce(&Handle) -> R + Send + 'static, R: IntoFuture, R::Future: 'static, { match self.inner { Mode::Tokio(ref remote) => remote.spawn(move |handle| { - let future = f().into_future(); + let future = f(handle).into_future(); let timeout = Timeout::new(duration, handle).expect("Event loop is still up."); future.select(timeout.then(move |_| { on_timeout(); @@ -177,11 +181,25 @@ impl Remote { })).then(|_| Ok(())) }), Mode::Sync => { - let _ = f().into_future().wait(); + let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail."); + let handle = core.handle(); + let future = f(&handle).into_future(); + let timeout = Timeout::new(duration, &handle).expect("Event loop is still up."); + let _: Result<(), ()> = core.run(future.select(timeout.then(move |_| { + on_timeout(); + Ok(()) + })).then(|_| Ok(()))); }, Mode::ThreadPerFuture => { thread::spawn(move || { - let _ = f().into_future().wait(); + let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail."); + let handle = core.handle(); + let future = f(&handle).into_future(); + let timeout = Timeout::new(duration, &handle).expect("Event loop is still up."); + let _: Result<(), ()> = core.run(future.select(timeout.then(move |_| { + on_timeout(); + Ok(()) + })).then(|_| Ok(()))); }); }, } -- GitLab From 4f447c50b2d90d1b012051c6fe1d0c52566ef2b4 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 10 Apr 2018 14:56:17 +0300 Subject: [PATCH 056/263] SecretStore: having , node: GenerationNode) -> Node { + fn create_node(meta: ShareChangeSessionMeta, admin_public: Public, all_nodes_set: BTreeSet, node: &GenerationNode) -> Node { for n in &all_nodes_set { node.cluster.add_node(n.clone()); } @@ -1065,18 +1072,18 @@ pub mod tests { Node { cluster: node.cluster.clone(), key_storage: node.key_storage.clone(), - session: create_session(meta, node.session.node().clone(), admin_public, all_nodes_set, node.cluster, node.key_storage), + session: create_session(meta, node.session.node().clone(), admin_public, all_nodes_set, node.cluster.clone(), node.key_storage.clone()), } } impl MessageLoop { - pub fn new(gml: GenerationMessageLoop, master_node_id: NodeId, new_nodes_ids: BTreeSet, removed_nodes_ids: BTreeSet, isolated_nodes_ids: BTreeSet) -> Self { + pub fn new(gml: &GenerationMessageLoop, master_node_id: NodeId, original_key_pair: Option, new_nodes_ids: BTreeSet, removed_nodes_ids: BTreeSet, isolated_nodes_ids: BTreeSet) -> Self { // generate admin key pair let admin_key_pair = Random.generate().unwrap(); let admin_public = admin_key_pair.public().clone(); // compute original secret key - let original_key_pair = gml.compute_key_pair(1); + let original_key_pair = original_key_pair.unwrap_or_else(|| gml.compute_key_pair(1)); // all active nodes set let mut all_nodes_set: BTreeSet<_> = gml.nodes.keys() @@ -1099,7 +1106,7 @@ pub mod tests { id: SessionId::default(), }; - let old_nodes = gml.nodes.into_iter().map(|n| create_node(meta.clone(), admin_public.clone(), all_nodes_set.clone(), n.1)); + let old_nodes = gml.nodes.iter().map(|n| create_node(meta.clone(), admin_public.clone(), all_nodes_set.clone(), n.1)); let new_nodes = new_nodes_ids.into_iter().map(|new_node_id| { let new_node_cluster = Arc::new(DummyCluster::new(new_node_id.clone())); for node in &all_nodes_set { @@ -1182,7 +1189,7 @@ pub mod tests { // insert 1 node so that it becames 2-of-4 session let nodes_to_add: BTreeSet<_> = (0..1).map(|_| Random.generate().unwrap().public().clone()).collect(); - let mut ml = MessageLoop::new(gml, master_node_id, nodes_to_add, BTreeSet::new(), BTreeSet::new()); + let mut ml = MessageLoop::new(&gml, master_node_id, None, nodes_to_add, BTreeSet::new(), BTreeSet::new()); ml.nodes[&master_node_id].session.initialize(ml.nodes.keys().cloned().collect(), ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); ml.run(); @@ -1205,7 +1212,7 @@ pub mod tests { // 3) delegated session is returned back to added node let nodes_to_add: BTreeSet<_> = (0..1).map(|_| Random.generate().unwrap().public().clone()).collect(); let master_node_id = nodes_to_add.iter().cloned().nth(0).unwrap(); - let mut ml = MessageLoop::new(gml, master_node_id, nodes_to_add, BTreeSet::new(), BTreeSet::new()); + let mut ml = MessageLoop::new(&gml, master_node_id, None, nodes_to_add, BTreeSet::new(), BTreeSet::new()); ml.nodes[&master_node_id].session.initialize(ml.nodes.keys().cloned().collect(), ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); ml.run(); @@ -1222,7 +1229,7 @@ pub mod tests { // remove 1 node && insert 1 node so that one share is moved let nodes_to_remove: BTreeSet<_> = gml.nodes.keys().cloned().skip(1).take(1).collect(); let nodes_to_add: BTreeSet<_> = (0..1).map(|_| Random.generate().unwrap().public().clone()).collect(); - let mut ml = MessageLoop::new(gml, master_node_id, nodes_to_add.clone(), nodes_to_remove.clone(), BTreeSet::new()); + let mut ml = MessageLoop::new(&gml, master_node_id, None, nodes_to_add.clone(), nodes_to_remove.clone(), BTreeSet::new()); let new_nodes_set = ml.nodes.keys().cloned().filter(|n| !nodes_to_remove.contains(n)).collect(); ml.nodes[&master_node_id].session.initialize(new_nodes_set, ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); ml.run(); @@ -1249,7 +1256,7 @@ pub mod tests { // remove 1 node so that session becames 2-of-2 let nodes_to_remove: BTreeSet<_> = gml.nodes.keys().cloned().skip(1).take(1).collect(); let new_nodes_set: BTreeSet<_> = gml.nodes.keys().cloned().filter(|n| !nodes_to_remove.contains(&n)).collect(); - let mut ml = MessageLoop::new(gml, master_node_id, BTreeSet::new(), nodes_to_remove.clone(), BTreeSet::new()); + let mut ml = MessageLoop::new(&gml, master_node_id, None, BTreeSet::new(), nodes_to_remove.clone(), BTreeSet::new()); ml.nodes[&master_node_id].session.initialize(new_nodes_set, ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); ml.run(); @@ -1275,7 +1282,7 @@ pub mod tests { // remove 1 node so that session becames 2-of-2 let nodes_to_isolate: BTreeSet<_> = gml.nodes.keys().cloned().skip(1).take(1).collect(); let new_nodes_set: BTreeSet<_> = gml.nodes.keys().cloned().filter(|n| !nodes_to_isolate.contains(&n)).collect(); - let mut ml = MessageLoop::new(gml, master_node_id, BTreeSet::new(), BTreeSet::new(), nodes_to_isolate.clone()); + let mut ml = MessageLoop::new(&gml, master_node_id, None, BTreeSet::new(), BTreeSet::new(), nodes_to_isolate.clone()); ml.nodes[&master_node_id].session.initialize(new_nodes_set, ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); ml.run(); @@ -1291,4 +1298,41 @@ pub mod tests { // check that all sessions have finished assert!(ml.nodes.iter().filter(|&(k, _)| !nodes_to_isolate.contains(k)).all(|(_, v)| v.session.is_finished())); } + + #[test] + fn having_less_than_required_nodes_after_change_does_not_fail_change_session() { + // initial 2-of-3 session + let gml = generate_key(1, generate_nodes_ids(3)); + let master_node_id = gml.nodes.keys().cloned().nth(0).unwrap(); + + // remove 2 nodes so that key becomes irrecoverable (make sure the session is completed, even though key is irrecoverable) + let nodes_to_remove: BTreeSet<_> = gml.nodes.keys().cloned().skip(1).take(2).collect(); + let new_nodes_set: BTreeSet<_> = gml.nodes.keys().cloned().filter(|n| !nodes_to_remove.contains(&n)).collect(); + let mut ml = MessageLoop::new(&gml, master_node_id, None, BTreeSet::new(), nodes_to_remove.clone(), BTreeSet::new()); + ml.nodes[&master_node_id].session.initialize(new_nodes_set, ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); + ml.run(); + + // check that all removed nodes do not own key share + assert!(ml.nodes.iter().filter(|&(k, _)| nodes_to_remove.contains(k)).all(|(_, v)| v.key_storage.get(&SessionId::default()).unwrap().is_none())); + + // check that all sessions have finished + assert!(ml.nodes.values().all(|n| n.session.is_finished())); + + // and now let's add new node (make sure the session is completed, even though key is still irrecoverable) + // isolated here are not actually isolated, but removed on the previous step + let nodes_to_add: BTreeSet<_> = (0..1).map(|_| Random.generate().unwrap().public().clone()).collect(); + let new_nodes_set: BTreeSet<_> = gml.nodes.keys().cloned().filter(|n| !nodes_to_remove.contains(&n)) + .chain(nodes_to_add.iter().cloned()) + .collect(); + let master_node_id = nodes_to_add.iter().cloned().nth(0).unwrap(); + let mut ml = MessageLoop::new(&gml, master_node_id, Some(ml.original_key_pair.clone()), nodes_to_add.clone(), BTreeSet::new(), nodes_to_remove.clone()); + ml.nodes[&master_node_id].session.initialize(new_nodes_set, ml.all_set_signature.clone(), ml.new_set_signature.clone()).unwrap(); + ml.run(); + + // check that all added nodes do not own key share (there's not enough nodes to run share add session) + assert!(ml.nodes.iter().filter(|&(k, _)| nodes_to_add.contains(k)).all(|(_, v)| v.key_storage.get(&SessionId::default()).unwrap().is_none())); + + // check that all sessions have finished + assert!(ml.nodes.iter().filter(|&(k, _)| !nodes_to_remove.contains(k)).all(|(_, n)| n.session.is_finished())); + } } diff --git a/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs index 228d7ba987..1e408ee52e 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use std::collections::{BTreeSet, BTreeMap}; use ethereum_types::H256; use ethkey::Secret; -use key_server_cluster::{Error, NodeId, SessionId, KeyStorage}; +use key_server_cluster::{Error, NodeId, SessionId, ServerKeyId, KeyStorage}; use key_server_cluster::cluster::Cluster; use key_server_cluster::cluster_sessions::ClusterSession; use key_server_cluster::math; @@ -235,7 +235,24 @@ impl ShareAddSessionTransport for ShareChangeTransport { } /// Prepare share change plan for moving from old `old_key_version_owners` to `new_nodes_set`. -pub fn prepare_share_change_session_plan(cluster_nodes: &BTreeSet, threshold: usize, key_version: H256, master: &NodeId, old_key_version_owners: &BTreeSet, new_nodes_set: &BTreeSet) -> Result { +pub fn prepare_share_change_session_plan(cluster_nodes: &BTreeSet, threshold: usize, key_id: &ServerKeyId, key_version: H256, master: &NodeId, old_key_version_owners: &BTreeSet, new_nodes_set: &BTreeSet) -> Result { + // we can't do anything if there are no enought shares + if old_key_version_owners.len() < threshold + 1 { + warn!("cannot add shares to key {} with threshold {}: only {} shares owners are available", + key_id, threshold, old_key_version_owners.len()); + return Ok(ShareChangeSessionPlan { + key_version: key_version, + consensus_group: Default::default(), + new_nodes_map: Default::default(), + }); + } + + // warn if we're loosing the key + if new_nodes_set.len() < threshold + 1 { + warn!("losing key {} with threshold {}: only {} nodes left after servers set change session", + key_id, threshold, new_nodes_set.len()); + } + // make new nodes map, so that: // all non-isolated old nodes will have their id number preserved // all new nodes will have new id number @@ -285,7 +302,8 @@ mod tests { let master = cluster_nodes[0].clone(); let old_key_version_owners = cluster_nodes.iter().cloned().collect(); let new_nodes_set = cluster_nodes.iter().cloned().collect(); - let plan = prepare_share_change_session_plan(&cluster_nodes.iter().cloned().collect(), 1, Default::default(), &master, &old_key_version_owners, &new_nodes_set).unwrap(); + let plan = prepare_share_change_session_plan(&cluster_nodes.iter().cloned().collect(), + 1, &Default::default(), Default::default(), &master, &old_key_version_owners, &new_nodes_set).unwrap(); assert!(plan.is_empty()); } @@ -296,7 +314,8 @@ mod tests { let master = cluster_nodes[0].clone(); let old_key_version_owners = cluster_nodes[0..2].iter().cloned().collect(); let new_nodes_set = cluster_nodes.iter().cloned().collect(); - let plan = prepare_share_change_session_plan(&cluster_nodes.iter().cloned().collect(), 1, Default::default(), &master, &old_key_version_owners, &new_nodes_set).unwrap(); + let plan = prepare_share_change_session_plan(&cluster_nodes.iter().cloned().collect(), + 1, &Default::default(), Default::default(), &master, &old_key_version_owners, &new_nodes_set).unwrap(); assert!(!plan.is_empty()); assert_eq!(old_key_version_owners, plan.consensus_group); -- GitLab From bd7273061e3f13f53fdd2fa91dc641a83bcc47f0 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 10 Apr 2018 13:56:56 +0200 Subject: [PATCH 057/263] ethcrypto renamed to ethcore-crypto and moved to ethcore dir (#8340) * ethcrypto renamed to ethcore-crypto and moved to ethcore dir * fixed renaming --- Cargo.lock | 38 +++++++++---------- {ethcrypto => ethcore/crypto}/Cargo.toml | 4 +- {ethcrypto => ethcore/crypto}/README.md | 0 {ethcrypto => ethcore/crypto}/src/lib.rs | 0 ethcore/private-tx/Cargo.toml | 2 +- ethcore/private-tx/src/encryptor.rs | 8 ++-- ethcore/private-tx/src/lib.rs | 6 +-- ethstore/Cargo.toml | 2 +- ethstore/src/lib.rs | 2 +- rpc/Cargo.toml | 2 +- rpc/src/lib.rs | 2 +- secret_store/Cargo.toml | 4 +- secret_store/src/key_server.rs | 32 ++++++++-------- .../client_sessions/decryption_session.rs | 8 ++-- .../src/key_server_cluster/io/handshake.rs | 2 +- .../src/key_server_cluster/io/message.rs | 4 +- .../key_server_cluster/jobs/decryption_job.rs | 4 +- secret_store/src/key_server_cluster/mod.rs | 6 +-- secret_store/src/lib.rs | 2 +- secret_store/src/node_key_pair.rs | 2 +- util/network-devp2p/Cargo.toml | 4 +- util/network-devp2p/src/lib.rs | 2 +- util/network/Cargo.toml | 6 +-- util/network/src/lib.rs | 2 +- whisper/Cargo.toml | 2 +- whisper/src/lib.rs | 2 +- whisper/src/rpc/crypto.rs | 5 ++- 27 files changed, 77 insertions(+), 76 deletions(-) rename {ethcrypto => ethcore/crypto}/Cargo.toml (81%) rename {ethcrypto => ethcore/crypto}/README.md (100%) rename {ethcrypto => ethcore/crypto}/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index f802b863e4..71ad5fc0bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,6 +566,18 @@ dependencies = [ name = "ethcore-bytes" version = "0.1.0" +[[package]] +name = "ethcore-crypto" +version = "0.1.0" +dependencies = [ + "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", + "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethkey 0.3.0", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-devtools" version = "1.11.0" @@ -671,8 +683,8 @@ name = "ethcore-network" version = "1.11.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-crypto 0.1.0", "ethcore-io 1.11.0", - "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -688,10 +700,10 @@ dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", + "ethcore-crypto 0.1.0", "ethcore-io 1.11.0", "ethcore-logger 1.11.0", "ethcore-network 1.11.0", - "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -725,11 +737,11 @@ dependencies = [ "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", + "ethcore-crypto 0.1.0", "ethcore-io 1.11.0", "ethcore-logger 1.11.0", "ethcore-miner 1.11.0", "ethcore-transaction 0.1.0", - "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", @@ -760,10 +772,10 @@ dependencies = [ "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", + "ethcore-crypto 0.1.0", "ethcore-logger 1.11.0", "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", - "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -868,18 +880,6 @@ dependencies = [ "unexpected 0.1.0", ] -[[package]] -name = "ethcrypto" -version = "0.1.0" -dependencies = [ - "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethkey 0.3.0", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ethereum-types" version = "0.3.0" @@ -950,7 +950,7 @@ name = "ethstore" version = "0.2.0" dependencies = [ "dir 0.1.0", - "ethcrypto 0.1.0", + "ethcore-crypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2157,6 +2157,7 @@ dependencies = [ "ethash 1.11.0", "ethcore 1.11.0", "ethcore-bytes 0.1.0", + "ethcore-crypto 0.1.0", "ethcore-devtools 1.11.0", "ethcore-io 1.11.0", "ethcore-light 1.11.0", @@ -2166,7 +2167,6 @@ dependencies = [ "ethcore-private-tx 1.0.0", "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", - "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", @@ -2341,8 +2341,8 @@ version = "0.1.0" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-crypto 0.1.0", "ethcore-network 1.11.0", - "ethcrypto 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcrypto/Cargo.toml b/ethcore/crypto/Cargo.toml similarity index 81% rename from ethcrypto/Cargo.toml rename to ethcore/crypto/Cargo.toml index 887b44ab4f..c3a2191b55 100644 --- a/ethcrypto/Cargo.toml +++ b/ethcore/crypto/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ethcrypto" +name = "ethcore-crypto" version = "0.1.0" authors = ["Parity Technologies "] @@ -7,7 +7,7 @@ authors = ["Parity Technologies "] rust-crypto = "0.2.36" tiny-keccak = "1.3" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true } -ethkey = { path = "../ethkey", optional = true } +ethkey = { path = "../../ethkey", optional = true } ethereum-types = "0.3" subtle = "0.5" diff --git a/ethcrypto/README.md b/ethcore/crypto/README.md similarity index 100% rename from ethcrypto/README.md rename to ethcore/crypto/README.md diff --git a/ethcrypto/src/lib.rs b/ethcore/crypto/src/lib.rs similarity index 100% rename from ethcrypto/src/lib.rs rename to ethcore/crypto/src/lib.rs diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index ff37f20ab2..0fa11aec84 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -12,11 +12,11 @@ ethabi-contract = "5.0" ethabi-derive = "5.0" ethcore = { path = ".." } ethcore-bytes = { path = "../../util/bytes" } +ethcore-crypto = { path = "../crypto" } ethcore-io = { path = "../../util/io" } ethcore-logger = { path = "../../logger" } ethcore-miner = { path = "../../miner" } ethcore-transaction = { path = "../transaction" } -ethcrypto = { path = "../../ethcrypto" } ethereum-types = "0.3" ethjson = { path = "../../json" } ethkey = { path = "../../ethkey" } diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs index fd7eaa680f..5d592de603 100644 --- a/ethcore/private-tx/src/encryptor.rs +++ b/ethcore/private-tx/src/encryptor.rs @@ -27,7 +27,7 @@ use ethcore::account_provider::AccountProvider; use ethereum_types::{H128, H256, Address}; use ethjson; use ethkey::{Signature, Public}; -use ethcrypto; +use crypto; use futures::Future; use fetch::{Fetch, Client as FetchClient, Method, BodyReader, Request}; use bytes::{Bytes, ToPretty}; @@ -151,7 +151,7 @@ impl SecretStoreEncryptor { let password = find_account_password(&self.config.passwords, &*accounts, &requester); // decrypt Public - let decrypted_bytes = accounts.decrypt(requester, password, ðcrypto::DEFAULT_MAC, &encrypted_bytes)?; + let decrypted_bytes = accounts.decrypt(requester, password, &crypto::DEFAULT_MAC, &encrypted_bytes)?; let decrypted_key = Public::from_slice(&decrypted_bytes); // and now take x coordinate of Public as a key @@ -217,7 +217,7 @@ impl Encryptor for SecretStoreEncryptor { // encrypt data let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len()); cypher.extend(repeat(0).take(plain_data.len())); - ethcrypto::aes::encrypt(&key, initialisation_vector, plain_data, &mut cypher); + crypto::aes::encrypt(&key, initialisation_vector, plain_data, &mut cypher); cypher.extend_from_slice(&initialisation_vector); Ok(cypher) @@ -243,7 +243,7 @@ impl Encryptor for SecretStoreEncryptor { let (cypher, iv) = cypher.split_at(cypher_len - INIT_VEC_LEN); let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN); plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN)); - ethcrypto::aes::decrypt(&key, &iv, cypher, &mut plain_data); + crypto::aes::decrypt(&key, &iv, cypher, &mut plain_data); Ok(plain_data) } diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 5b7a62b7cd..ef97c6e2e6 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -26,11 +26,11 @@ mod messages; mod error; extern crate ethcore; -extern crate ethcore_io as io; extern crate ethcore_bytes as bytes; -extern crate ethcore_transaction as transaction; +extern crate ethcore_crypto as crypto; +extern crate ethcore_io as io; extern crate ethcore_miner; -extern crate ethcrypto; +extern crate ethcore_transaction as transaction; extern crate ethabi; extern crate ethereum_types; extern crate ethkey; diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index 34f61a8f75..d0524baeaf 100755 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -17,7 +17,7 @@ tiny-keccak = "1.3" time = "0.1.34" itertools = "0.5" parking_lot = "0.5" -ethcrypto = { path = "../ethcrypto" } +ethcore-crypto = { path = "../ethcore/crypto" } ethereum-types = "0.3" dir = { path = "../util/dir" } smallvec = "0.4" diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index 3422a5ff72..75df0953ce 100755 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -33,7 +33,7 @@ extern crate time; extern crate tiny_keccak; extern crate tempdir; -extern crate ethcrypto as crypto; +extern crate ethcore_crypto as crypto; extern crate ethereum_types; extern crate ethkey as _ethkey; extern crate parity_wordlist; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 7f975ca9dd..c467f05537 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -39,6 +39,7 @@ jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git", branch = " ethash = { path = "../ethash" } ethcore = { path = "../ethcore" } ethcore-bytes = { path = "../util/bytes" } +ethcore-crypto = { path = "../ethcore/crypto" } ethcore-devtools = { path = "../devtools" } ethcore-io = { path = "../util/io" } ethcore-light = { path = "../ethcore/light" } @@ -49,7 +50,6 @@ ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" -ethcrypto = { path = "../ethcrypto" } ethjson = { path = "../json" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 13e700375e..1a0989d4a2 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -46,6 +46,7 @@ extern crate jsonrpc_pubsub; extern crate ethash; extern crate ethcore; extern crate ethcore_bytes as bytes; +extern crate ethcore_crypto as crypto; extern crate ethcore_devtools as devtools; extern crate ethcore_io as io; extern crate ethcore_light as light; @@ -54,7 +55,6 @@ extern crate ethcore_miner as miner; extern crate ethcore_private_tx; extern crate ethcore_sync as sync; extern crate ethcore_transaction as transaction; -extern crate ethcrypto as crypto; extern crate ethereum_types; extern crate ethkey; extern crate ethstore; diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index b9dee7303b..fcd022f7d9 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -24,14 +24,14 @@ tokio-proto = "0.1" url = "1.0" ethcore = { path = "../ethcore" } ethcore-bytes = { path = "../util/bytes" } +ethcore-crypto = { path = "../ethcore/crypto" } +ethcore-logger = { path = "../logger" } ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" kvdb = { path = "../util/kvdb" } kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } keccak-hash = { path = "../util/hash" } -ethcore-logger = { path = "../logger" } -ethcrypto = { path = "../ethcrypto" } ethkey = { path = "../ethkey" } lazy_static = "1.0" ethabi = "5.1" diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs index 02d19eede1..783e760455 100644 --- a/secret_store/src/key_server.rs +++ b/secret_store/src/key_server.rs @@ -21,7 +21,7 @@ use std::sync::mpsc; use futures::{self, Future}; use parking_lot::Mutex; use tokio_core::reactor::Core; -use ethcrypto; +use crypto; use super::acl_storage::AclStorage; use super::key_storage::KeyStorage; use super::key_server_set::KeyServerSet; @@ -105,7 +105,7 @@ impl DocumentKeyServer for KeyServerImpl { self.store_document_key(key_id, author, encrypted_document_key.common_point, encrypted_document_key.encrypted_point)?; // encrypt document key with requestor public key - let document_key = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &document_key) + let document_key = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &document_key) .map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?; Ok(document_key) } @@ -122,7 +122,7 @@ impl DocumentKeyServer for KeyServerImpl { .decrypted_secret; // encrypt document key with requestor public key - let document_key = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &document_key) + let document_key = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &document_key) .map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?; Ok(document_key) } @@ -152,7 +152,7 @@ impl MessageSigner for KeyServerImpl { combined_signature[32..].clone_from_slice(&**message_signature.1); // encrypt combined signature with requestor public key - let message_signature = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &combined_signature) + let message_signature = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &combined_signature) .map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?; Ok(message_signature) } @@ -167,7 +167,7 @@ impl MessageSigner for KeyServerImpl { let message_signature = signing_session.wait()?; // encrypt combined signature with requestor public key - let message_signature = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &*message_signature) + let message_signature = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &*message_signature) .map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?; Ok(message_signature) } @@ -229,7 +229,7 @@ pub mod tests { use std::sync::Arc; use std::net::SocketAddr; use std::collections::BTreeMap; - use ethcrypto; + use crypto; use ethkey::{self, Secret, Random, Generator, verify_public}; use acl_storage::DummyAclStorage; use key_storage::KeyStorage; @@ -358,12 +358,12 @@ pub mod tests { let secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&secret, &document).unwrap(); let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap(); - let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap(); + let generated_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &generated_key).unwrap(); // now let's try to retrieve key back for key_server in key_servers.iter() { let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap(); - let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); + let retrieved_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap(); assert_eq!(retrieved_key, generated_key); } } @@ -380,12 +380,12 @@ pub mod tests { let secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&secret, &document).unwrap(); let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), *threshold).unwrap(); - let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap(); + let generated_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &generated_key).unwrap(); // now let's try to retrieve key back for (i, key_server) in key_servers.iter().enumerate() { let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap(); - let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); + let retrieved_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap(); assert_eq!(retrieved_key, generated_key); let key_share = key_storages[i].get(&document).unwrap().unwrap(); @@ -419,7 +419,7 @@ pub mod tests { // now let's try to retrieve key back for key_server in key_servers.iter() { let retrieved_key = key_server.restore_document_key(&server_key_id, &signature.clone().into()).unwrap(); - let retrieved_key = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); + let retrieved_key = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap(); let retrieved_key = Public::from_slice(&retrieved_key); assert_eq!(retrieved_key, generated_key); } @@ -442,7 +442,7 @@ pub mod tests { // sign message let message_hash = H256::from(42); let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); - let combined_signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &combined_signature).unwrap(); + let combined_signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap(); let signature_c = Secret::from_slice(&combined_signature[..32]); let signature_s = Secret::from_slice(&combined_signature[32..]); @@ -462,14 +462,14 @@ pub mod tests { let secret = Random.generate().unwrap().secret().clone(); let signature = ethkey::sign(&secret, &document).unwrap(); let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap(); - let generated_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &generated_key).unwrap(); + let generated_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &generated_key).unwrap(); // remove key from node0 key_servers[0].cluster().key_storage().remove(&document).unwrap(); // now let's try to retrieve key back by requesting it from node0, so that session must be delegated let retrieved_key = key_servers[0].restore_document_key(&document, &signature.into()).unwrap(); - let retrieved_key = ethcrypto::ecies::decrypt(&secret, ðcrypto::DEFAULT_MAC, &retrieved_key).unwrap(); + let retrieved_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap(); assert_eq!(retrieved_key, generated_key); } @@ -491,7 +491,7 @@ pub mod tests { // sign message let message_hash = H256::from(42); let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); - let combined_signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &combined_signature).unwrap(); + let combined_signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap(); let signature_c = Secret::from_slice(&combined_signature[..32]); let signature_s = Secret::from_slice(&combined_signature[32..]); @@ -517,7 +517,7 @@ pub mod tests { // sign message let message_hash = H256::random(); let signature = key_servers[0].sign_message_ecdsa(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); - let signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &signature).unwrap(); + let signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &signature).unwrap(); let signature: H520 = signature[0..65].into(); // check signature diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs index 49c4e26d61..3343652c2b 100644 --- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs @@ -1269,8 +1269,8 @@ mod tests { assert!(decrypted_secret.common_point.is_some()); assert!(decrypted_secret.decrypt_shadows.is_some()); // check that KS client is able to restore original secret - use ethcrypto::DEFAULT_MAC; - use ethcrypto::ecies::decrypt; + use crypto::DEFAULT_MAC; + use crypto::ecies::decrypt; let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter() .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap())) .collect(); @@ -1413,8 +1413,8 @@ mod tests { assert_eq!(1, sessions.iter().skip(1).filter(|s| s.broadcast_shadows().is_none()).count()); // 4 nodes must be able to recover original secret - use ethcrypto::DEFAULT_MAC; - use ethcrypto::ecies::decrypt; + use crypto::DEFAULT_MAC; + use crypto::ecies::decrypt; let result = sessions[0].decrypted_secret().unwrap().unwrap(); assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == Some(Ok(result.clone()))).count()); let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter() diff --git a/secret_store/src/key_server_cluster/io/handshake.rs b/secret_store/src/key_server_cluster/io/handshake.rs index c48ed27dae..838e48e1f7 100644 --- a/secret_store/src/key_server_cluster/io/handshake.rs +++ b/secret_store/src/key_server_cluster/io/handshake.rs @@ -37,7 +37,7 @@ use std::sync::Arc; use std::collections::BTreeSet; use futures::{Future, Poll, Async}; use tokio_io::{AsyncRead, AsyncWrite}; -use ethcrypto::ecdh::agree; +use crypto::ecdh::agree; use ethkey::{Random, Generator, KeyPair, Public, Signature, verify_public, sign, recover}; use ethereum_types::H256; use key_server_cluster::{NodeId, Error, NodeKeyPair}; diff --git a/secret_store/src/key_server_cluster/io/message.rs b/secret_store/src/key_server_cluster/io/message.rs index 94030ef416..784b0b2b6a 100644 --- a/secret_store/src/key_server_cluster/io/message.rs +++ b/secret_store/src/key_server_cluster/io/message.rs @@ -19,7 +19,7 @@ use std::u16; use std::ops::Deref; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use serde_json; -use ethcrypto::ecies; +use crypto::ecies; use ethkey::{Secret, KeyPair}; use ethkey::math::curve_order; use ethereum_types::{H256, U256}; @@ -306,7 +306,7 @@ pub mod tests { use futures::Poll; use tokio_io::{AsyncRead, AsyncWrite}; use ethkey::{Random, Generator, KeyPair}; - use ethcrypto::ecdh::agree; + use crypto::ecdh::agree; use key_server_cluster::Error; use key_server_cluster::message::Message; use super::{MESSAGE_HEADER_SIZE, CURRENT_HEADER_VERSION, MessageHeader, fix_shared_key, encrypt_message, diff --git a/secret_store/src/key_server_cluster/jobs/decryption_job.rs b/secret_store/src/key_server_cluster/jobs/decryption_job.rs index 7bf1a294ac..6864665f3b 100644 --- a/secret_store/src/key_server_cluster/jobs/decryption_job.rs +++ b/secret_store/src/key_server_cluster/jobs/decryption_job.rs @@ -17,8 +17,8 @@ use std::collections::{BTreeSet, BTreeMap}; use ethereum_types::H256; use ethkey::{Public, Secret}; -use ethcrypto::ecies::encrypt; -use ethcrypto::DEFAULT_MAC; +use crypto::ecies::encrypt; +use crypto::DEFAULT_MAC; use key_server_cluster::{Error, NodeId, DocumentKeyShare, EncryptedDocumentKeyShadow}; use key_server_cluster::math; use key_server_cluster::jobs::job_session::{JobPartialRequestAction, JobPartialResponseAction, JobExecutor}; diff --git a/secret_store/src/key_server_cluster/mod.rs b/secret_store/src/key_server_cluster/mod.rs index 804c85e311..94386d0510 100644 --- a/secret_store/src/key_server_cluster/mod.rs +++ b/secret_store/src/key_server_cluster/mod.rs @@ -17,7 +17,7 @@ use std::fmt; use std::io::Error as IoError; use ethkey; -use ethcrypto; +use crypto; use super::types::all::ServerKeyId; pub use super::traits::NodeKeyPair; @@ -124,8 +124,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: ethcrypto::Error) -> Self { +impl From for Error { + fn from(err: crypto::Error) -> Self { Error::EthKey(err.into()) } } diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index c087d66511..9a7310b11d 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -18,10 +18,10 @@ extern crate byteorder; extern crate ethabi; extern crate ethcore; extern crate ethcore_bytes as bytes; +extern crate ethcore_crypto as crypto; extern crate ethcore_logger as logger; extern crate ethcore_sync as sync; extern crate ethcore_transaction as transaction; -extern crate ethcrypto; extern crate ethereum_types; extern crate ethkey; extern crate futures_cpupool; diff --git a/secret_store/src/node_key_pair.rs b/secret_store/src/node_key_pair.rs index 75c8401856..55c2a8a28a 100644 --- a/secret_store/src/node_key_pair.rs +++ b/secret_store/src/node_key_pair.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::sync::Arc; -use ethcrypto::ecdh::agree; +use crypto::ecdh::agree; use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_address}; use ethcore::account_provider::AccountProvider; use ethereum_types::{H256, Address}; diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 466ff95161..f6718d6b51 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -21,13 +21,13 @@ ansi_term = "0.10" rustc-hex = "1.0" ethcore-io = { path = "../io" } ethcore-bytes = { path = "../bytes" } +ethcore-crypto = { path = "../../ethcore/crypto" } +ethcore-logger = { path ="../../logger" } ethcore-network = { path = "../network" } ethereum-types = "0.3" ethkey = { path = "../../ethkey" } -ethcrypto = { path = "../../ethcrypto" } rlp = { path = "../rlp" } path = { path = "../path" } -ethcore-logger = { path ="../../logger" } ipnetwork = "0.12.6" keccak-hash = { path = "../hash" } snappy = { git = "https://github.com/paritytech/rust-snappy" } diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index fc3e66e3a5..f326ff4b1e 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -61,6 +61,7 @@ extern crate ethcore_io as io; extern crate ethcore_bytes; +extern crate ethcore_crypto as crypto; extern crate ethereum_types; extern crate parking_lot; extern crate mio; @@ -73,7 +74,6 @@ extern crate igd; extern crate libc; extern crate slab; extern crate ethkey; -extern crate ethcrypto as crypto; extern crate rlp; extern crate bytes; extern crate path; diff --git a/util/network/Cargo.toml b/util/network/Cargo.toml index 7d3d48b5af..f98cd9e93c 100644 --- a/util/network/Cargo.toml +++ b/util/network/Cargo.toml @@ -7,11 +7,11 @@ version = "1.11.0" authors = ["Parity Technologies "] [dependencies] +error-chain = { version = "0.11", default-features = false } +ethcore-crypto = { path = "../../ethcore/crypto" } ethcore-io = { path = "../io" } ethereum-types = "0.3" ethkey = { path = "../../ethkey" } -ethcrypto = { path = "../../ethcrypto" } -rlp = { path = "../rlp" } ipnetwork = "0.12.6" +rlp = { path = "../rlp" } snappy = { git = "https://github.com/paritytech/rust-snappy" } -error-chain = { version = "0.11", default-features = false } diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 7bd13d1f39..55c31dd2e6 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -16,8 +16,8 @@ #![recursion_limit="128"] +extern crate ethcore_crypto as crypto; extern crate ethcore_io as io; -extern crate ethcrypto as crypto; extern crate ethereum_types; extern crate ethkey; extern crate rlp; diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index b972bf5cf1..49d4dffede 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -9,7 +9,7 @@ bitflags = "0.9" byteorder = "1.0.0" ethereum-types = "0.3" ethcore-network = { path = "../util/network" } -ethcrypto = { path = "../ethcrypto" } +ethcore-crypto = { path = "../ethcore/crypto" } ethkey = { path = "../ethkey" } hex = "0.2" log = "0.3" diff --git a/whisper/src/lib.rs b/whisper/src/lib.rs index 1f8449604b..bcee122ec0 100644 --- a/whisper/src/lib.rs +++ b/whisper/src/lib.rs @@ -18,8 +18,8 @@ //! interface. extern crate byteorder; +extern crate ethcore_crypto as crypto; extern crate ethcore_network as network; -extern crate ethcrypto; extern crate ethereum_types; extern crate ethkey; extern crate hex; diff --git a/whisper/src/rpc/crypto.rs b/whisper/src/rpc/crypto.rs index 8dcfed88a6..e7782a0772 100644 --- a/whisper/src/rpc/crypto.rs +++ b/whisper/src/rpc/crypto.rs @@ -16,6 +16,7 @@ //! Encryption schemes supported by RPC layer. +use crypto; use ethereum_types::H256; use ethkey::{self, Public, Secret}; use ring::aead::{self, AES_256_GCM, SealingKey, OpeningKey}; @@ -117,7 +118,7 @@ impl EncryptionInstance { } } EncryptionInner::ECIES(valid_public) => { - ::ethcrypto::ecies::encrypt(&valid_public, &[], plain) + crypto::ecies::encrypt(&valid_public, &[], plain) .expect("validity of public key an invariant of the type; qed") } } @@ -213,7 +214,7 @@ impl DecryptionInstance { } DecryptionInner::ECIES(secret) => { // secret is checked for validity, so only fails on invalid message. - ::ethcrypto::ecies::decrypt(&secret, &[], ciphertext).ok() + crypto::ecies::decrypt(&secret, &[], ciphertext).ok() } } } -- GitLab From 8348147a4ff101688736f82b36d2da78d9348486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 10 Apr 2018 16:14:15 +0200 Subject: [PATCH 058/263] Enable UI by default, but only display deprecation notice (#8262) * Enable UI by default, but only display info page. * Fix test. * Fix naming and remove old todo. * Change "wallet" with "browser UI" * Update text, its not deprecated, its moved --- Cargo.lock | 8 ++ dapps/Cargo.toml | 1 + dapps/src/apps/mod.rs | 13 +-- dapps/src/lib.rs | 19 ++++ dapps/src/router.rs | 14 ++- dapps/src/tests/helpers/mod.rs | 1 + dapps/ui-deprecation/Cargo.toml | 18 ++++ dapps/ui-deprecation/build.rs | 21 +++++ dapps/ui-deprecation/build/index.html | 119 ++++++++++++++++++++++++++ dapps/ui-deprecation/src/lib.rs | 21 +++++ dapps/ui-deprecation/src/lib.rs.in | 55 ++++++++++++ parity/configuration.rs | 110 +++++++++++++++++------- parity/dapps.rs | 2 + parity/rpc.rs | 6 +- parity/run.rs | 4 +- 15 files changed, 369 insertions(+), 43 deletions(-) create mode 100644 dapps/ui-deprecation/Cargo.toml create mode 100644 dapps/ui-deprecation/build.rs create mode 100644 dapps/ui-deprecation/build/index.html create mode 100644 dapps/ui-deprecation/src/lib.rs create mode 100644 dapps/ui-deprecation/src/lib.rs.in diff --git a/Cargo.lock b/Cargo.lock index 71ad5fc0bb..4f86b1df4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2037,6 +2037,7 @@ dependencies = [ "parity-hash-fetch 1.11.0", "parity-reactor 0.1.0", "parity-ui 1.11.0", + "parity-ui-deprecation 1.10.0", "parity-version 1.11.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2256,6 +2257,13 @@ dependencies = [ "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parity-ui-deprecation" +version = "1.10.0" +dependencies = [ + "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parity-ui-dev" version = "1.9.0" diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index d63150b0a5..fdd497763f 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -35,6 +35,7 @@ node-health = { path = "./node-health" } parity-hash-fetch = { path = "../hash-fetch" } parity-reactor = { path = "../util/reactor" } parity-ui = { path = "./ui" } +parity-ui-deprecation = { path = "./ui-deprecation" } keccak-hash = { path = "../util/hash" } parity-version = { path = "../util/version" } registrar = { path = "../registrar" } diff --git a/dapps/src/apps/mod.rs b/dapps/src/apps/mod.rs index 0b8865e76f..21947b928b 100644 --- a/dapps/src/apps/mod.rs +++ b/dapps/src/apps/mod.rs @@ -23,7 +23,6 @@ use page; use proxypac::ProxyPac; use web::Web; use fetch::Fetch; -use parity_ui; use {WebProxyTokens, ParentFrameSettings}; mod app; @@ -43,11 +42,15 @@ pub const WEB_PATH: &'static str = "web"; pub const URL_REFERER: &'static str = "__referer="; pub fn utils(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::new(pool, parity_ui::App::default())) + Box::new(page::builtin::Dapp::new(pool, ::parity_ui::App::default())) } pub fn ui(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::with_fallback_to_index(pool, parity_ui::App::default())) + Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui::App::default())) +} + +pub fn ui_deprecation(pool: CpuPool) -> Box { + Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui_deprecation::App::default())) } pub fn ui_redirection(embeddable: Option) -> Box { @@ -77,13 +80,13 @@ pub fn all_endpoints( // NOTE [ToDr] Dapps will be currently embeded on 8180 pages.insert( "ui".into(), - Box::new(page::builtin::Dapp::new_safe_to_embed(pool.clone(), parity_ui::App::default(), embeddable.clone())) + Box::new(page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::App::default(), embeddable.clone())) ); // old version pages.insert( "v1".into(), Box::new({ - let mut page = page::builtin::Dapp::new_safe_to_embed(pool.clone(), parity_ui::old::App::default(), embeddable.clone()); + let mut page = page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::old::App::default(), embeddable.clone()); // allow JS eval on old Wallet page.allow_js_eval(); page diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index 482ee39595..c4e244b251 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -39,6 +39,7 @@ extern crate node_health; extern crate parity_dapps_glue as parity_dapps; extern crate parity_hash_fetch as hash_fetch; extern crate parity_ui; +extern crate parity_ui_deprecation; extern crate keccak_hash as hash; extern crate parity_version; extern crate registrar; @@ -159,6 +160,7 @@ impl Middleware { registrar: Arc>, sync_status: Arc, fetch: F, + info_page_only: bool, ) -> Self { let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( hash_fetch::urlhint::URLHintContract::new(registrar), @@ -166,6 +168,23 @@ impl Middleware { fetch.clone(), pool.clone(), ).embeddable_on(None).allow_dapps(false)); + + if info_page_only { + let mut special = HashMap::default(); + special.insert(router::SpecialEndpoint::Home, Some(apps::ui_deprecation(pool.clone()))); + + return Middleware { + endpoints: Default::default(), + router: router::Router::new( + content_fetcher, + None, + special, + None, + dapps_domain.to_owned(), + ), + } + } + let special = { let mut special = special_endpoints( pool.clone(), diff --git a/dapps/src/router.rs b/dapps/src/router.rs index e5770ca72b..d5f4647049 100644 --- a/dapps/src/router.rs +++ b/dapps/src/router.rs @@ -150,10 +150,20 @@ impl Router { } }, // RPC by default - _ => { + _ if self.special.contains_key(&SpecialEndpoint::Rpc) => { trace!(target: "dapps", "Resolving to RPC call."); Response::None(req) - } + }, + // 404 otherwise + _ => { + Response::Some(Box::new(future::ok(handlers::ContentHandler::error( + hyper::StatusCode::NotFound, + "404 Not Found", + "Requested content was not found.", + None, + self.embeddable_on.clone(), + ).into()))) + }, }) } } diff --git a/dapps/src/tests/helpers/mod.rs b/dapps/src/tests/helpers/mod.rs index 3a1311578c..41df0db61b 100644 --- a/dapps/src/tests/helpers/mod.rs +++ b/dapps/src/tests/helpers/mod.rs @@ -240,6 +240,7 @@ impl Server { registrar, sync_status, fetch, + false, ) } else { Middleware::dapps( diff --git a/dapps/ui-deprecation/Cargo.toml b/dapps/ui-deprecation/Cargo.toml new file mode 100644 index 0000000000..f4479c2367 --- /dev/null +++ b/dapps/ui-deprecation/Cargo.toml @@ -0,0 +1,18 @@ +[package] +description = "Parity UI deprecation notice." +name = "parity-ui-deprecation" +version = "1.10.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] +build = "build.rs" + +[features] +default = ["with-syntex", "use-precompiled-js"] +use-precompiled-js = ["parity-dapps-glue/use-precompiled-js"] +with-syntex = ["parity-dapps-glue/with-syntex"] + +[build-dependencies] +parity-dapps-glue = "1.9" + +[dependencies] +parity-dapps-glue = "1.9" diff --git a/dapps/ui-deprecation/build.rs b/dapps/ui-deprecation/build.rs new file mode 100644 index 0000000000..c427f3d54d --- /dev/null +++ b/dapps/ui-deprecation/build.rs @@ -0,0 +1,21 @@ +// Copyright 2015-2018 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 . + +extern crate parity_dapps_glue; + +fn main() { + parity_dapps_glue::generate(); +} diff --git a/dapps/ui-deprecation/build/index.html b/dapps/ui-deprecation/build/index.html new file mode 100644 index 0000000000..07059743c6 --- /dev/null +++ b/dapps/ui-deprecation/build/index.html @@ -0,0 +1,119 @@ + + + + + + Parity + + + +
+
+
+

The Parity UI has been split off into a standalone project.

+

Get the standalone Parity UI from here

+

+ +

+
+
+
+ + diff --git a/dapps/ui-deprecation/src/lib.rs b/dapps/ui-deprecation/src/lib.rs new file mode 100644 index 0000000000..79a4a42497 --- /dev/null +++ b/dapps/ui-deprecation/src/lib.rs @@ -0,0 +1,21 @@ +// Copyright 2015-2018 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 . + +#[cfg(feature = "with-syntex")] +include!(concat!(env!("OUT_DIR"), "/lib.rs")); + +#[cfg(not(feature = "with-syntex"))] +include!("lib.rs.in"); diff --git a/dapps/ui-deprecation/src/lib.rs.in b/dapps/ui-deprecation/src/lib.rs.in new file mode 100644 index 0000000000..892ebbded2 --- /dev/null +++ b/dapps/ui-deprecation/src/lib.rs.in @@ -0,0 +1,55 @@ +// Copyright 2015-2018 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 . + +extern crate parity_dapps_glue; + +use std::collections::HashMap; +use parity_dapps_glue::{WebApp, File, Info}; + +#[derive(WebAppFiles)] +#[webapp(path = "../build")] +pub struct App { + pub files: HashMap<&'static str, File>, +} + +impl Default for App { + fn default() -> App { + App { + files: Self::files(), + } + } +} + +impl WebApp for App { + fn file(&self, path: &str) -> Option<&File> { + self.files.get(path) + } + + fn info(&self) -> Info { + Info { + name: "Parity Wallet info page", + version: env!("CARGO_PKG_VERSION"), + author: "Parity ", + description: "Deprecation notice for Parity Wallet", + icon_url: "icon.png", + } + } +} + +#[test] +fn test_js() { + parity_dapps_glue::js::build(env!("CARGO_MANIFEST_DIR"), "build"); +} diff --git a/parity/configuration.rs b/parity/configuration.rs index d1c02d5bc7..96f819cba2 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -581,11 +581,13 @@ impl Configuration { } fn ui_config(&self) -> UiConfiguration { + let ui = self.ui_enabled(); UiConfiguration { - enabled: self.ui_enabled(), + enabled: ui.enabled, interface: self.ui_interface(), port: self.ui_port(), hosts: self.ui_hosts(), + info_page_only: ui.info_page_only, } } @@ -1176,16 +1178,22 @@ impl Configuration { into_secretstore_service_contract_address(self.args.arg_secretstore_doc_sretr_contract.as_ref()) } - fn ui_enabled(&self) -> bool { + fn ui_enabled(&self) -> UiEnabled { if self.args.flag_force_ui { - return true; + return UiEnabled { + enabled: true, + info_page_only: false, + }; } let ui_disabled = self.args.arg_unlock.is_some() || self.args.flag_geth || self.args.flag_no_ui; - self.args.cmd_ui && !ui_disabled && cfg!(feature = "ui-enabled") + return UiEnabled { + enabled: (self.args.cmd_ui || !ui_disabled) && cfg!(feature = "ui-enabled"), + info_page_only: !self.args.cmd_ui, + } } fn verifier_settings(&self) -> VerifierSettings { @@ -1206,6 +1214,12 @@ impl Configuration { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +struct UiEnabled { + pub enabled: bool, + pub info_page_only: bool, +} + fn into_secretstore_service_contract_address(s: &str) -> Result, String> { match s { "none" => Ok(None), @@ -1418,15 +1432,16 @@ mod tests { origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]), hosts: Some(vec![]), signer_path: expected.into(), - ui_address: None, + ui_address: Some("127.0.0.1:8180".into()), dapps_address: Some("127.0.0.1:8545".into()), support_token_api: true, max_connections: 100, }, UiConfiguration { - enabled: false, + enabled: true, interface: "127.0.0.1".into(), port: 8180, hosts: Some(vec![]), + info_page_only: true, }, LogConfig { color: true, mode: None, @@ -1698,10 +1713,26 @@ mod tests { // when let conf0 = parse(&["parity", "--geth"]); let conf1 = parse(&["parity", "--geth", "--force-ui"]); + let conf2 = parse(&["parity", "--geth", "ui"]); + let conf3 = parse(&["parity"]); // then - assert_eq!(conf0.ui_enabled(), false); - assert_eq!(conf1.ui_enabled(), true); + assert_eq!(conf0.ui_enabled(), UiEnabled { + enabled: false, + info_page_only: true, + }); + assert_eq!(conf1.ui_enabled(), UiEnabled { + enabled: true, + info_page_only: false, + }); + assert_eq!(conf2.ui_enabled(), UiEnabled { + enabled: true, + info_page_only: false, + }); + assert_eq!(conf3.ui_enabled(), UiEnabled { + enabled: true, + info_page_only: true, + }); } #[test] @@ -1712,7 +1743,10 @@ mod tests { let conf0 = parse(&["parity", "--unlock", "0x0"]); // then - assert_eq!(conf0.ui_enabled(), false); + assert_eq!(conf0.ui_enabled(), UiEnabled { + enabled: false, + info_page_only: true, + }); } #[test] @@ -1730,54 +1764,64 @@ mod tests { // then assert_eq!(conf0.directories().signer, "signer".to_owned()); assert_eq!(conf0.ui_config(), UiConfiguration { - enabled: false, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - }); - assert!(conf4.ws_config().unwrap().hosts.is_some()); - assert_eq!(conf4.directories().signer, "signer".to_owned()); - assert_eq!(conf4.ui_config(), UiConfiguration { enabled: true, interface: "127.0.0.1".into(), port: 8180, hosts: Some(vec![]), + info_page_only: true, }); - assert!(conf5.ws_config().unwrap().hosts.is_some()); - assert!(conf5.ws_config().unwrap().hosts.is_some()); - assert_eq!(conf5.directories().signer, "signer".to_owned()); - assert_eq!(conf5.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - }); - assert!(conf5.ws_config().unwrap().hosts.is_some()); + + assert!(conf1.ws_config().unwrap().hosts.is_some()); + assert_eq!(conf1.ws_config().unwrap().origins, None); assert_eq!(conf1.directories().signer, "signer".to_owned()); assert_eq!(conf1.ui_config(), UiConfiguration { - enabled: false, + enabled: true, interface: "127.0.0.1".into(), port: 8180, hosts: Some(vec![]), + info_page_only: true, }); assert_eq!(conf1.dapps_config().extra_embed_on, vec![("127.0.0.1".to_owned(), 3000)]); - assert_eq!(conf1.ws_config().unwrap().origins, None); + + assert!(conf2.ws_config().unwrap().hosts.is_some()); assert_eq!(conf2.directories().signer, "signer".to_owned()); assert_eq!(conf2.ui_config(), UiConfiguration { - enabled: false, + enabled: true, interface: "127.0.0.1".into(), port: 3123, hosts: Some(vec![]), + info_page_only: true, }); - assert!(conf2.ws_config().unwrap().hosts.is_some()); + + assert!(conf3.ws_config().unwrap().hosts.is_some()); assert_eq!(conf3.directories().signer, "signer".to_owned()); assert_eq!(conf3.ui_config(), UiConfiguration { - enabled: false, + enabled: true, interface: "test".into(), port: 8180, hosts: Some(vec![]), + info_page_only: true, + }); + + assert!(conf4.ws_config().unwrap().hosts.is_some()); + assert_eq!(conf4.directories().signer, "signer".to_owned()); + assert_eq!(conf4.ui_config(), UiConfiguration { + enabled: true, + interface: "127.0.0.1".into(), + port: 8180, + hosts: Some(vec![]), + info_page_only: false, + }); + + assert!(conf5.ws_config().unwrap().hosts.is_some()); + assert_eq!(conf5.directories().signer, "signer".to_owned()); + assert_eq!(conf5.ui_config(), UiConfiguration { + enabled: true, + interface: "127.0.0.1".into(), + port: 8180, + hosts: Some(vec![]), + info_page_only: false, }); - assert!(conf3.ws_config().unwrap().hosts.is_some()); } #[test] diff --git a/parity/dapps.rs b/parity/dapps.rs index 42ff21b58f..2219f7cbee 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -164,6 +164,7 @@ pub struct Dependencies { pub pool: CpuPool, pub signer: Arc, pub ui_address: Option<(String, u16)>, + pub info_page_only: bool, } pub fn new(configuration: Configuration, deps: Dependencies) -> Result, String> { @@ -281,6 +282,7 @@ mod server { deps.contract_client, deps.sync_status, deps.fetch, + deps.info_page_only, )) } diff --git a/parity/rpc.rs b/parity/rpc.rs index a1b2271c44..66a2715d42 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -74,6 +74,7 @@ pub struct UiConfiguration { pub interface: String, pub port: u16, pub hosts: Option>, + pub info_page_only: bool, } impl UiConfiguration { @@ -110,10 +111,11 @@ impl From for HttpConfiguration { impl Default for UiConfiguration { fn default() -> Self { UiConfiguration { - enabled: false, + enabled: cfg!(feature = "ui-enabled"), port: 8180, interface: "127.0.0.1".into(), hosts: Some(vec![]), + info_page_only: true, } } } @@ -168,7 +170,7 @@ impl Default for WsConfiguration { hosts: Some(Vec::new()), signer_path: replace_home(&data_dir, "$BASE/signer").into(), support_token_api: true, - ui_address: None, + ui_address: Some("127.0.0.1:8180".into()), dapps_address: Some("127.0.0.1:8545".into()), } } diff --git a/parity/run.rs b/parity/run.rs index 8fa76693b8..4cc7b29b04 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -365,6 +365,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: pool: cpu_pool.clone(), signer: signer_service.clone(), ui_address: cmd.ui_conf.redirection_address(), + info_page_only: cmd.ui_conf.info_page_only, }) }; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; @@ -970,7 +972,7 @@ impl RunningClient { } pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<(bool, Option), String> { - if cmd.ui_conf.enabled { + if cmd.ui_conf.enabled && !cmd.ui_conf.info_page_only { warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead.")); warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases")); } -- GitLab From 99e37844fddc827cb871ba0e239b182e3495ab7b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 11 Apr 2018 01:25:27 +0800 Subject: [PATCH 059/263] Use async hyper server in secret_store and upgrade igd (#8359) * Update secret_store hyper dep to 0.11 * Upgrade igd to 0.7 * typo: spawn --- Cargo.lock | 85 ++---- secret_store/Cargo.toml | 7 +- secret_store/src/lib.rs | 1 + secret_store/src/listener/http_listener.rs | 335 +++++++++++---------- secret_store/src/types/all.rs | 14 + util/network-devp2p/Cargo.toml | 2 +- 6 files changed, 228 insertions(+), 216 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f86b1df4b..dbc605dac5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -706,7 +706,7 @@ dependencies = [ "ethcore-network 1.11.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", - "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -780,7 +780,7 @@ dependencies = [ "ethkey 0.3.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", @@ -793,6 +793,7 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1200,24 +1201,6 @@ name = "httparse" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "hyper" -version = "0.10.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hyper" version = "0.11.24" @@ -1271,14 +1254,18 @@ dependencies = [ [[package]] name = "igd" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1654,14 +1641,6 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "mime" version = "0.3.4" @@ -3291,6 +3270,17 @@ dependencies = [ "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-retry" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-rustls" version = "0.4.0" @@ -3398,11 +3388,6 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "transaction-pool" version = "1.11.0" @@ -3450,11 +3435,6 @@ dependencies = [ "trie-standardmap 0.1.0", ] -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "uint" version = "0.2.0" @@ -3731,18 +3711,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "xml-rs" -version = "0.3.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "xmltree" -version = "0.3.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3831,11 +3811,10 @@ dependencies = [ "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)" = "" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)" = "df4dd5dae401458087396b6db7fabc4d6760aa456a5fa8e92bda549f39cae661" "checksum hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6cdc1751771a14b8175764394f025e309a28c825ed9eaf97fa62bb831dc8c5" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" -"checksum igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356a0dc23a4fa0f8ce4777258085d00a01ea4923b2efd93538fc44bf5e1bda76" +"checksum igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a254e265e8810deb357a9de757f784787ec415d056ededf410c0aa460afee9e" "checksum integer-encoding 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a053c9c7dcb7db1f2aa012c37dc176c62e4cdf14898dee0eecc606de835b8acb" "checksum interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "141340095b15ed7491bd3d4ced9d20cebfb826174b6bb03386381f62b01e3d77" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" @@ -3870,7 +3849,6 @@ dependencies = [ "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e3d709ffbb330e1566dc2f2a3c9b58a5ad4a381f740b810cd305dc3f089bc160" "checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" @@ -3996,6 +3974,7 @@ dependencies = [ "checksum tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes)" = "" "checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" "checksum tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3cedc8e5af5131dc3423ffa4f877cce78ad25259a9a62de0613735a13ebc64b" +"checksum tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f05746ae87dca83a2016b4f5dba5b237b897dd12fd324f60afe282112f16969a" "checksum tokio-rustls 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9263e472d976e4345e50c6cce4cfe6b17c71593ea593cce1df26f1efd36debb" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" @@ -4005,10 +3984,8 @@ dependencies = [ "checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a" "checksum tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6116c71be48f8f1656551fd16458247fdd6c03201d7893ad81189055fcde03e8" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "715254c8f0811be1a79ad3ea5e6fa3c8eddec2b03d7f5ba78cf093e56d79c24f" "checksum trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)" = "" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6477b2716357758c176c36719023e1f9726974d762150e4fc0a9c8c75488c343" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" @@ -4038,6 +4015,6 @@ dependencies = [ "checksum ws 0.7.5 (git+https://github.com/tomusdrw/ws-rs)" = "" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" -"checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562" -"checksum xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "472a9d37c7c53ab2391161df5b89b1f3bf76dab6ab150d7941ecbdd832282082" +"checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" +"checksum xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9cfb54ca6b8f17d2377219ce485b134d53561b77e1393c7ea416f543a527431" "checksum zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c0deac03fc7d43abcf19f2c2db6bd9289f9ea3d31f350e26eb0ed8b4117983c1" diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index fcd022f7d9..91889d7012 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Parity Technologies "] byteorder = "1.0" log = "0.3" parking_lot = "0.5" -hyper = { version = "0.10", default-features = false } +hyper = { version = "0.11", default-features = false } serde = "1.0" serde_json = "1.0" serde_derive = "1.0" @@ -17,8 +17,9 @@ futures = "0.1" futures-cpupool = "0.1" rustc-hex = "1.0" tiny-keccak = "1.3" -tokio-core = "0.1.6" -tokio-io = "0.1.0" +tokio = "0.1" +tokio-core = "0.1" +tokio-io = "0.1" tokio-service = "0.1" tokio-proto = "0.1" url = "1.0" diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 9a7310b11d..dc45f1af36 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -34,6 +34,7 @@ extern crate rustc_hex; extern crate serde; extern crate serde_json; extern crate tiny_keccak; +extern crate tokio; extern crate tokio_core; extern crate tokio_io; extern crate tokio_proto; diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index 1680201e19..7d4385ccc5 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -15,16 +15,16 @@ // along with Parity. If not, see . use std::collections::BTreeSet; -use std::io::Read; use std::sync::{Arc, Weak}; -use hyper::header; -use hyper::uri::RequestUri; -use hyper::method::Method as HttpMethod; -use hyper::status::StatusCode as HttpStatusCode; -use hyper::server::{Server as HttpServer, Request as HttpRequest, Response as HttpResponse, Handler as HttpHandler, - Listening as HttpListening}; +use hyper::{self, header, Chunk, Uri, Request as HttpRequest, Response as HttpResponse, Method as HttpMethod, StatusCode as HttpStatusCode}; +use hyper::server::Http; use serde::Serialize; use serde_json; +use tokio::executor::current_thread; +use tokio::net::TcpListener; +use tokio::runtime::Runtime; +use tokio_service::Service; +use futures::{future, Future, Stream}; use url::percent_encoding::percent_decode; use traits::KeyServer; @@ -34,16 +34,16 @@ use types::all::{Error, Public, MessageHash, NodeAddress, RequestSignature, Serv /// Key server http-requests listener. Available requests: /// To generate server key: POST /shadow/{server_key_id}/{signature}/{threshold} -/// To store pregenerated encrypted document key: POST /shadow/{server_key_id}/{signature}/{common_point}/{encrypted_key} -/// To generate server && document key: POST /{server_key_id}/{signature}/{threshold} +/// To store pregenerated encrypted document key: POST /shadow/{server_key_id}/{signature}/{common_point}/{encrypted_key} +/// To generate server && document key: POST /{server_key_id}/{signature}/{threshold} /// To get document key: GET /{server_key_id}/{signature} -/// To get document key shadow: GET /shadow/{server_key_id}/{signature} +/// To get document key shadow: GET /shadow/{server_key_id}/{signature} /// To generate Schnorr signature with server key: GET /schnorr/{server_key_id}/{signature}/{message_hash} /// To generate ECDSA signature with server key: GET /ecdsa/{server_key_id}/{signature}/{message_hash} /// To change servers set: POST /admin/servers_set_change/{old_signature}/{new_signature} + BODY: json array of hex-encoded nodes ids pub struct KeyServerHttpListener { - http_server: HttpListening, + _runtime: Runtime, _handler: Arc, } @@ -71,6 +71,7 @@ enum Request { } /// Cloneable http handler +#[derive(Clone)] struct KeyServerHttpHandler { handler: Arc, } @@ -87,194 +88,212 @@ impl KeyServerHttpListener { key_server: key_server, }); - let listener_address = format!("{}:{}", listener_address.address, listener_address.port); - let http_server = HttpServer::http(&listener_address) - .and_then(|http_server| http_server.handle(KeyServerHttpHandler { - handler: shared_handler.clone(), - })).map_err(|err| Error::Hyper(format!("{}", err)))?; + let mut runtime = Runtime::new()?; + let listener_address = format!("{}:{}", listener_address.address, listener_address.port).parse()?; + let listener = TcpListener::bind(&listener_address)?; + + let shared_handler2 = shared_handler.clone(); + + let server = listener.incoming() + .map_err(|e| warn!("Key server listener error: {:?}", e)) + .for_each(move |socket| { + let http: Http = Http::new(); + let serve = http.serve_connection(socket, KeyServerHttpHandler { + handler: shared_handler2.clone(), + }).map(|_| ()).map_err(|e| { + warn!("Key server handler error: {:?}", e); + }); + + // TODO: Change this to tokio::spawn once hyper is Send. + current_thread::spawn(serve); + future::ok(()) + }); + + runtime.spawn(server); let listener = KeyServerHttpListener { - http_server: http_server, + _runtime: runtime, _handler: shared_handler, }; + Ok(listener) } } -impl Drop for KeyServerHttpListener { - fn drop(&mut self) { - // ignore error as we are dropping anyway - let _ = self.http_server.close(); +impl KeyServerHttpHandler { + fn process(self, req_method: HttpMethod, req_uri: Uri, path: &str, req_body: &[u8]) -> HttpResponse { + match parse_request(&req_method, &path, &req_body) { + Request::GenerateServerKey(document, signature, threshold) => { + return_server_public_key(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.generate_key(&document, &signature.into(), threshold)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "GenerateServerKey request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::StoreDocumentKey(document, signature, common_point, encrypted_document_key) => { + return_empty(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.store_document_key(&document, &signature.into(), common_point, encrypted_document_key)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "StoreDocumentKey request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::GenerateDocumentKey(document, signature, threshold) => { + return_document_key(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.generate_document_key(&document, &signature.into(), threshold)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "GenerateDocumentKey request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::GetDocumentKey(document, signature) => { + return_document_key(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.restore_document_key(&document, &signature.into())) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "GetDocumentKey request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::GetDocumentKeyShadow(document, signature) => { + return_document_key_shadow(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.restore_document_key_shadow(&document, &signature.into())) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "GetDocumentKeyShadow request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::SchnorrSignMessage(document, signature, message_hash) => { + return_message_signature(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.sign_message_schnorr(&document, &signature.into(), message_hash)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "SchnorrSignMessage request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::EcdsaSignMessage(document, signature, message_hash) => { + return_message_signature(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.sign_message_ecdsa(&document, &signature.into(), message_hash)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "EcdsaSignMessage request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::ChangeServersSet(old_set_signature, new_set_signature, new_servers_set) => { + return_empty(&req_uri, self.handler.key_server.upgrade() + .map(|key_server| key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set)) + .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) + .map_err(|err| { + warn!(target: "secretstore", "ChangeServersSet request {} has failed with: {}", req_uri, err); + err + })) + }, + Request::Invalid => { + warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri); + HttpResponse::new().with_status(HttpStatusCode::BadRequest) + }, + } } } -impl HttpHandler for KeyServerHttpHandler { - fn handle(&self, mut req: HttpRequest, mut res: HttpResponse) { - if req.headers.has::() { - warn!(target: "secretstore", "Ignoring {}-request {} with Origin header", req.method, req.uri); - *res.status_mut() = HttpStatusCode::NotFound; - return; - } +impl Service for KeyServerHttpHandler { + type Request = HttpRequest; + type Response = HttpResponse; + type Error = hyper::Error; + type Future = Box>; - let mut req_body = Default::default(); - if let Err(error) = req.read_to_string(&mut req_body) { - warn!(target: "secretstore", "Error {} reading body of {}-request {}", error, req.method, req.uri); - *res.status_mut() = HttpStatusCode::BadRequest; - return; + fn call(&self, req: HttpRequest) -> Self::Future { + if req.headers().has::() { + warn!(target: "secretstore", "Ignoring {}-request {} with Origin header", req.method(), req.uri()); + return Box::new(future::ok(HttpResponse::new().with_status(HttpStatusCode::NotFound))); } - let req_method = req.method.clone(); - let req_uri = req.uri.clone(); - match &req_uri { - &RequestUri::AbsolutePath(ref path) => match parse_request(&req_method, &path, &req_body) { - Request::GenerateServerKey(document, signature, threshold) => { - return_server_public_key(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.generate_key(&document, &signature.into(), threshold)) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "GenerateServerKey request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::StoreDocumentKey(document, signature, common_point, encrypted_document_key) => { - return_empty(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.store_document_key(&document, &signature.into(), common_point, encrypted_document_key)) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "StoreDocumentKey request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::GenerateDocumentKey(document, signature, threshold) => { - return_document_key(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.generate_document_key(&document, &signature.into(), threshold)) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "GenerateDocumentKey request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::GetDocumentKey(document, signature) => { - return_document_key(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.restore_document_key(&document, &signature.into())) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "GetDocumentKey request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::GetDocumentKeyShadow(document, signature) => { - return_document_key_shadow(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.restore_document_key_shadow(&document, &signature.into())) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "GetDocumentKeyShadow request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::SchnorrSignMessage(document, signature, message_hash) => { - return_message_signature(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.sign_message_schnorr(&document, &signature.into(), message_hash)) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "SchnorrSignMessage request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::EcdsaSignMessage(document, signature, message_hash) => { - return_message_signature(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.sign_message_ecdsa(&document, &signature.into(), message_hash)) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "EcdsaSignMessage request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::ChangeServersSet(old_set_signature, new_set_signature, new_servers_set) => { - return_empty(req, res, self.handler.key_server.upgrade() - .map(|key_server| key_server.change_servers_set(old_set_signature, new_set_signature, new_servers_set)) - .unwrap_or(Err(Error::Internal("KeyServer is already destroyed".into()))) - .map_err(|err| { - warn!(target: "secretstore", "ChangeServersSet request {} has failed with: {}", req_uri, err); - err - })); - }, - Request::Invalid => { - warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri); - *res.status_mut() = HttpStatusCode::BadRequest; - }, - }, - _ => { + let req_method = req.method().clone(); + let req_uri = req.uri().clone(); + // We cannot consume Self because of the Service trait requirement. + let this = self.clone(); + + Box::new(req.body().concat2().map(move |body| { + let path = req_uri.path().to_string(); + if req_uri.is_absolute() { + this.process(req_method, req_uri, &path, &body) + } else { warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri); - *res.status_mut() = HttpStatusCode::NotFound; - }, - }; + HttpResponse::new().with_status(HttpStatusCode::NotFound) + } + })) } } -fn return_empty(req: HttpRequest, res: HttpResponse, empty: Result<(), Error>) { - return_bytes::(req, res, empty.map(|_| None)) +fn return_empty(req_uri: &Uri, empty: Result<(), Error>) -> HttpResponse { + return_bytes::(req_uri, empty.map(|_| None)) } -fn return_server_public_key(req: HttpRequest, res: HttpResponse, server_public: Result) { - return_bytes(req, res, server_public.map(|k| Some(SerializablePublic(k)))) +fn return_server_public_key(req_uri: &Uri, server_public: Result) -> HttpResponse { + return_bytes(req_uri, server_public.map(|k| Some(SerializablePublic(k)))) } -fn return_message_signature(req: HttpRequest, res: HttpResponse, signature: Result) { - return_bytes(req, res, signature.map(|s| Some(SerializableBytes(s)))) +fn return_message_signature(req_uri: &Uri, signature: Result) -> HttpResponse { + return_bytes(req_uri, signature.map(|s| Some(SerializableBytes(s)))) } -fn return_document_key(req: HttpRequest, res: HttpResponse, document_key: Result) { - return_bytes(req, res, document_key.map(|k| Some(SerializableBytes(k)))) +fn return_document_key(req_uri: &Uri, document_key: Result) -> HttpResponse { + return_bytes(req_uri, document_key.map(|k| Some(SerializableBytes(k)))) } -fn return_document_key_shadow(req: HttpRequest, res: HttpResponse, document_key_shadow: Result) { - return_bytes(req, res, document_key_shadow.map(|k| Some(SerializableEncryptedDocumentKeyShadow { +fn return_document_key_shadow(req_uri: &Uri, document_key_shadow: Result) -> HttpResponse { + return_bytes(req_uri, document_key_shadow.map(|k| Some(SerializableEncryptedDocumentKeyShadow { decrypted_secret: k.decrypted_secret.into(), common_point: k.common_point.expect("always filled when requesting document_key_shadow; qed").into(), decrypt_shadows: k.decrypt_shadows.expect("always filled when requesting document_key_shadow; qed").into_iter().map(Into::into).collect(), }))) } -fn return_bytes(req: HttpRequest, mut res: HttpResponse, result: Result, Error>) { +fn return_bytes(req_uri: &Uri, result: Result, Error>) -> HttpResponse { match result { Ok(Some(result)) => match serde_json::to_vec(&result) { - Ok(result) => { - res.headers_mut().set(header::ContentType::json()); - if let Err(err) = res.send(&result) { - // nothing to do, but to log an error - warn!(target: "secretstore", "response to request {} has failed with: {}", req.uri, err); - } - }, + Ok(result) => HttpResponse::new() + .with_header(header::ContentType::json()) + .with_body(result), Err(err) => { - warn!(target: "secretstore", "response to request {} has failed with: {}", req.uri, err); + warn!(target: "secretstore", "response to request {} has failed with: {}", req_uri, err); + HttpResponse::new().with_status(HttpStatusCode::InternalServerError) } }, - Ok(None) => *res.status_mut() = HttpStatusCode::Ok, - Err(err) => return_error(res, err), + Ok(None) => HttpResponse::new().with_status(HttpStatusCode::Ok), + Err(err) => return_error(err), } } -fn return_error(mut res: HttpResponse, err: Error) { - match err { - Error::InsufficientRequesterData(_) => *res.status_mut() = HttpStatusCode::BadRequest, - Error::AccessDenied => *res.status_mut() = HttpStatusCode::Forbidden, - Error::DocumentNotFound => *res.status_mut() = HttpStatusCode::NotFound, - Error::Hyper(_) => *res.status_mut() = HttpStatusCode::BadRequest, - Error::Serde(_) => *res.status_mut() = HttpStatusCode::BadRequest, - Error::Database(_) => *res.status_mut() = HttpStatusCode::InternalServerError, - Error::Internal(_) => *res.status_mut() = HttpStatusCode::InternalServerError, - } +fn return_error(err: Error) -> HttpResponse { + let mut res = match err { + Error::InsufficientRequesterData(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), + Error::AccessDenied => HttpResponse::new().with_status(HttpStatusCode::Forbidden), + Error::DocumentNotFound => HttpResponse::new().with_status(HttpStatusCode::NotFound), + Error::Hyper(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), + Error::Serde(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), + Error::Database(_) => HttpResponse::new().with_status(HttpStatusCode::InternalServerError), + Error::Internal(_) => HttpResponse::new().with_status(HttpStatusCode::InternalServerError), + }; // return error text. ignore errors when returning error let error_text = format!("\"{}\"", err); if let Ok(error_text) = serde_json::to_vec(&error_text) { res.headers_mut().set(header::ContentType::json()); - let _ = res.send(&error_text); + res.set_body(error_text); } + + res } -fn parse_request(method: &HttpMethod, uri_path: &str, body: &str) -> Request { +fn parse_request(method: &HttpMethod, uri_path: &str, body: &[u8]) -> Request { let uri_path = match percent_decode(uri_path.as_bytes()).decode_utf8() { Ok(path) => path, Err(_) => return Request::Invalid, @@ -328,7 +347,7 @@ fn parse_request(method: &HttpMethod, uri_path: &str, body: &str) -> Request { } } -fn parse_admin_request(method: &HttpMethod, path: Vec, body: &str) -> Request { +fn parse_admin_request(method: &HttpMethod, path: Vec, body: &[u8]) -> Request { let args_count = path.len(); if *method != HttpMethod::Post || args_count != 4 || path[1] != "servers_set_change" { return Request::Invalid; @@ -344,7 +363,7 @@ fn parse_admin_request(method: &HttpMethod, path: Vec, body: &str) -> Re _ => return Request::Invalid, }; - let new_servers_set: BTreeSet = match serde_json::from_str(body) { + let new_servers_set: BTreeSet = match serde_json::from_slice(body) { Ok(new_servers_set) => new_servers_set, _ => return Request::Invalid, }; @@ -356,7 +375,7 @@ fn parse_admin_request(method: &HttpMethod, path: Vec, body: &str) -> Re #[cfg(test)] mod tests { use std::sync::Arc; - use hyper::method::Method as HttpMethod; + use hyper::Method as HttpMethod; use ethkey::Public; use traits::KeyServer; use key_server::tests::DummyKeyServer; @@ -370,7 +389,7 @@ mod tests { let listener = KeyServerHttpListener::start(address, Arc::downgrade(&key_server)).unwrap(); drop(listener); } - + #[test] fn parse_request_successful() { // POST /shadow/{server_key_id}/{signature}/{threshold} => generate server key @@ -416,7 +435,7 @@ mod tests { let nodes = vec![node1, node2].into_iter().collect(); assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/b199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", &r#"["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91", - "0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]"#), + "0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]"#.as_bytes()), Request::ChangeServersSet( "a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(), "b199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(), @@ -437,9 +456,9 @@ mod tests { assert_eq!(parse_request(&HttpMethod::Get, "/ecdsa/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/0000000000000000000000000000000000000000000000000000000000000002/0000000000000000000000000000000000000000000000000000000000000002", Default::default()), Request::Invalid); assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/xxx/yyy", &r#"["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91", - "0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]"#), + "0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]"#.as_bytes()), Request::Invalid); - assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", ""), + assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", "".as_bytes()), Request::Invalid); } } diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index 356f1f1f00..5e28415b18 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -15,6 +15,8 @@ // along with Parity. If not, see . use std::fmt; +use std::io; +use std::net; use std::collections::BTreeMap; use serde_json; @@ -162,6 +164,18 @@ impl From for Error { } } +impl From for Error { + fn from(err: io::Error) -> Error { + Error::Internal(err.to_string()) + } +} + +impl From for Error { + fn from(err: net::AddrParseError) -> Error { + Error::Internal(err.to_string()) + } +} + impl From for Error { fn from(err: kvdb::Error) -> Self { Error::Database(err.to_string()) diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index f6718d6b51..74edf83ad5 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -14,7 +14,7 @@ rand = "0.4" tiny-keccak = "1.3" rust-crypto = "0.2.34" slab = "0.2" -igd = "0.6" +igd = "0.7" libc = "0.2.7" parking_lot = "0.5" ansi_term = "0.10" -- GitLab From 6cf441fc9e73c50f50d599f792cda0399d1c700c Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 11 Apr 2018 11:41:02 +0200 Subject: [PATCH 060/263] bump snappy and ring, use single rayon version, closes #8296 (#8364) --- Cargo.lock | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbc605dac5..0447506781 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1112,9 +1112,6 @@ dependencies = [ name = "gcc" version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "getopts" @@ -2625,23 +2622,6 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rayon" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rayon" version = "1.0.1" @@ -2707,12 +2687,12 @@ dependencies = [ [[package]] name = "ring" version = "0.12.1" -source = "git+https://github.com/paritytech/ring#13eec16273e5e8fbbb21def81eaeb11972f4f903" +source = "git+https://github.com/paritytech/ring#b98d7f586c0467d68e9946a5f47b4a04b9a86b4a" dependencies = [ "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2986,7 +2966,7 @@ dependencies = [ [[package]] name = "snappy" version = "0.1.0" -source = "git+https://github.com/paritytech/rust-snappy#858eac97192ea25d18d3f3626a8cc13ca0b175bb" +source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", @@ -2995,9 +2975,9 @@ dependencies = [ [[package]] name = "snappy-sys" version = "0.1.0" -source = "git+https://github.com/paritytech/rust-snappy#858eac97192ea25d18d3f3626a8cc13ca0b175bb" +source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3906,8 +3886,6 @@ dependencies = [ "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" -"checksum rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" -- GitLab From 9fe991db1cd0962851832c9fd0f2f3fdec1ed6d8 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 11 Apr 2018 11:59:04 +0200 Subject: [PATCH 061/263] util `fake-fetch` (#8363) * start * hash-fetch * rpc * revert price-info * remove used file * adapt to changes in fetch * make fake-fetch generic over * fix tests to comply with the new `fake-fetch` --- Cargo.lock | 13 ++++ Cargo.toml | 1 + hash-fetch/Cargo.toml | 1 + hash-fetch/src/client.rs | 53 ++------------- hash-fetch/src/lib.rs | 4 ++ price-info/Cargo.toml | 1 + price-info/src/lib.rs | 65 +++---------------- rpc/Cargo.toml | 1 + rpc/src/lib.rs | 3 + rpc/src/v1/tests/helpers/mod.rs | 2 - rpc/src/v1/tests/mocked/parity_set.rs | 8 ++- util/fake-fetch/Cargo.toml | 11 ++++ .../fetch.rs => util/fake-fetch/src/lib.rs | 47 ++++++++------ 13 files changed, 82 insertions(+), 128 deletions(-) create mode 100644 util/fake-fetch/Cargo.toml rename rpc/src/v1/tests/helpers/fetch.rs => util/fake-fetch/src/lib.rs (58%) diff --git a/Cargo.lock b/Cargo.lock index 0447506781..d5c7963f64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1025,6 +1025,15 @@ dependencies = [ "vm 0.1.0", ] +[[package]] +name = "fake-fetch" +version = "0.0.1" +dependencies = [ + "fetch 0.1.0", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fdlimit" version = "0.1.1" @@ -1940,6 +1949,7 @@ dependencies = [ "ethcore-transaction 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", + "fake-fetch 0.0.1", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2063,6 +2073,7 @@ dependencies = [ "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-fetch 0.0.1", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2148,6 +2159,7 @@ dependencies = [ "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", + "fake-fetch 0.0.1", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2465,6 +2477,7 @@ dependencies = [ name = "price-info" version = "1.11.0" dependencies = [ + "fake-fetch 0.0.1", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 09c00b3386..291e157cc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,7 @@ rustc_version = "0.2" pretty_assertions = "0.1" ipnetwork = "0.12.6" tempdir = "0.3" +fake-fetch = { path = "util/fake-fetch" } [target.'cfg(windows)'.dependencies] winapi = "0.2" diff --git a/hash-fetch/Cargo.toml b/hash-fetch/Cargo.toml index 12d49e648c..6a735fe37e 100644 --- a/hash-fetch/Cargo.toml +++ b/hash-fetch/Cargo.toml @@ -28,3 +28,4 @@ ethabi-contract = "5.0" [dev-dependencies] hyper = "0.11" parking_lot = "0.5" +fake-fetch = { path = "../util/fake-fetch" } diff --git a/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index 201d65ba79..1c7d417758 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -193,53 +193,14 @@ fn random_temp_path() -> PathBuf { #[cfg(test)] mod tests { - extern crate hyper; + use fake_fetch::FakeFetch; use rustc_hex::FromHex; use std::sync::{Arc, mpsc}; use parking_lot::Mutex; - use futures::future; use futures_cpupool::CpuPool; - use fetch::{self, Fetch, Url, Request}; use parity_reactor::Remote; use urlhint::tests::{FakeRegistrar, URLHINT}; use super::{Error, Client, HashFetch, random_temp_path}; - use self::hyper::StatusCode; - - - #[derive(Clone)] - struct FakeFetch { - return_success: bool - } - - impl Fetch for FakeFetch { - type Result = future::Ok; - - fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { - assert_eq!(request.url().as_str(), "https://parity.io/assets/images/ethcore-black-horizontal.png"); - let u = request.url().clone(); - future::ok(if self.return_success { - fetch::client::Response::new(u, hyper::Response::new().with_body(&b"result"[..]), abort) - } else { - fetch::client::Response::new(u, hyper::Response::new().with_status(StatusCode::NotFound), abort) - }) - } - - fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return future::err(e.into()) - }; - self.fetch(Request::get(url), abort) - } - - fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return future::err(e.into()) - }; - self.fetch(Request::post(url), abort) - } - } fn registrar() -> FakeRegistrar { let mut registrar = FakeRegistrar::new(); @@ -254,7 +215,7 @@ mod tests { fn should_return_error_if_hash_not_found() { // given let contract = Arc::new(FakeRegistrar::new()); - let fetch = FakeFetch { return_success: false }; + let fetch = FakeFetch::new(None::); let client = Client::with_fetch(contract.clone(), CpuPool::new(1), fetch, Remote::new_sync()); // when @@ -272,7 +233,7 @@ mod tests { fn should_return_error_if_response_is_not_successful() { // given let registrar = Arc::new(registrar()); - let fetch = FakeFetch { return_success: false }; + let fetch = FakeFetch::new(None::); let client = Client::with_fetch(registrar.clone(), CpuPool::new(1), fetch, Remote::new_sync()); // when @@ -290,7 +251,7 @@ mod tests { fn should_return_hash_mismatch() { // given let registrar = Arc::new(registrar()); - let fetch = FakeFetch { return_success: true }; + let fetch = FakeFetch::new(Some(1)); let mut client = Client::with_fetch(registrar.clone(), CpuPool::new(1), fetch, Remote::new_sync()); let path = random_temp_path(); let path2 = path.clone(); @@ -304,7 +265,7 @@ mod tests { // then let result = rx.recv().unwrap(); - let hash = "0x06b0a4f426f6713234b2d4b2468640bc4e0bb72657a920ad24c5087153c593c8".into(); + let hash = "0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".into(); assert_eq!(result.unwrap_err(), Error::HashMismatch { expected: 2.into(), got: hash }); assert!(!path.exists(), "Temporary file should be removed."); } @@ -313,12 +274,12 @@ mod tests { fn should_return_path_if_hash_matches() { // given let registrar = Arc::new(registrar()); - let fetch = FakeFetch { return_success: true }; + let fetch = FakeFetch::new(Some(1)); let client = Client::with_fetch(registrar.clone(), CpuPool::new(1), fetch, Remote::new_sync()); // when let (tx, rx) = mpsc::channel(); - client.fetch("0x06b0a4f426f6713234b2d4b2468640bc4e0bb72657a920ad24c5087153c593c8".into(), + client.fetch("0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".into(), Default::default(), Box::new(move |result| { tx.send(result).unwrap(); })); diff --git a/hash-fetch/src/lib.rs b/hash-fetch/src/lib.rs index 6e74982bb8..18176be500 100644 --- a/hash-fetch/src/lib.rs +++ b/hash-fetch/src/lib.rs @@ -42,6 +42,10 @@ extern crate ethabi_derive; extern crate ethabi_contract; #[cfg(test)] extern crate parking_lot; +#[cfg(test)] +extern crate hyper; +#[cfg(test)] +extern crate fake_fetch; mod client; diff --git a/price-info/Cargo.toml b/price-info/Cargo.toml index 5122ebb9dd..8dd497be9a 100644 --- a/price-info/Cargo.toml +++ b/price-info/Cargo.toml @@ -16,3 +16,4 @@ serde_json = "1.0" [dev-dependencies] hyper = "0.11" parking_lot = "0.5" +fake-fetch = { path = "../util/fake-fetch" } diff --git a/price-info/src/lib.rs b/price-info/src/lib.rs index 8b87f0c11d..9685fc7eee 100644 --- a/price-info/src/lib.rs +++ b/price-info/src/lib.rs @@ -25,6 +25,9 @@ extern crate serde_json; #[macro_use] extern crate log; +#[cfg(test)] +extern crate fake_fetch; + pub extern crate fetch; use std::cmp; @@ -133,68 +136,18 @@ impl Client { #[cfg(test)] mod test { - extern crate hyper; - extern crate parking_lot; - - use self::parking_lot::Mutex; use std::sync::Arc; - use std::sync::atomic::{AtomicBool, Ordering}; - use fetch; - use fetch::{Fetch, Url, Request}; use futures_cpupool::CpuPool; - use futures::future::{self, FutureResult}; use Client; - use self::hyper::StatusCode; - - #[derive(Clone)] - struct FakeFetch(Option, Arc>); - - impl FakeFetch { - fn new() -> Result { - Ok(FakeFetch(None, Default::default())) - } - } - - impl Fetch for FakeFetch { - type Result = FutureResult; - - fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { - assert_eq!(request.url().as_str(), "https://api.etherscan.io/api?module=stats&action=ethprice"); - let u = request.url().clone(); - let mut val = self.1.lock(); - *val = *val + 1; - if let Some(ref response) = self.0 { - let r = hyper::Response::new().with_body(response.clone()); - future::ok(fetch::client::Response::new(u, r, abort)) - } else { - let r = hyper::Response::new().with_status(StatusCode::NotFound); - future::ok(fetch::client::Response::new(u, r, abort)) - } - } - - fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return future::err(e.into()) - }; - self.fetch(Request::get(url), abort) - } - - fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return future::err(e.into()) - }; - self.fetch(Request::post(url), abort) - } - } + use std::sync::atomic::{AtomicBool, Ordering}; + use fake_fetch::FakeFetch; - fn price_info_ok(response: &str) -> Client { - Client::new(FakeFetch(Some(response.to_owned()), Default::default()), CpuPool::new(1)) + fn price_info_ok(response: &str) -> Client> { + Client::new(FakeFetch::new(Some(response.to_owned())), CpuPool::new(1)) } - fn price_info_not_found() -> Client { - Client::new(FakeFetch::new().unwrap(), CpuPool::new(1)) + fn price_info_not_found() -> Client> { + Client::new(FakeFetch::new(None::), CpuPool::new(1)) } #[test] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index c467f05537..a0639c4ccc 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -70,3 +70,4 @@ pretty_assertions = "0.1" macros = { path = "../util/macros" } ethcore-network = { path = "../util/network" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } +fake-fetch = { path = "../util/fake-fetch" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 1a0989d4a2..f3ba68a065 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -91,6 +91,9 @@ extern crate macros; #[cfg(test)] extern crate kvdb_memorydb; +#[cfg(test)] +extern crate fake_fetch; + extern crate tempdir; pub extern crate jsonrpc_ws_server as ws; diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index aae48a2d28..8e1aeeb147 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -17,14 +17,12 @@ //! Test rpc services. mod dapps; -mod fetch; mod miner_service; mod snapshot_service; mod sync_provider; mod update_service; pub use self::dapps::TestDappsService; -pub use self::fetch::TestFetch; pub use self::miner_service::TestMinerService; pub use self::snapshot_service::TestSnapshotService; pub use self::sync_provider::{Config, TestSyncProvider}; diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index 2ae8ab5b2b..af08236fdf 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -26,9 +26,11 @@ use futures_cpupool::CpuPool; use jsonrpc_core::IoHandler; use v1::{ParitySet, ParitySetClient}; -use v1::tests::helpers::{TestMinerService, TestFetch, TestUpdater, TestDappsService}; +use v1::tests::helpers::{TestMinerService, TestUpdater, TestDappsService}; use super::manage_network::TestManageNetwork; +use fake_fetch::FakeFetch; + fn miner_service() -> Arc { Arc::new(TestMinerService::default()) } @@ -45,7 +47,7 @@ fn updater_service() -> Arc { Arc::new(TestUpdater::default()) } -pub type TestParitySetClient = ParitySetClient; +pub type TestParitySetClient = ParitySetClient>; fn parity_set_client( client: &Arc, @@ -55,7 +57,7 @@ fn parity_set_client( ) -> TestParitySetClient { let dapps_service = Arc::new(TestDappsService); let pool = CpuPool::new(1); - ParitySetClient::new(client, miner, updater, &(net.clone() as Arc), Some(dapps_service), TestFetch::default(), pool) + ParitySetClient::new(client, miner, updater, &(net.clone() as Arc), Some(dapps_service), FakeFetch::new(Some(1)), pool) } #[test] diff --git a/util/fake-fetch/Cargo.toml b/util/fake-fetch/Cargo.toml new file mode 100644 index 0000000000..217d7f461a --- /dev/null +++ b/util/fake-fetch/Cargo.toml @@ -0,0 +1,11 @@ +[package] +description = "Mock fetcher for testing" +name = "fake-fetch" +version = "0.0.1" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[dependencies] +fetch = { path = "../fetch" } +futures = "0.1" +hyper = "0.11" diff --git a/rpc/src/v1/tests/helpers/fetch.rs b/util/fake-fetch/src/lib.rs similarity index 58% rename from rpc/src/v1/tests/helpers/fetch.rs rename to util/fake-fetch/src/lib.rs index 7de3949c4b..9dbe05b9ca 100644 --- a/rpc/src/v1/tests/helpers/fetch.rs +++ b/util/fake-fetch/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,37 +14,42 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Test implementation of fetch client. +extern crate fetch; +extern crate hyper; +extern crate futures; -use std::thread; -use std::boxed::Box; -use jsonrpc_core::futures::{self, Future}; -use fetch::{self, Fetch, Url, Request}; -use futures::future; -use hyper; +use hyper::StatusCode; +use futures::{future, future::FutureResult}; +use fetch::{Fetch, Url, Request}; -/// Test implementation of fetcher. Will always return the same file. -#[derive(Default, Clone)] -pub struct TestFetch; +#[derive(Clone, Default)] +pub struct FakeFetch where T: Clone + Send + Sync { + val: Option, +} -impl Fetch for TestFetch { - type Result = Box + Send + 'static>; +impl FakeFetch where T: Clone + Send + Sync { + pub fn new(t: Option) -> Self { + FakeFetch { val : t } + } +} + +impl Fetch for FakeFetch where T: Clone + Send+ Sync { + type Result = FutureResult; fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { let u = request.url().clone(); - let (tx, rx) = futures::oneshot(); - thread::spawn(move || { + future::ok(if self.val.is_some() { let r = hyper::Response::new().with_body(&b"Some content"[..]); - tx.send(fetch::Response::new(u, r, abort)).unwrap(); - }); - - Box::new(rx.map_err(|_| fetch::Error::Aborted)) + fetch::client::Response::new(u, r, abort) + } else { + fetch::client::Response::new(u, hyper::Response::new().with_status(StatusCode::NotFound), abort) + }) } fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result { let url: Url = match url.parse() { Ok(u) => u, - Err(e) => return Box::new(future::err(e.into())) + Err(e) => return future::err(e.into()) }; self.fetch(Request::get(url), abort) } @@ -52,7 +57,7 @@ impl Fetch for TestFetch { fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result { let url: Url = match url.parse() { Ok(u) => u, - Err(e) => return Box::new(future::err(e.into())) + Err(e) => return future::err(e.into()) }; self.fetch(Request::post(url), abort) } -- GitLab From 6737484eda25aa9c5bc816e8318c8ce1f133c68b Mon Sep 17 00:00:00 2001 From: Thibaut S <33178835+Tbaut@users.noreply.github.com> Date: Wed, 11 Apr 2018 12:10:57 +0200 Subject: [PATCH 062/263] Increase gasLimit to 8'000'000 (#8362) - fix https://github.com/paritytech/parity/issues/8342 --- ethcore/res/instant_seal.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index e01c927ffd..acd1b49ed0 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -24,7 +24,7 @@ "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "extraData": "0x", - "gasLimit": "0x5B8D80" + "gasLimit": "0x7A1200" }, "accounts": { "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, -- GitLab From dd2c27958cfaabfab040a1cd583eee60c16ec2b1 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 11 Apr 2018 12:56:37 +0200 Subject: [PATCH 063/263] use atty instead of isatty (#8365) --- Cargo.lock | 45 +++++++++++++++++++++++++++------------------ Cargo.toml | 2 +- logger/Cargo.toml | 2 +- logger/src/lib.rs | 14 +++++++------- parity/informant.rs | 4 ++-- parity/main.rs | 2 +- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5c7963f64..6315a88c2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,12 +40,12 @@ dependencies = [ [[package]] name = "atty" -version = "0.2.2" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -220,7 +220,7 @@ version = "2.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -635,8 +635,8 @@ version = "1.11.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1298,16 +1298,6 @@ name = "ipnetwork" version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "isatty" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itertools" version = "0.5.10" @@ -1927,6 +1917,7 @@ version = "1.11.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)", "daemonize 0.2.3 (git+https://github.com/paritytech/daemonize)", @@ -1954,7 +1945,6 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", - "isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "keccak-hash 0.1.0", @@ -2661,6 +2651,14 @@ name = "redox_syscall" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex" version = "0.2.5" @@ -3125,6 +3123,16 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "textwrap" version = "0.9.0" @@ -3735,7 +3743,7 @@ dependencies = [ "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" -"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" +"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" "checksum backtrace-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c63ea141ef8fdb10409d0f5daf30ac51f84ef43bff66f16627773d2a292cd189" "checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1" @@ -3812,7 +3820,6 @@ dependencies = [ "checksum interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "141340095b15ed7491bd3d4ced9d20cebfb826174b6bb03386381f62b01e3d77" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2134e210e2a024b5684f90e1556d5f71a1ce7f8b12e9ac9924c67fb36f63b336" -"checksum isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa500db770a99afe2a0f2229be2a3d09c7ed9d7e4e8440bf71253141994e240f" "checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)" = "" @@ -3902,6 +3909,7 @@ dependencies = [ "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" @@ -3953,6 +3961,7 @@ dependencies = [ "checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" diff --git a/Cargo.toml b/Cargo.toml index 291e157cc4..b6c573a23b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ semver = "0.9" ansi_term = "0.10" parking_lot = "0.5" regex = "0.2" -isatty = "0.1" +atty = "0.2.8" toml = "0.4" serde = "1.0" serde_json = "1.0" diff --git a/logger/Cargo.toml b/logger/Cargo.toml index 0e1b03f941..368d860fd4 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Parity Technologies "] [dependencies] log = "0.3" env_logger = "0.4" -isatty = "0.1" +atty = "0.2" lazy_static = "1.0" regex = "0.2" time = "0.1" diff --git a/logger/src/lib.rs b/logger/src/lib.rs index a2cf6d2a02..863075a0e5 100644 --- a/logger/src/lib.rs +++ b/logger/src/lib.rs @@ -16,23 +16,23 @@ //! Logger for parity executables +extern crate ansi_term; extern crate arrayvec; +extern crate atty; +extern crate env_logger; extern crate log as rlog; -extern crate isatty; +extern crate parking_lot; extern crate regex; -extern crate env_logger; extern crate time; + #[macro_use] extern crate lazy_static; -extern crate parking_lot; -extern crate ansi_term; mod rotating; use std::{env, thread, fs}; use std::sync::{Weak, Arc}; use std::io::Write; -use isatty::{stderr_isatty, stdout_isatty}; use env_logger::LogBuilder; use regex::Regex; use ansi_term::Colour; @@ -86,7 +86,7 @@ pub fn setup_log(config: &Config) -> Result, String> { builder.parse(s); } - let isatty = stderr_isatty(); + let isatty = atty::is(atty::Stream::Stderr); let enable_color = config.color && isatty; let logs = Arc::new(RotatingLogger::new(levels)); let logger = logs.clone(); @@ -122,7 +122,7 @@ pub fn setup_log(config: &Config) -> Result, String> { let _ = file.write_all(b"\n"); } logger.append(removed_color); - if !isatty && record.level() <= LogLevel::Info && stdout_isatty() { + if !isatty && record.level() <= LogLevel::Info && atty::is(atty::Stream::Stdout) { // duplicate INFO/WARN output to console println!("{}", ret); } diff --git a/parity/informant.rs b/parity/informant.rs index 2ccc622a70..fddcadebd8 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -22,6 +22,7 @@ use std::sync::{Arc}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::time::{Instant, Duration}; +use atty; use ethcore::client::{ BlockId, BlockChainClient, ChainInfo, BlockInfo, BlockChainInfo, BlockQueueInfo, ChainNotify, ClientReport, Client, ClientIoMessage @@ -31,7 +32,6 @@ use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; use ethcore::snapshot::service::Service as SnapshotService; use sync::{LightSyncProvider, LightSync, SyncProvider, ManageNetwork}; use io::{TimerToken, IoContext, IoHandler}; -use isatty::{stdout_isatty}; use light::Cache as LightDataCache; use light::client::LightChainClient; use number_prefix::{binary_prefix, Standalone, Prefixed}; @@ -293,7 +293,7 @@ impl Informant { *self.last_tick.write() = Instant::now(); - let paint = |c: Style, t: String| match self.with_color && stdout_isatty() { + let paint = |c: Style, t: String| match self.with_color && atty::is(atty::Stream::Stdout) { true => format!("{}", c.paint(t)), false => t, }; diff --git a/parity/main.rs b/parity/main.rs index 7179996bf5..4908f38d9a 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -29,7 +29,7 @@ extern crate env_logger; extern crate fdlimit; extern crate futures; extern crate futures_cpupool; -extern crate isatty; +extern crate atty; extern crate jsonrpc_core; extern crate num_cpus; extern crate number_prefix; -- GitLab From 2b05eb43a989fae5239e01fa93da294c43ec7d99 Mon Sep 17 00:00:00 2001 From: Toralf Wittner Date: Wed, 11 Apr 2018 13:57:12 +0200 Subject: [PATCH 064/263] Add `util/mem` to zero out memory on drop. (#8356) * Add `util/mem` to zero out memory on drop. * Remove nonsense. * Remove `Into` impls for `Memzero`. * Update ethereum-types and remove H256Mut. --- Cargo.lock | 107 ++++++++++-------- Cargo.toml | 1 + .../src/snapshot/tests/proof_of_authority.rs | 2 +- ethcore/transaction/src/transaction.rs | 2 +- ethkey/Cargo.toml | 1 + ethkey/src/extended.rs | 4 +- ethkey/src/lib.rs | 1 + ethkey/src/secret.rs | 30 +++-- rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/tests/mocked/signing.rs | 2 +- secret_store/src/key_server.rs | 8 +- .../client_sessions/decryption_session.rs | 4 +- secret_store/src/key_server_cluster/math.rs | 4 +- util/mem/Cargo.toml | 6 + util/mem/src/lib.rs | 57 ++++++++++ whisper/Cargo.toml | 1 + whisper/src/lib.rs | 1 + whisper/src/rpc/crypto.rs | 40 ++++--- whisper/src/rpc/key_store.rs | 9 +- whisper/src/rpc/mod.rs | 3 +- 20 files changed, 190 insertions(+), 95 deletions(-) create mode 100644 util/mem/Cargo.toml create mode 100644 util/mem/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6315a88c2d..9456324fda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,7 +233,7 @@ name = "common-types" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -362,7 +362,7 @@ name = "dir" version = "0.1.0" dependencies = [ "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", ] @@ -434,7 +434,7 @@ version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -479,7 +479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -505,7 +505,7 @@ dependencies = [ "ethcore-miner 1.11.0", "ethcore-stratum 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -571,7 +571,7 @@ name = "ethcore-crypto" version = "0.1.0" dependencies = [ "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -603,7 +603,7 @@ dependencies = [ "ethcore-io 1.11.0", "ethcore-network 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -661,7 +661,7 @@ dependencies = [ "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -685,7 +685,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-io 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -704,7 +704,7 @@ dependencies = [ "ethcore-io 1.11.0", "ethcore-logger 1.11.0", "ethcore-network 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -742,7 +742,7 @@ dependencies = [ "ethcore-logger 1.11.0", "ethcore-miner 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "fetch 0.1.0", @@ -776,7 +776,7 @@ dependencies = [ "ethcore-logger 1.11.0", "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -824,7 +824,7 @@ version = "1.11.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -847,7 +847,7 @@ dependencies = [ "ethcore-network 1.11.0", "ethcore-network-devp2p 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ dependencies = [ name = "ethcore-transaction" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "evm 0.1.0", @@ -883,13 +883,13 @@ dependencies = [ [[package]] name = "ethereum-types" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -907,7 +907,7 @@ dependencies = [ name = "ethjson" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -921,9 +921,10 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mem 0.1.0", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -952,7 +953,7 @@ version = "0.2.0" dependencies = [ "dir 0.1.0", "ethcore-crypto 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -994,7 +995,7 @@ name = "evm" version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1013,7 +1014,7 @@ dependencies = [ "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "evm 0.1.0", "panic_hook 0.1.0", @@ -1058,7 +1059,7 @@ dependencies = [ [[package]] name = "fixed-hash" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1153,7 +1154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "hardware-wallet" version = "1.11.0" dependencies = [ - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", @@ -1169,7 +1170,7 @@ name = "hashdb" version = "0.1.1" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1317,7 +1318,7 @@ version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -1432,7 +1433,7 @@ name = "keccak-hash" version = "0.1.0" dependencies = [ "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1468,7 +1469,7 @@ name = "kvdb-rocksdb" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1576,6 +1577,10 @@ name = "matches" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "mem" +version = "0.1.0" + [[package]] name = "memchr" version = "2.0.1" @@ -1617,7 +1622,7 @@ version = "0.1.1" dependencies = [ "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -1764,7 +1769,7 @@ dependencies = [ "ethcore 1.11.0", "ethcore-io 1.11.0", "ethcore-network-devp2p 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1938,7 +1943,7 @@ dependencies = [ "ethcore-stratum 1.11.0", "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fake-fetch 0.0.1", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1951,6 +1956,7 @@ dependencies = [ "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mem 0.1.0", "migration 0.1.0", "node-filter 1.11.0", "node-health 0.1.0", @@ -1997,7 +2003,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-devtools 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2062,7 +2068,7 @@ dependencies = [ "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-fetch 0.0.1", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2086,7 +2092,7 @@ dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2115,7 +2121,7 @@ dependencies = [ name = "parity-machine" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2145,7 +2151,7 @@ dependencies = [ "ethcore-private-tx 1.0.0", "ethcore-sync 1.11.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -2284,7 +2290,7 @@ dependencies = [ "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-sync 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2329,13 +2335,14 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-network 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mem 0.1.0", "ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2391,7 +2398,7 @@ dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-logger 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2447,7 +2454,7 @@ name = "plain_hasher" version = "0.1.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2546,7 +2553,7 @@ version = "0.1.0" dependencies = [ "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2714,7 +2721,7 @@ version = "0.2.1" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3394,7 +3401,7 @@ name = "transaction-pool" version = "1.11.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3420,7 +3427,7 @@ name = "trie-standardmap" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "rlp 0.2.1", ] @@ -3430,7 +3437,7 @@ name = "triehash" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "rlp 0.2.1", "trie-standardmap 0.1.0", @@ -3545,7 +3552,7 @@ name = "util-error" version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3577,7 +3584,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3596,7 +3603,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.11.0", - "ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3791,10 +3798,10 @@ dependencies = [ "checksum ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca2263c24359e827348ac99aa1f2e28ba5bab0d6c0b83941fa252de8a9e9c073" "checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" -"checksum ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53eabbad504e438e20b6559fd070d79b92cb31c02f994c7ecb05e9b2df716013" +"checksum ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3ae691a36ce5d25b433e63128ce5579f4a18457b6a9c849832b2c9e0fec92a" "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" -"checksum fixed-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "362f32e2fbc5ed45f01a23ca074f936bb3aee4122a66e7118e8c3e965d96104c" +"checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" "checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" diff --git a/Cargo.toml b/Cargo.toml index b6c573a23b..ffeb01ef87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ migration = { path = "util/migration" } kvdb = { path = "util/kvdb" } kvdb-rocksdb = { path = "util/kvdb-rocksdb" } journaldb = { path = "util/journaldb" } +mem = { path = "util/mem" } parity-dapps = { path = "dapps", optional = true } ethcore-secretstore = { path = "secret_store", optional = true } diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index 7283a05863..b0741b4c49 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -39,7 +39,7 @@ const TRANSITION_BLOCK_1: usize = 2; // block at which the contract becomes acti const TRANSITION_BLOCK_2: usize = 10; // block at which the second contract activates. macro_rules! secret { - ($e: expr) => { Secret::from_slice(&$crate::hash::keccak($e)) } + ($e: expr) => { Secret::from($crate::hash::keccak($e).0) } } lazy_static! { diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 4df63294bd..49f2534fac 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -141,7 +141,7 @@ impl HeapSizeOf for Transaction { impl From for SignedTransaction { fn from(t: ethjson::state::Transaction) -> Self { let to: Option = t.to.into(); - let secret = t.secret.map(|s| Secret::from_slice(&s.0)); + let secret = t.secret.map(|s| Secret::from(s.0)); let tx = Transaction { nonce: t.nonce.into(), gas_price: t.gas_price.into(), diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index 51052bdca6..335f92fe15 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -10,6 +10,7 @@ eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } ethereum-types = "0.3" lazy_static = "1.0" log = "0.3" +mem = { path = "../util/mem" } parity-wordlist = "1.2" rand = "0.4" rust-crypto = "0.2" diff --git a/ethkey/src/extended.rs b/ethkey/src/extended.rs index 23aff0bee8..55bae62754 100644 --- a/ethkey/src/extended.rs +++ b/ethkey/src/extended.rs @@ -99,7 +99,7 @@ impl ExtendedSecret { pub fn derive(&self, index: Derivation) -> ExtendedSecret where T: Label { let (derived_key, next_chain_code) = derivation::private(*self.secret, self.chain_code, index); - let derived_secret = Secret::from_slice(&*derived_key); + let derived_secret = Secret::from(derived_key.0); ExtendedSecret::with_code(derived_secret, next_chain_code) } @@ -399,7 +399,7 @@ mod tests { fn test_extended(f: F, test_private: H256) where F: Fn(ExtendedSecret) -> ExtendedSecret { let (private_seed, chain_code) = master_chain_basic(); - let extended_secret = ExtendedSecret::with_code(Secret::from_slice(&*private_seed), chain_code); + let extended_secret = ExtendedSecret::with_code(Secret::from(private_seed.0), chain_code); let derived = f(extended_secret); assert_eq!(**derived.as_raw(), test_private); } diff --git a/ethkey/src/lib.rs b/ethkey/src/lib.rs index 09a100b74c..951179771b 100644 --- a/ethkey/src/lib.rs +++ b/ethkey/src/lib.rs @@ -20,6 +20,7 @@ extern crate byteorder; extern crate crypto as rcrypto; extern crate edit_distance; extern crate ethereum_types; +extern crate mem; extern crate parity_wordlist; extern crate rand; extern crate rustc_hex; diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index 9b2faee7c6..c3bf2a12ba 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -18,18 +18,20 @@ use std::fmt; use std::ops::Deref; use std::str::FromStr; use rustc_hex::ToHex; +use secp256k1::constants::{SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE}; use secp256k1::key; use ethereum_types::H256; +use mem::Memzero; use {Error, SECP256K1}; #[derive(Clone, PartialEq, Eq)] pub struct Secret { - inner: H256, + inner: Memzero, } impl ToHex for Secret { fn to_hex(&self) -> String { - format!("{:x}", self.inner) + format!("{:x}", *self.inner) } } @@ -52,17 +54,19 @@ impl fmt::Display for Secret { } impl Secret { - pub fn from_slice(key: &[u8]) -> Self { - assert_eq!(32, key.len(), "Caller should provide 32-byte length slice"); - + /// Creates a `Secret` from the given slice, returning `None` if the slice length != 32. + pub fn from_slice(key: &[u8]) -> Option { + if key.len() != 32 { + return None + } let mut h = H256::default(); h.copy_from_slice(&key[0..32]); - Secret { inner: h } + Some(Secret { inner: Memzero::from(h) }) } /// Creates zero key, which is invalid for crypto operations, but valid for math operation. pub fn zero() -> Self { - Secret { inner: Default::default() } + Secret { inner: Memzero::from(H256::default()) } } /// Imports and validates the key. @@ -208,9 +212,15 @@ impl FromStr for Secret { } } +impl From<[u8; 32]> for Secret { + fn from(k: [u8; 32]) -> Self { + Secret { inner: Memzero::from(H256(k)) } + } +} + impl From for Secret { fn from(s: H256) -> Self { - Secret::from_slice(&s) + s.0.into() } } @@ -222,7 +232,9 @@ impl From<&'static str> for Secret { impl From for Secret { fn from(key: key::SecretKey) -> Self { - Self::from_slice(&key[0..32]) + let mut a = [0; SECP256K1_SECRET_KEY_SIZE]; + a.copy_from_slice(&key[0 .. SECP256K1_SECRET_KEY_SIZE]); + a.into() } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index e79411f705..c79b02c2d2 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -329,7 +329,7 @@ fn rpc_eth_submit_hashrate() { fn rpc_eth_sign() { let tester = EthTester::default(); - let account = tester.accounts_provider.insert_account(Secret::from_slice(&[69u8; 32]), "abcd").unwrap(); + let account = tester.accounts_provider.insert_account(Secret::from([69u8; 32]), "abcd").unwrap(); tester.accounts_provider.unlock_account_permanently(account, "abcd".into()).unwrap(); let _message = "0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f".from_hex().unwrap(); diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 11e1ac44d4..118bbe91ce 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -211,7 +211,7 @@ fn should_sign_if_account_is_unlocked() { // given let tester = eth_signing(); let data = vec![5u8]; - let acc = tester.accounts.insert_account(Secret::from_slice(&[69u8; 32]), "test").unwrap(); + let acc = tester.accounts.insert_account(Secret::from([69u8; 32]), "test").unwrap(); tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap(); // when diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs index 783e760455..ea3a3c0a57 100644 --- a/secret_store/src/key_server.rs +++ b/secret_store/src/key_server.rs @@ -443,8 +443,8 @@ pub mod tests { let message_hash = H256::from(42); let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); let combined_signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap(); - let signature_c = Secret::from_slice(&combined_signature[..32]); - let signature_s = Secret::from_slice(&combined_signature[32..]); + let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap(); + let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap(); // check signature assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true)); @@ -492,8 +492,8 @@ pub mod tests { let message_hash = H256::from(42); let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap(); let combined_signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap(); - let signature_c = Secret::from_slice(&combined_signature[..32]); - let signature_s = Secret::from_slice(&combined_signature[32..]); + let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap(); + let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap(); // check signature assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true)); diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs index 3343652c2b..c47dd26bad 100644 --- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs @@ -1272,7 +1272,7 @@ mod tests { use crypto::DEFAULT_MAC; use crypto::ecies::decrypt; let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter() - .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap())) + .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap()) .collect(); let decrypted_secret = math::decrypt_with_shadow_coefficients(decrypted_secret.decrypted_secret, decrypted_secret.common_point.unwrap(), decrypt_shadows).unwrap(); assert_eq!(decrypted_secret, SECRET_PLAIN.into()); @@ -1418,7 +1418,7 @@ mod tests { let result = sessions[0].decrypted_secret().unwrap().unwrap(); assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == Some(Ok(result.clone()))).count()); let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter() - .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap())) + .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap()) .collect(); let decrypted_secret = math::decrypt_with_shadow_coefficients(result.decrypted_secret, result.common_point.unwrap(), decrypt_shadows).unwrap(); assert_eq!(decrypted_secret, SECRET_PLAIN.into()); diff --git a/secret_store/src/key_server_cluster/math.rs b/secret_store/src/key_server_cluster/math.rs index 78c444822b..ef6d88f67c 100644 --- a/secret_store/src/key_server_cluster/math.rs +++ b/secret_store/src/key_server_cluster/math.rs @@ -37,7 +37,7 @@ pub fn zero_scalar() -> Secret { pub fn to_scalar(hash: H256) -> Result { let scalar: U256 = hash.into(); let scalar: H256 = (scalar % math::curve_order()).into(); - let scalar = Secret::from_slice(&*scalar); + let scalar = Secret::from(scalar.0); scalar.check_validity()?; Ok(scalar) } @@ -697,7 +697,7 @@ pub mod tests { // === required to generate shares of inv(x) mod r with out revealing // === any information about x or inv(x). // === https://www.researchgate.net/publication/280531698_Robust_Threshold_Elliptic_Curve_Digital_Signature - + // generate shared random secret e for given t let n = artifacts.id_numbers.len(); assert!(t * 2 + 1 <= n); diff --git a/util/mem/Cargo.toml b/util/mem/Cargo.toml new file mode 100644 index 0000000000..1cca222142 --- /dev/null +++ b/util/mem/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "mem" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] diff --git a/util/mem/src/lib.rs b/util/mem/src/lib.rs new file mode 100644 index 0000000000..a8b9e53f66 --- /dev/null +++ b/util/mem/src/lib.rs @@ -0,0 +1,57 @@ +// Copyright 2018 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 . + +use std::ops::{Deref, DerefMut}; +use std::ptr; + +/// Wrapper to zero out memory when dropped. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Memzero> { + mem: T, +} + +impl> From for Memzero { + fn from(mem: T) -> Memzero { + Memzero { mem } + } +} + +impl> Drop for Memzero { + fn drop(&mut self) { + let n = self.mem.as_mut().len(); + let p = self.mem.as_mut().as_mut_ptr(); + for i in 0..n { + unsafe { + ptr::write_volatile(p.offset(i as isize), 0) + } + } + } +} + +impl> Deref for Memzero { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.mem + } +} + +impl> DerefMut for Memzero { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.mem + } +} + diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index 49d4dffede..bd1fc2dbb0 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -13,6 +13,7 @@ ethcore-crypto = { path = "../ethcore/crypto" } ethkey = { path = "../ethkey" } hex = "0.2" log = "0.3" +mem = { path = "../util/mem" } ordered-float = "0.5" parking_lot = "0.5" rand = "0.4" diff --git a/whisper/src/lib.rs b/whisper/src/lib.rs index bcee122ec0..4aa1a99b9e 100644 --- a/whisper/src/lib.rs +++ b/whisper/src/lib.rs @@ -23,6 +23,7 @@ extern crate ethcore_network as network; extern crate ethereum_types; extern crate ethkey; extern crate hex; +extern crate mem; extern crate ordered_float; extern crate parking_lot; extern crate rand; diff --git a/whisper/src/rpc/crypto.rs b/whisper/src/rpc/crypto.rs index e7782a0772..8780045b47 100644 --- a/whisper/src/rpc/crypto.rs +++ b/whisper/src/rpc/crypto.rs @@ -19,6 +19,7 @@ use crypto; use ethereum_types::H256; use ethkey::{self, Public, Secret}; +use mem::Memzero; use ring::aead::{self, AES_256_GCM, SealingKey, OpeningKey}; /// Length of AES key @@ -36,7 +37,7 @@ enum AesEncode { } enum EncryptionInner { - AES([u8; AES_KEY_LEN], [u8; AES_NONCE_LEN], AesEncode), + AES(Memzero<[u8; AES_KEY_LEN]>, [u8; AES_NONCE_LEN], AesEncode), ECIES(Public), } @@ -58,7 +59,7 @@ impl EncryptionInstance { /// /// If generating nonces with a secure RNG, limit uses such that /// the chance of collision is negligible. - pub fn aes(key: [u8; AES_KEY_LEN], nonce: [u8; AES_NONCE_LEN]) -> Self { + pub fn aes(key: Memzero<[u8; AES_KEY_LEN]>, nonce: [u8; AES_NONCE_LEN]) -> Self { EncryptionInstance(EncryptionInner::AES(key, nonce, AesEncode::AppendedNonce)) } @@ -66,7 +67,7 @@ impl EncryptionInstance { /// /// Key reuse here is extremely dangerous. It should be randomly generated /// with a secure RNG. - pub fn broadcast(key: [u8; AES_KEY_LEN], topics: Vec) -> Self { + pub fn broadcast(key: Memzero<[u8; AES_KEY_LEN]>, topics: Vec) -> Self { EncryptionInstance(EncryptionInner::AES(key, BROADCAST_IV, AesEncode::OnTopics(topics))) } @@ -74,7 +75,7 @@ impl EncryptionInstance { pub fn encrypt(self, plain: &[u8]) -> Vec { match self.0 { EncryptionInner::AES(key, nonce, encode) => { - let sealing_key = SealingKey::new(&AES_256_GCM, &key) + let sealing_key = SealingKey::new(&AES_256_GCM, &*key) .expect("key is of correct len; qed"); let encrypt_plain = move |buf: &mut Vec| { @@ -106,12 +107,10 @@ impl EncryptionInstance { } AesEncode::OnTopics(topics) => { let mut buf = Vec::new(); - let key = H256(key); - - for topic in topics { - buf.extend(&*(topic ^ key)); + for mut t in topics { + xor(&mut t.0, &key); + buf.extend(&t.0); } - encrypt_plain(&mut buf); buf } @@ -125,8 +124,15 @@ impl EncryptionInstance { } } +#[inline] +fn xor(a: &mut [u8; 32], b: &[u8; 32]) { + for i in 0 .. 32 { + a[i] ^= b[i] + } +} + enum AesExtract { - AppendedNonce([u8; AES_KEY_LEN]), // extract appended nonce. + AppendedNonce(Memzero<[u8; AES_KEY_LEN]>), // extract appended nonce. OnTopics(usize, usize, H256), // number of topics, index we know, topic we know. } @@ -147,7 +153,7 @@ impl DecryptionInstance { } /// 256-bit AES GCM decryption with appended nonce. - pub fn aes(key: [u8; AES_KEY_LEN]) -> Self { + pub fn aes(key: Memzero<[u8; AES_KEY_LEN]>) -> Self { DecryptionInstance(DecryptionInner::AES(AesExtract::AppendedNonce(key))) } @@ -164,13 +170,13 @@ impl DecryptionInstance { match self.0 { DecryptionInner::AES(extract) => { let decrypt = | - key: [u8; AES_KEY_LEN], + key: Memzero<[u8; AES_KEY_LEN]>, nonce: [u8; AES_NONCE_LEN], ciphertext: &[u8] | { if ciphertext.len() < AES_256_GCM.tag_len() { return None } - let opening_key = OpeningKey::new(&AES_256_GCM, &key) + let opening_key = OpeningKey::new(&AES_256_GCM, &*key) .expect("key length is valid for mode; qed"); let mut buf = ciphertext.to_vec(); @@ -205,7 +211,7 @@ impl DecryptionInstance { let mut salted_topic = H256::new(); salted_topic.copy_from_slice(&ciphertext[(known_index * 32)..][..32]); - let key = (salted_topic ^ known_topic).0; + let key = Memzero::from((salted_topic ^ known_topic).0); let offset = num_topics * 32; decrypt(key, BROADCAST_IV, &ciphertext[offset..]) @@ -264,9 +270,9 @@ mod tests { let mut rng = OsRng::new().unwrap(); let mut test_message = move |message: &[u8]| { - let key = rng.gen(); + let key = Memzero::from(rng.gen::<[u8; 32]>()); - let instance = EncryptionInstance::aes(key, rng.gen()); + let instance = EncryptionInstance::aes(key.clone(), rng.gen()); let ciphertext = instance.encrypt(message); if !message.is_empty() { @@ -294,7 +300,7 @@ mod tests { let all_topics = (0..5).map(|_| rng.gen()).collect::>(); let known_idx = 2; let known_topic = all_topics[2]; - let key = rng.gen(); + let key = Memzero::from(rng.gen::<[u8; 32]>()); let instance = EncryptionInstance::broadcast(key, all_topics); let ciphertext = instance.encrypt(message); diff --git a/whisper/src/rpc/key_store.rs b/whisper/src/rpc/key_store.rs index f71ec5bf3b..02781e20ad 100644 --- a/whisper/src/rpc/key_store.rs +++ b/whisper/src/rpc/key_store.rs @@ -23,6 +23,7 @@ use std::collections::HashMap; use ethereum_types::H256; use ethkey::{KeyPair, Public, Secret}; +use mem::Memzero; use rand::{Rng, OsRng}; use ring::error::Unspecified; @@ -35,7 +36,7 @@ pub enum Key { /// and signing. Asymmetric(KeyPair), /// AES-256 GCM mode. Suitable for encryption, decryption, but not signing. - Symmetric([u8; AES_KEY_LEN]), + Symmetric(Memzero<[u8; AES_KEY_LEN]>), } impl Key { @@ -49,7 +50,7 @@ impl Key { /// Generate a random symmetric key with the given cryptographic RNG. pub fn new_symmetric(rng: &mut OsRng) -> Self { - Key::Symmetric(rng.gen()) + Key::Symmetric(Memzero::from(rng.gen::<[u8; 32]>())) } /// From secret asymmetric key. Fails if secret is invalid. @@ -61,7 +62,7 @@ impl Key { /// From raw symmetric key. pub fn from_raw_symmetric(key: [u8; AES_KEY_LEN]) -> Self { - Key::Symmetric(key) + Key::Symmetric(Memzero::from(key)) } /// Get a handle to the public key if this is an asymmetric key. @@ -177,7 +178,7 @@ mod tests { #[test] fn rejects_invalid_secret() { - let bad_secret = ::ethkey::Secret::from_slice(&[0xff; 32]); + let bad_secret = ::ethkey::Secret::from([0xff; 32]); assert!(Key::from_secret(bad_secret).is_err()); } diff --git a/whisper/src/rpc/mod.rs b/whisper/src/rpc/mod.rs index 039df08a87..e9e6577085 100644 --- a/whisper/src/rpc/mod.rs +++ b/whisper/src/rpc/mod.rs @@ -28,6 +28,7 @@ use jsonrpc_pubsub::{Session, PubSubMetadata, SubscriptionId}; use jsonrpc_macros::pubsub; use ethereum_types::H256; +use mem::Memzero; use parking_lot::RwLock; use self::filter::Filter; @@ -286,7 +287,7 @@ impl Whisper for WhisperClien let mut rng = OsRng::new() .map_err(|_| whisper_error("unable to acquire secure randomness"))?; - let key = rng.gen(); + let key = Memzero::from(rng.gen::<[u8; 32]>()); if req.topics.is_empty() { return Err(whisper_error("must supply at least one topic for broadcast message")); } -- GitLab From 0a9114203b8346971fdeab24e181e88a0d180d08 Mon Sep 17 00:00:00 2001 From: Maciej Hirsz Date: Wed, 11 Apr 2018 14:41:06 +0200 Subject: [PATCH 065/263] No hardcoded client name (#8368) * Fixes issues with version string if client name is substituted (required for Energy Web) --- rpc/src/v1/impls/web3.rs | 2 +- rpc/src/v1/tests/mocked/web3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index 6915af1d1e..6fd6ff7a46 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -31,7 +31,7 @@ impl Web3Client { impl Web3 for Web3Client { fn client_version(&self) -> Result { - Ok(version().to_owned().replace("Parity/", "Parity//")) + Ok(version().to_owned().replacen("/", "//", 1)) } fn sha3(&self, data: Bytes) -> Result { diff --git a/rpc/src/v1/tests/mocked/web3.rs b/rpc/src/v1/tests/mocked/web3.rs index aceb36e565..3c78d67ad3 100644 --- a/rpc/src/v1/tests/mocked/web3.rs +++ b/rpc/src/v1/tests/mocked/web3.rs @@ -24,7 +24,7 @@ fn rpc_web3_version() { let mut io = IoHandler::new(); io.extend_with(web3); - let v = version().to_owned().replace("Parity/", "Parity//"); + let v = version().to_owned().replacen("/", "//", 1); let request = r#"{"jsonrpc": "2.0", "method": "web3_clientVersion", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"VER","id":1}"#.to_owned().replace("VER", v.as_ref()); -- GitLab From 1356d6d8d55d98fc328bbf1e0c6ae4e3f64be1ee Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 11 Apr 2018 15:22:48 +0200 Subject: [PATCH 066/263] parity uses winapi 0.3.4 (#8366) * parity uses winapi 0.3.4 * remove redundant unsafe --- Cargo.lock | 3 +-- Cargo.toml | 3 +-- parity/main.rs | 7 +++---- parity/url.rs | 33 +++++++++------------------------ 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9456324fda..fb1d9ce557 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1991,8 +1991,7 @@ dependencies = [ "term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ffeb01ef87..5103c2b2b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,6 @@ app_dirs = "1.2.1" futures = "0.1" futures-cpupool = "0.1" fdlimit = "0.1" -ws2_32-sys = "0.2" ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } ethcore = { path = "ethcore" } @@ -86,7 +85,7 @@ tempdir = "0.3" fake-fetch = { path = "util/fake-fetch" } [target.'cfg(windows)'.dependencies] -winapi = "0.2" +winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] } [target.'cfg(not(windows))'.dependencies] daemonize = { git = "https://github.com/paritytech/daemonize" } diff --git a/parity/main.rs b/parity/main.rs index 4908f38d9a..0b7c31d954 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -95,7 +95,6 @@ extern crate parity_dapps; #[macro_use] extern crate pretty_assertions; -#[cfg(windows)] extern crate ws2_32; #[cfg(windows)] extern crate winapi; #[cfg(test)] @@ -238,7 +237,7 @@ fn global_cleanup() { // The loop is required because of internal refernce counter for winsock dll. We don't know how many crates we use do // initialize it. There's at least 2 now. for _ in 0.. 10 { - unsafe { ::ws2_32::WSACleanup(); } + unsafe { ::winapi::um::winsock2::WSACleanup(); } } } @@ -250,8 +249,8 @@ fn global_init() { // When restarting in the same process this reinits windows sockets. unsafe { const WS_VERSION: u16 = 0x202; - let mut wsdata: ::winapi::winsock2::WSADATA = ::std::mem::zeroed(); - ::ws2_32::WSAStartup(WS_VERSION, &mut wsdata); + let mut wsdata: ::winapi::um::winsock2::WSADATA = ::std::mem::zeroed(); + ::winapi::um::winsock2::WSAStartup(WS_VERSION, &mut wsdata); } } diff --git a/parity/url.rs b/parity/url.rs index fd64e46eca..9b8959f01d 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -16,34 +16,19 @@ //! Cross-platform open url in default browser -#[cfg(windows)] -mod shell { - extern crate winapi; - - use self::winapi::*; - extern "system" { - pub fn ShellExecuteA( - hwnd: HWND, lpOperation: LPCSTR, lpFile: LPCSTR, lpParameters: LPCSTR, lpDirectory: LPCSTR, - nShowCmd: c_int - ) -> HINSTANCE; - } - - pub use self::winapi::SW_SHOWNORMAL as Normal; -} - #[cfg(windows)] pub fn open(url: &str) { use std::ffi::CString; use std::ptr; - - unsafe { - shell::ShellExecuteA(ptr::null_mut(), - CString::new("open").unwrap().as_ptr(), - CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), - ptr::null(), - ptr::null(), - shell::Normal); - } + use winapi::um::shellapi::ShellExecuteA; + use winapi::um::winuser::SW_SHOWNORMAL as Normal; + + ShellExecuteA(ptr::null_mut(), + CString::new("open").unwrap().as_ptr(), + CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), + ptr::null(), + ptr::null(), + Normal); } #[cfg(any(target_os="macos", target_os="freebsd"))] -- GitLab From 0a170efaa5ee9a1df824630db2a997ad52f6ef57 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 11 Apr 2018 18:21:29 +0200 Subject: [PATCH 067/263] fixed unsafe shell call on windows (#8372) --- parity/url.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/parity/url.rs b/parity/url.rs index 9b8959f01d..4189ae2418 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -23,12 +23,14 @@ pub fn open(url: &str) { use winapi::um::shellapi::ShellExecuteA; use winapi::um::winuser::SW_SHOWNORMAL as Normal; - ShellExecuteA(ptr::null_mut(), - CString::new("open").unwrap().as_ptr(), - CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), - ptr::null(), - ptr::null(), - Normal); + unsafe { + ShellExecuteA(ptr::null_mut(), + CString::new("open").unwrap().as_ptr(), + CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), + ptr::null(), + ptr::null(), + Normal); + } } #[cfg(any(target_os="macos", target_os="freebsd"))] -- GitLab From 16f435b906836a7979d50120d27d384641bec9e2 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 12 Apr 2018 13:05:45 +0200 Subject: [PATCH 068/263] Fix config test by adding no-hardcodec-sync (#8380) --- parity/cli/tests/config.full.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/parity/cli/tests/config.full.toml b/parity/cli/tests/config.full.toml index 08df68ee50..fb3614aa96 100644 --- a/parity/cli/tests/config.full.toml +++ b/parity/cli/tests/config.full.toml @@ -17,6 +17,7 @@ db_path = "$HOME/.parity/chains" keys_path = "$HOME/.parity/keys" identity = "" light = false +no_hardcoded_sync = false [account] unlock = ["0xdeadbeefcafe0000000000000000000000000000"] -- GitLab From bc2f5586eeb902860f81558d274264b8c1f084b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 12 Apr 2018 14:53:54 +0100 Subject: [PATCH 069/263] ci: fix change detection in master builds (#8382) --- scripts/gitlab-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gitlab-test.sh b/scripts/gitlab-test.sh index 812317a270..a617f68e22 100755 --- a/scripts/gitlab-test.sh +++ b/scripts/gitlab-test.sh @@ -2,7 +2,7 @@ #ARGUMENT test for RUST and COVERAGE set -e # fail on any error set -u # treat unset variables as error -if [[ "$CI_COMMIT_REF_NAME" = "beta" || "$CI_COMMIT_REF_NAME" = "stable" ]]; then +if [[ "$CI_COMMIT_REF_NAME" = "master" || "$CI_COMMIT_REF_NAME" = "beta" || "$CI_COMMIT_REF_NAME" = "stable" ]]; then export GIT_COMPARE=$CI_COMMIT_REF_NAME~; else export GIT_COMPARE=master; -- GitLab From 869fa6fda832db108e5524be701704ff4b34bc8b Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 13 Apr 2018 14:06:22 +0200 Subject: [PATCH 070/263] handle queue import errors a bit more gracefully (#8385) --- ethcore/sync/src/light_sync/mod.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index ef1bd8742f..df76d25ccc 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -427,6 +427,8 @@ impl LightSync { // handles request dispatch, block import, state machine transitions, and timeouts. fn maintain_sync(&self, ctx: &BasicContext) { + use ethcore::error::{BlockImportError, ImportError}; + const DRAIN_AMOUNT: usize = 128; let client = self.client.as_light_client(); @@ -453,11 +455,20 @@ impl LightSync { trace!(target: "sync", "Drained {} headers to import", sink.len()); for header in sink.drain(..) { - if let Err(e) = client.queue_header(header) { - debug!(target: "sync", "Found bad header ({:?}). Reset to search state.", e); + match client.queue_header(header) { + Ok(_) => {} + Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + trace!(target: "sync", "Block already in chain. Continuing."); + }, + Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + trace!(target: "sync", "Block already queued. Continuing."); + }, + Err(e) => { + debug!(target: "sync", "Found bad header ({:?}). Reset to search state.", e); - self.begin_search(&mut state); - break 'a; + self.begin_search(&mut state); + break 'a; + } } } } -- GitLab From 03b96a7c0a97f8c7dc2fd5e49724277c002ab5ef Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 13 Apr 2018 14:21:15 +0200 Subject: [PATCH 071/263] Some tweaks to main.rs for parity as a library (#8370) * Some tweaks to main.rs for parity as a library * Remove pub from PostExecutionAction --- parity/configuration.rs | 33 ++++++++++++++------------------- parity/main.rs | 32 +++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/parity/configuration.rs b/parity/configuration.rs index 96f819cba2..d921c9377b 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -95,16 +95,14 @@ pub struct Execute { #[derive(Debug, PartialEq)] pub struct Configuration { pub args: Args, - pub spec_name_override: Option, } impl Configuration { - pub fn parse>(command: &[S], spec_name_override: Option) -> Result { + pub fn parse>(command: &[S]) -> Result { let args = Args::parse(command)?; let config = Configuration { args: args, - spec_name_override: spec_name_override, }; Ok(config) @@ -462,9 +460,7 @@ impl Configuration { } fn chain(&self) -> Result { - let name = if let Some(ref s) = self.spec_name_override { - s.clone() - } else if self.args.flag_testnet { + let name = if self.args.flag_testnet { "testnet".to_owned() } else { self.args.arg_chain.clone() @@ -1264,7 +1260,6 @@ mod tests { fn parse(args: &[&str]) -> Configuration { Configuration { args: Args::parse_without_config(args).unwrap(), - spec_name_override: None, } } @@ -1844,7 +1839,7 @@ mod tests { let filename = tempdir.path().join("peers"); File::create(&filename).unwrap().write_all(b" \n\t\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); assert!(conf.init_reserved_nodes().is_ok()); } @@ -1854,7 +1849,7 @@ mod tests { let filename = tempdir.path().join("peers_comments"); File::create(&filename).unwrap().write_all(b"# Sample comment\nenode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@172.0.0.1:30303\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); let reserved_nodes = conf.init_reserved_nodes(); assert!(reserved_nodes.is_ok()); assert_eq!(reserved_nodes.unwrap().len(), 1); @@ -1863,7 +1858,7 @@ mod tests { #[test] fn test_dev_preset() { let args = vec!["parity", "--config", "dev"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1877,7 +1872,7 @@ mod tests { #[test] fn test_mining_preset() { let args = vec!["parity", "--config", "mining"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 50); @@ -1899,7 +1894,7 @@ mod tests { #[test] fn test_non_standard_ports_preset() { let args = vec!["parity", "--config", "non-standard-ports"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.network_port, 30305); @@ -1912,7 +1907,7 @@ mod tests { #[test] fn test_insecure_preset() { let args = vec!["parity", "--config", "insecure"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.update_policy.require_consensus, false); @@ -1932,7 +1927,7 @@ mod tests { #[test] fn test_dev_insecure_preset() { let args = vec!["parity", "--config", "dev-insecure"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1955,7 +1950,7 @@ mod tests { #[test] fn test_override_preset() { let args = vec!["parity", "--config", "mining", "--min-peers=99"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 99); @@ -2078,7 +2073,7 @@ mod tests { #[test] fn should_respect_only_max_peers_and_default() { let args = vec!["parity", "--max-peers=50"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 25); @@ -2091,7 +2086,7 @@ mod tests { #[test] fn should_respect_only_max_peers_less_than_default() { let args = vec!["parity", "--max-peers=5"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2104,7 +2099,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_default() { let args = vec!["parity", "--min-peers=5"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2117,7 +2112,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_greater_than_default() { let args = vec!["parity", "--min-peers=500"]; - let conf = Configuration::parse(&args, None).unwrap(); + let conf = Configuration::parse(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 500); diff --git a/parity/main.rs b/parity/main.rs index 0b7c31d954..d7d5b137e3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -180,9 +180,10 @@ fn execute(command: Execute, can_restart: bool) -> Result Result { - let args: Vec = env::args().collect(); - let conf = Configuration::parse(&args, take_spec_name_override()).unwrap_or_else(|e| e.exit()); +fn start(mut args: Vec) -> Result { + args.insert(0, "parity".to_owned()); + let conf = Configuration::parse(&args).unwrap_or_else(|e| e.exit()); + let can_restart = conf.args.flag_can_restart; let deprecated = find_deprecated(&conf.args); for d in deprecated { @@ -276,7 +277,7 @@ const PLEASE_RESTART_EXIT_CODE: i32 = 69; // Run our version of parity. // Returns the exit error code. -fn main_direct(can_restart: bool) -> i32 { +fn main_direct(force_can_restart: bool) -> i32 { global_init(); let mut alt_mains = HashMap::new(); sync_main(&mut alt_mains); @@ -285,7 +286,25 @@ fn main_direct(can_restart: bool) -> i32 { f(); 0 } else { - match start(can_restart) { + let mut args = std::env::args().skip(1).collect::>(); + if force_can_restart && !args.iter().any(|arg| arg == "--can-restart") { + args.push("--can-restart".to_owned()); + } + + if let Some(spec_override) = take_spec_name_override() { + args.retain(|f| f != "--testnet"); + args.retain(|f| !f.starts_with("--chain=")); + while let Some(pos) = args.iter().position(|a| a == "--chain") { + if args.len() > pos + 1 { + args.remove(pos + 1); + } + args.remove(pos); + } + args.push("--chain".to_owned()); + args.push(spec_override); + } + + match start(args) { Ok(result) => match result { PostExecutionAction::Print(s) => { println!("{}", s); 0 }, PostExecutionAction::Restart(spec_name_override) => { @@ -365,7 +384,6 @@ fn main() { } else { trace_main!("Running direct"); // Otherwise, we're presumably running the version we want. Just run and fall-through. - let can_restart = std::env::args().any(|arg| arg == "--can-restart"); - process::exit(main_direct(can_restart)); + process::exit(main_direct(false)); } } -- GitLab From 1cd93e4cebeeb7b14e02b4e82bc0d4f73ed713d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 13 Apr 2018 17:34:27 +0200 Subject: [PATCH 072/263] New Transaction Queue implementation (#8074) * Implementation of Verifier, Scoring and Ready. * Queue in progress. * TransactionPool. * Prepare for txpool release. * Miner refactor [WiP] * WiP reworking miner. * Make it compile. * Add some docs. * Split blockchain access to a separate file. * Work on miner API. * Fix ethcore tests. * Refactor miner interface for sealing/work packages. * Implement next nonce. * RPC compiles. * Implement couple of missing methdods for RPC. * Add transaction queue listeners. * Compiles! * Clean-up and parallelize. * Get rid of RefCell in header. * Revert "Get rid of RefCell in header." This reverts commit 0f2424c9b7319a786e1565ea2a8a6d801a21b4fb. * Override Sync requirement. * Fix status display. * Unify logging. * Extract some cheap checks. * Measurements and optimizations. * Fix scoring bug, heap size of bug and add cache * Disable tx queueing and parallel verification. * Make ethcore and ethcore-miner compile again. * Make RPC compile again. * Bunch of txpool tests. * Migrate transaction queue tests. * Nonce Cap * Nonce cap cache and tests. * Remove stale future transactions from the queue. * Optimize scoring and write some tests. * Simple penalization. * Clean up and support for different scoring algorithms. * Add CLI parameters for the new queue. * Remove banning queue. * Disable debug build. * Change per_sender limit to be 1% instead of 5% * Avoid cloning when propagating transactions. * Remove old todo. * Post-review fixes. * Fix miner options default. * Implement back ready transactions for light client. * Get rid of from_pending_block * Pass rejection reason. * Add more details to drop. * Rollback heap size of. * Avoid cloning hashes when propagating and include more details on rejection. * Fix tests. * Introduce nonces cache. * Remove uneccessary hashes allocation. * Lower the mem limit. * Re-enable parallel verification. * Add miner log. Don't check the type if not below min_gas_price. * Add more traces, fix disabling miner. * Fix creating pending blocks twice on AuRa authorities. * Fix tests. * re-use pending blocks in AuRa * Use reseal_min_period to prevent too frequent update_sealing. * Fix log to contain hash not sender. * Optimize local transactions. * Fix aura tests. * Update locks comments. * Get rid of unsafe Sync impl. * Review fixes. * Remove excessive matches. * Fix compilation errors. * Use new pool in private transactions. * Fix private-tx test. * Fix secret store tests. * Actually use gas_floor_target * Fix config tests. * Fix pool tests. * Address grumbles. --- Cargo.lock | 23 +- ethcore/Cargo.toml | 15 +- ethcore/light/src/provider.rs | 3 + ethcore/light/src/transaction_queue.rs | 24 +- ethcore/node_filter/src/lib.rs | 2 +- ethcore/private-tx/src/lib.rs | 97 +- .../private-tx/src/private_transactions.rs | 105 +- ethcore/private-tx/tests/private_contract.rs | 11 +- ethcore/service/src/service.rs | 15 +- ethcore/src/account_provider/mod.rs | 3 - ethcore/src/block.rs | 81 +- ethcore/src/blockchain/best_block.rs | 1 + ethcore/src/client/chain_notify.rs | 5 +- ethcore/src/client/client.rs | 95 +- ethcore/src/client/mod.rs | 2 +- ethcore/src/client/test_client.rs | 39 +- ethcore/src/client/traits.rs | 20 +- ethcore/src/engines/authority_round/mod.rs | 17 +- ethcore/src/engines/basic_authority.rs | 6 +- ethcore/src/engines/mod.rs | 26 +- ethcore/src/engines/tendermint/mod.rs | 14 +- ethcore/src/engines/validator_set/contract.rs | 4 +- ethcore/src/engines/validator_set/multi.rs | 8 +- .../engines/validator_set/safe_contract.rs | 6 +- ethcore/src/json_tests/chain.rs | 2 +- ethcore/src/lib.rs | 19 +- ethcore/src/machine.rs | 10 +- ethcore/src/miner/miner.rs | 1618 ++++----- ethcore/src/miner/mod.rs | 248 +- ethcore/src/miner/pool_client.rs | 216 ++ .../src/miner/service_transaction_checker.rs | 19 +- ethcore/src/miner/stratum.rs | 25 +- .../src/snapshot/tests/proof_of_authority.rs | 6 +- ethcore/src/snapshot/tests/service.rs | 2 +- ethcore/src/test_helpers.rs | 4 +- ethcore/src/tests/client.rs | 16 +- ethcore/src/tests/trace.rs | 2 +- ethcore/src/tx_filter.rs | 2 +- ethcore/sync/src/api.rs | 5 +- ethcore/sync/src/chain.rs | 44 +- ethcore/sync/src/tests/consensus.rs | 38 +- ethcore/sync/src/tests/helpers.rs | 12 +- ethcore/transaction/src/lib.rs | 11 - ethcore/transaction/src/transaction.rs | 2 +- miner/Cargo.toml | 29 +- miner/src/banning_queue.rs | 321 -- miner/src/gas_pricer.rs | 97 + miner/src/lib.rs | 24 +- miner/src/local_transactions.rs | 220 -- miner/src/pool/client.rs | 71 + miner/src/pool/listener.rs | 161 + miner/src/pool/local_transactions.rs | 273 ++ miner/src/pool/mod.rs | 135 + miner/src/pool/queue.rs | 445 +++ miner/src/pool/ready.rs | 212 ++ miner/src/pool/scoring.rs | 171 + miner/src/pool/tests/client.rs | 125 + miner/src/pool/tests/mod.rs | 757 +++++ miner/src/pool/tests/tx.rs | 185 ++ miner/src/pool/verifier.rs | 288 ++ miner/src/transaction_queue.rs | 2944 ----------------- parity/blockchain.rs | 12 +- parity/cli/mod.rs | 32 +- parity/cli/presets/config.mining.toml | 9 +- parity/configuration.rs | 96 +- parity/helpers.rs | 23 +- parity/params.rs | 36 +- parity/run.rs | 48 +- parity/snapshot.rs | 6 +- price-info/src/lib.rs | 2 +- rpc/Cargo.toml | 7 +- rpc/src/lib.rs | 2 + rpc/src/v1/helpers/dispatch.rs | 13 +- rpc/src/v1/helpers/errors.rs | 4 +- rpc/src/v1/impls/eth.rs | 121 +- rpc/src/v1/impls/eth_filter.rs | 29 +- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 15 + rpc/src/v1/impls/parity.rs | 46 +- rpc/src/v1/impls/parity_set.rs | 50 +- rpc/src/v1/impls/traces.rs | 4 +- rpc/src/v1/tests/eth.rs | 31 +- rpc/src/v1/tests/helpers/miner_service.rs | 238 +- rpc/src/v1/tests/mocked/eth.rs | 20 +- rpc/src/v1/tests/mocked/parity.rs | 25 +- rpc/src/v1/tests/mocked/parity_set.rs | 14 +- rpc/src/v1/tests/mocked/personal.rs | 2 +- rpc/src/v1/tests/mocked/signing.rs | 2 +- rpc/src/v1/traits/parity.rs | 8 +- rpc/src/v1/types/transaction.rs | 31 +- secret_store/src/trusted_client.rs | 2 +- transaction-pool/Cargo.toml | 1 + transaction-pool/src/error.rs | 10 +- transaction-pool/src/lib.rs | 3 + transaction-pool/src/listener.rs | 46 +- transaction-pool/src/options.rs | 2 +- transaction-pool/src/pool.rs | 93 +- transaction-pool/src/scoring.rs | 16 +- transaction-pool/src/status.rs | 4 +- transaction-pool/src/tests/helpers.rs | 17 +- transaction-pool/src/tests/mod.rs | 94 +- transaction-pool/src/transactions.rs | 19 +- util/table/Cargo.toml | 6 - util/table/src/lib.rs | 261 -- util/using_queue/src/lib.rs | 4 +- 105 files changed, 5144 insertions(+), 5743 deletions(-) create mode 100644 ethcore/src/miner/pool_client.rs delete mode 100644 miner/src/banning_queue.rs create mode 100644 miner/src/gas_pricer.rs delete mode 100644 miner/src/local_transactions.rs create mode 100644 miner/src/pool/client.rs create mode 100644 miner/src/pool/listener.rs create mode 100644 miner/src/pool/local_transactions.rs create mode 100644 miner/src/pool/mod.rs create mode 100644 miner/src/pool/queue.rs create mode 100644 miner/src/pool/ready.rs create mode 100644 miner/src/pool/scoring.rs create mode 100644 miner/src/pool/tests/client.rs create mode 100644 miner/src/pool/tests/mod.rs create mode 100644 miner/src/pool/tests/tx.rs create mode 100644 miner/src/pool/verifier.rs delete mode 100644 miner/src/transaction_queue.rs delete mode 100644 util/table/Cargo.toml delete mode 100644 util/table/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fb1d9ce557..70f7a02661 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -511,7 +511,6 @@ dependencies = [ "ethstore 0.2.0", "evm 0.1.0", "fetch 0.1.0", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hardware-wallet 1.11.0", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -532,7 +531,6 @@ dependencies = [ "parity-machine 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", - "price-info 1.11.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -543,7 +541,6 @@ dependencies = [ "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", "stats 0.1.0", "stop-guard 0.1.0", - "table 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", "trie-standardmap 0.1.0", @@ -655,16 +652,16 @@ dependencies = [ name = "ethcore-miner" version = "1.11.0" dependencies = [ - "common-types 0.1.0", - "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -672,9 +669,11 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "price-info 1.11.0", + "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "table 0.1.0", - "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", + "transaction-pool 1.11.0", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2191,6 +2190,7 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "transaction-pool 1.11.0", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -3076,10 +3076,6 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "table" -version = "0.1.0" - [[package]] name = "take" version = "0.1.0" @@ -3403,6 +3399,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", ] [[package]] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 0ffb7034a3..b8035f0712 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -34,7 +34,6 @@ ethjson = { path = "../json" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } evm = { path = "evm" } -futures-cpupool = "0.1" hardware-wallet = { path = "../hw" } heapsize = "0.4" itertools = "0.5" @@ -45,7 +44,6 @@ num = { version = "0.1", default-features = false, features = ["bigint"] } num_cpus = "1.2" parity-machine = { path = "../machine" } parking_lot = "0.5" -price-info = { path = "../price-info" } rayon = "1.0" rand = "0.4" rlp = { path = "../util/rlp" } @@ -63,7 +61,6 @@ rustc-hex = "1.0" stats = { path = "../util/stats" } trace-time = { path = "../util/trace-time" } using_queue = { path = "../util/using_queue" } -table = { path = "../util/table" } vm = { path = "vm" } wasm = { path = "wasm" } keccak-hash = { path = "../util/hash" } @@ -76,10 +73,18 @@ tempdir = "0.3" trie-standardmap = { path = "../util/trie-standardmap" } [features] +# Display EVM debug traces. evm-debug = ["slow-blocks"] +# Display EVM debug traces when running tests. evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"] -slow-blocks = [] # Use SLOW_TX_DURATION="50" (compile time!) to track transactions over 50ms +# Measure time of transaction execution. +# Whenever the transaction execution time (in millis) exceeds the value of +# SLOW_TX_DURATION env variable (provided compile time!) +# EVM debug traces are printed. +slow-blocks = [] +# Run JSON consensus tests. json-tests = ["ethcore-transaction/json-tests"] +# Run memory/cpu heavy tests. test-heavy = [] -default = [] +# Compile benches benches = [] diff --git a/ethcore/light/src/provider.rs b/ethcore/light/src/provider.rs index 1d9af0ac19..aaa6f5858a 100644 --- a/ethcore/light/src/provider.rs +++ b/ethcore/light/src/provider.rs @@ -282,6 +282,9 @@ impl Provider for T { fn ready_transactions(&self) -> Vec { BlockChainClient::ready_transactions(self) + .into_iter() + .map(|tx| tx.pending().clone()) + .collect() } fn epoch_signal(&self, req: request::CompleteSignalRequest) -> Option { diff --git a/ethcore/light/src/transaction_queue.rs b/ethcore/light/src/transaction_queue.rs index 156152253d..ae3dc26915 100644 --- a/ethcore/light/src/transaction_queue.rs +++ b/ethcore/light/src/transaction_queue.rs @@ -120,6 +120,18 @@ impl AccountTransactions { } } +/// Transaction import result. +pub enum ImportDestination { + /// Transaction has been imported to the current queue. + /// + /// It's going to be propagated to peers. + Current, + /// Transaction has been imported to future queue. + /// + /// It means it won't be propagated until the gap is filled. + Future, +} + type Listener = Box; /// Light transaction queue. See module docs for more details. @@ -142,7 +154,7 @@ impl fmt::Debug for TransactionQueue { impl TransactionQueue { /// Import a pending transaction to be queued. - pub fn import(&mut self, tx: PendingTransaction) -> Result { + pub fn import(&mut self, tx: PendingTransaction) -> Result { let sender = tx.sender(); let hash = tx.hash(); let nonce = tx.nonce; @@ -158,7 +170,7 @@ impl TransactionQueue { future: BTreeMap::new(), }); - (transaction::ImportResult::Current, vec![hash]) + (ImportDestination::Current, vec![hash]) } Entry::Occupied(mut entry) => { let acct_txs = entry.get_mut(); @@ -180,7 +192,7 @@ impl TransactionQueue { let old = ::std::mem::replace(&mut acct_txs.current[idx], tx_info); self.by_hash.remove(&old.hash); - (transaction::ImportResult::Current, vec![hash]) + (ImportDestination::Current, vec![hash]) } Err(idx) => { let cur_len = acct_txs.current.len(); @@ -202,13 +214,13 @@ impl TransactionQueue { acct_txs.future.insert(future_nonce, future); } - (transaction::ImportResult::Current, vec![hash]) + (ImportDestination::Current, vec![hash]) } else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) { trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce); let future_nonce = nonce; acct_txs.future.insert(future_nonce, tx_info); - (transaction::ImportResult::Future, vec![]) + (ImportDestination::Future, vec![]) } else { trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce); @@ -217,7 +229,7 @@ impl TransactionQueue { let mut promoted = acct_txs.adjust_future(); promoted.insert(0, hash); - (transaction::ImportResult::Current, promoted) + (ImportDestination::Current, promoted) } } } diff --git a/ethcore/node_filter/src/lib.rs b/ethcore/node_filter/src/lib.rs index cbf5f4e5d4..715b7ae3e9 100644 --- a/ethcore/node_filter/src/lib.rs +++ b/ethcore/node_filter/src/lib.rs @@ -132,7 +132,7 @@ mod test { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let filter = NodeFilter::new(Arc::downgrade(&client) as Weak, contract_addr); diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index ef97c6e2e6..e28dd7c331 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -78,12 +78,10 @@ use ethcore::executed::{Executed}; use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction}; use ethcore::{contract_address as ethcore_contract_address}; use ethcore::client::{ - Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, - MiningBlockChainClient, ChainInfo, Nonce, CallContract + Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, CallContract }; use ethcore::account_provider::AccountProvider; -use ethcore_miner::transaction_queue::{TransactionDetailsProvider as TransactionQueueDetailsProvider, AccountDetails}; -use ethcore::miner::MinerService; +use ethcore::miner::{self, Miner, MinerService}; use ethcore::trace::{Tracer, VMTracer}; use rustc_hex::FromHex; @@ -95,35 +93,6 @@ use_contract!(private, "PrivateContract", "res/private.json"); /// Initialization vector length. const INIT_VEC_LEN: usize = 16; -struct TransactionDetailsProvider<'a> { - client: &'a MiningBlockChainClient, -} - -impl<'a> TransactionDetailsProvider<'a> { - pub fn new(client: &'a MiningBlockChainClient) -> Self { - TransactionDetailsProvider { - client: client, - } - } -} - -impl<'a> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a> { - fn fetch_account(&self, address: &Address) -> AccountDetails { - AccountDetails { - nonce: self.client.latest_nonce(address), - balance: self.client.latest_balance(address), - } - } - - fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256 { - tx.gas_required(&self.client.latest_schedule()).into() - } - - fn is_service_transaction_acceptable(&self, _tx: &SignedTransaction) -> Result { - Ok(false) - } -} - /// Configurtion for private transaction provider #[derive(Default, PartialEq, Debug, Clone)] pub struct ProviderConfig { @@ -154,8 +123,10 @@ pub struct Provider { passwords: Vec, notify: RwLock>>, transactions_for_signing: Mutex, + // TODO [ToDr] Move the Mutex/RwLock inside `VerificationStore` after refactored to `drain`. transactions_for_verification: Mutex, client: Arc, + miner: Arc, accounts: Arc, channel: IoChannel, } @@ -172,6 +143,7 @@ impl Provider where { /// Create a new provider. pub fn new( client: Arc, + miner: Arc, accounts: Arc, encryptor: Box, config: ProviderConfig, @@ -186,6 +158,7 @@ impl Provider where { transactions_for_signing: Mutex::default(), transactions_for_verification: Mutex::default(), client, + miner, accounts, channel, }) @@ -282,6 +255,9 @@ impl Provider where { match validation_account { None => { + // TODO [ToDr] This still seems a bit invalid, imho we should still import the transaction to the pool. + // Importing to pool verifies correctness and nonce; here we are just blindly forwarding. + // // Not for verification, broadcast further to peers self.broadcast_private_transaction(rlp.into()); return Ok(()); @@ -291,29 +267,59 @@ impl Provider where { trace!("Private transaction taken for verification"); let original_tx = self.extract_original_transaction(private_tx, &contract)?; trace!("Validating transaction: {:?}", original_tx); - let details_provider = TransactionDetailsProvider::new(&*self.client as &MiningBlockChainClient); - let insertion_time = self.client.chain_info().best_block_number; // Verify with the first account available trace!("The following account will be used for verification: {:?}", validation_account); - self.transactions_for_verification.lock() - .add_transaction(original_tx, contract, validation_account, hash, &details_provider, insertion_time)?; + let nonce_cache = Default::default(); + self.transactions_for_verification.lock().add_transaction( + original_tx, + contract, + validation_account, + hash, + self.pool_client(&nonce_cache), + )?; + // NOTE This will just fire `on_private_transaction_queued` but from a client thread. + // It seems that a lot of heavy work (verification) is done in this thread anyway + // it might actually make sense to decouple it from clientService and just use dedicated thread + // for both verification and execution. self.channel.send(ClientIoMessage::NewPrivateTransaction).map_err(|_| ErrorKind::ClientIsMalformed.into()) } } } + fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { + let engine = self.client.engine(); + let refuse_service_transactions = true; + miner::pool_client::PoolClient::new( + &*self.client, + nonce_cache, + engine, + Some(&*self.accounts), + refuse_service_transactions, + ) + } + /// Private transaction for validation added into queue pub fn on_private_transaction_queued(&self) -> Result<(), Error> { self.process_queue() } /// Retrieve and verify the first available private transaction for every sender + /// + /// TODO [ToDr] It seems that: + /// 1. This method will fail on any error without removing invalid transaction. + /// 2. It means that the transaction will be stuck there forever and we will never be able to make any progress. + /// + /// It might be more sensible to `drain()` transactions from the queue instead and process all of them, + /// possibly printing some errors in case of failures. + /// The 3 methods `ready_transaction,get_descriptor,remove` are always used in conjuction so most likely + /// can be replaced with a single `drain()` method instead. + /// Thanks to this we also don't really need to lock the entire verification for the time of execution. fn process_queue(&self) -> Result<(), Error> { + let nonce_cache = Default::default(); let mut verification_queue = self.transactions_for_verification.lock(); - let ready_transactions = verification_queue.ready_transactions(); - let fetch_nonce = |a: &Address| self.client.latest_nonce(a); + let ready_transactions = verification_queue.ready_transactions(self.pool_client(&nonce_cache)); for transaction in ready_transactions { - let transaction_hash = transaction.hash(); + let transaction_hash = transaction.signed().hash(); match verification_queue.private_transaction_descriptor(&transaction_hash) { Ok(desc) => { if !self.validator_accounts.contains(&desc.validator_account) { @@ -321,9 +327,10 @@ impl Provider where { bail!(ErrorKind::ValidatorAccountNotSet); } let account = desc.validator_account; - if let Action::Call(contract) = transaction.action { + if let Action::Call(contract) = transaction.signed().action { + // TODO [ToDr] Usage of BlockId::Latest let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest)?; - let private_state = self.execute_private_transaction(BlockId::Latest, &transaction)?; + let private_state = self.execute_private_transaction(BlockId::Latest, transaction.signed())?; let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce); trace!("Hashed effective private state for validator: {:?}", private_state_hash); let password = find_account_password(&self.passwords, &*self.accounts, &account); @@ -341,7 +348,7 @@ impl Provider where { bail!(e); } } - verification_queue.remove_private_transaction(&transaction_hash, &fetch_nonce); + verification_queue.remove_private_transaction(&transaction_hash); } Ok(()) } @@ -354,6 +361,8 @@ impl Provider where { let private_hash = tx.private_transaction_hash(); let desc = match self.transactions_for_signing.lock().get(&private_hash) { None => { + // TODO [ToDr] Verification (we can't just blindly forward every transaction) + // Not our transaction, broadcast further to peers self.broadcast_signed_private_transaction(rlp.into()); return Ok(()); @@ -383,7 +392,7 @@ impl Provider where { let password = find_account_password(&self.passwords, &*self.accounts, &signer_account); let signature = self.accounts.sign(signer_account, password, hash)?; let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?; - match self.client.miner().import_own_transaction(&*self.client, signed.into()) { + match self.miner.import_own_transaction(&*self.client, signed.into()) { Ok(_) => trace!("Public transaction added to queue"), Err(err) => { trace!("Failed to add transaction to queue, error: {:?}", err); diff --git a/ethcore/private-tx/src/private_transactions.rs b/ethcore/private-tx/src/private_transactions.rs index 502694294e..1a018d927a 100644 --- a/ethcore/private-tx/src/private_transactions.rs +++ b/ethcore/private-tx/src/private_transactions.rs @@ -14,15 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::Signature; +use std::sync::Arc; +use std::collections::{HashMap, HashSet}; + use bytes::Bytes; -use std::collections::HashMap; +use ethcore_miner::pool; use ethereum_types::{H256, U256, Address}; +use ethkey::Signature; use transaction::{UnverifiedTransaction, SignedTransaction}; -use ethcore_miner::transaction_queue::{TransactionQueue, RemovalReason, - TransactionDetailsProvider as TransactionQueueDetailsProvider, TransactionOrigin}; + use error::{Error, ErrorKind}; -use ethcore::header::BlockNumber; /// Maximum length for private transactions queues. const MAX_QUEUE_LEN: usize = 8312; @@ -39,56 +40,92 @@ pub struct PrivateTransactionDesc { } /// Storage for private transactions for verification -#[derive(Default)] pub struct VerificationStore { /// Descriptors for private transactions in queue for verification with key - hash of the original transaction descriptors: HashMap, /// Queue with transactions for verification - transactions: TransactionQueue, + /// + /// TODO [ToDr] Might actually be better to use `txpool` directly and: + /// 1. Store descriptors inside `VerifiedTransaction` + /// 2. Use custom `ready` implementation to only fetch one transaction per sender. + /// 3. Get rid of passing dummy `block_number` and `timestamp` + transactions: pool::TransactionQueue, +} + +impl Default for VerificationStore { + fn default() -> Self { + VerificationStore { + descriptors: Default::default(), + transactions: pool::TransactionQueue::new( + pool::Options { + max_count: MAX_QUEUE_LEN, + max_per_sender: MAX_QUEUE_LEN / 10, + max_mem_usage: 8 * 1024 * 1024, + }, + pool::verifier::Options { + // TODO [ToDr] This should probably be based on some real values? + minimal_gas_price: 0.into(), + block_gas_limit: 8_000_000.into(), + tx_gas_limit: U256::max_value(), + }, + pool::PrioritizationStrategy::GasPriceOnly, + ) + } + } } impl VerificationStore { /// Adds private transaction for verification into the store - pub fn add_transaction( + pub fn add_transaction( &mut self, transaction: UnverifiedTransaction, contract: Address, validator_account: Address, private_hash: H256, - details_provider: &TransactionQueueDetailsProvider, - insertion_time: BlockNumber, + client: C, ) -> Result<(), Error> { if self.descriptors.len() > MAX_QUEUE_LEN { bail!(ErrorKind::QueueIsFull); } - if self.descriptors.get(&transaction.hash()).is_some() { + let transaction_hash = transaction.hash(); + if self.descriptors.get(&transaction_hash).is_some() { bail!(ErrorKind::PrivateTransactionAlreadyImported); } - let transaction_hash = transaction.hash(); - let signed_transaction = SignedTransaction::new(transaction)?; - self.transactions - .add(signed_transaction, TransactionOrigin::External, insertion_time, None, details_provider) - .and_then(|_| { - self.descriptors.insert(transaction_hash, PrivateTransactionDesc{ - private_hash, - contract, - validator_account, - }); - Ok(()) - }) - .map_err(Into::into) + + let results = self.transactions.import( + client, + vec![pool::verifier::Transaction::Unverified(transaction)], + ); + + // Verify that transaction was imported + results.into_iter() + .next() + .expect("One transaction inserted; one result returned; qed")?; + + self.descriptors.insert(transaction_hash, PrivateTransactionDesc { + private_hash, + contract, + validator_account, + }); + + Ok(()) } /// Returns transactions ready for verification /// Returns only one transaction per sender because several cannot be verified in a row without verification from other peers - pub fn ready_transactions(&self) -> Vec { - // TODO [ToDr] Performance killer, re-work with new transaction queue. - let mut transactions = self.transactions.top_transactions(); - // TODO [ToDr] Potential issue (create low address to have your transactions processed first) - transactions.sort_by(|a, b| a.sender().cmp(&b.sender())); - transactions.dedup_by(|a, b| a.sender().eq(&b.sender())); - transactions + pub fn ready_transactions(&self, client: C) -> Vec> { + // We never store PendingTransactions and we don't use internal cache, + // so we don't need to provide real block number of timestamp here + let block_number = 0; + let timestamp = 0; + let nonce_cap = None; + + self.transactions.collect_pending(client, block_number, timestamp, nonce_cap, |transactions| { + // take only one transaction per sender + let mut senders = HashSet::with_capacity(self.descriptors.len()); + transactions.filter(move |tx| senders.insert(tx.signed().sender())).collect() + }) } /// Returns descriptor of the corresponding private transaction @@ -97,11 +134,9 @@ impl VerificationStore { } /// Remove transaction from the queue for verification - pub fn remove_private_transaction(&mut self, transaction_hash: &H256, fetch_nonce: &F) - where F: Fn(&Address) -> U256 { - + pub fn remove_private_transaction(&mut self, transaction_hash: &H256) { self.descriptors.remove(transaction_hash); - self.transactions.remove(transaction_hash, fetch_nonce, RemovalReason::Invalid); + self.transactions.remove(&[*transaction_hash], true); } } diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs index ba918c9636..e53ad5e5f6 100644 --- a/ethcore/private-tx/tests/private_contract.rs +++ b/ethcore/private-tx/tests/private_contract.rs @@ -36,6 +36,7 @@ use ethcore::account_provider::AccountProvider; use ethcore::client::BlockChainClient; use ethcore::client::BlockId; use ethcore::executive::{contract_address}; +use ethcore::miner::Miner; use ethcore::test_helpers::{generate_dummy_client, push_block_with_transactions}; use ethcore_transaction::{Transaction, Action}; use ethkey::{Secret, KeyPair, Signature}; @@ -65,7 +66,15 @@ fn private_contract() { }; let io = ethcore_io::IoChannel::disconnected(); - let pm = Arc::new(Provider::new(client.clone(), ap.clone(), Box::new(NoopEncryptor::default()), config, io).unwrap()); + let miner = Arc::new(Miner::new_for_tests(&::ethcore::spec::Spec::new_test(), None)); + let pm = Arc::new(Provider::new( + client.clone(), + miner, + ap.clone(), + Box::new(NoopEncryptor::default()), + config, + io, + ).unwrap()); let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]); diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 8fab545574..b57d613e3b 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -92,7 +92,7 @@ impl ClientService { info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name())); let pruning = config.pruning; - let client = Client::new(config, &spec, client_db.clone(), miner, io_service.channel())?; + let client = Client::new(config, &spec, client_db.clone(), miner.clone(), io_service.channel())?; let snapshot_params = SnapServiceParams { engine: spec.engine.clone(), @@ -105,7 +105,14 @@ impl ClientService { }; let snapshot = Arc::new(SnapshotService::new(snapshot_params)?); - let provider = Arc::new(ethcore_private_tx::Provider::new(client.clone(), account_provider, encryptor, private_tx_conf, io_service.channel())?); + let provider = Arc::new(ethcore_private_tx::Provider::new( + client.clone(), + miner, + account_provider, + encryptor, + private_tx_conf, + io_service.channel())?, + ); let private_tx = Arc::new(PrivateTxService::new(provider)); let client_io = Arc::new(ClientIoHandler { @@ -292,10 +299,10 @@ mod tests { &snapshot_path, restoration_db_handler, tempdir.path(), - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ); assert!(service.is_ok()); drop(service.unwrap()); diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 74d24e7f50..2edb42be1e 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -66,8 +66,6 @@ pub enum SignError { Hardware(HardwareError), /// Low-level error from store SStore(SSError), - /// Inappropriate chain - InappropriateChain, } impl fmt::Display for SignError { @@ -77,7 +75,6 @@ impl fmt::Display for SignError { SignError::NotFound => write!(f, "Account does not exist"), SignError::Hardware(ref e) => write!(f, "{}", e), SignError::SStore(ref e) => write!(f, "{}", e), - SignError::InappropriateChain => write!(f, "Inappropriate chain"), } } } diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 8e1fac1792..4cbc0bac9f 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -337,8 +337,33 @@ impl<'x> OpenBlock<'x> { } /// Push transactions onto the block. - pub fn push_transactions(&mut self, transactions: &[SignedTransaction]) -> Result<(), Error> { - push_transactions(self, transactions) + #[cfg(not(feature = "slow-blocks"))] + fn push_transactions(&mut self, transactions: Vec) -> Result<(), Error> { + for t in transactions { + self.push_transaction(t, None)?; + } + Ok(()) + } + + /// Push transactions onto the block. + #[cfg(feature = "slow-blocks")] + fn push_transactions(&mut self, transactions: Vec) -> Result<(), Error> { + use std::time; + + let slow_tx = option_env!("SLOW_TX_DURATION").and_then(|v| v.parse().ok()).unwrap_or(100); + for t in transactions { + let hash = t.hash(); + let start = time::Instant::now(); + self.push_transaction(t, None)?; + let took = start.elapsed(); + let took_ms = took.as_secs() * 1000 + took.subsec_nanos() as u64 / 1000000; + if took > time::Duration::from_millis(slow_tx) { + warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, block.header().number(), hash); + } + debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms); + } + + Ok(()) } /// Populate self from a header. @@ -534,10 +559,10 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact( - header: &Header, - transactions: &[SignedTransaction], - uncles: &[Header], +fn enact( + header: Header, + transactions: Vec, + uncles: Vec
, engine: &EthEngine, tracing: bool, db: StateDB, @@ -568,11 +593,11 @@ pub fn enact( is_epoch_begin, )?; - b.populate_from(header); + b.populate_from(&header); b.push_transactions(transactions)?; for u in uncles { - b.push_uncle(u.clone())?; + b.push_uncle(u)?; } if strip_receipts { @@ -584,38 +609,9 @@ pub fn enact( Ok(b.close_and_lock()) } -#[inline] -#[cfg(not(feature = "slow-blocks"))] -fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> { - for t in transactions { - block.push_transaction(t.clone(), None)?; - } - Ok(()) -} - -#[cfg(feature = "slow-blocks")] -fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> { - use std::time; - - let slow_tx = option_env!("SLOW_TX_DURATION").and_then(|v| v.parse().ok()).unwrap_or(100); - for t in transactions { - let hash = t.hash(); - let start = time::Instant::now(); - block.push_transaction(t.clone(), None)?; - let took = start.elapsed(); - let took_ms = took.as_secs() * 1000 + took.subsec_nanos() as u64 / 1000000; - if took > time::Duration::from_millis(slow_tx) { - warn!("Heavy ({} ms) transaction in block {:?}: {:?}", took_ms, block.header().number(), hash); - } - debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms); - } - Ok(()) -} - -// TODO [ToDr] Pass `PreverifiedBlock` by move, this will avoid unecessary allocation /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header pub fn enact_verified( - block: &PreverifiedBlock, + block: PreverifiedBlock, engine: &EthEngine, tracing: bool, db: StateDB, @@ -629,9 +625,9 @@ pub fn enact_verified( let view = BlockView::new(&block.bytes); enact( - &block.header, - &block.transactions, - &view.uncles(), + block.header, + block.transactions, + view.uncles(), engine, tracing, db, @@ -700,7 +696,7 @@ mod tests { )?; b.populate_from(&header); - b.push_transactions(&transactions)?; + b.push_transactions(transactions)?; for u in &block.uncles() { b.push_uncle(u.clone())?; @@ -793,3 +789,4 @@ mod tests { assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); } } + diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index d5a6ce91a4..017c4f86ea 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use ethereum_types::{H256, U256}; + use encoded; use header::{Header, BlockNumber}; diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index bdd8d00278..ccfb2558d6 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -14,8 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; use bytes::Bytes; +use ethereum_types::H256; +use transaction::UnverifiedTransaction; /// Messages to broadcast via chain pub enum ChainMessageType { @@ -59,7 +60,7 @@ pub trait ChainNotify : Send + Sync { /// fires when new transactions are received from a peer fn transactions_received(&self, - _hashes: Vec, + _txs: &[UnverifiedTransaction], _peer_id: usize, ) { // does nothing by default diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a8ce3f65c3..fb3f07e41e 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -44,7 +44,7 @@ use client::{ }; use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, - MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, + TraceFilter, CallAnalytics, BlockImportError, Mode, ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType }; use encoded; @@ -58,6 +58,7 @@ use header::{BlockNumber, Header}; use io::IoChannel; use log_entry::LocalizedLogEntry; use miner::{Miner, MinerService}; +use ethcore_miner::pool::VerifiedTransaction; use parking_lot::{Mutex, RwLock}; use rand::OsRng; use receipt::{Receipt, LocalizedReceipt}; @@ -68,7 +69,7 @@ use state_db::StateDB; use state::{self, State}; use trace; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; -use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, PendingTransaction, Action}; +use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, Action}; use types::filter::Filter; use types::mode::Mode as IpcMode; use verification; @@ -103,10 +104,10 @@ pub struct ClientReport { impl ClientReport { /// Alter internal reporting to reflect the additional `block` has been processed. - pub fn accrue_block(&mut self, block: &PreverifiedBlock) { + pub fn accrue_block(&mut self, header: &Header, transactions: usize) { self.blocks_imported += 1; - self.transactions_applied += block.transactions.len(); - self.gas_processed = self.gas_processed + block.header.gas_used().clone(); + self.transactions_applied += transactions; + self.gas_processed = self.gas_processed + *header.gas_used(); } } @@ -295,23 +296,29 @@ impl Importer { let start = Instant::now(); for block in blocks { - let header = &block.header; + let header = block.header.clone(); + let bytes = block.bytes.clone(); + let hash = header.hash(); + let is_invalid = invalid_blocks.contains(header.parent_hash()); if is_invalid { - invalid_blocks.insert(header.hash()); + invalid_blocks.insert(hash); continue; } - if let Ok(closed_block) = self.check_and_close_block(&block, client) { - if self.engine.is_proposal(&block.header) { - self.block_queue.mark_as_good(&[header.hash()]); - proposed_blocks.push(block.bytes); + + if let Ok(closed_block) = self.check_and_close_block(block, client) { + if self.engine.is_proposal(&header) { + self.block_queue.mark_as_good(&[hash]); + proposed_blocks.push(bytes); } else { - imported_blocks.push(header.hash()); + imported_blocks.push(hash); + + let transactions_len = closed_block.transactions().len(); - let route = self.commit_block(closed_block, &header, &block.bytes, client); + let route = self.commit_block(closed_block, &header, &bytes, client); import_results.push(route); - client.report.write().accrue_block(&block); + client.report.write().accrue_block(&header, transactions_len); } } else { invalid_blocks.insert(header.hash()); @@ -337,7 +344,7 @@ impl Importer { let (enacted, retracted) = self.calculate_enacted_retracted(&import_results); if is_empty { - self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, &enacted, &retracted); + self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, &enacted, &retracted, false); } client.notify(|notify| { @@ -358,9 +365,9 @@ impl Importer { imported } - fn check_and_close_block(&self, block: &PreverifiedBlock, client: &Client) -> Result { + fn check_and_close_block(&self, block: PreverifiedBlock, client: &Client) -> Result { let engine = &*self.engine; - let header = &block.header; + let header = block.header.clone(); // Check the block isn't so old we won't be able to enact it. let best_block_number = client.chain.read().best_block_number(); @@ -381,7 +388,7 @@ impl Importer { let chain = client.chain.read(); // Verify Block Family let verify_family_result = self.verifier.verify_block_family( - header, + &header, &parent, engine, Some(verification::FullFamilyParams { @@ -397,7 +404,7 @@ impl Importer { return Err(()); }; - let verify_external_result = self.verifier.verify_block_external(header, engine); + let verify_external_result = self.verifier.verify_block_external(&header, engine); if let Err(e) = verify_external_result { warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); @@ -409,7 +416,8 @@ impl Importer { let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some(); let strip_receipts = header.number() < engine.params().validate_receipts_transition; - let enact_result = enact_verified(block, + let enact_result = enact_verified( + block, engine, client.tracedb.read().tracing_enabled(), db, @@ -425,7 +433,7 @@ impl Importer { })?; // Final Verification - if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) { + if let Err(e) = self.verifier.verify_block_final(&header, locked_block.block().header()) { warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); } @@ -975,19 +983,24 @@ impl Client { /// Import transactions from the IO queue pub fn import_queued_transactions(&self, transactions: &[Bytes], peer_id: usize) -> usize { - trace!(target: "external_tx", "Importing queued"); trace_time!("import_queued_transactions"); self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst); - let txs: Vec = transactions.iter().filter_map(|bytes| UntrustedRlp::new(bytes).as_val().ok()).collect(); - let hashes: Vec<_> = txs.iter().map(|tx| tx.hash()).collect(); + + let txs: Vec = transactions + .iter() + .filter_map(|bytes| UntrustedRlp::new(bytes).as_val().ok()) + .collect(); + self.notify(|notify| { - notify.transactions_received(hashes.clone(), peer_id); + notify.transactions_received(&txs, peer_id); }); + let results = self.importer.miner.import_external_transactions(self, txs); results.len() } /// Get shared miner reference. + #[cfg(test)] pub fn miner(&self) -> Arc { self.importer.miner.clone() } @@ -1915,12 +1928,8 @@ impl BlockChainClient for Client { } } - fn ready_transactions(&self) -> Vec { - let (number, timestamp) = { - let chain = self.chain.read(); - (chain.best_block_number(), chain.best_block_timestamp()) - }; - self.importer.miner.ready_transactions(number, timestamp) + fn ready_transactions(&self) -> Vec> { + self.importer.miner.ready_transactions(self) } fn queue_consensus_message(&self, message: Bytes) { @@ -1951,17 +1960,19 @@ impl BlockChainClient for Client { } } - fn transact_contract(&self, address: Address, data: Bytes) -> Result { + fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> { + let authoring_params = self.importer.miner.authoring_params(); let transaction = Transaction { - nonce: self.latest_nonce(&self.importer.miner.author()), + nonce: self.latest_nonce(&authoring_params.author), action: Action::Call(address), - gas: self.importer.miner.gas_floor_target(), + gas: self.importer.miner.sensible_gas_limit(), gas_price: self.importer.miner.sensible_gas_price(), value: U256::zero(), data: data, }; let chain_id = self.engine.signing_chain_id(&self.latest_env_info()); - let signature = self.engine.sign(transaction.hash(chain_id))?; + let signature = self.engine.sign(transaction.hash(chain_id)) + .map_err(|e| transaction::Error::InvalidSignature(e.to_string()))?; let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?; self.importer.miner.import_own_transaction(self, signed.into()) } @@ -2070,7 +2081,7 @@ impl ImportSealedBlock for Client { route }; let (enacted, retracted) = self.importer.calculate_enacted_retracted(&[route]); - self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted); + self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted, true); self.notify(|notify| { notify.new_blocks( vec![h.clone()], @@ -2108,11 +2119,8 @@ impl BroadcastProposalBlock for Client { impl SealedBlockImporter for Client {} -impl MiningBlockChainClient for Client { - fn vm_factory(&self) -> &VmFactory { - &self.factories.vm - } -} +impl ::miner::TransactionVerifierClient for Client {} +impl ::miner::BlockChainClient for Client {} impl super::traits::EngineClient for Client { fn update_sealing(&self) { @@ -2120,8 +2128,9 @@ impl super::traits::EngineClient for Client { } fn submit_seal(&self, block_hash: H256, seal: Vec) { - if self.importer.miner.submit_seal(self, block_hash, seal).is_err() { - warn!(target: "poa", "Wrong internal seal submission!") + let import = self.importer.miner.submit_seal(block_hash, seal).and_then(|block| self.import_sealed_block(block)); + if let Err(err) = import { + warn!(target: "poa", "Wrong internal seal submission! {:?}", err); } } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 2ae3436aa9..8f6b624a5e 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -38,7 +38,7 @@ pub use self::traits::{ }; //pub use self::private_notify::PrivateNotify; pub use state::StateInfo; -pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient, ProvingBlockChainClient}; +pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient}; pub use types::ids::*; pub use types::trace_filter::Filter as TraceFilter; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 6d61035af2..02067afd00 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -31,11 +31,12 @@ use kvdb_memorydb; use bytes::Bytes; use rlp::{UntrustedRlp, RlpStream}; use ethkey::{Generator, Random}; -use transaction::{self, Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action}; +use ethcore_miner::pool::VerifiedTransaction; +use transaction::{self, Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::{TreeRoute, BlockReceipts}; use client::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, CallContract, TransactionInfo, RegistryInfo, - PrepareOpenBlock, BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId, + PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter @@ -45,9 +46,7 @@ use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; use receipt::{Receipt, LocalizedReceipt, TransactionOutcome}; -use error::{ImportResult, Error as EthcoreError}; -use evm::VMType; -use factory::VmFactory; +use error::ImportResult; use vm::Schedule; use miner::{Miner, MinerService}; use spec::Spec; @@ -102,8 +101,6 @@ pub struct TestBlockChainClient { pub miner: Arc, /// Spec pub spec: Spec, - /// VM Factory - pub vm_factory: VmFactory, /// Timestamp assigned to latest sealed block pub latest_block_timestamp: RwLock, /// Ancient block info. @@ -174,9 +171,8 @@ impl TestBlockChainClient { receipts: RwLock::new(HashMap::new()), logs: RwLock::new(Vec::new()), queue_size: AtomicUsize::new(0), - miner: Arc::new(Miner::with_spec(&spec)), + miner: Arc::new(Miner::new_for_tests(&spec, None)), spec: spec, - vm_factory: VmFactory::new(VMType::Interpreter, 1024 * 1024), latest_block_timestamp: RwLock::new(10_000_000), ancient_block: RwLock::new(None), first_block: RwLock::new(None), @@ -345,8 +341,8 @@ impl TestBlockChainClient { self.set_balance(signed_tx.sender(), 10_000_000_000_000_000_000u64.into()); let hash = signed_tx.hash(); let res = self.miner.import_external_transactions(self, vec![signed_tx.into()]); - let res = res.into_iter().next().unwrap().expect("Successful import"); - assert_eq!(res, transaction::ImportResult::Current); + let res = res.into_iter().next().unwrap(); + assert!(res.is_ok()); hash } @@ -423,11 +419,8 @@ impl BroadcastProposalBlock for TestBlockChainClient { impl SealedBlockImporter for TestBlockChainClient {} -impl MiningBlockChainClient for TestBlockChainClient { - fn vm_factory(&self) -> &VmFactory { - &self.vm_factory - } -} +impl ::miner::TransactionVerifierClient for TestBlockChainClient {} +impl ::miner::BlockChainClient for TestBlockChainClient {} impl Nonce for TestBlockChainClient { fn nonce(&self, address: &Address, id: BlockId) -> Option { @@ -826,9 +819,8 @@ impl BlockChainClient for TestBlockChainClient { self.spec.engine.handle_message(&message).unwrap(); } - fn ready_transactions(&self) -> Vec { - let info = self.chain_info(); - self.miner.ready_transactions(info.best_block_number, info.best_block_timestamp) + fn ready_transactions(&self) -> Vec> { + self.miner.ready_transactions(self) } fn signing_chain_id(&self) -> Option { None } @@ -851,9 +843,9 @@ impl BlockChainClient for TestBlockChainClient { } } - fn transact_contract(&self, address: Address, data: Bytes) -> Result { + fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> { let transaction = Transaction { - nonce: self.latest_nonce(&self.miner.author()), + nonce: self.latest_nonce(&self.miner.authoring_params().author), action: Action::Call(address), gas: self.spec.gas_limit, gas_price: U256::zero(), @@ -895,8 +887,9 @@ impl super::traits::EngineClient for TestBlockChainClient { } fn submit_seal(&self, block_hash: H256, seal: Vec) { - if self.miner.submit_seal(self, block_hash, seal).is_err() { - warn!(target: "poa", "Wrong internal seal submission!") + let import = self.miner.submit_seal(block_hash, seal).and_then(|block| self.import_sealed_block(block)); + if let Err(err) = import { + warn!(target: "poa", "Wrong internal seal submission! {:?}", err); } } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 901ba30db3..7d4d5846c6 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -15,28 +15,30 @@ // along with Parity. If not, see . use std::collections::BTreeMap; +use std::sync::Arc; + use itertools::Itertools; use block::{OpenBlock, SealedBlock, ClosedBlock}; use blockchain::TreeRoute; use encoded; use vm::LastHashes; -use error::{ImportResult, CallError, Error as EthcoreError, BlockImportError}; +use error::{ImportResult, CallError, BlockImportError}; use evm::Schedule; -use factory::VmFactory; use executive::Executed; use filter::Filter; use header::{BlockNumber}; use log_entry::LocalizedLogEntry; use receipt::LocalizedReceipt; use trace::LocalizedTrace; -use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction, ImportResult as TransactionImportResult}; +use transaction::{self, LocalizedTransaction, SignedTransaction}; use verification::queue::QueueInfo as BlockQueueInfo; use state::StateInfo; use header::Header; use engines::EthEngine; use ethereum_types::{H256, U256, Address}; +use ethcore_miner::pool::VerifiedTransaction; use bytes::Bytes; use hashdb::DBValue; @@ -315,7 +317,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn queue_consensus_message(&self, message: Bytes); /// List all transactions that are allowed into the next block. - fn ready_transactions(&self) -> Vec; + fn ready_transactions(&self) -> Vec>; /// Sorted list of transaction gas prices from at least last sample_size blocks. fn gas_price_corpus(&self, sample_size: usize) -> ::stats::Corpus { @@ -366,8 +368,8 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Returns information about pruning/data availability. fn pruning_info(&self) -> PruningInfo; - /// Import a transaction: used for misbehaviour reporting. - fn transact_contract(&self, address: Address, data: Bytes) -> Result; + /// Schedule state-altering transaction to be executed on the next pending block. + fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error>; /// Get the address of the registry itself. fn registrar_address(&self) -> Option
; @@ -416,12 +418,6 @@ pub trait BroadcastProposalBlock { /// Provides methods to import sealed block and broadcast a block proposal pub trait SealedBlockImporter: ImportSealedBlock + BroadcastProposalBlock {} -/// Extended client interface used for mining -pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + ScheduleInfo + SealedBlockImporter { - /// Returns EvmFactory. - fn vm_factory(&self) -> &VmFactory; -} - /// Client facilities used by internally sealing Engines. pub trait EngineClient: Sync + Send + ChainInfo { /// Make a new block and seal it. diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 8282e5738a..e3acc5eed9 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -38,7 +38,7 @@ use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; use self::finality::RollingFinality; -use ethkey::{public_to_address, recover, verify_address, Signature}; +use ethkey::{self, Signature}; use io::{IoContext, IoHandler, TimerToken, IoService}; use itertools::{self, Itertools}; use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; @@ -292,14 +292,14 @@ impl EmptyStep { let message = keccak(empty_step_rlp(self.step, &self.parent_hash)); let correct_proposer = step_proposer(validators, &self.parent_hash, self.step); - verify_address(&correct_proposer, &self.signature.into(), &message) + ethkey::verify_address(&correct_proposer, &self.signature.into(), &message) .map_err(|e| e.into()) } fn author(&self) -> Result { let message = keccak(empty_step_rlp(self.step, &self.parent_hash)); - let public = recover(&self.signature.into(), &message)?; - Ok(public_to_address(&public)) + let public = ethkey::recover(&self.signature.into(), &message)?; + Ok(ethkey::public_to_address(&public)) } fn sealed(&self) -> SealedEmptyStep { @@ -555,7 +555,7 @@ fn verify_external(header: &Header, validators: &ValidatorSet, empty_steps_trans }; let header_seal_hash = header_seal_hash(header, empty_steps_rlp); - !verify_address(&correct_proposer, &proposer_signature, &header_seal_hash)? + !ethkey::verify_address(&correct_proposer, &proposer_signature, &header_seal_hash)? }; if is_invalid_proposer { @@ -824,7 +824,10 @@ impl Engine for AuthorityRound { fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal { // first check to avoid generating signature most of the time // (but there's still a race to the `compare_and_swap`) - if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; } + if !self.can_propose.load(AtomicOrdering::SeqCst) { + trace!(target: "engine", "Aborting seal generation. Can't propose."); + return Seal::None; + } let header = block.header(); let parent_step: U256 = header_step(parent, self.empty_steps_transition) @@ -1305,7 +1308,7 @@ impl Engine for AuthorityRound { } fn sign(&self, hash: H256) -> Result { - self.signer.read().sign(hash).map_err(Into::into) + Ok(self.signer.read().sign(hash)?) } fn snapshot_components(&self) -> Option> { diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index c4eafd851c..768cde3d5e 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -19,7 +19,7 @@ use std::sync::{Weak, Arc}; use ethereum_types::{H256, H520, Address}; use parking_lot::RwLock; -use ethkey::{recover, public_to_address, Signature}; +use ethkey::{self, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, ConstructedVerifier, EngineError}; @@ -61,7 +61,7 @@ fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Err // Check if the signature belongs to a validator, can depend on parent state. let sig = UntrustedRlp::new(&header.seal()[0]).as_val::()?; - let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?); + let signer = ethkey::public_to_address(ðkey::recover(&sig.into(), &header.bare_hash())?); if *header.author() != signer { return Err(EngineError::NotAuthorized(*header.author()).into()) @@ -185,7 +185,7 @@ impl Engine for BasicAuthority { } fn sign(&self, hash: H256) -> Result { - self.signer.read().sign(hash).map_err(Into::into) + Ok(self.signer.read().sign(hash)?) } fn snapshot_components(&self) -> Option> { diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 65fa13b54e..4d22bd1f76 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -48,7 +48,7 @@ use error::Error; use header::{Header, BlockNumber}; use snapshot::SnapshotComponents; use spec::CommonParams; -use transaction::{UnverifiedTransaction, SignedTransaction}; +use transaction::{self, UnverifiedTransaction, SignedTransaction}; use ethkey::Signature; use parity_machine::{Machine, LocalizedMachine as Localized}; @@ -387,14 +387,28 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> { } /// Verify a particular transaction is valid. - fn verify_transaction_unordered(&self, t: UnverifiedTransaction, header: &Header) -> Result { + /// + /// Unordered verification doesn't rely on the transaction execution order, + /// i.e. it should only verify stuff that doesn't assume any previous transactions + /// has already been verified and executed. + /// + /// NOTE This function consumes an `UnverifiedTransaction` and produces `SignedTransaction` + /// which implies that a heavy check of the signature is performed here. + fn verify_transaction_unordered(&self, t: UnverifiedTransaction, header: &Header) -> Result { self.machine().verify_transaction_unordered(t, header) } - /// Additional verification for transactions in blocks. - // TODO: Add flags for which bits of the transaction to check. - // TODO: consider including State in the params. - fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> { + /// Perform basic/cheap transaction verification. + /// + /// This should include all cheap checks that can be done before + /// actually checking the signature, like chain-replay protection. + /// + /// NOTE This is done before the signature is recovered so avoid + /// doing any state-touching checks that might be expensive. + /// + /// TODO: Add flags for which bits of the transaction to check. + /// TODO: consider including State in the params. + fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), transaction::Error> { self.machine().verify_transaction_basic(t, header) } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 011e3f8d42..c9312e9043 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -37,7 +37,7 @@ use bytes::Bytes; use error::{Error, BlockError}; use header::{Header, BlockNumber}; use rlp::UntrustedRlp; -use ethkey::{Message, public_to_address, recover, Signature}; +use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; @@ -518,8 +518,8 @@ impl Engine for Tendermint { let message: ConsensusMessage = rlp.as_val().map_err(fmt_err)?; if !self.votes.is_old_or_known(&message) { let msg_hash = keccak(rlp.at(1).map_err(fmt_err)?.as_raw()); - let sender = public_to_address( - &recover(&message.signature.into(), &msg_hash).map_err(fmt_err)? + let sender = ethkey::public_to_address( + ðkey::recover(&message.signature.into(), &msg_hash).map_err(fmt_err)? ); if !self.is_authority(&sender) { @@ -614,7 +614,7 @@ impl Engine for Tendermint { }; let address = match self.votes.get(&precommit) { Some(a) => a, - None => public_to_address(&recover(&precommit.signature.into(), &precommit_hash)?), + None => ethkey::public_to_address(ðkey::recover(&precommit.signature.into(), &precommit_hash)?), }; if !self.validators.contains(header.parent_hash(), &address) { return Err(EngineError::NotAuthorized(address.to_owned()).into()); @@ -669,7 +669,7 @@ impl Engine for Tendermint { let verifier = Box::new(EpochVerifier { subchain_validators: list, recover: |signature: &Signature, message: &Message| { - Ok(public_to_address(&::ethkey::recover(&signature, &message)?)) + Ok(ethkey::public_to_address(ðkey::recover(&signature, &message)?)) }, }); @@ -690,7 +690,7 @@ impl Engine for Tendermint { } fn sign(&self, hash: H256) -> Result { - self.signer.read().sign(hash).map_err(Into::into) + Ok(self.signer.read().sign(hash)?) } fn snapshot_components(&self) -> Option> { @@ -1026,7 +1026,7 @@ mod tests { let client = generate_dummy_client_with_spec_and_accounts(Spec::new_test_tendermint, Some(tap.clone())); let engine = client.engine(); - client.miner().set_engine_signer(v1.clone(), "1".into()).unwrap(); + client.miner().set_author(v1.clone(), Some("1".into())).unwrap(); let notify = Arc::new(TestNotify::default()); client.add_notify(notify.clone()); diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index fb9fccf3e2..00f74fd2eb 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -169,8 +169,8 @@ mod tests { let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); // Make sure reporting can be done. - client.miner().set_gas_floor_target(1_000_000.into()); - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_gas_range_target((1_000_000.into(), 1_000_000.into())); + client.miner().set_author(v1, Some("".into())).unwrap(); // Check a block that is a bit in future, reject it but don't report the validator. let mut header = Header::default(); diff --git a/ethcore/src/engines/validator_set/multi.rs b/ethcore/src/engines/validator_set/multi.rs index 9c287f9a37..89a33abc74 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -171,22 +171,22 @@ mod tests { client.engine().register_client(Arc::downgrade(&client) as _); // Make sure txs go through. - client.miner().set_gas_floor_target(1_000_000.into()); + client.miner().set_gas_range_target((1_000_000.into(), 1_000_000.into())); // Wrong signer for the first block. - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); client.transact_contract(Default::default(), Default::default()).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 0); // Right signer for the first block. - client.miner().set_engine_signer(v0, "".into()).unwrap(); + client.miner().set_author(v0, Some("".into())).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); // This time v0 is wrong. client.transact_contract(Default::default(), Default::default()).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 2); // v1 is still good. diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 82befdadff..5c73cb28d1 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -484,7 +484,7 @@ mod tests { client.engine().register_client(Arc::downgrade(&client) as _); let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); // Remove "1" validator. let tx = Transaction { nonce: 0.into(), @@ -512,11 +512,11 @@ mod tests { assert_eq!(client.chain_info().best_block_number, 1); // Switch to the validator that is still there. - client.miner().set_engine_signer(v0, "".into()).unwrap(); + client.miner().set_author(v0, Some("".into())).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 2); // Switch back to the added validator, since the state is updated. - client.miner().set_engine_signer(v1, "".into()).unwrap(); + client.miner().set_author(v1, Some("".into())).unwrap(); let tx = Transaction { nonce: 2.into(), gas_price: 0.into(), diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 64414450bd..89b8df4a26 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -64,7 +64,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { config, &spec, db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); for b in &blockchain.blocks_rlp() { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index c71a266f74..abb680c952 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -71,7 +71,6 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethjson; extern crate ethkey; -extern crate futures_cpupool; extern crate hardware_wallet; extern crate hashdb; extern crate itertools; @@ -80,7 +79,6 @@ extern crate num_cpus; extern crate num; extern crate parity_machine; extern crate parking_lot; -extern crate price_info; extern crate rand; extern crate rayon; extern crate rlp; @@ -99,18 +97,10 @@ extern crate util_error; extern crate snappy; extern crate ethabi; -#[macro_use] -extern crate ethabi_derive; -#[macro_use] -extern crate ethabi_contract; - -#[macro_use] -extern crate rlp_derive; extern crate rustc_hex; extern crate stats; extern crate stop_guard; extern crate using_queue; -extern crate table; extern crate vm; extern crate wasm; extern crate memory_cache; @@ -119,13 +109,20 @@ extern crate journaldb; extern crate tempdir; #[macro_use] -extern crate macros; +extern crate ethabi_derive; +#[macro_use] +extern crate ethabi_contract; #[macro_use] extern crate log; #[macro_use] extern crate lazy_static; #[macro_use] +extern crate macros; +#[macro_use] +extern crate rlp_derive; +#[macro_use] extern crate trace_time; + #[cfg_attr(test, macro_use)] extern crate evm; diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index fa6a62454e..7d488e0d0c 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -334,12 +334,12 @@ impl EthereumMachine { } /// Verify a particular transaction is valid, regardless of order. - pub fn verify_transaction_unordered(&self, t: UnverifiedTransaction, _header: &Header) -> Result { + pub fn verify_transaction_unordered(&self, t: UnverifiedTransaction, _header: &Header) -> Result { Ok(SignedTransaction::new(t)?) } /// Does basic verification of the transaction. - pub fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> { + pub fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), transaction::Error> { let check_low_s = match self.ethash_extensions { Some(ref ext) => header.number() >= ext.homestead_transition, None => true, @@ -358,9 +358,9 @@ impl EthereumMachine { } /// Does verification of the transaction against the parent state. - // TODO: refine the bound here to be a "state provider" or similar as opposed - // to full client functionality. - pub fn verify_transaction(&self, t: &SignedTransaction, header: &Header, client: &C) -> Result<(), Error> { + pub fn verify_transaction(&self, t: &SignedTransaction, header: &Header, client: &C) + -> Result<(), transaction::Error> + { if let Some(ref filter) = self.tx_filter.as_ref() { if !filter.transaction_allowed(header.parent_hash(), t, client) { return Err(transaction::Error::NotAllowed.into()) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 755294637b..e344ee6b12 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -15,49 +15,38 @@ // along with Parity. If not, see . use std::time::{Instant, Duration}; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, HashMap}; use std::sync::Arc; -use account_provider::{AccountProvider, SignError as AccountError}; use ansi_term::Colour; -use ethereum_types::{H256, U256, Address}; -use parking_lot::{Mutex, RwLock}; use bytes::Bytes; use engines::{EthEngine, Seal}; -use error::{ExecutionError, Error}; -use ethcore_miner::banning_queue::{BanningTransactionQueue, Threshold}; -use ethcore_miner::local_transactions::{Status as LocalTransactionStatus}; -use ethcore_miner::transaction_queue::{ - TransactionQueue, - RemovalReason, - TransactionDetailsProvider as TransactionQueueDetailsProvider, - PrioritizationStrategy, - AccountDetails, - TransactionOrigin, -}; -use futures_cpupool::CpuPool; +use error::{Error, ExecutionError}; +use ethcore_miner::gas_pricer::GasPricer; +use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy}; use ethcore_miner::work_notify::NotifyWork; -use miner::service_transaction_checker::ServiceTransactionChecker; -use miner::{MinerService, MinerStatus}; -use price_info::fetch::Client as FetchClient; -use price_info::{Client as PriceInfoClient, PriceInfo}; +use ethereum_types::{H256, U256, Address}; +use parking_lot::{Mutex, RwLock}; +use rayon::prelude::*; use transaction::{ + self, Action, UnverifiedTransaction, - PendingTransaction, SignedTransaction, - Condition as TransactionCondition, - ImportResult as TransactionImportResult, - Error as TransactionError, + PendingTransaction, }; use using_queue::{UsingQueue, GetAction}; -use block::{ClosedBlock, IsBlock, Block}; + +use account_provider::{AccountProvider, SignError as AccountError}; +use block::{ClosedBlock, IsBlock, Block, SealedBlock}; use client::{ - AccountData, BlockChain, RegistryInfo, ScheduleInfo, CallContract, BlockProducer, SealedBlockImporter + BlockChain, ChainInfo, CallContract, BlockProducer, SealedBlockImporter, Nonce }; -use client::{BlockId, TransactionId, MiningBlockChainClient}; +use client::BlockId; use executive::contract_address; use header::{Header, BlockNumber}; +use miner; +use miner::pool_client::{PoolClient, CachedNonceClient}; use receipt::{Receipt, RichReceipt}; use spec::Spec; use state::State; @@ -68,39 +57,44 @@ pub enum PendingSet { /// Always just the transactions in the queue. These have had only cheap checks. AlwaysQueue, /// Always just the transactions in the sealing block. These have had full checks but - /// may be empty if the node is not actively mining or has force_sealing enabled. + /// may be empty if the node is not actively mining or has no force_sealing enabled. AlwaysSealing, - /// Try the sealing block, but if it is not currently sealing, fallback to the queue. + /// Takes from sealing if mining, from queue otherwise. SealingOrElseQueue, } -/// Type of the gas limit to apply to the transaction queue. -#[derive(Debug, PartialEq)] -pub enum GasLimit { - /// Depends on the block gas limit and is updated with every block. - Auto, - /// No limit. - None, - /// Set to a fixed gas value. - Fixed(U256), -} - -/// Transaction queue banning settings. +/// Transaction queue penalization settings. +/// +/// Senders of long-running transactions (above defined threshold) +/// will get lower priority. #[derive(Debug, PartialEq, Clone)] -pub enum Banning { - /// Banning in transaction queue is disabled +pub enum Penalization { + /// Penalization in transaction queue is disabled Disabled, - /// Banning in transaction queue is enabled + /// Penalization in transaction queue is enabled Enabled { - /// Upper limit of transaction processing time before banning. + /// Upper limit of transaction processing time before penalizing. offend_threshold: Duration, - /// Number of similar offending transactions before banning. - min_offends: u16, - /// Number of seconds the offender is banned for. - ban_duration: Duration, }, } +/// Initial minimal gas price. +/// +/// Gas price should be later overwritten externally +/// for instance by a dynamic gas price mechanism or CLI parameter. +/// This constant controls the initial value. +const DEFAULT_MINIMAL_GAS_PRICE: u64 = 20_000_000_000; + +/// Allowed number of skipped transactions when constructing pending block. +/// +/// When we push transactions to pending block, some of the transactions might +/// get skipped because of block gas limit being reached. +/// This constant controls how many transactions we can skip because of that +/// before stopping attempts to push more transactions to the block. +/// This is an optimization that prevents traversing the entire pool +/// in case we have only a fraction of available block gas limit left. +const MAX_SKIPPED_TRANSACTIONS: usize = 8; + /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] pub struct MinerOptions { @@ -116,30 +110,28 @@ pub struct MinerOptions { pub reseal_min_period: Duration, /// Maximum period between blocks (enables force sealing after that). pub reseal_max_period: Duration, - /// Maximum amount of gas to bother considering for block insertion. - pub tx_gas_limit: U256, - /// Maximum size of the transaction queue. - pub tx_queue_size: usize, - /// Maximum memory usage of transactions in the queue (current / future). - pub tx_queue_memory_limit: Option, - /// Strategy to use for prioritizing transactions in the queue. - pub tx_queue_strategy: PrioritizationStrategy, /// Whether we should fallback to providing all the queue's transactions or just pending. pub pending_set: PendingSet, /// How many historical work packages can we store before running out? pub work_queue_size: usize, /// Can we submit two different solutions for the same block and expect both to result in an import? pub enable_resubmission: bool, - /// Global gas limit for all transaction in the queue except for local and retracted. - pub tx_queue_gas_limit: GasLimit, - /// Banning settings. - pub tx_queue_banning: Banning, - /// Do we refuse to accept service transactions even if sender is certified. - pub refuse_service_transactions: bool, /// Create a pending block with maximal possible gas limit. /// NOTE: Such block will contain all pending transactions but /// will be invalid if mined. pub infinite_pending_block: bool, + + + /// Strategy to use for prioritizing transactions in the queue. + pub tx_queue_strategy: PrioritizationStrategy, + /// Simple senders penalization. + pub tx_queue_penalization: Penalization, + /// Do we refuse to accept service transactions even if sender is certified. + pub refuse_service_transactions: bool, + /// Transaction pool limits. + pub pool_limits: pool::Options, + /// Initial transaction verification options. + pub pool_verification_options: pool::verifier::Options, } impl Default for MinerOptions { @@ -149,249 +141,185 @@ impl Default for MinerOptions { reseal_on_external_tx: false, reseal_on_own_tx: true, reseal_on_uncle: false, - tx_gas_limit: !U256::zero(), - tx_queue_size: 8192, - tx_queue_memory_limit: Some(2 * 1024 * 1024), - tx_queue_gas_limit: GasLimit::None, - tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, - pending_set: PendingSet::AlwaysQueue, reseal_min_period: Duration::from_secs(2), reseal_max_period: Duration::from_secs(120), + pending_set: PendingSet::AlwaysQueue, work_queue_size: 20, enable_resubmission: true, - tx_queue_banning: Banning::Disabled, - refuse_service_transactions: false, infinite_pending_block: false, + tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, + tx_queue_penalization: Penalization::Disabled, + refuse_service_transactions: false, + pool_limits: pool::Options { + max_count: 8_192, + max_per_sender: 81, + max_mem_usage: 4 * 1024 * 1024, + }, + pool_verification_options: pool::verifier::Options { + minimal_gas_price: DEFAULT_MINIMAL_GAS_PRICE.into(), + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + }, } } } -/// Options for the dynamic gas price recalibrator. -#[derive(Debug, PartialEq)] -pub struct GasPriceCalibratorOptions { - /// Base transaction price to match against. - pub usd_per_tx: f32, - /// How frequently we should recalibrate. - pub recalibration_period: Duration, -} - -/// The gas price validator variant for a `GasPricer`. -#[derive(Debug, PartialEq)] -pub struct GasPriceCalibrator { - options: GasPriceCalibratorOptions, - next_calibration: Instant, - price_info: PriceInfoClient, -} - -impl GasPriceCalibrator { - fn recalibrate(&mut self, set_price: F) { - trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration); - if Instant::now() >= self.next_calibration { - let usd_per_tx = self.options.usd_per_tx; - trace!(target: "miner", "Getting price info"); - - self.price_info.get(move |price: PriceInfo| { - trace!(target: "miner", "Price info arrived: {:?}", price); - let usd_per_eth = price.ethusd; - let wei_per_usd: f32 = 1.0e18 / usd_per_eth; - let gas_per_tx: f32 = 21000.0; - let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; - info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas))); - set_price(U256::from(wei_per_gas as u64)); - }); - - self.next_calibration = Instant::now() + self.options.recalibration_period; - } - } -} - -/// Struct to look after updating the acceptable gas price of a miner. -#[derive(Debug, PartialEq)] -pub enum GasPricer { - /// A fixed gas price in terms of Wei - always the argument given. - Fixed(U256), - /// Gas price is calibrated according to a fixed amount of USD. - Calibrated(GasPriceCalibrator), -} - -impl GasPricer { - /// Create a new Calibrated `GasPricer`. - pub fn new_calibrated(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPricer { - GasPricer::Calibrated(GasPriceCalibrator { - options: options, - next_calibration: Instant::now(), - price_info: PriceInfoClient::new(fetch, p), - }) - } - - /// Create a new Fixed `GasPricer`. - pub fn new_fixed(gas_price: U256) -> GasPricer { - GasPricer::Fixed(gas_price) - } - - fn recalibrate(&mut self, set_price: F) { - match *self { - GasPricer::Fixed(ref max) => set_price(max.clone()), - GasPricer::Calibrated(ref mut cal) => cal.recalibrate(set_price), - } - } +/// Configurable parameters of block authoring. +#[derive(Debug, Default, Clone)] +pub struct AuthoringParams { + /// Lower and upper bound of block gas limit that we are targeting + pub gas_range_target: (U256, U256), + /// Block author + pub author: Address, + /// Block extra data + pub extra_data: Bytes, } struct SealingWork { queue: UsingQueue, enabled: bool, + next_allowed_reseal: Instant, + next_mandatory_reseal: Instant, + // block number when sealing work was last requested + last_request: u64, +} + +impl SealingWork { + /// Are we allowed to do a non-mandatory reseal? + fn reseal_allowed(&self) -> bool { + Instant::now() > self.next_allowed_reseal + } } /// Keeps track of transactions using priority queue and holds currently mined block. /// Handles preparing work for "work sealing" or seals "internally" if Engine does not require work. pub struct Miner { // NOTE [ToDr] When locking always lock in this order! - transaction_queue: Arc>, - transaction_listener: RwLock>>, - sealing_work: Mutex, - next_allowed_reseal: Mutex, - next_mandatory_reseal: RwLock, - sealing_block_last_request: Mutex, - // for sealing... + sealing: Mutex, + params: RwLock, + listeners: RwLock>>, + nonce_cache: RwLock>, + gas_pricer: Mutex, options: MinerOptions, - - gas_range_target: RwLock<(U256, U256)>, - author: RwLock
, - extra_data: RwLock, + // TODO [ToDr] Arc is only required because of price updater + transaction_queue: Arc, engine: Arc, - accounts: Option>, - notifiers: RwLock>>, - gas_pricer: Mutex, - service_transaction_action: ServiceTransactionAction, } impl Miner { - /// Push notifier that will handle new jobs - pub fn push_notifier(&self, notifier: Box) { - self.notifiers.write().push(notifier); - self.sealing_work.lock().enabled = true; + /// Push listener that will handle new jobs + pub fn add_work_listener(&self, notifier: Box) { + self.listeners.write().push(notifier); + self.sealing.lock().enabled = true; } - /// Creates new instance of miner Arc. - pub fn new(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option>) -> Arc { - Arc::new(Miner::new_raw(options, gas_pricer, spec, accounts)) + /// Set a callback to be notified about imported transactions' hashes. + pub fn add_transactions_listener(&self, f: Box) { + self.transaction_queue.add_listener(f); } - /// Creates new instance of miner. - fn new_raw(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option>) -> Miner { - let gas_limit = match options.tx_queue_gas_limit { - GasLimit::Fixed(ref limit) => *limit, - _ => !U256::zero(), - }; - let mem_limit = options.tx_queue_memory_limit.unwrap_or_else(usize::max_value); - - let txq = TransactionQueue::with_limits( - options.tx_queue_strategy, - options.tx_queue_size, - mem_limit, - gas_limit, - options.tx_gas_limit - ); - let txq = match options.tx_queue_banning { - Banning::Disabled => BanningTransactionQueue::new(txq, Threshold::NeverBan, Duration::from_secs(180)), - Banning::Enabled { ban_duration, min_offends, .. } => BanningTransactionQueue::new( - txq, - Threshold::BanAfter(min_offends), - ban_duration, - ), - }; - - let notifiers: Vec> = Vec::new(); - - let service_transaction_action = match options.refuse_service_transactions { - true => ServiceTransactionAction::Refuse, - false => ServiceTransactionAction::Check(ServiceTransactionChecker::default()), - }; + /// Creates new instance of miner Arc. + pub fn new(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option>) -> Self { + let limits = options.pool_limits.clone(); + let verifier_options = options.pool_verification_options.clone(); + let tx_queue_strategy = options.tx_queue_strategy; Miner { - transaction_queue: Arc::new(RwLock::new(txq)), - transaction_listener: RwLock::new(vec![]), - next_allowed_reseal: Mutex::new(Instant::now()), - next_mandatory_reseal: RwLock::new(Instant::now() + options.reseal_max_period), - sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(SealingWork{ + sealing: Mutex::new(SealingWork { queue: UsingQueue::new(options.work_queue_size), enabled: options.force_sealing - || spec.engine.seals_internally().is_some() + || spec.engine.seals_internally().is_some(), + next_allowed_reseal: Instant::now(), + next_mandatory_reseal: Instant::now() + options.reseal_max_period, + last_request: 0, }), - gas_range_target: RwLock::new((U256::zero(), U256::zero())), - author: RwLock::new(Address::default()), - extra_data: RwLock::new(Vec::new()), - options: options, - accounts: accounts, - engine: spec.engine.clone(), - notifiers: RwLock::new(notifiers), + params: RwLock::new(AuthoringParams::default()), + listeners: RwLock::new(vec![]), gas_pricer: Mutex::new(gas_pricer), - service_transaction_action: service_transaction_action, + nonce_cache: RwLock::new(HashMap::with_capacity(1024)), + options, + transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)), + accounts, + engine: spec.engine.clone(), } } - /// Creates new instance of miner with accounts and with given spec. - pub fn with_spec_and_accounts(spec: &Spec, accounts: Option>) -> Miner { - Miner::new_raw(Default::default(), GasPricer::new_fixed(20_000_000_000u64.into()), spec, accounts) - } - - /// Creates new instance of miner without accounts, but with given spec. - pub fn with_spec(spec: &Spec) -> Miner { - Miner::new_raw(Default::default(), GasPricer::new_fixed(20_000_000_000u64.into()), spec, None) - } - - fn forced_sealing(&self) -> bool { - self.options.force_sealing || !self.notifiers.read().is_empty() + /// Creates new instance of miner with given spec and accounts. + /// + /// NOTE This should be only used for tests. + pub fn new_for_tests(spec: &Spec, accounts: Option>) -> Miner { + let minimal_gas_price = 0.into(); + Miner::new(MinerOptions { + pool_verification_options: pool::verifier::Options { + minimal_gas_price, + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + }, + reseal_min_period: Duration::from_secs(0), + ..Default::default() + }, GasPricer::new_fixed(minimal_gas_price), spec, accounts) } /// Clear all pending block states pub fn clear(&self) { - self.sealing_work.lock().queue.reset(); + self.sealing.lock().queue.reset(); } - /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. - pub fn pending_state(&self, latest_block_number: BlockNumber) -> Option> { - self.map_pending_block(|b| b.state().clone(), latest_block_number) - } - - /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. - pub fn pending_block(&self, latest_block_number: BlockNumber) -> Option { - self.map_pending_block(|b| b.to_base(), latest_block_number) - } - - /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. - pub fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
{ - self.map_pending_block(|b| b.header().clone(), latest_block_number) + /// Updates transaction queue verification limits. + /// + /// Limits consist of current block gas limit and minimal gas price. + pub fn update_transaction_queue_limits(&self, block_gas_limit: U256) { + trace!(target: "miner", "minimal_gas_price: recalibrating..."); + let txq = self.transaction_queue.clone(); + let mut options = self.options.pool_verification_options.clone(); + self.gas_pricer.lock().recalibrate(move |gas_price| { + debug!(target: "miner", "minimal_gas_price: Got gas price! {}", gas_price); + options.minimal_gas_price = gas_price; + options.block_gas_limit = block_gas_limit; + txq.set_verifier_options(options); + }); } - /// Set a callback to be notified about imported transactions' hashes. - pub fn add_transactions_listener(&self, f: Box) { - self.transaction_listener.write().push(f); + /// Retrieves an existing pending block iff it's not older than given block number. + /// + /// NOTE: This will not prepare a new pending block if it's not existing. + /// See `map_pending_block` for alternative behaviour. + fn map_existing_pending_block(&self, f: F, latest_block_number: BlockNumber) -> Option where + F: FnOnce(&ClosedBlock) -> T, + { + self.sealing.lock().queue + .peek_last_ref() + .and_then(|b| if b.block().header().number() > latest_block_number { + Some(f(b)) + } else { + None + }) } - fn map_pending_block(&self, f: F, latest_block_number: BlockNumber) -> Option where - F: FnOnce(&ClosedBlock) -> T, + fn pool_client<'a, C: 'a>(&'a self, chain: &'a C) -> PoolClient<'a, C> where + C: BlockChain + CallContract, { - self.from_pending_block( - latest_block_number, - || None, - |block| Some(f(block)), + PoolClient::new( + chain, + &self.nonce_cache, + &*self.engine, + self.accounts.as_ref().map(|x| &**x), + self.options.refuse_service_transactions, ) } /// Prepares new block for sealing including top transactions from queue. - fn prepare_block(&self, chain: &C) -> (ClosedBlock, Option) { + fn prepare_block(&self, chain: &C) -> (ClosedBlock, Option) where + C: BlockChain + CallContract + BlockProducer + Nonce + Sync, + { trace_time!("prepare_block"); let chain_info = chain.chain_info(); - let (transactions, mut open_block, original_work_hash) = { - let nonce_cap = if chain_info.best_block_number + 1 >= self.engine.params().dust_protection_transition { - Some((self.engine.params().nonce_cap_increment * (chain_info.best_block_number + 1)).into()) - } else { None }; - let transactions = {self.transaction_queue.read().top_transactions_at(chain_info.best_block_number, chain_info.best_block_timestamp, nonce_cap)}; - let mut sealing_work = self.sealing_work.lock(); - let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().header().hash()); + + // Open block + let (mut open_block, original_work_hash) = { + let mut sealing = self.sealing.lock(); + let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.block().header().hash()); let best_hash = chain_info.best_block_hash; // check to see if last ClosedBlock in would_seals is actually same parent block. @@ -400,7 +328,7 @@ impl Miner { // if at least one was pushed successfully, close and enqueue new ClosedBlock; // otherwise, leave everything alone. // otherwise, author a fresh block. - let mut open_block = match sealing_work.queue.pop_if(|b| b.block().header().parent_hash() == &best_hash) { + let mut open_block = match sealing.queue.pop_if(|b| b.block().header().parent_hash() == &best_hash) { Some(old_block) => { trace!(target: "miner", "prepare_block: Already have previous work; updating and returning"); // add transactions to old_block @@ -409,10 +337,11 @@ impl Miner { None => { // block not found - create it. trace!(target: "miner", "prepare_block: No existing work - making new block"); + let params = self.params.read().clone(); chain.prepare_open_block( - self.author(), - (self.gas_floor_target(), self.gas_ceil_target()), - self.extra_data() + params.author, + params.gas_range_target, + params.extra_data, ) } }; @@ -421,58 +350,87 @@ impl Miner { open_block.remove_gas_limit(); } - (transactions, open_block, last_work_hash) + (open_block, last_work_hash) }; let mut invalid_transactions = HashSet::new(); - let mut non_allowed_transactions = HashSet::new(); - let mut transactions_to_penalize = HashSet::new(); + let mut not_allowed_transactions = HashSet::new(); + let mut senders_to_penalize = HashSet::new(); let block_number = open_block.block().header().number(); - let mut tx_count: usize = 0; - let tx_total = transactions.len(); - for tx in transactions { - let hash = tx.hash(); + let mut tx_count = 0usize; + let mut skipped_transactions = 0usize; + + let client = self.pool_client(chain); + let engine_params = self.engine.params(); + let min_tx_gas = self.engine.schedule(chain_info.best_block_number).tx_gas.into(); + let nonce_cap: Option = if chain_info.best_block_number + 1 >= engine_params.dust_protection_transition { + Some((engine_params.nonce_cap_increment * (chain_info.best_block_number + 1)).into()) + } else { + None + }; + + let pending: Vec> = self.transaction_queue.pending( + client.clone(), + chain_info.best_block_number, + chain_info.best_block_timestamp, + nonce_cap, + ); + + let took_ms = |elapsed: &Duration| { + elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000 + }; + + let block_start = Instant::now(); + debug!(target: "miner", "Attempting to push {} transactions.", pending.len()); + + for tx in pending { let start = Instant::now(); - // Check whether transaction type is allowed for sender - let result = match self.engine.machine().verify_transaction(&tx, open_block.header(), chain) { - Err(Error::Transaction(TransactionError::NotAllowed)) => { - Err(TransactionError::NotAllowed.into()) - } - _ => { - open_block.push_transaction(tx, None) - } - }; + + let transaction = tx.signed().clone(); + let hash = transaction.hash(); + let sender = transaction.sender(); + + // Re-verify transaction again vs current state. + let result = client.verify_signed(&transaction) + .map_err(Error::Transaction) + .and_then(|_| { + open_block.push_transaction(transaction, None) + }); + let took = start.elapsed(); // Check for heavy transactions - match self.options.tx_queue_banning { - Banning::Enabled { ref offend_threshold, .. } if &took > offend_threshold => { - match self.transaction_queue.write().ban_transaction(&hash) { - true => { - warn!(target: "miner", "Detected heavy transaction. Banning the sender and recipient/code."); - }, - false => { - transactions_to_penalize.insert(hash); - debug!(target: "miner", "Detected heavy transaction. Penalizing sender.") - } - } + match self.options.tx_queue_penalization { + Penalization::Enabled { ref offend_threshold } if &took > offend_threshold => { + senders_to_penalize.insert(sender); + debug!(target: "miner", "Detected heavy transaction ({} ms). Penalizing sender.", took_ms(&took)); }, _ => {}, } - trace!(target: "miner", "Adding tx {:?} took {:?}", hash, took); + + debug!(target: "miner", "Adding tx {:?} took {} ms", hash, took_ms(&took)); match result { Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) => { debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?})", hash, gas_limit, gas_used, gas); // Penalize transaction if it's above current gas limit if gas > gas_limit { - transactions_to_penalize.insert(hash); + debug!(target: "txqueue", "[{:?}] Transaction above block gas limit.", hash); + invalid_transactions.insert(hash); } // Exit early if gas left is smaller then min_tx_gas - let min_tx_gas: U256 = 21000.into(); // TODO: figure this out properly. - if gas_limit - gas_used < min_tx_gas { + let gas_left = gas_limit - gas_used; + if gas_left < min_tx_gas { + debug!(target: "miner", "Remaining gas is lower than minimal gas for a transaction. Block is full."); + break; + } + + // Avoid iterating over the entire queue in case block is almost full. + skipped_transactions += 1; + if skipped_transactions > MAX_SKIPPED_TRANSACTIONS { + debug!(target: "miner", "Reached skipped transactions threshold. Assuming block is full."); break; } }, @@ -482,338 +440,281 @@ impl Miner { debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got); }, // already have transaction - ignore - Err(Error::Transaction(TransactionError::AlreadyImported)) => {}, - Err(Error::Transaction(TransactionError::NotAllowed)) => { - non_allowed_transactions.insert(hash); - debug!(target: "miner", - "Skipping non-allowed transaction for sender {:?}", - hash); + Err(Error::Transaction(transaction::Error::AlreadyImported)) => {}, + Err(Error::Transaction(transaction::Error::NotAllowed)) => { + not_allowed_transactions.insert(hash); + debug!(target: "miner", "Skipping non-allowed transaction for sender {:?}", hash); }, Err(e) => { + debug!(target: "txqueue", "[{:?}] Marking as invalid: {:?}.", hash, e); + debug!( + target: "miner", "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", block_number, hash, e + ); invalid_transactions.insert(hash); - debug!(target: "miner", - "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", - block_number, hash, e); }, - _ => { - tx_count += 1; - } // imported ok + // imported ok + _ => tx_count += 1, } } - trace!(target: "miner", "Pushed {}/{} transactions", tx_count, tx_total); + let elapsed = block_start.elapsed(); + debug!(target: "miner", "Pushed {} transactions in {} ms", tx_count, took_ms(&elapsed)); let block = open_block.close(); - let fetch_nonce = |a: &Address| chain.latest_nonce(a); - { - let mut queue = self.transaction_queue.write(); - for hash in invalid_transactions { - queue.remove(&hash, &fetch_nonce, RemovalReason::Invalid); - } - for hash in non_allowed_transactions { - queue.remove(&hash, &fetch_nonce, RemovalReason::NotAllowed); - } - for hash in transactions_to_penalize { - queue.penalize(&hash); - } + self.transaction_queue.remove(invalid_transactions.iter(), true); + self.transaction_queue.remove(not_allowed_transactions.iter(), false); + self.transaction_queue.penalize(senders_to_penalize.iter()); } + (block, original_work_hash) } - /// Asynchronously updates minimal gas price for transaction queue - pub fn recalibrate_minimal_gas_price(&self) { - debug!(target: "miner", "minimal_gas_price: recalibrating..."); - let txq = self.transaction_queue.clone(); - self.gas_pricer.lock().recalibrate(move |price| { - debug!(target: "miner", "minimal_gas_price: Got gas price! {}", price); - txq.write().set_minimal_gas_price(price); - }); + /// Returns `true` if we should create pending block even if some other conditions are not met. + /// + /// In general we always seal iff: + /// 1. --force-sealing CLI parameter is provided + /// 2. There are listeners awaiting new work packages (e.g. remote work notifications or stratum). + fn forced_sealing(&self) -> bool { + self.options.force_sealing || !self.listeners.read().is_empty() } /// Check is reseal is allowed and necessary. fn requires_reseal(&self, best_block: BlockNumber) -> bool { - let has_local_transactions = self.transaction_queue.read().has_local_pending_transactions(); - let mut sealing_work = self.sealing_work.lock(); - if sealing_work.enabled { - trace!(target: "miner", "requires_reseal: sealing enabled"); - let last_request = *self.sealing_block_last_request.lock(); - let should_disable_sealing = !self.forced_sealing() - && !has_local_transactions - && self.engine.seals_internally().is_none() - && best_block > last_request - && best_block - last_request > SEALING_TIMEOUT_IN_BLOCKS; - - trace!(target: "miner", "requires_reseal: should_disable_sealing={}; best_block={}, last_request={}", should_disable_sealing, best_block, last_request); - - if should_disable_sealing { - trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, last_request); - sealing_work.enabled = false; - sealing_work.queue.reset(); - false - } else { - // sealing enabled and we don't want to sleep. - *self.next_allowed_reseal.lock() = Instant::now() + self.options.reseal_min_period; - true - } - } else { + let mut sealing = self.sealing.lock(); + if !sealing.enabled { trace!(target: "miner", "requires_reseal: sealing is disabled"); + return false + } + + if !sealing.reseal_allowed() { + trace!(target: "miner", "requires_reseal: reseal too early"); + return false + } + + trace!(target: "miner", "requires_reseal: sealing enabled"); + + // Disable sealing if there were no requests for SEALING_TIMEOUT_IN_BLOCKS + let had_requests = best_block > sealing.last_request + && best_block - sealing.last_request <= SEALING_TIMEOUT_IN_BLOCKS; + + // keep sealing enabled if any of the conditions is met + let sealing_enabled = self.forced_sealing() + || self.transaction_queue.has_local_pending_transactions() + || self.engine.seals_internally() == Some(true) + || had_requests; + + + let should_disable_sealing = !sealing_enabled; + + trace!(target: "miner", "requires_reseal: should_disable_sealing={}; forced={:?}, has_local={:?}, internal={:?}, had_requests={:?}", + should_disable_sealing, + self.forced_sealing(), + self.transaction_queue.has_local_pending_transactions(), + self.engine.seals_internally(), + had_requests, + ); + + if should_disable_sealing { + trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, sealing.last_request); + sealing.enabled = false; + sealing.queue.reset(); false + } else { + // sealing enabled and we don't want to sleep. + sealing.next_allowed_reseal = Instant::now() + self.options.reseal_min_period; + true } } /// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal. - fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool - where C: BlockChain + SealedBlockImporter + fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool where + C: BlockChain + SealedBlockImporter, { - if !block.transactions().is_empty() || self.forced_sealing() || Instant::now() > *self.next_mandatory_reseal.read() { - trace!(target: "miner", "seal_block_internally: attempting internal seal."); + { + let sealing = self.sealing.lock(); + if block.transactions().is_empty() + && !self.forced_sealing() + && Instant::now() <= sealing.next_mandatory_reseal + { + return false + } + } - let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) { - Some(hdr) => hdr.decode(), - None => return false, - }; + trace!(target: "miner", "seal_block_internally: attempting internal seal."); - match self.engine.generate_seal(block.block(), &parent_header) { - // Save proposal for later seal submission and broadcast it. - Seal::Proposal(seal) => { - trace!(target: "miner", "Received a Proposal seal."); - *self.next_mandatory_reseal.write() = Instant::now() + self.options.reseal_max_period; - { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.queue.push(block.clone()); - sealing_work.queue.use_last_ref(); - } - block - .lock() - .seal(&*self.engine, seal) - .map(|sealed| { chain.broadcast_proposal_block(sealed); true }) - .unwrap_or_else(|e| { - warn!("ERROR: seal failed when given internally generated seal: {}", e); - false - }) - }, - // Directly import a regular sealed block. - Seal::Regular(seal) => { - *self.next_mandatory_reseal.write() = Instant::now() + self.options.reseal_max_period; - block - .lock() - .seal(&*self.engine, seal) - .map(|sealed| chain.import_sealed_block(sealed).is_ok()) - .unwrap_or_else(|e| { - warn!("ERROR: seal failed when given internally generated seal: {}", e); - false - }) - }, - Seal::None => false, - } - } else { - false + let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) { + Some(hdr) => hdr.decode(), + None => return false, + }; + + match self.engine.generate_seal(block.block(), &parent_header) { + // Save proposal for later seal submission and broadcast it. + Seal::Proposal(seal) => { + trace!(target: "miner", "Received a Proposal seal."); + { + let mut sealing = self.sealing.lock(); + sealing.next_mandatory_reseal = Instant::now() + self.options.reseal_max_period; + sealing.queue.push(block.clone()); + sealing.queue.use_last_ref(); + } + + block + .lock() + .seal(&*self.engine, seal) + .map(|sealed| { + chain.broadcast_proposal_block(sealed); + true + }) + .unwrap_or_else(|e| { + warn!("ERROR: seal failed when given internally generated seal: {}", e); + false + }) + }, + // Directly import a regular sealed block. + Seal::Regular(seal) => { + trace!(target: "miner", "Received a Regular seal."); + { + let mut sealing = self.sealing.lock(); + sealing.next_mandatory_reseal = Instant::now() + self.options.reseal_max_period; + } + + block + .lock() + .seal(&*self.engine, seal) + .map(|sealed| { + chain.import_sealed_block(sealed).is_ok() + }) + .unwrap_or_else(|e| { + warn!("ERROR: seal failed when given internally generated seal: {}", e); + false + }) + }, + Seal::None => false, } } /// Prepares work which has to be done to seal. fn prepare_work(&self, block: ClosedBlock, original_work_hash: Option) { let (work, is_new) = { - let mut sealing_work = self.sealing_work.lock(); - let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().header().hash()); - trace!(target: "miner", "prepare_work: Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", original_work_hash, last_work_hash, block.block().header().hash()); - let (work, is_new) = if last_work_hash.map_or(true, |h| h != block.block().header().hash()) { - trace!(target: "miner", "prepare_work: Pushing a new, refreshed or borrowed pending {}...", block.block().header().hash()); - let pow_hash = block.block().header().hash(); - let number = block.block().header().number(); - let difficulty = *block.block().header().difficulty(); - let is_new = original_work_hash.map_or(true, |h| block.block().header().hash() != h); - sealing_work.queue.push(block); + let block_header = block.block().header().clone(); + let block_hash = block_header.hash(); + + let mut sealing = self.sealing.lock(); + let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.block().header().hash()); + + trace!( + target: "miner", + "prepare_work: Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", + original_work_hash, last_work_hash, block_hash + ); + + let (work, is_new) = if last_work_hash.map_or(true, |h| h != block_hash) { + trace!( + target: "miner", + "prepare_work: Pushing a new, refreshed or borrowed pending {}...", + block_hash + ); + let is_new = original_work_hash.map_or(true, |h| h != block_hash); + + sealing.queue.push(block); // If push notifications are enabled we assume all work items are used. - if !self.notifiers.read().is_empty() && is_new { - sealing_work.queue.use_last_ref(); + if is_new && !self.listeners.read().is_empty() { + sealing.queue.use_last_ref(); } - (Some((pow_hash, difficulty, number)), is_new) + + (Some((block_hash, *block_header.difficulty(), block_header.number())), is_new) } else { (None, false) }; - trace!(target: "miner", "prepare_work: leaving (last={:?})", sealing_work.queue.peek_last_ref().map(|b| b.block().header().hash())); + trace!( + target: "miner", + "prepare_work: leaving (last={:?})", + sealing.queue.peek_last_ref().map(|b| b.block().header().hash()) + ); (work, is_new) }; if is_new { work.map(|(pow_hash, difficulty, number)| { - for notifier in self.notifiers.read().iter() { + for notifier in self.listeners.read().iter() { notifier.notify(pow_hash, difficulty, number) } }); } } - fn update_gas_limit(&self, client: &C) { - let gas_limit = *client.best_block_header().gas_limit(); - let mut queue = self.transaction_queue.write(); - queue.set_gas_limit(gas_limit); - if let GasLimit::Auto = self.options.tx_queue_gas_limit { - // Set total tx queue gas limit to be 20x the block gas limit. - queue.set_total_gas_limit(gas_limit * 20u32); - } - } - /// Returns true if we had to prepare new pending block. - fn prepare_work_sealing(&self, client: &C) -> bool { - trace!(target: "miner", "prepare_work_sealing: entering"); + fn prepare_pending_block(&self, client: &C) -> bool where + C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, + { + trace!(target: "miner", "prepare_pending_block: entering"); let prepare_new = { - let mut sealing_work = self.sealing_work.lock(); - let have_work = sealing_work.queue.peek_last_ref().is_some(); - trace!(target: "miner", "prepare_work_sealing: have_work={}", have_work); + let mut sealing = self.sealing.lock(); + let have_work = sealing.queue.peek_last_ref().is_some(); + trace!(target: "miner", "prepare_pending_block: have_work={}", have_work); if !have_work { - sealing_work.enabled = true; + sealing.enabled = true; true } else { false } }; + if prepare_new { // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | + // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- let (block, original_work_hash) = self.prepare_block(client); self.prepare_work(block, original_work_hash); } - let mut sealing_block_last_request = self.sealing_block_last_request.lock(); + let best_number = client.chain_info().best_block_number; - if *sealing_block_last_request != best_number { - trace!(target: "miner", "prepare_work_sealing: Miner received request (was {}, now {}) - waking up.", *sealing_block_last_request, best_number); - *sealing_block_last_request = best_number; + let mut sealing = self.sealing.lock(); + if sealing.last_request != best_number { + trace!( + target: "miner", + "prepare_pending_block: Miner received request (was {}, now {}) - waking up.", + sealing.last_request, best_number + ); + sealing.last_request = best_number; } // Return if we restarted prepare_new } - - fn add_transactions_to_queue( - &self, - client: &C, - transactions: Vec, - default_origin: TransactionOrigin, - condition: Option, - transaction_queue: &mut BanningTransactionQueue, - ) -> Vec> { - let best_block_header = client.best_block_header(); - let insertion_time = client.chain_info().best_block_number; - let mut inserted = Vec::with_capacity(transactions.len()); - - let results = transactions.into_iter() - .map(|tx| { - let hash = tx.hash(); - if client.transaction_block(TransactionId::Hash(hash)).is_some() { - debug!(target: "miner", "Rejected tx {:?}: already in the blockchain", hash); - return Err(Error::Transaction(TransactionError::AlreadyImported)); - } - match self.engine.verify_transaction_basic(&tx, &best_block_header) - .and_then(|_| self.engine.verify_transaction_unordered(tx, &best_block_header)) - { - Err(e) => { - debug!(target: "miner", "Rejected tx {:?} with invalid signature: {:?}", hash, e); - Err(e) - }, - Ok(transaction) => { - // This check goes here because verify_transaction takes SignedTransaction parameter - self.engine.machine().verify_transaction(&transaction, &best_block_header, client)?; - - let origin = self.accounts.as_ref().and_then(|accounts| { - match accounts.has_account(transaction.sender()).unwrap_or(false) { - true => Some(TransactionOrigin::Local), - false => None, - } - }).unwrap_or(default_origin); - - let details_provider = TransactionDetailsProvider::new(client, &self.service_transaction_action); - let hash = transaction.hash(); - let result = match origin { - TransactionOrigin::Local | TransactionOrigin::RetractedBlock => { - transaction_queue.add(transaction, origin, insertion_time, condition.clone(), &details_provider)? - }, - TransactionOrigin::External => { - transaction_queue.add_with_banlist(transaction, insertion_time, &details_provider)? - }, - }; - - inserted.push(hash); - Ok(result) - }, - } - }) - .collect(); - - for listener in &*self.transaction_listener.read() { - listener(&inserted); - } - - results - } - - /// Are we allowed to do a non-mandatory reseal? - fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock() } - - fn from_pending_block(&self, latest_block_number: BlockNumber, from_chain: F, map_block: G) -> H - where F: Fn() -> H, G: FnOnce(&ClosedBlock) -> H { - let sealing_work = self.sealing_work.lock(); - sealing_work.queue.peek_last_ref().map_or_else( - || from_chain(), - |b| { - if b.block().header().number() > latest_block_number { - map_block(b) - } else { - from_chain() - } - } - ) - } } const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; -impl MinerService for Miner { +impl miner::MinerService for Miner { type State = State<::state_db::StateDB>; - fn clear_and_reset(&self, chain: &C) { - self.transaction_queue.write().clear(); - // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - self.update_sealing(chain); + fn authoring_params(&self) -> AuthoringParams { + self.params.read().clone() } - fn status(&self) -> MinerStatus { - let status = self.transaction_queue.read().status(); - let sealing_work = self.sealing_work.lock(); - MinerStatus { - transactions_in_pending_queue: status.pending, - transactions_in_future_queue: status.future, - transactions_in_pending_block: sealing_work.queue.peek_last_ref().map_or(0, |b| b.transactions().len()), - } + fn set_gas_range_target(&self, gas_range_target: (U256, U256)) { + self.params.write().gas_range_target = gas_range_target; } - fn set_author(&self, author: Address) { - if self.engine.seals_internally().is_some() { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.enabled = true; - } - *self.author.write() = author; + fn set_extra_data(&self, extra_data: Bytes) { + self.params.write().extra_data = extra_data; } - fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> { - if self.engine.seals_internally().is_some() { + fn set_author(&self, address: Address, password: Option) -> Result<(), AccountError> { + self.params.write().author = address; + + if self.engine.seals_internally().is_some() && password.is_some() { if let Some(ref ap) = self.accounts { + let password = password.unwrap_or_default(); + // Sign test message ap.sign(address.clone(), Some(password.clone()), Default::default())?; - // Limit the scope of the locks. - { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.enabled = true; - *self.author.write() = address; - } + // Enable sealing + self.sealing.lock().enabled = true; // -------------------------------------------------------------------------- - // | NOTE Code below may require author and sealing_work locks | - // | (some `Engine`s call `EngineClient.update_sealing()`) |. + // | NOTE Code below may require author and sealing locks | + // | (some `Engine`s call `EngineClient.update_sealing()`) | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- self.engine.set_signer(ap.clone(), address, password); @@ -823,132 +724,64 @@ impl MinerService for Miner { Err(AccountError::NotFound) } } else { - warn!(target: "miner", "Cannot set engine signer on a PoW chain."); - Err(AccountError::InappropriateChain) + Ok(()) } } - fn set_extra_data(&self, extra_data: Bytes) { - *self.extra_data.write() = extra_data; - } - - /// Set the gas limit we wish to target when sealing a new block. - fn set_gas_floor_target(&self, target: U256) { - self.gas_range_target.write().0 = target; - } - - fn set_gas_ceil_target(&self, target: U256) { - self.gas_range_target.write().1 = target; - } - - fn set_minimal_gas_price(&self, min_gas_price: U256) { - self.transaction_queue.write().set_minimal_gas_price(min_gas_price); - } - - fn minimal_gas_price(&self) -> U256 { - *self.transaction_queue.read().minimal_gas_price() - } - fn sensible_gas_price(&self) -> U256 { // 10% above our minimum. - *self.transaction_queue.read().minimal_gas_price() * 110u32 / 100.into() + self.transaction_queue.current_worst_gas_price() * 110u32 / 100.into() } fn sensible_gas_limit(&self) -> U256 { - self.gas_range_target.read().0 / 5.into() - } - - fn transactions_limit(&self) -> usize { - self.transaction_queue.read().limit() - } - - fn set_transactions_limit(&self, limit: usize) { - self.transaction_queue.write().set_limit(limit) - } - - fn set_tx_gas_limit(&self, limit: U256) { - self.transaction_queue.write().set_tx_gas_limit(limit) - } - - /// Get the author that we will seal blocks as. - fn author(&self) -> Address { - *self.author.read() - } - - /// Get the extra_data that we will seal blocks with. - fn extra_data(&self) -> Bytes { - self.extra_data.read().clone() - } - - /// Get the gas limit we wish to target when sealing a new block. - fn gas_floor_target(&self) -> U256 { - self.gas_range_target.read().0 - } - - /// Get the gas limit we wish to target when sealing a new block. - fn gas_ceil_target(&self) -> U256 { - self.gas_range_target.read().1 + self.params.read().gas_range_target.0 / 5.into() } - fn import_external_transactions( + fn import_external_transactions( &self, - client: &C, + chain: &C, transactions: Vec - ) -> Vec> { + ) -> Vec> { trace!(target: "external_tx", "Importing external transactions"); - let results = { - let mut transaction_queue = self.transaction_queue.write(); - self.add_transactions_to_queue( - client, transactions, TransactionOrigin::External, None, &mut transaction_queue - ) - }; + let client = self.pool_client(chain); + let results = self.transaction_queue.import( + client, + transactions.into_iter().map(pool::verifier::Transaction::Unverified).collect(), + ); - if !results.is_empty() && self.options.reseal_on_external_tx && self.tx_reseal_allowed() { + if !results.is_empty() && self.options.reseal_on_external_tx && self.sealing.lock().reseal_allowed() { // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | + // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- - self.update_sealing(client); + self.update_sealing(chain); } + results } - fn import_own_transaction( + fn import_own_transaction( &self, chain: &C, pending: PendingTransaction, - ) -> Result { + ) -> Result<(), transaction::Error> { trace!(target: "own_tx", "Importing transaction: {:?}", pending); - let imported = { - // Be sure to release the lock before we call prepare_work_sealing - let mut transaction_queue = self.transaction_queue.write(); - // We need to re-validate transactions - let import = self.add_transactions_to_queue( - chain, vec![pending.transaction.into()], TransactionOrigin::Local, pending.condition, &mut transaction_queue - ).pop().expect("one result returned per added transaction; one added => one result; qed"); - - match import { - Ok(_) => { - trace!(target: "own_tx", "Status: {:?}", transaction_queue.status()); - }, - Err(ref e) => { - trace!(target: "own_tx", "Status: {:?}", transaction_queue.status()); - warn!(target: "own_tx", "Error importing transaction: {:?}", e); - }, - } - import - }; + let client = self.pool_client(chain); + let imported = self.transaction_queue.import( + client, + vec![pool::verifier::Transaction::Local(pending)] + ).pop().expect("one result returned per added transaction; one added => one result; qed"); // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | + // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | // -------------------------------------------------------------------------- - if imported.is_ok() && self.options.reseal_on_own_tx && self.tx_reseal_allowed() { + if imported.is_ok() && self.options.reseal_on_own_tx && self.sealing.lock().reseal_allowed() { // Make sure to do it after transaction is imported and lock is droped. // We need to create pending block and enable sealing. - if self.engine.seals_internally().unwrap_or(false) || !self.prepare_work_sealing(chain) { + if self.engine.seals_internally().unwrap_or(false) || !self.prepare_pending_block(chain) { // If new block has not been prepared (means we already had one) // or Engine might be able to seal internally, // we need to update sealing. @@ -959,215 +792,185 @@ impl MinerService for Miner { imported } - fn pending_transactions(&self) -> Vec { - let queue = self.transaction_queue.read(); - queue.pending_transactions(BlockNumber::max_value(), u64::max_value()) + fn local_transactions(&self) -> BTreeMap { + self.transaction_queue.local_transactions() } - fn local_transactions(&self) -> BTreeMap { - let queue = self.transaction_queue.read(); - queue.local_transactions() - .iter() - .map(|(hash, status)| (*hash, status.clone())) - .collect() + fn queued_transactions(&self) -> Vec> { + self.transaction_queue.all_transactions() } - fn future_transactions(&self) -> Vec { - self.transaction_queue.read().future_transactions() - } + fn ready_transactions(&self, chain: &C) -> Vec> where + C: ChainInfo + Nonce + Sync, + { + let chain_info = chain.chain_info(); - fn ready_transactions(&self, best_block: BlockNumber, best_block_timestamp: u64) -> Vec { - let queue = self.transaction_queue.read(); - match self.options.pending_set { - PendingSet::AlwaysQueue => queue.pending_transactions(best_block, best_block_timestamp), - PendingSet::SealingOrElseQueue => { - self.from_pending_block( - best_block, - || queue.pending_transactions(best_block, best_block_timestamp), - |sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect() - ) - }, - PendingSet::AlwaysSealing => { - self.from_pending_block( - best_block, - || vec![], - |sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect() - ) - }, - } - } + let from_queue = || { + self.transaction_queue.pending( + CachedNonceClient::new(chain, &self.nonce_cache), + chain_info.best_block_number, + chain_info.best_block_timestamp, + // We propagate transactions over the nonce cap. + // The mechanism is only to limit number of transactions in pending block + // those transactions are valid and will just be ready to be included in next block. + None, + ) + }; + + let from_pending = || { + self.map_existing_pending_block(|sealing| { + sealing.transactions() + .iter() + .map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone())) + .map(Arc::new) + .collect() + }, chain_info.best_block_number) + }; - fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec { - let queue = self.transaction_queue.read(); match self.options.pending_set { - PendingSet::AlwaysQueue => queue.pending_hashes(), - PendingSet::SealingOrElseQueue => { - self.from_pending_block( - best_block, - || queue.pending_hashes(), - |sealing| sealing.transactions().iter().map(|t| t.hash()).collect() - ) + PendingSet::AlwaysQueue => { + from_queue() }, PendingSet::AlwaysSealing => { - self.from_pending_block( - best_block, - || vec![], - |sealing| sealing.transactions().iter().map(|t| t.hash()).collect() - ) + from_pending().unwrap_or_default() }, - } - } - - fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option { - let queue = self.transaction_queue.read(); - match self.options.pending_set { - PendingSet::AlwaysQueue => queue.find(hash), PendingSet::SealingOrElseQueue => { - self.from_pending_block( - best_block, - || queue.find(hash), - |sealing| sealing.transactions().iter().find(|t| &t.hash() == hash).cloned().map(Into::into) - ) - }, - PendingSet::AlwaysSealing => { - self.from_pending_block( - best_block, - || None, - |sealing| sealing.transactions().iter().find(|t| &t.hash() == hash).cloned().map(Into::into) - ) + from_pending().unwrap_or_else(from_queue) }, } } - fn remove_pending_transaction(&self, chain: &C, hash: &H256) -> Option { - let mut queue = self.transaction_queue.write(); - let tx = queue.find(hash); - if tx.is_some() { - let fetch_nonce = |a: &Address| chain.latest_nonce(a); - queue.remove(hash, &fetch_nonce, RemovalReason::Canceled); - } - tx + fn next_nonce(&self, chain: &C, address: &Address) -> U256 where + C: Nonce + Sync, + { + self.transaction_queue.next_nonce(CachedNonceClient::new(chain, &self.nonce_cache), address) + .unwrap_or_else(|| chain.latest_nonce(address)) } - fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option { - self.from_pending_block( - best_block, - || None, - |pending| { - let txs = pending.transactions(); - txs.iter() - .map(|t| t.hash()) - .position(|t| t == *hash) - .map(|index| { - let prev_gas = if index == 0 { Default::default() } else { pending.receipts()[index - 1].gas_used }; - let tx = &txs[index]; - let receipt = &pending.receipts()[index]; - RichReceipt { - transaction_hash: hash.clone(), - transaction_index: index, - cumulative_gas_used: receipt.gas_used, - gas_used: receipt.gas_used - prev_gas, - contract_address: match tx.action { - Action::Call(_) => None, - Action::Create => { - let sender = tx.sender(); - Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data).0) - } - }, - logs: receipt.logs.clone(), - log_bloom: receipt.log_bloom, - outcome: receipt.outcome.clone(), - } - }) - } - ) + fn transaction(&self, hash: &H256) -> Option> { + self.transaction_queue.find(hash) } - fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap { - self.from_pending_block( - best_block, - BTreeMap::new, - |pending| { - let hashes = pending.transactions() - .iter() - .map(|t| t.hash()); - - let receipts = pending.receipts().iter().cloned(); + fn remove_transaction(&self, hash: &H256) -> Option> { + self.transaction_queue.remove(::std::iter::once(hash), false) + .pop() + .expect("remove() returns one result per hash; one hash passed; qed") + } - hashes.zip(receipts).collect() - } - ) + fn queue_status(&self) -> QueueStatus { + self.transaction_queue.status() } - fn last_nonce(&self, address: &Address) -> Option { - self.transaction_queue.read().last_nonce(address) + fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option { + self.map_existing_pending_block(|pending| { + let txs = pending.transactions(); + txs.iter() + .map(|t| t.hash()) + .position(|t| t == *hash) + .map(|index| { + let receipts = pending.receipts(); + let prev_gas = if index == 0 { Default::default() } else { receipts[index - 1].gas_used }; + let tx = &txs[index]; + let receipt = &receipts[index]; + RichReceipt { + transaction_hash: hash.clone(), + transaction_index: index, + cumulative_gas_used: receipt.gas_used, + gas_used: receipt.gas_used - prev_gas, + contract_address: match tx.action { + Action::Call(_) => None, + Action::Create => { + let sender = tx.sender(); + Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data).0) + } + }, + logs: receipt.logs.clone(), + log_bloom: receipt.log_bloom, + outcome: receipt.outcome.clone(), + } + }) + }, best_block).and_then(|x| x) } - fn can_produce_work_package(&self) -> bool { - self.engine.seals_internally().is_none() + fn pending_receipts(&self, best_block: BlockNumber) -> Option> { + self.map_existing_pending_block(|pending| { + let hashes = pending.transactions().iter().map(|t| t.hash()); + let receipts = pending.receipts().iter().cloned(); + + hashes.zip(receipts).collect() + }, best_block) } /// Update sealing if required. /// Prepare the block and work if the Engine does not seal internally. - fn update_sealing(&self, chain: &C) - where C: AccountData + BlockChain + RegistryInfo - + CallContract + BlockProducer + SealedBlockImporter + fn update_sealing(&self, chain: &C) where + C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, { trace!(target: "miner", "update_sealing"); - const NO_NEW_CHAIN_WITH_FORKS: &str = "Your chain specification contains one or more hard forks which are required to be \ - on by default. Please remove these forks and start your chain again."; - if self.requires_reseal(chain.chain_info().best_block_number) { - // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - trace!(target: "miner", "update_sealing: preparing a block"); - let (block, original_work_hash) = self.prepare_block(chain); - - // refuse to seal the first block of the chain if it contains hard forks - // which should be on by default. - if block.block().header().number() == 1 && self.engine.params().contains_bugfix_hard_fork() { - warn!("{}", NO_NEW_CHAIN_WITH_FORKS); - return; - } + // Do nothing if reseal is not required, + // but note that `requires_reseal` updates internal state. + if !self.requires_reseal(chain.chain_info().best_block_number) { + return; + } - match self.engine.seals_internally() { - Some(true) => { - trace!(target: "miner", "update_sealing: engine indicates internal sealing"); - if self.seal_and_import_block_internally(chain, block) { - trace!(target: "miner", "update_sealing: imported internally sealed block"); - } - }, - Some(false) => trace!(target: "miner", "update_sealing: engine is not keen to seal internally right now"), - None => { - trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); - self.prepare_work(block, original_work_hash) - }, - } + // -------------------------------------------------------------------------- + // | NOTE Code below requires sealing locks. | + // | Make sure to release the locks before calling that method. | + // -------------------------------------------------------------------------- + trace!(target: "miner", "update_sealing: preparing a block"); + let (block, original_work_hash) = self.prepare_block(chain); + + // refuse to seal the first block of the chain if it contains hard forks + // which should be on by default. + if block.block().header().number() == 1 && self.engine.params().contains_bugfix_hard_fork() { + warn!("Your chain specification contains one or more hard forks which are required to be \ + on by default. Please remove these forks and start your chain again."); + return; + } + + match self.engine.seals_internally() { + Some(true) => { + trace!(target: "miner", "update_sealing: engine indicates internal sealing"); + if self.seal_and_import_block_internally(chain, block) { + trace!(target: "miner", "update_sealing: imported internally sealed block"); + } + }, + Some(false) => { + trace!(target: "miner", "update_sealing: engine is not keen to seal internally right now"); + // anyway, save the block for later use + self.sealing.lock().queue.push(block); + }, + None => { + trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); + self.prepare_work(block, original_work_hash) + }, } } fn is_currently_sealing(&self) -> bool { - self.sealing_work.lock().queue.is_in_use() + self.sealing.lock().queue.is_in_use() } - fn map_sealing_work(&self, client: &C, f: F) -> Option - where C: AccountData + BlockChain + BlockProducer + CallContract, - F: FnOnce(&ClosedBlock) -> T + fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> where + C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, { - trace!(target: "miner", "map_sealing_work: entering"); - self.prepare_work_sealing(client); - trace!(target: "miner", "map_sealing_work: sealing prepared"); - let mut sealing_work = self.sealing_work.lock(); - let ret = sealing_work.queue.use_last_ref(); - trace!(target: "miner", "map_sealing_work: leaving use_last_ref={:?}", ret.as_ref().map(|b| b.block().header().hash())); - ret.map(f) + if self.engine.seals_internally().is_some() { + return None; + } + + self.prepare_pending_block(chain); + + self.sealing.lock().queue.use_last_ref().map(|b| { + let header = b.header(); + (header.hash(), header.number(), header.timestamp(), *header.difficulty()) + }) } - fn submit_seal(&self, chain: &C, block_hash: H256, seal: Vec) -> Result<(), Error> { + // Note used for external submission (PoW) and internally by sealing engines. + fn submit_seal(&self, block_hash: H256, seal: Vec) -> Result { let result = - if let Some(b) = self.sealing_work.lock().queue.get_used_if( + if let Some(b) = self.sealing.lock().queue.get_used_if( if self.options.enable_resubmission { GetAction::Clone } else { @@ -1184,18 +987,17 @@ impl MinerService for Miner { warn!(target: "miner", "Submitted solution rejected: Block unknown or out of date."); Err(Error::PowHashInvalid) }; + result.and_then(|sealed| { let n = sealed.header().number(); let h = sealed.header().hash(); - chain.import_sealed_block(sealed)?; info!(target: "miner", "Submitted block imported OK. #{}: {}", Colour::White.bold().paint(format!("{}", n)), Colour::White.bold().paint(format!("{:x}", h))); - Ok(()) + Ok(sealed) }) } - fn chain_new_blocks(&self, chain: &C, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) - where C: AccountData + BlockChain + CallContract + RegistryInfo - + BlockProducer + ScheduleInfo + SealedBlockImporter + fn chain_new_blocks(&self, chain: &C, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256], is_internal_import: bool) + where C: miner::BlockChainClient, { trace!(target: "miner", "chain_new_blocks"); @@ -1203,133 +1005,89 @@ impl MinerService for Miner { // 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that // are in those blocks - // First update gas limit in transaction queue - self.update_gas_limit(chain); + // Clear nonce cache + self.nonce_cache.write().clear(); - // Update minimal gas price - self.recalibrate_minimal_gas_price(); + // First update gas limit in transaction queue and minimal gas price. + let gas_limit = *chain.best_block_header().gas_limit(); + self.update_transaction_queue_limits(gas_limit); // Then import all transactions... + let client = self.pool_client(chain); { - - let mut transaction_queue = self.transaction_queue.write(); - for hash in retracted { - let block = chain.block(BlockId::Hash(*hash)) - .expect("Client is sending message after commit to db and inserting to chain; the block is available; qed"); - let txs = block.transactions(); - let _ = self.add_transactions_to_queue( - chain, txs, TransactionOrigin::RetractedBlock, None, &mut transaction_queue - ); - } + retracted + .par_iter() + .for_each(|hash| { + let block = chain.block(BlockId::Hash(*hash)) + .expect("Client is sending message after commit to db and inserting to chain; the block is available; qed"); + let txs = block.transactions() + .into_iter() + .map(pool::verifier::Transaction::Retracted) + .collect(); + let _ = self.transaction_queue.import( + client.clone(), + txs, + ); + }); } // ...and at the end remove the old ones - { - let fetch_account = |a: &Address| AccountDetails { - nonce: chain.latest_nonce(a), - balance: chain.latest_balance(a), - }; - let time = chain.chain_info().best_block_number; - let mut transaction_queue = self.transaction_queue.write(); - transaction_queue.remove_old(&fetch_account, time); - } + self.transaction_queue.cull(client); if enacted.len() > 0 || (imported.len() > 0 && self.options.reseal_on_uncle) { - // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - self.update_sealing(chain); + // Reset `next_allowed_reseal` in case a block is imported. + // Even if min_period is high, we will always attempt to create + // new pending block. + self.sealing.lock().next_allowed_reseal = Instant::now(); + + if !is_internal_import { + // -------------------------------------------------------------------------- + // | NOTE Code below requires sealing locks. | + // | Make sure to release the locks before calling that method. | + // -------------------------------------------------------------------------- + self.update_sealing(chain); + } } } fn pending_state(&self, latest_block_number: BlockNumber) -> Option { - Miner::pending_state(self, latest_block_number) + self.map_existing_pending_block(|b| b.state().clone(), latest_block_number) } fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
{ - Miner::pending_block_header(self, latest_block_number) + self.map_existing_pending_block(|b| b.header().clone(), latest_block_number) } fn pending_block(&self, latest_block_number: BlockNumber) -> Option { - Miner::pending_block(self, latest_block_number) + self.map_existing_pending_block(|b| b.to_base(), latest_block_number) } -} - -/// Action when service transaction is received -enum ServiceTransactionAction { - /// Refuse service transaction immediately - Refuse, - /// Accept if sender is certified to send service transactions - Check(ServiceTransactionChecker), -} -impl ServiceTransactionAction { - pub fn check(&self, client: &C, tx: &SignedTransaction) -> Result - { - match *self { - ServiceTransactionAction::Refuse => Err("configured to refuse service transactions".to_owned()), - ServiceTransactionAction::Check(ref checker) => checker.check(client, tx), - } - } -} - -struct TransactionDetailsProvider<'a, C: 'a> { - client: &'a C, - service_transaction_action: &'a ServiceTransactionAction, -} - -impl<'a, C> TransactionDetailsProvider<'a, C> { - pub fn new(client: &'a C, service_transaction_action: &'a ServiceTransactionAction) -> Self { - TransactionDetailsProvider { - client: client, - service_transaction_action: service_transaction_action, - } - } -} - -impl<'a, C> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a, C> - where C: AccountData + CallContract + RegistryInfo + ScheduleInfo -{ - fn fetch_account(&self, address: &Address) -> AccountDetails { - AccountDetails { - nonce: self.client.latest_nonce(address), - balance: self.client.latest_balance(address), - } - } - - fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256 { - tx.gas_required(&self.client.latest_schedule()).into() - } - - fn is_service_transaction_acceptable(&self, tx: &SignedTransaction) -> Result { - self.service_transaction_action.check(self.client, tx) + fn pending_transactions(&self, latest_block_number: BlockNumber) -> Option> { + self.map_existing_pending_block(|b| b.transactions().into_iter().cloned().collect(), latest_block_number) } } #[cfg(test)] mod tests { use super::*; - use ethcore_miner::transaction_queue::PrioritizationStrategy; - use ethereum_types::U256; use ethkey::{Generator, Random}; - use client::{TestBlockChainClient, EachBlockWith, ChainInfo}; use hash::keccak; use header::BlockNumber; use rustc_hex::FromHex; - use spec::Spec; - use transaction::{SignedTransaction, Transaction, PendingTransaction, Action}; + + use client::{TestBlockChainClient, EachBlockWith, ChainInfo, ImportSealedBlock}; use miner::MinerService; use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts}; + use transaction::{Transaction}; #[test] fn should_prepare_block_to_seal() { // given let client = TestBlockChainClient::default(); - let miner = Miner::with_spec(&Spec::new_test()); + let miner = Miner::new_for_tests(&Spec::new_test(), None); // when - let sealing_work = miner.map_sealing_work(&client, |_| ()); + let sealing_work = miner.work_package(&client); assert!(sealing_work.is_some(), "Expected closed block"); } @@ -1337,25 +1095,26 @@ mod tests { fn should_still_work_after_a_couple_of_blocks() { // given let client = TestBlockChainClient::default(); - let miner = Miner::with_spec(&Spec::new_test()); + let miner = Miner::new_for_tests(&Spec::new_test(), None); - let res = miner.map_sealing_work(&client, |b| b.block().header().hash()); - assert!(res.is_some()); - assert!(miner.submit_seal(&client, res.unwrap(), vec![]).is_ok()); + let res = miner.work_package(&client); + let hash = res.unwrap().0; + let block = miner.submit_seal(hash, vec![]).unwrap(); + client.import_sealed_block(block).unwrap(); // two more blocks mined, work requested. client.add_blocks(1, EachBlockWith::Uncle); - miner.map_sealing_work(&client, |b| b.block().header().hash()); + miner.work_package(&client); client.add_blocks(1, EachBlockWith::Uncle); - miner.map_sealing_work(&client, |b| b.block().header().hash()); + miner.work_package(&client); // solution to original work submitted. - assert!(miner.submit_seal(&client, res.unwrap(), vec![]).is_ok()); + assert!(miner.submit_seal(hash, vec![]).is_ok()); } fn miner() -> Miner { - Arc::try_unwrap(Miner::new( + Miner::new( MinerOptions { force_sealing: false, reseal_on_external_tx: false, @@ -1363,22 +1122,24 @@ mod tests { reseal_on_uncle: false, reseal_min_period: Duration::from_secs(5), reseal_max_period: Duration::from_secs(120), - tx_gas_limit: !U256::zero(), - tx_queue_size: 1024, - tx_queue_memory_limit: None, - tx_queue_gas_limit: GasLimit::None, - tx_queue_strategy: PrioritizationStrategy::GasFactorAndGasPrice, pending_set: PendingSet::AlwaysSealing, work_queue_size: 5, enable_resubmission: true, - tx_queue_banning: Banning::Disabled, - refuse_service_transactions: false, infinite_pending_block: false, + tx_queue_penalization: Penalization::Disabled, + tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, + refuse_service_transactions: false, + pool_limits: Default::default(), + pool_verification_options: pool::verifier::Options { + minimal_gas_price: 0.into(), + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + }, }, GasPricer::new_fixed(0u64.into()), &Spec::new_test(), None, // accounts provider - )).ok().expect("Miner was just created.") + ) } fn transaction() -> SignedTransaction { @@ -1408,13 +1169,12 @@ mod tests { let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None)); // then - assert_eq!(res.unwrap(), TransactionImportResult::Current); - assert_eq!(miner.pending_transactions().len(), 1); - assert_eq!(miner.ready_transactions(best_block, 0).len(), 1); - assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1); - assert_eq!(miner.pending_receipts(best_block).len(), 1); + assert_eq!(res.unwrap(), ()); + assert_eq!(miner.pending_transactions(best_block).unwrap().len(), 1); + assert_eq!(miner.pending_receipts(best_block).unwrap().len(), 1); + assert_eq!(miner.ready_transactions(&client).len(), 1); // This method will let us know if pending block was created (before calling that method) - assert!(!miner.prepare_work_sealing(&client)); + assert!(!miner.prepare_pending_block(&client)); } #[test] @@ -1428,11 +1188,10 @@ mod tests { let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None)); // then - assert_eq!(res.unwrap(), TransactionImportResult::Current); - assert_eq!(miner.pending_transactions().len(), 1); - assert_eq!(miner.ready_transactions(best_block, 0).len(), 0); - assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0); - assert_eq!(miner.pending_receipts(best_block).len(), 0); + assert_eq!(res.unwrap(), ()); + assert_eq!(miner.pending_transactions(best_block), None); + assert_eq!(miner.pending_receipts(best_block), None); + assert_eq!(miner.ready_transactions(&client).len(), 1); } #[test] @@ -1446,13 +1205,16 @@ mod tests { let res = miner.import_external_transactions(&client, vec![transaction]).pop().unwrap(); // then - assert_eq!(res.unwrap(), TransactionImportResult::Current); - assert_eq!(miner.pending_transactions().len(), 1); - assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0); - assert_eq!(miner.ready_transactions(best_block, 0).len(), 0); - assert_eq!(miner.pending_receipts(best_block).len(), 0); + assert_eq!(res.unwrap(), ()); + // By default we don't reseal on external transactions + assert_eq!(miner.pending_transactions(best_block), None); + assert_eq!(miner.pending_receipts(best_block), None); + // By default we use PendingSet::AlwaysSealing, so no transactions yet. + assert_eq!(miner.ready_transactions(&client).len(), 0); // This method will let us know if pending block was created (before calling that method) - assert!(miner.prepare_work_sealing(&client)); + assert!(miner.prepare_pending_block(&client)); + // After pending block is created we should see a transaction. + assert_eq!(miner.ready_transactions(&client).len(), 1); } #[test] @@ -1463,7 +1225,7 @@ mod tests { assert!(!miner.requires_reseal(1u8.into())); miner.import_external_transactions(&client, vec![transaction().into()]).pop().unwrap().unwrap(); - assert!(miner.prepare_work_sealing(&client)); + assert!(miner.prepare_pending_block(&client)); // Unless asked to prepare work. assert!(miner.requires_reseal(1u8.into())); } @@ -1471,18 +1233,19 @@ mod tests { #[test] fn internal_seals_without_work() { let spec = Spec::new_instant(); - let miner = Miner::with_spec(&spec); + let miner = Miner::new_for_tests(&spec, None); let client = generate_dummy_client(2); - assert_eq!(miner.import_external_transactions(&*client, vec![transaction_with_chain_id(spec.chain_id()).into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); + let import = miner.import_external_transactions(&*client, vec![transaction_with_chain_id(spec.chain_id()).into()]).pop().unwrap(); + assert_eq!(import.unwrap(), ()); miner.update_sealing(&*client); client.flush_queue(); assert!(miner.pending_block(0).is_none()); assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber); - assert_eq!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction_with_chain_id(spec.chain_id()).into(), None)).unwrap(), TransactionImportResult::Current); + assert!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction_with_chain_id(spec.chain_id()).into(), None)).is_ok()); miner.update_sealing(&*client); client.flush_queue(); @@ -1490,21 +1253,12 @@ mod tests { assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber); } - #[test] - fn should_fail_setting_engine_signer_on_pow() { - let spec = Spec::new_pow_test_spec; - let tap = Arc::new(AccountProvider::transient_provider()); - let addr = tap.insert_account(keccak("1").into(), "").unwrap(); - let client = generate_dummy_client_with_spec_and_accounts(spec, Some(tap.clone())); - assert!(match client.miner().set_engine_signer(addr, "".into()) { Err(AccountError::InappropriateChain) => true, _ => false }) - } - #[test] fn should_fail_setting_engine_signer_without_account_provider() { let spec = Spec::new_instant; let tap = Arc::new(AccountProvider::transient_provider()); let addr = tap.insert_account(keccak("1").into(), "").unwrap(); let client = generate_dummy_client_with_spec_and_accounts(spec, None); - assert!(match client.miner().set_engine_signer(addr, "".into()) { Err(AccountError::NotFound) => true, _ => false }); + assert!(match client.miner().set_author(addr, Some("".into())) { Err(AccountError::NotFound) => true, _ => false }); } } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 5f451fdc2a..fbf4f11b7a 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -17,191 +17,169 @@ #![warn(missing_docs)] //! Miner module -//! Keeps track of transactions and mined block. -//! -//! Usage example: -//! -//! ```rust -//! extern crate ethcore; -//! use std::env; -//! use ethcore::ethereum; -//! use ethcore::client::{Client, ClientConfig}; -//! use ethcore::miner::{Miner, MinerService}; -//! -//! fn main() { -//! let miner: Miner = Miner::with_spec(ðereum::new_foundation(&env::temp_dir())); -//! // get status -//! assert_eq!(miner.status().transactions_in_pending_queue, 0); -//! -//! // Check block for sealing -//! //assert!(miner.sealing_block(&*client).lock().is_some()); -//! } -//! ``` +//! Keeps track of transactions and currently sealed pending block. mod miner; -mod stratum; mod service_transaction_checker; -pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit}; -pub use self::stratum::{Stratum, Error as StratumError, Options as StratumOptions}; +pub mod pool_client; +pub mod stratum; -pub use ethcore_miner::local_transactions::Status as LocalTransactionStatus; +pub use self::miner::{Miner, MinerOptions, Penalization, PendingSet, AuthoringParams}; +use std::sync::Arc; use std::collections::BTreeMap; -use block::{ClosedBlock, Block}; use bytes::Bytes; +use ethereum_types::{H256, U256, Address}; +use ethcore_miner::pool::{VerifiedTransaction, QueueStatus, local_transactions}; + +use block::{Block, SealedBlock}; use client::{ - MiningBlockChainClient, CallContract, RegistryInfo, ScheduleInfo, - BlockChain, AccountData, BlockProducer, SealedBlockImporter + CallContract, RegistryInfo, ScheduleInfo, + BlockChain, BlockProducer, SealedBlockImporter, ChainInfo, + AccountData, Nonce, }; -use error::{Error}; -use ethereum_types::{H256, U256, Address}; +use error::Error; use header::{BlockNumber, Header}; use receipt::{RichReceipt, Receipt}; -use transaction::{UnverifiedTransaction, PendingTransaction, ImportResult as TransactionImportResult}; +use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; use state::StateInfo; +/// Provides methods to verify incoming external transactions +pub trait TransactionVerifierClient: Send + Sync + // Required for ServiceTransactionChecker + + CallContract + RegistryInfo + // Required for verifiying transactions + + BlockChain + ScheduleInfo + AccountData +{} + +/// Extended client interface used for mining +pub trait BlockChainClient: TransactionVerifierClient + BlockProducer + SealedBlockImporter {} + /// Miner client API pub trait MinerService : Send + Sync { /// Type representing chain state type State: StateInfo + 'static; - /// Returns miner's status. - fn status(&self) -> MinerStatus; - - /// Get the author that we will seal blocks as. - fn author(&self) -> Address; - - /// Set the author that we will seal blocks as. - fn set_author(&self, author: Address); + // Sealing - /// Set info necessary to sign consensus messages. - fn set_engine_signer(&self, address: Address, password: String) -> Result<(), ::account_provider::SignError>; - - /// Get the extra_data that we will seal blocks with. - fn extra_data(&self) -> Bytes; - - /// Set the extra_data that we will seal blocks with. - fn set_extra_data(&self, extra_data: Bytes); - - /// Get current minimal gas price for transactions accepted to queue. - fn minimal_gas_price(&self) -> U256; + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result; - /// Set minimal gas price of transaction to be accepted for mining. - fn set_minimal_gas_price(&self, min_gas_price: U256); + /// Is it currently sealing? + fn is_currently_sealing(&self) -> bool; - /// Get the lower bound of the gas limit we wish to target when sealing a new block. - fn gas_floor_target(&self) -> U256; + /// Get the sealing work package preparing it if doesn't exist yet. + /// + /// Returns `None` if engine seals internally. + fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> + where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; - /// Get the upper bound of the gas limit we wish to target when sealing a new block. - fn gas_ceil_target(&self) -> U256; + /// Update current pending block + fn update_sealing(&self, chain: &C) + where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; - // TODO: coalesce into single set_range function. - /// Set the lower bound of gas limit we wish to target when sealing a new block. - fn set_gas_floor_target(&self, target: U256); - /// Set the upper bound of gas limit we wish to target when sealing a new block. - fn set_gas_ceil_target(&self, target: U256); + // Notifications - /// Get current transactions limit in queue. - fn transactions_limit(&self) -> usize; + /// Called when blocks are imported to chain, updates transactions queue. + /// `is_internal_import` indicates that the block has just been created in miner and internally sealed by the engine, + /// so we shouldn't attempt creating new block again. + fn chain_new_blocks(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256], is_internal_import: bool) + where C: BlockChainClient; - /// Set maximal number of transactions kept in the queue (both current and future). - fn set_transactions_limit(&self, limit: usize); - /// Set maximum amount of gas allowed for any single transaction to mine. - fn set_tx_gas_limit(&self, limit: U256); + // Pending block - /// Imports transactions to transaction queue. - fn import_external_transactions(&self, client: &C, transactions: Vec) -> - Vec>; + /// Get a list of all pending receipts from pending block. + fn pending_receipts(&self, best_block: BlockNumber) -> Option>; - /// Imports own (node owner) transaction to queue. - fn import_own_transaction(&self, chain: &C, transaction: PendingTransaction) -> - Result; + /// Get a particular receipt from pending block. + fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option; - /// Returns hashes of transactions currently in pending - fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec; + /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. + fn pending_state(&self, latest_block_number: BlockNumber) -> Option; - /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, chain: &C); + /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. + fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
; - /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) - where C: AccountData + BlockChain + CallContract + RegistryInfo + BlockProducer + ScheduleInfo + SealedBlockImporter; + /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. + fn pending_block(&self, latest_block_number: BlockNumber) -> Option; - /// PoW chain - can produce work package - fn can_produce_work_package(&self) -> bool; + /// Get `Some` `clone()` of the current pending block transactions or `None` if we're not sealing. + fn pending_transactions(&self, latest_block_number: BlockNumber) -> Option>; - /// New chain head event. Restart mining operation. - fn update_sealing(&self, chain: &C) - where C: AccountData + BlockChain + RegistryInfo + CallContract + BlockProducer + SealedBlockImporter; + // Block authoring - /// Submit `seal` as a valid solution for the header of `pow_hash`. - /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, chain: &C, pow_hash: H256, seal: Vec) -> Result<(), Error>; + /// Get current authoring parameters. + fn authoring_params(&self) -> AuthoringParams; - /// Get the sealing work package and if `Some`, apply some transform. - fn map_sealing_work(&self, client: &C, f: F) -> Option - where C: AccountData + BlockChain + BlockProducer + CallContract, - F: FnOnce(&ClosedBlock) -> T, - Self: Sized; + /// Set the lower and upper bound of gas limit we wish to target when sealing a new block. + fn set_gas_range_target(&self, gas_range_target: (U256, U256)); - /// Query pending transactions for hash. - fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option; + /// Set the extra_data that we will seal blocks with. + fn set_extra_data(&self, extra_data: Bytes); - /// Removes transaction from the queue. - /// NOTE: The transaction is not removed from pending block if mining. - fn remove_pending_transaction(&self, chain: &C, hash: &H256) -> Option; + /// Set info necessary to sign consensus messages and block authoring. + /// + /// On PoW password is optional. + fn set_author(&self, address: Address, password: Option) -> Result<(), ::account_provider::SignError>; - /// Get a list of all pending transactions in the queue. - fn pending_transactions(&self) -> Vec; + // Transaction Pool - /// Get a list of all transactions that can go into the given block. - fn ready_transactions(&self, best_block: BlockNumber, best_block_timestamp: u64) -> Vec; + /// Imports transactions to transaction queue. + fn import_external_transactions(&self, client: &C, transactions: Vec) + -> Vec> + where C: BlockChainClient; - /// Get a list of all future transactions. - fn future_transactions(&self) -> Vec; + /// Imports own (node owner) transaction to queue. + fn import_own_transaction(&self, chain: &C, transaction: PendingTransaction) + -> Result<(), transaction::Error> + where C: BlockChainClient; + + /// Removes transaction from the pool. + /// + /// Attempts to "cancel" a transaction. If it was not propagated yet (or not accepted by other peers) + /// there is a good chance that the transaction will actually be removed. + /// NOTE: The transaction is not removed from pending block if there is one. + fn remove_transaction(&self, hash: &H256) -> Option>; + + /// Query transaction from the pool given it's hash. + fn transaction(&self, hash: &H256) -> Option>; + + /// Returns next valid nonce for given address. + /// + /// This includes nonces of all transactions from this address in the pending queue + /// if they are consecutive. + /// NOTE: pool may contain some future transactions that will become pending after + /// transaction with nonce returned from this function is signed on. + fn next_nonce(&self, chain: &C, address: &Address) -> U256 + where C: Nonce + Sync; + + /// Get a list of all ready transactions. + /// + /// Depending on the settings may look in transaction pool or only in pending block. + fn ready_transactions(&self, chain: &C) -> Vec> + where C: ChainInfo + Nonce + Sync; + + /// Get a list of all transactions in the pool (some of them might not be ready for inclusion yet). + fn queued_transactions(&self) -> Vec>; /// Get a list of local transactions with statuses. - fn local_transactions(&self) -> BTreeMap; - - /// Get a list of all pending receipts. - fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap; + fn local_transactions(&self) -> BTreeMap; - /// Get a particular reciept. - fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option; + /// Get current queue status. + /// + /// Status includes verification thresholds and current pool utilization and limits. + fn queue_status(&self) -> QueueStatus; - /// Returns highest transaction nonce for given address. - fn last_nonce(&self, address: &Address) -> Option; - - /// Is it currently sealing? - fn is_currently_sealing(&self) -> bool; + // Misc /// Suggested gas price. fn sensible_gas_price(&self) -> U256; /// Suggested gas limit. - fn sensible_gas_limit(&self) -> U256 { 21000.into() } - - /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. - fn pending_state(&self, latest_block_number: BlockNumber) -> Option; - - /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. - fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
; - - /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. - fn pending_block(&self, latest_block_number: BlockNumber) -> Option; -} - -/// Mining status -#[derive(Debug)] -pub struct MinerStatus { - /// Number of transactions in queue with state `pending` (ready to be included in block) - pub transactions_in_pending_queue: usize, - /// Number of transactions in queue with state `future` (not yet ready to be included in block) - pub transactions_in_future_queue: usize, - /// Number of transactions included in currently mined block - pub transactions_in_pending_block: usize, + fn sensible_gas_limit(&self) -> U256; } diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs new file mode 100644 index 0000000000..61153be025 --- /dev/null +++ b/ethcore/src/miner/pool_client.rs @@ -0,0 +1,216 @@ +// 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 . + +//! Blockchain access for transaction pool. + +use std::fmt; +use std::collections::HashMap; + +use ethereum_types::{H256, U256, Address}; +use ethcore_miner::pool; +use ethcore_miner::pool::client::NonceClient; +use transaction::{ + self, + UnverifiedTransaction, + SignedTransaction, +}; +use parking_lot::RwLock; + +use account_provider::AccountProvider; +use client::{TransactionId, BlockInfo, CallContract, Nonce}; +use engines::EthEngine; +use header::Header; +use miner; +use miner::service_transaction_checker::ServiceTransactionChecker; + +type NoncesCache = RwLock>; + +const MAX_NONCE_CACHE_SIZE: usize = 4096; +const EXPECTED_NONCE_CACHE_SIZE: usize = 2048; + +/// Blockchain accesss for transaction pool. +pub struct PoolClient<'a, C: 'a> { + chain: &'a C, + cached_nonces: CachedNonceClient<'a, C>, + engine: &'a EthEngine, + accounts: Option<&'a AccountProvider>, + best_block_header: Header, + service_transaction_checker: Option, +} + +impl<'a, C: 'a> Clone for PoolClient<'a, C> { + fn clone(&self) -> Self { + PoolClient { + chain: self.chain, + cached_nonces: self.cached_nonces.clone(), + engine: self.engine, + accounts: self.accounts.clone(), + best_block_header: self.best_block_header.clone(), + service_transaction_checker: self.service_transaction_checker.clone(), + } + } +} + +impl<'a, C: 'a> PoolClient<'a, C> where +C: BlockInfo + CallContract, +{ + /// Creates new client given chain, nonce cache, accounts and service transaction verifier. + pub fn new( + chain: &'a C, + cache: &'a NoncesCache, + engine: &'a EthEngine, + accounts: Option<&'a AccountProvider>, + refuse_service_transactions: bool, + ) -> Self { + let best_block_header = chain.best_block_header(); + PoolClient { + chain, + cached_nonces: CachedNonceClient::new(chain, cache), + engine, + accounts, + best_block_header, + service_transaction_checker: if refuse_service_transactions { + None + } else { + Some(Default::default()) + }, + } + } + + /// Verifies if signed transaction is executable. + /// + /// This should perform any verifications that rely on chain status. + pub fn verify_signed(&self, tx: &SignedTransaction) -> Result<(), transaction::Error> { + self.engine.machine().verify_transaction(&tx, &self.best_block_header, self.chain) + } +} + +impl<'a, C: 'a> fmt::Debug for PoolClient<'a, C> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "PoolClient") + } +} + +impl<'a, C: 'a> pool::client::Client for PoolClient<'a, C> where + C: miner::TransactionVerifierClient + Sync, +{ + fn transaction_already_included(&self, hash: &H256) -> bool { + self.chain.transaction_block(TransactionId::Hash(*hash)).is_some() + } + + fn verify_transaction(&self, tx: UnverifiedTransaction)-> Result { + self.engine.verify_transaction_basic(&tx, &self.best_block_header)?; + let tx = self.engine.verify_transaction_unordered(tx, &self.best_block_header)?; + + self.verify_signed(&tx)?; + + Ok(tx) + } + + fn account_details(&self, address: &Address) -> pool::client::AccountDetails { + pool::client::AccountDetails { + nonce: self.cached_nonces.account_nonce(address), + balance: self.chain.latest_balance(address), + is_local: self.accounts.map_or(false, |accounts| accounts.has_account(*address).unwrap_or(false)), + } + } + + fn required_gas(&self, tx: &transaction::Transaction) -> U256 { + tx.gas_required(&self.chain.latest_schedule()).into() + } + + fn transaction_type(&self, tx: &SignedTransaction) -> pool::client::TransactionType { + match self.service_transaction_checker { + None => pool::client::TransactionType::Regular, + Some(ref checker) => match checker.check(self.chain, &tx) { + Ok(true) => pool::client::TransactionType::Service, + Ok(false) => pool::client::TransactionType::Regular, + Err(e) => { + debug!(target: "txqueue", "Unable to verify service transaction: {:?}", e); + pool::client::TransactionType::Regular + }, + } + } + } +} + +impl<'a, C: 'a> NonceClient for PoolClient<'a, C> where + C: Nonce + Sync, +{ + fn account_nonce(&self, address: &Address) -> U256 { + self.cached_nonces.account_nonce(address) + } +} + +pub(crate) struct CachedNonceClient<'a, C: 'a> { + client: &'a C, + cache: &'a NoncesCache, +} + +impl<'a, C: 'a> Clone for CachedNonceClient<'a, C> { + fn clone(&self) -> Self { + CachedNonceClient { + client: self.client, + cache: self.cache, + } + } +} + +impl<'a, C: 'a> fmt::Debug for CachedNonceClient<'a, C> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("CachedNonceClient") + .field("cache", &self.cache.read().len()) + .finish() + } +} + +impl<'a, C: 'a> CachedNonceClient<'a, C> { + pub fn new(client: &'a C, cache: &'a NoncesCache) -> Self { + CachedNonceClient { + client, + cache, + } + } +} + +impl<'a, C: 'a> NonceClient for CachedNonceClient<'a, C> where + C: Nonce + Sync, +{ + fn account_nonce(&self, address: &Address) -> U256 { + if let Some(nonce) = self.cache.read().get(address) { + return *nonce; + } + + // We don't check again if cache has been populated. + // It's not THAT expensive to fetch the nonce from state. + let mut cache = self.cache.write(); + let nonce = self.client.latest_nonce(address); + cache.insert(*address, nonce); + + if cache.len() < MAX_NONCE_CACHE_SIZE { + return nonce + } + + // Remove excessive amount of entries from the cache + while cache.len() > EXPECTED_NONCE_CACHE_SIZE { + // Just remove random entry + if let Some(key) = cache.keys().next().cloned() { + cache.remove(&key); + } + } + nonce + } +} diff --git a/ethcore/src/miner/service_transaction_checker.rs b/ethcore/src/miner/service_transaction_checker.rs index a555829c5f..f085564d22 100644 --- a/ethcore/src/miner/service_transaction_checker.rs +++ b/ethcore/src/miner/service_transaction_checker.rs @@ -16,33 +16,38 @@ //! A service transactions contract checker. -use client::{RegistryInfo, CallContract}; +use client::{RegistryInfo, CallContract, BlockId}; use transaction::SignedTransaction; -use types::ids::BlockId; use_contract!(service_transaction, "ServiceTransaction", "res/contracts/service_transaction.json"); const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker"; /// Service transactions checker. -#[derive(Default)] +#[derive(Default, Clone)] pub struct ServiceTransactionChecker { contract: service_transaction::ServiceTransaction, } impl ServiceTransactionChecker { - /// Checks if service transaction can be appended to the transaction queue. + /// Checks if given address is whitelisted to send service transactions. pub fn check(&self, client: &C, tx: &SignedTransaction) -> Result { - assert!(tx.gas_price.is_zero()); + let sender = tx.sender(); + let hash = tx.hash(); + + // Skip checking the contract if the transaction does not have zero gas price + if !tx.gas_price.is_zero() { + return Ok(false) + } let address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) .ok_or_else(|| "contract is not configured")?; - trace!(target: "txqueue", "Checking service transaction checker contract from {}", address); + trace!(target: "txqueue", "[{:?}] Checking service transaction checker contract from {}", hash, sender); self.contract.functions() .certified() - .call(tx.sender(), &|data| client.call_contract(BlockId::Latest, address, data)) + .call(sender, &|data| client.call_contract(BlockId::Latest, address, data)) .map_err(|e| e.to_string()) } } diff --git a/ethcore/src/miner/stratum.rs b/ethcore/src/miner/stratum.rs index c8c387e510..c63124dcd0 100644 --- a/ethcore/src/miner/stratum.rs +++ b/ethcore/src/miner/stratum.rs @@ -20,8 +20,7 @@ use std::sync::{Arc, Weak}; use std::net::{SocketAddr, AddrParseError}; use std::fmt; -use block::IsBlock; -use client::Client; +use client::{Client, ImportSealedBlock}; use ethereum_types::{H64, H256, clean_0x, U256}; use ethereum::ethash::Ethash; use ethash::SeedHashCompute; @@ -30,7 +29,7 @@ use ethcore_stratum::{ JobDispatcher, PushWorkHandler, Stratum as StratumService, Error as StratumServiceError, }; -use miner::{self, Miner, MinerService}; +use miner::{Miner, MinerService}; use parking_lot::Mutex; use rlp::encode; @@ -120,14 +119,9 @@ impl JobDispatcher for StratumJobDispatcher { } fn job(&self) -> Option { - self.with_core(|client, miner| miner.map_sealing_work(&*client, |b| { - let pow_hash = b.hash(); - let number = b.block().header().number(); - let difficulty = b.block().header().difficulty(); - - self.payload(pow_hash, *difficulty, number) - }) - ) + self.with_core(|client, miner| miner.work_package(&*client).map(|(pow_hash, number, _timestamp, difficulty)| { + self.payload(pow_hash, difficulty, number) + })) } fn submit(&self, payload: Vec) -> Result<(), StratumServiceError> { @@ -145,7 +139,10 @@ impl JobDispatcher for StratumJobDispatcher { self.with_core_result(|client, miner| { let seal = vec![encode(&payload.mix_hash).into_vec(), encode(&payload.nonce).into_vec()]; - match miner.submit_seal(&*client, payload.pow_hash, seal) { + + let import = miner.submit_seal(payload.pow_hash, seal) + .and_then(|block| client.import_sealed_block(block)); + match import { Ok(_) => Ok(()), Err(e) => { warn!(target: "stratum", "submit_seal error: {:?}", e); @@ -247,8 +244,8 @@ impl Stratum { /// Start STRATUM job dispatcher and register it in the miner pub fn register(cfg: &Options, miner: Arc, client: Weak) -> Result<(), Error> { - let stratum = miner::Stratum::start(cfg, Arc::downgrade(&miner.clone()), client)?; - miner.push_notifier(Box::new(stratum) as Box); + let stratum = Stratum::start(cfg, Arc::downgrade(&miner.clone()), client)?; + miner.add_work_listener(Box::new(stratum) as Box); Ok(()) } } diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index b0741b4c49..4b1b3d6ad0 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -107,13 +107,11 @@ fn make_chain(accounts: Arc, blocks_beyond: usize, transitions: trace!(target: "snapshot", "Pushing block #{}, {} txs, author={}", n, txs.len(), signers[idx]); - client.miner().set_author(signers[idx]); + client.miner().set_author(signers[idx], Some(PASS.into())).unwrap(); client.miner().import_external_transactions(&*client, txs.into_iter().map(Into::into).collect()); - let engine = client.engine(); - engine.set_signer(accounts.clone(), signers[idx], PASS.to_owned()); - engine.step(); + client.engine().step(); assert_eq!(client.chain_info().best_block_number, n); }; diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 7e81b05796..d49e6fd63b 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -58,7 +58,7 @@ fn restored_is_equivalent() { Default::default(), &spec, Arc::new(client_db), - Arc::new(::miner::Miner::with_spec(&spec)), + Arc::new(::miner::Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 4c013dd251..8d10e4b3b8 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -120,7 +120,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun ClientConfig::default(), &test_spec, client_db, - Arc::new(Miner::with_spec_and_accounts(&test_spec, accounts)), + Arc::new(Miner::new_for_tests(&test_spec, accounts)), IoChannel::disconnected(), ).unwrap(); let test_engine = &*test_spec.engine; @@ -243,7 +243,7 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> Arc { ClientConfig::default(), &test_spec, client_db, - Arc::new(Miner::with_spec(&test_spec)), + Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected(), ).unwrap(); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index e6333f56ad..fc5f84bfae 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -49,7 +49,7 @@ fn imports_from_empty() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); client.import_verified_blocks(); @@ -67,7 +67,7 @@ fn should_return_registrar() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let params = client.additional_params(); @@ -97,7 +97,7 @@ fn imports_good_block() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let good_block = get_good_dummy_block(); @@ -122,7 +122,7 @@ fn query_none_block() { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let non_existant = client.block_header(BlockId::Number(188)); @@ -277,7 +277,7 @@ fn change_history_size() { ClientConfig::default(), &test_spec, client_db.clone(), - Arc::new(Miner::with_spec(&test_spec)), + Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected() ).unwrap(); @@ -295,7 +295,7 @@ fn change_history_size() { config, &test_spec, client_db, - Arc::new(Miner::with_spec(&test_spec)), + Arc::new(Miner::new_for_tests(&test_spec, None)), IoChannel::disconnected(), ).unwrap(); assert_eq!(client.state().balance(&address).unwrap(), 100.into()); @@ -326,11 +326,11 @@ fn does_not_propagate_delayed_transactions() { client.miner().import_own_transaction(&*client, tx0).unwrap(); client.miner().import_own_transaction(&*client, tx1).unwrap(); assert_eq!(0, client.ready_transactions().len()); - assert_eq!(2, client.miner().pending_transactions().len()); + assert_eq!(0, client.miner().ready_transactions(&*client).len()); push_blocks_to_client(&client, 53, 2, 2); client.flush_queue(); assert_eq!(2, client.ready_transactions().len()); - assert_eq!(2, client.miner().pending_transactions().len()); + assert_eq!(2, client.miner().ready_transactions(&*client).len()); } #[test] diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 4646bc091f..1626e828cc 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -50,7 +50,7 @@ fn can_trace_block_and_uncle_reward() { client_config, &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index a4fa8a0874..8bbb499052 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -164,7 +164,7 @@ mod test { ClientConfig::default(), &spec, client_db, - Arc::new(Miner::with_spec(&spec)), + Arc::new(Miner::new_for_tests(&spec, None)), IoChannel::disconnected(), ).unwrap(); let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000001")).unwrap(); diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 62a237da48..eeccb46112 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -39,6 +39,7 @@ use light::Provider; use light::net::{self as light_net, LightProtocol, Params as LightParams, Capabilities, Handler as LightHandler, EventContext}; use network::IpFilter; use private_tx::PrivateTxHandler; +use transaction::UnverifiedTransaction; /// Parity sync protocol pub const WARP_SYNC_PROTOCOL_ID: ProtocolId = *b"par"; @@ -486,9 +487,9 @@ impl ChainNotify for EthSync { }); } - fn transactions_received(&self, hashes: Vec, peer_id: PeerId) { + fn transactions_received(&self, txs: &[UnverifiedTransaction], peer_id: PeerId) { let mut sync = self.eth_handler.sync.write(); - sync.transactions_received(hashes, peer_id); + sync.transactions_received(txs, peer_id); } } diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index b2494e1f03..44ab1971a9 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -104,15 +104,16 @@ use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo}; use ethcore::error::*; use ethcore::snapshot::{ManifestData, RestorationStatus}; -use transaction::PendingTransaction; +use transaction::SignedTransaction; use sync_io::SyncIo; use super::{WarpSync, SyncConfig}; use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction}; use rand::Rng; use snapshot::{Snapshot, ChunkType}; use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; -use transactions_stats::{TransactionsStats, Stats as TransactionStats}; use private_tx::PrivateTxHandler; +use transactions_stats::{TransactionsStats, Stats as TransactionStats}; +use transaction::UnverifiedTransaction; known_heap_size!(0, PeerInfo); @@ -478,9 +479,9 @@ impl ChainSync { } /// Updates transactions were received by a peer - pub fn transactions_received(&mut self, hashes: Vec, peer_id: PeerId) { + pub fn transactions_received(&mut self, txs: &[UnverifiedTransaction], peer_id: PeerId) { if let Some(peer_info) = self.peers.get_mut(&peer_id) { - peer_info.last_sent_transactions.extend(&hashes); + peer_info.last_sent_transactions.extend(txs.iter().map(|tx| tx.hash())); } } @@ -2026,8 +2027,9 @@ impl ChainSync { return 0; } - let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.into_iter() - .partition(|tx| !tx.transaction.gas_price.is_zero()); + let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.iter() + .map(|tx| tx.signed()) + .partition(|tx| !tx.gas_price.is_zero()); // usual transactions could be propagated to all peers let mut affected_peers = HashSet::new(); @@ -2062,13 +2064,13 @@ impl ChainSync { .collect() } - fn propagate_transactions_to_peers(&mut self, io: &mut SyncIo, peers: Vec, transactions: Vec) -> HashSet { + fn propagate_transactions_to_peers(&mut self, io: &mut SyncIo, peers: Vec, transactions: Vec<&SignedTransaction>) -> HashSet { let all_transactions_hashes = transactions.iter() - .map(|tx| tx.transaction.hash()) + .map(|tx| tx.hash()) .collect::>(); let all_transactions_rlp = { let mut packet = RlpStream::new_list(transactions.len()); - for tx in &transactions { packet.append(&tx.transaction); } + for tx in &transactions { packet.append(&**tx); } packet.out() }; @@ -2112,10 +2114,10 @@ impl ChainSync { packet.begin_unbounded_list(); let mut pushed = 0; for tx in &transactions { - let hash = tx.transaction.hash(); + let hash = tx.hash(); if to_send.contains(&hash) { let mut transaction = RlpStream::new(); - tx.transaction.rlp_append(&mut transaction); + tx.rlp_append(&mut transaction); let appended = packet.append_raw_checked(&transaction.drain(), 1, MAX_TRANSACTION_PACKET_SIZE); if !appended { // Maximal packet size reached just proceed with sending @@ -2329,7 +2331,6 @@ mod tests { use ethcore::header::*; use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; use ethcore::miner::MinerService; - use transaction::UnverifiedTransaction; use private_tx::NoopPrivateTxHandler; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { @@ -3064,10 +3065,9 @@ mod tests { let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0); - assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 1); + assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); } // We need to update nonce status (because we say that the block has been imported) for h in &[good_blocks[0]] { @@ -3078,14 +3078,12 @@ mod tests { let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let mut io = TestIo::new(&client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks, false); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); } // then - let status = client.miner.status(); - assert_eq!(status.transactions_in_pending_queue, 1); - assert_eq!(status.transactions_in_future_queue, 0); + assert_eq!(client.miner.ready_transactions(&client).len(), 1); } #[test] @@ -3106,13 +3104,11 @@ mod tests { // when sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0); - assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 0); + assert_eq!(io.chain.miner.queue_status().status.transaction_count, 0); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); // then - let status = io.chain.miner.status(); - assert_eq!(status.transactions_in_pending_queue, 0); - assert_eq!(status.transactions_in_future_queue, 0); + let status = io.chain.miner.queue_status(); + assert_eq!(status.status.transaction_count, 0); } } diff --git a/ethcore/sync/src/tests/consensus.rs b/ethcore/sync/src/tests/consensus.rs index f4a58a18af..287a61916a 100644 --- a/ethcore/sync/src/tests/consensus.rs +++ b/ethcore/sync/src/tests/consensus.rs @@ -52,8 +52,8 @@ fn authority_round() { let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // 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(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap(); + net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".to_owned())).unwrap(); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1))); @@ -61,15 +61,15 @@ fn authority_round() { // exchange statuses net.sync(); // Trigger block proposal - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); // Sync a block net.sync(); assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); // Move to next proposer step. net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); @@ -78,8 +78,8 @@ fn authority_round() { assert_eq!(net.peer(1).chain.chain_info().best_block_number, 2); // Fork the network with equal height. - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); // Let both nodes build one block. net.peer(0).chain.engine().step(); let early_hash = net.peer(0).chain.chain_info().best_block_hash; @@ -101,8 +101,8 @@ fn authority_round() { assert_eq!(ci1.best_block_hash, early_hash); // Selfish miner - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 3.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 3.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 3.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 3.into(), chain_id)).unwrap(); // Node 0 is an earlier primary. net.peer(0).chain.engine().step(); assert_eq!(net.peer(0).chain.chain_info().best_block_number, 4); @@ -113,7 +113,7 @@ fn authority_round() { // Node 1 makes 2 blocks, but is a later primary on the first one. net.peer(1).chain.engine().step(); net.peer(1).chain.engine().step(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 4.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 4.into(), chain_id)).unwrap(); net.peer(1).chain.engine().step(); net.peer(1).chain.engine().step(); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 5); @@ -139,9 +139,9 @@ fn tendermint() { let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them issues a proposal. - net.peer(0).chain.miner().set_engine_signer(s0.address(), "".to_owned()).unwrap(); + net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); trace!(target: "poa", "Peer 0 is {}.", s0.address()); - net.peer(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".into())).unwrap(); trace!(target: "poa", "Peer 1 is {}.", s1.address()); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); @@ -150,7 +150,7 @@ fn tendermint() { // Exhange statuses net.sync(); // Propose - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), chain_id)).unwrap(); net.sync(); // Propose timeout, synchronous for now net.peer(0).chain.engine().step(); @@ -161,7 +161,7 @@ fn tendermint() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), chain_id)).unwrap(); // Commit timeout net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); @@ -175,8 +175,8 @@ fn tendermint() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 2); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 2); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), chain_id)).unwrap(); // Peers get disconnected. // Commit net.peer(0).chain.engine().step(); @@ -184,8 +184,8 @@ fn tendermint() { // Propose net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); + net.peer(0).miner.import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), chain_id)).unwrap(); + net.peer(1).miner.import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), chain_id)).unwrap(); // Send different prevotes net.sync(); // Prevote timeout diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 495603020d..54b62c79a0 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -206,6 +206,7 @@ pub trait Peer { pub struct EthPeer where C: FlushingBlockChainClient { pub chain: Arc, + pub miner: Arc, pub snapshot_service: Arc, pub sync: RwLock, pub queue: RwLock>, @@ -340,6 +341,7 @@ impl TestNet> { sync: RwLock::new(sync), snapshot_service: ss, chain: Arc::new(chain), + miner: Arc::new(Miner::new_for_tests(&Spec::new_test(), None)), queue: RwLock::new(VecDeque::new()), private_tx_handler, io_queue: RwLock::new(VecDeque::new()), @@ -382,11 +384,12 @@ impl TestNet> { pub fn add_peer_with_private_config(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { let channel = IoChannel::disconnected(); + let miner = Arc::new(Miner::new_for_tests(&spec, accounts.clone())); let client = EthcoreClient::new( ClientConfig::default(), &spec, Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), - Arc::new(Miner::with_spec_and_accounts(&spec, accounts.clone())), + miner.clone(), channel.clone() ).unwrap(); @@ -397,6 +400,7 @@ impl TestNet> { sync: RwLock::new(sync), snapshot_service: ss, chain: client, + miner, queue: RwLock::new(VecDeque::new()), private_tx_handler, io_queue: RwLock::new(VecDeque::new()), @@ -408,11 +412,12 @@ impl TestNet> { } pub fn add_peer(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { + let miner = Arc::new(Miner::new_for_tests(&spec, accounts)); let client = EthcoreClient::new( ClientConfig::default(), &spec, Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), - Arc::new(Miner::with_spec_and_accounts(&spec, accounts)), + miner.clone(), IoChannel::disconnected(), ).unwrap(); @@ -422,8 +427,9 @@ impl TestNet> { let peer = Arc::new(EthPeer { sync: RwLock::new(sync), snapshot_service: ss, - chain: client, queue: RwLock::new(VecDeque::new()), + chain: client, + miner, private_tx_handler, io_queue: RwLock::new(VecDeque::new()), new_blocks_queue: RwLock::new(VecDeque::new()), diff --git a/ethcore/transaction/src/lib.rs b/ethcore/transaction/src/lib.rs index 6d6c269f30..6a478b9463 100644 --- a/ethcore/transaction/src/lib.rs +++ b/ethcore/transaction/src/lib.rs @@ -33,14 +33,3 @@ mod transaction; pub use error::Error; pub use transaction::*; - -// TODO [ToDr] Move to miner! - -/// Represents the result of importing transaction. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum ImportResult { - /// Transaction was imported to current queue. - Current, - /// Transaction was imported to future queue. - Future -} diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 49f2534fac..6e8e78cc48 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -377,7 +377,7 @@ impl UnverifiedTransaction { } } - /// Get the hash of this header (keccak of the RLP). + /// Get the hash of this transaction (keccak of the RLP). pub fn hash(&self) -> H256 { self.hash } diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 4ee8d74c0f..cf8eb0cdd8 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -7,24 +7,31 @@ version = "1.11.0" authors = ["Parity Technologies "] [dependencies] -common-types = { path = "../ethcore/types" } -ethabi = "5.1" -ethabi-contract = "5.0" -ethabi-derive = "5.0" +# Only work_notify, consider a separate crate ethash = { path = "../ethash" } +fetch = { path = "../util/fetch" } +hyper = "0.11" +parity-reactor = { path = "../util/reactor" } +url = "1" + +# Miner +ansi_term = "0.10" +error-chain = "0.11" ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" -ethkey = { path = "../ethkey" } futures = "0.1" +futures-cpupool = "0.1" heapsize = "0.4" keccak-hash = { path = "../util/hash" } linked-hash-map = "0.5" log = "0.3" parking_lot = "0.5" +price-info = { path = "../price-info" } +rayon = "1.0" +trace-time = { path = "../util/trace-time" } +transaction-pool = { path = "../transaction-pool" } + +[dev-dependencies] +env_logger = "0.4" +ethkey = { path = "../ethkey" } rustc-hex = "1.0" -table = { path = "../util/table" } -transient-hashmap = "0.4" -fetch = { path = "../util/fetch" } -parity-reactor = { path = "../util/reactor" } -url = "1" -hyper = "0.11" diff --git a/miner/src/banning_queue.rs b/miner/src/banning_queue.rs deleted file mode 100644 index 388ae5e001..0000000000 --- a/miner/src/banning_queue.rs +++ /dev/null @@ -1,321 +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 . - -//! Banning Queue -//! Transacton Queue wrapper maintaining additional list of banned senders and contract hashes. - -use std::time::Duration; -use std::ops::{Deref, DerefMut}; -use ethereum_types::{H256, U256, Address}; -use hash::keccak; -use transaction::{self, SignedTransaction, Action}; -use transient_hashmap::TransientHashMap; - -use transaction_queue::{TransactionQueue, TransactionDetailsProvider, TransactionOrigin, QueuingInstant}; - -type Count = u16; - -/// Auto-Banning threshold -pub enum Threshold { - /// Should ban after given number of misbehaves reported. - BanAfter(Count), - /// Should never ban anything - NeverBan -} - -impl Default for Threshold { - fn default() -> Self { - Threshold::NeverBan - } -} - -/// Transaction queue with banlist. -pub struct BanningTransactionQueue { - queue: TransactionQueue, - ban_threshold: Threshold, - senders_bans: TransientHashMap, - recipients_bans: TransientHashMap, - codes_bans: TransientHashMap, -} - -impl BanningTransactionQueue { - /// Creates new banlisting transaction queue - pub fn new(queue: TransactionQueue, ban_threshold: Threshold, ban_lifetime: Duration) -> Self { - let ban_lifetime_sec = ban_lifetime.as_secs() as u32; - assert!(ban_lifetime_sec > 0, "Lifetime has to be specified in seconds."); - BanningTransactionQueue { - queue: queue, - ban_threshold: ban_threshold, - senders_bans: TransientHashMap::new(ban_lifetime_sec), - recipients_bans: TransientHashMap::new(ban_lifetime_sec), - codes_bans: TransientHashMap::new(ban_lifetime_sec), - } - } - - /// Borrows internal queue. - /// NOTE: you can insert transactions to the queue even - /// if they would be rejected because of ban otherwise. - /// But probably you shouldn't. - pub fn queue(&mut self) -> &mut TransactionQueue { - &mut self.queue - } - - /// Add to the queue taking bans into consideration. - /// May reject transaction because of the banlist. - pub fn add_with_banlist( - &mut self, - transaction: SignedTransaction, - time: QueuingInstant, - details_provider: &TransactionDetailsProvider, - ) -> Result { - if let Threshold::BanAfter(threshold) = self.ban_threshold { - // NOTE In all checks use direct query to avoid increasing ban timeout. - - // Check sender - let sender = transaction.sender(); - let count = self.senders_bans.direct().get(&sender).cloned().unwrap_or(0); - if count > threshold { - debug!(target: "txqueue", "Ignoring transaction {:?} because sender is banned.", transaction.hash()); - return Err(transaction::Error::SenderBanned); - } - - // Check recipient - if let Action::Call(recipient) = transaction.action { - let count = self.recipients_bans.direct().get(&recipient).cloned().unwrap_or(0); - if count > threshold { - debug!(target: "txqueue", "Ignoring transaction {:?} because recipient is banned.", transaction.hash()); - return Err(transaction::Error::RecipientBanned); - } - } - - // Check code - if let Action::Create = transaction.action { - let code_hash = keccak(&transaction.data); - let count = self.codes_bans.direct().get(&code_hash).cloned().unwrap_or(0); - if count > threshold { - debug!(target: "txqueue", "Ignoring transaction {:?} because code is banned.", transaction.hash()); - return Err(transaction::Error::CodeBanned); - } - } - } - self.queue.add(transaction, TransactionOrigin::External, time, None, details_provider) - } - - /// Ban transaction with given hash. - /// Transaction has to be in the queue. - /// - /// Bans sender and recipient/code and returns `true` when any ban has reached threshold. - pub fn ban_transaction(&mut self, hash: &H256) -> bool { - let transaction = self.queue.find(hash); - match transaction { - Some(transaction) => { - let sender = transaction.sender(); - // Ban sender - let sender_banned = self.ban_sender(sender); - // Ban recipient and codehash - let recipient_or_code_banned = match transaction.action { - Action::Call(recipient) => { - self.ban_recipient(recipient) - }, - Action::Create => { - self.ban_codehash(keccak(&transaction.data)) - }, - }; - sender_banned || recipient_or_code_banned - }, - None => false, - } - } - - /// Ban given sender. - /// If bans threshold is reached all subsequent transactions from this sender will be rejected. - /// Reaching bans threshold also removes all existsing transaction from this sender that are already in the - /// queue. - fn ban_sender(&mut self, address: Address) -> bool { - let count = { - let count = self.senders_bans.entry(address).or_insert_with(|| 0); - *count = count.saturating_add(1); - *count - }; - match self.ban_threshold { - Threshold::BanAfter(threshold) if count > threshold => { - // Banlist the sender. - // Remove all transactions from the queue. - self.cull(address, !U256::zero()); - true - }, - _ => false - } - } - - /// Ban given recipient. - /// If bans threshold is reached all subsequent transactions to this address will be rejected. - /// Returns true if bans threshold has been reached. - fn ban_recipient(&mut self, address: Address) -> bool { - let count = { - let count = self.recipients_bans.entry(address).or_insert_with(|| 0); - *count = count.saturating_add(1); - *count - }; - match self.ban_threshold { - // TODO [ToDr] Consider removing other transactions to the same recipient from the queue? - Threshold::BanAfter(threshold) if count > threshold => true, - _ => false - } - } - - - /// Ban given codehash. - /// If bans threshold is reached all subsequent transactions to contracts with this codehash will be rejected. - /// Returns true if bans threshold has been reached. - fn ban_codehash(&mut self, code_hash: H256) -> bool { - let count = self.codes_bans.entry(code_hash).or_insert_with(|| 0); - *count = count.saturating_add(1); - - match self.ban_threshold { - // TODO [ToDr] Consider removing other transactions with the same code from the queue? - Threshold::BanAfter(threshold) if *count > threshold => true, - _ => false, - } - } -} - -impl Deref for BanningTransactionQueue { - type Target = TransactionQueue; - - fn deref(&self) -> &Self::Target { - &self.queue - } -} -impl DerefMut for BanningTransactionQueue { - fn deref_mut(&mut self) -> &mut Self::Target { - self.queue() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ethkey::{Random, Generator}; - use rustc_hex::FromHex; - use transaction_queue::test::DummyTransactionDetailsProvider; - use ethereum_types::{U256, Address}; - - fn queue() -> BanningTransactionQueue { - BanningTransactionQueue::new(TransactionQueue::default(), Threshold::BanAfter(1), Duration::from_secs(180)) - } - - fn default_tx_provider() -> DummyTransactionDetailsProvider { - DummyTransactionDetailsProvider::default().with_account_nonce(U256::zero()) - } - - fn transaction(action: Action) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - transaction::Transaction { - action: action, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: U256::from(100_000), - gas_price: U256::from(10), - nonce: U256::from(0), - }.sign(keypair.secret(), None) - } - - fn unwrap_err(res: Result) -> transaction::Error { - res.unwrap_err() - } - - #[test] - fn should_allow_to_borrow_the_queue() { - // given - let tx = transaction(Action::Create); - let mut txq = queue(); - - // when - txq.queue().add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - // should also deref to queue - assert_eq!(txq.status().pending, 1); - } - - #[test] - fn should_not_accept_transactions_from_banned_sender() { - // given - let tx = transaction(Action::Create); - let mut txq = queue(); - // Banlist once (threshold not reached) - let banlist1 = txq.ban_sender(tx.sender()); - assert!(!banlist1, "Threshold not reached yet."); - // Insert once - let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap(); - assert_eq!(import1, transaction::ImportResult::Current); - - // when - let banlist2 = txq.ban_sender(tx.sender()); - let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()); - - // then - assert!(banlist2, "Threshold should be reached - banned."); - assert_eq!(unwrap_err(import2), transaction::Error::SenderBanned); - // Should also remove transacion from the queue - assert_eq!(txq.find(&tx.hash()), None); - } - - #[test] - fn should_not_accept_transactions_to_banned_recipient() { - // given - let recipient = Address::default(); - let tx = transaction(Action::Call(recipient)); - let mut txq = queue(); - // Banlist once (threshold not reached) - let banlist1 = txq.ban_recipient(recipient); - assert!(!banlist1, "Threshold not reached yet."); - // Insert once - let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap(); - assert_eq!(import1, transaction::ImportResult::Current); - - // when - let banlist2 = txq.ban_recipient(recipient); - let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()); - - // then - assert!(banlist2, "Threshold should be reached - banned."); - assert_eq!(unwrap_err(import2), transaction::Error::RecipientBanned); - } - - #[test] - fn should_not_accept_transactions_with_banned_code() { - // given - let tx = transaction(Action::Create); - let codehash = keccak(&tx.data); - let mut txq = queue(); - // Banlist once (threshold not reached) - let banlist1 = txq.ban_codehash(codehash); - assert!(!banlist1, "Threshold not reached yet."); - // Insert once - let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap(); - assert_eq!(import1, transaction::ImportResult::Current); - - // when - let banlist2 = txq.ban_codehash(codehash); - let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()); - - // then - assert!(banlist2, "Threshold should be reached - banned."); - assert_eq!(unwrap_err(import2), transaction::Error::CodeBanned); - } -} diff --git a/miner/src/gas_pricer.rs b/miner/src/gas_pricer.rs new file mode 100644 index 0000000000..f826ccf77d --- /dev/null +++ b/miner/src/gas_pricer.rs @@ -0,0 +1,97 @@ +// 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 . + +//! Auto-updates minimal gas price requirement. + +use std::time::{Instant, Duration}; + +use ansi_term::Colour; +use ethereum_types::U256; +use futures_cpupool::CpuPool; +use price_info::{Client as PriceInfoClient, PriceInfo}; +use price_info::fetch::Client as FetchClient; + +/// Options for the dynamic gas price recalibrator. +#[derive(Debug, PartialEq)] +pub struct GasPriceCalibratorOptions { + /// Base transaction price to match against. + pub usd_per_tx: f32, + /// How frequently we should recalibrate. + pub recalibration_period: Duration, +} + +/// The gas price validator variant for a `GasPricer`. +#[derive(Debug, PartialEq)] +pub struct GasPriceCalibrator { + options: GasPriceCalibratorOptions, + next_calibration: Instant, + price_info: PriceInfoClient, +} + +impl GasPriceCalibrator { + fn recalibrate(&mut self, set_price: F) { + trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration); + if Instant::now() >= self.next_calibration { + let usd_per_tx = self.options.usd_per_tx; + trace!(target: "miner", "Getting price info"); + + self.price_info.get(move |price: PriceInfo| { + trace!(target: "miner", "Price info arrived: {:?}", price); + let usd_per_eth = price.ethusd; + let wei_per_usd: f32 = 1.0e18 / usd_per_eth; + let gas_per_tx: f32 = 21000.0; + let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; + info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas))); + set_price(U256::from(wei_per_gas as u64)); + }); + + self.next_calibration = Instant::now() + self.options.recalibration_period; + } + } +} + +/// Struct to look after updating the acceptable gas price of a miner. +#[derive(Debug, PartialEq)] +pub enum GasPricer { + /// A fixed gas price in terms of Wei - always the argument given. + Fixed(U256), + /// Gas price is calibrated according to a fixed amount of USD. + Calibrated(GasPriceCalibrator), +} + +impl GasPricer { + /// Create a new Calibrated `GasPricer`. + pub fn new_calibrated(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPricer { + GasPricer::Calibrated(GasPriceCalibrator { + options: options, + next_calibration: Instant::now(), + price_info: PriceInfoClient::new(fetch, p), + }) + } + + /// Create a new Fixed `GasPricer`. + pub fn new_fixed(gas_price: U256) -> GasPricer { + GasPricer::Fixed(gas_price) + } + + /// Recalibrate current gas price. + pub fn recalibrate(&mut self, set_price: F) { + match *self { + GasPricer::Fixed(ref max) => set_price(max.clone()), + GasPricer::Calibrated(ref mut cal) => cal.recalibrate(set_price), + } + } +} diff --git a/miner/src/lib.rs b/miner/src/lib.rs index e8a86bd02a..197823aec7 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -19,27 +19,33 @@ //! Miner module //! Keeps track of transactions and mined block. -extern crate common_types as types; -extern crate ethabi; +extern crate ansi_term; extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate futures; +extern crate futures_cpupool; extern crate heapsize; extern crate keccak_hash as hash; extern crate linked_hash_map; extern crate parking_lot; -extern crate table; -extern crate transient_hashmap; +extern crate price_info; +extern crate rayon; +extern crate trace_time; +extern crate transaction_pool as txpool; -#[cfg(test)] -extern crate ethkey; +#[macro_use] +extern crate error_chain; #[macro_use] extern crate log; + #[cfg(test)] extern crate rustc_hex; +#[cfg(test)] +extern crate ethkey; +#[cfg(test)] +extern crate env_logger; -pub mod banning_queue; pub mod external; -pub mod local_transactions; -pub mod transaction_queue; +pub mod gas_pricer; +pub mod pool; pub mod work_notify; diff --git a/miner/src/local_transactions.rs b/miner/src/local_transactions.rs deleted file mode 100644 index e8d1988a4f..0000000000 --- a/miner/src/local_transactions.rs +++ /dev/null @@ -1,220 +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 . - -//! Local Transactions List. - -use ethereum_types::{H256, U256}; -use linked_hash_map::LinkedHashMap; -use transaction::{self, SignedTransaction, PendingTransaction}; - -/// Status of local transaction. -/// Can indicate that the transaction is currently part of the queue (`Pending/Future`) -/// or gives a reason why the transaction was removed. -#[derive(Debug, PartialEq, Clone)] -pub enum Status { - /// The transaction is currently in the transaction queue. - Pending, - /// The transaction is in future part of the queue. - Future, - /// Transaction is already mined. - Mined(SignedTransaction), - /// Transaction is dropped because of limit - Dropped(SignedTransaction), - /// Replaced because of higher gas price of another transaction. - Replaced(SignedTransaction, U256, H256), - /// Transaction was never accepted to the queue. - Rejected(SignedTransaction, transaction::Error), - /// Transaction is invalid. - Invalid(SignedTransaction), - /// Transaction was canceled. - Canceled(PendingTransaction), -} - -impl Status { - fn is_current(&self) -> bool { - *self == Status::Pending || *self == Status::Future - } -} - -/// Keeps track of local transactions that are in the queue or were mined/dropped recently. -#[derive(Debug)] -pub struct LocalTransactionsList { - max_old: usize, - transactions: LinkedHashMap, -} - -impl Default for LocalTransactionsList { - fn default() -> Self { - Self::new(10) - } -} - -impl LocalTransactionsList { - /// Create a new list of local transactions. - pub fn new(max_old: usize) -> Self { - LocalTransactionsList { - max_old: max_old, - transactions: Default::default(), - } - } - - /// Mark transaction with given hash as pending. - pub fn mark_pending(&mut self, hash: H256) { - debug!(target: "own_tx", "Imported to Current (hash {:?})", hash); - self.clear_old(); - self.transactions.insert(hash, Status::Pending); - } - - /// Mark transaction with given hash as future. - pub fn mark_future(&mut self, hash: H256) { - debug!(target: "own_tx", "Imported to Future (hash {:?})", hash); - self.transactions.insert(hash, Status::Future); - self.clear_old(); - } - - /// Mark given transaction as rejected from the queue. - pub fn mark_rejected(&mut self, tx: SignedTransaction, err: transaction::Error) { - debug!(target: "own_tx", "Transaction rejected (hash {:?}): {:?}", tx.hash(), err); - self.transactions.insert(tx.hash(), Status::Rejected(tx, err)); - self.clear_old(); - } - - /// Mark the transaction as replaced by transaction with given hash. - pub fn mark_replaced(&mut self, tx: SignedTransaction, gas_price: U256, hash: H256) { - debug!(target: "own_tx", "Transaction replaced (hash {:?}) by {:?} (new gas price: {:?})", tx.hash(), hash, gas_price); - self.transactions.insert(tx.hash(), Status::Replaced(tx, gas_price, hash)); - self.clear_old(); - } - - /// Mark transaction as invalid. - pub fn mark_invalid(&mut self, tx: SignedTransaction) { - warn!(target: "own_tx", "Transaction marked invalid (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Invalid(tx)); - self.clear_old(); - } - - /// Mark transaction as canceled. - pub fn mark_canceled(&mut self, tx: PendingTransaction) { - warn!(target: "own_tx", "Transaction canceled (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Canceled(tx)); - self.clear_old(); - } - - /// Mark transaction as dropped because of limit. - pub fn mark_dropped(&mut self, tx: SignedTransaction) { - warn!(target: "own_tx", "Transaction dropped (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Dropped(tx)); - self.clear_old(); - } - - /// Mark transaction as mined. - pub fn mark_mined(&mut self, tx: SignedTransaction) { - info!(target: "own_tx", "Transaction mined (hash {:?})", tx.hash()); - self.transactions.insert(tx.hash(), Status::Mined(tx)); - self.clear_old(); - } - - /// Returns true if the transaction is already in local transactions. - pub fn contains(&self, hash: &H256) -> bool { - self.transactions.contains_key(hash) - } - - /// Return a map of all currently stored transactions. - pub fn all_transactions(&self) -> &LinkedHashMap { - &self.transactions - } - - fn clear_old(&mut self) { - let number_of_old = self.transactions - .values() - .filter(|status| !status.is_current()) - .count(); - - if self.max_old >= number_of_old { - return; - } - - let to_remove = self.transactions - .iter() - .filter(|&(_, status)| !status.is_current()) - .map(|(hash, _)| *hash) - .take(number_of_old - self.max_old) - .collect::>(); - - for hash in to_remove { - self.transactions.remove(&hash); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ethereum_types::U256; - use ethkey::{Random, Generator}; - - #[test] - fn should_add_transaction_as_pending() { - // given - let mut list = LocalTransactionsList::default(); - - // when - list.mark_pending(10.into()); - list.mark_future(20.into()); - - // then - assert!(list.contains(&10.into()), "Should contain the transaction."); - assert!(list.contains(&20.into()), "Should contain the transaction."); - let statuses = list.all_transactions().values().cloned().collect::>(); - assert_eq!(statuses, vec![Status::Pending, Status::Future]); - } - - #[test] - fn should_clear_old_transactions() { - // given - let mut list = LocalTransactionsList::new(1); - let tx1 = new_tx(10.into()); - let tx1_hash = tx1.hash(); - let tx2 = new_tx(50.into()); - let tx2_hash = tx2.hash(); - - list.mark_pending(10.into()); - list.mark_invalid(tx1); - list.mark_dropped(tx2); - assert!(list.contains(&tx2_hash)); - assert!(!list.contains(&tx1_hash)); - assert!(list.contains(&10.into())); - - // when - list.mark_future(15.into()); - - // then - assert!(list.contains(&10.into())); - assert!(list.contains(&15.into())); - } - - fn new_tx(nonce: U256) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - transaction::Transaction { - action: transaction::Action::Create, - value: U256::from(100), - data: Default::default(), - gas: U256::from(10), - gas_price: U256::from(1245), - nonce: nonce - }.sign(keypair.secret(), None) - } -} diff --git a/miner/src/pool/client.rs b/miner/src/pool/client.rs new file mode 100644 index 0000000000..4243e8d26b --- /dev/null +++ b/miner/src/pool/client.rs @@ -0,0 +1,71 @@ +// 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 . + +//! Transaction Pool state client. +//! +//! `Client` encapsulates all external data required for the verifaction and readiness. +//! It includes any Ethereum state parts required for checking the transaction and +//! any consensus-required structure of the transaction. + +use std::fmt; + +use ethereum_types::{U256, H256, H160 as Address}; +use transaction; + +/// Account Details +#[derive(Debug, Clone)] +pub struct AccountDetails { + /// Current account nonce + pub nonce: U256, + /// Current account balance + pub balance: U256, + /// Is this account a local account? + pub is_local: bool, +} + +/// Transaction type +#[derive(Debug, PartialEq)] +pub enum TransactionType { + /// Regular transaction + Regular, + /// Service transaction (allowed by a contract to have gas_price=0) + Service, +} + +/// Verification client. +pub trait Client: fmt::Debug + Sync { + /// Is transaction with given hash already in the blockchain? + fn transaction_already_included(&self, hash: &H256) -> bool; + + /// Structurarily verify given transaction. + fn verify_transaction(&self, tx: transaction::UnverifiedTransaction) + -> Result; + + /// Estimate minimal gas requirurement for given transaction. + fn required_gas(&self, tx: &transaction::Transaction) -> U256; + + /// Fetch account details for given sender. + fn account_details(&self, address: &Address) -> AccountDetails; + + /// Classify transaction (check if transaction is filtered by some contracts). + fn transaction_type(&self, tx: &transaction::SignedTransaction) -> TransactionType; +} + +/// State nonce client +pub trait NonceClient: fmt::Debug + Sync { + /// Fetch only account nonce for given sender. + fn account_nonce(&self, address: &Address) -> U256; +} diff --git a/miner/src/pool/listener.rs b/miner/src/pool/listener.rs new file mode 100644 index 0000000000..3f42372e84 --- /dev/null +++ b/miner/src/pool/listener.rs @@ -0,0 +1,161 @@ +// 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 . + +//! Notifier for new transaction hashes. + +use std::fmt; +use std::sync::Arc; + +use ethereum_types::H256; +use txpool::{self, VerifiedTransaction}; + +use pool::VerifiedTransaction as Transaction; + +type Listener = Box; + +/// Manages notifications to pending transaction listeners. +#[derive(Default)] +pub struct Notifier { + listeners: Vec, + pending: Vec, +} + +impl fmt::Debug for Notifier { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Notifier") + .field("listeners", &self.listeners.len()) + .field("pending", &self.pending) + .finish() + } +} + +impl Notifier { + /// Add new listener to receive notifications. + pub fn add(&mut self, f: Listener) { + self.listeners.push(f) + } + + /// Notify listeners about all currently pending transactions. + pub fn notify(&mut self) { + for l in &self.listeners { + (l)(&self.pending); + } + + self.pending.clear(); + } +} + +impl txpool::Listener for Notifier { + fn added(&mut self, tx: &Arc, _old: Option<&Arc>) { + self.pending.push(*tx.hash()); + } +} + + +/// Transaction pool logger. +#[derive(Default, Debug)] +pub struct Logger; + +impl txpool::Listener for Logger { + fn added(&mut self, tx: &Arc, old: Option<&Arc>) { + debug!(target: "txqueue", "[{:?}] Added to the pool.", tx.hash()); + debug!( + target: "txqueue", + "[{hash:?}] Sender: {sender}, nonce: {nonce}, gasPrice: {gas_price}, gas: {gas}, value: {value}, dataLen: {data}))", + hash = tx.hash(), + sender = tx.sender(), + nonce = tx.signed().nonce, + gas_price = tx.signed().gas_price, + gas = tx.signed().gas, + value = tx.signed().value, + data = tx.signed().data.len(), + ); + + if let Some(old) = old { + debug!(target: "txqueue", "[{:?}] Dropped. Replaced by [{:?}]", old.hash(), tx.hash()); + } + } + + fn rejected(&mut self, _tx: &Arc, reason: &txpool::ErrorKind) { + trace!(target: "txqueue", "Rejected {}.", reason); + } + + fn dropped(&mut self, tx: &Arc, new: Option<&Transaction>) { + match new { + Some(new) => debug!(target: "txqueue", "[{:?}] Pushed out by [{:?}]", tx.hash(), new.hash()), + None => debug!(target: "txqueue", "[{:?}] Dropped.", tx.hash()), + } + } + + fn invalid(&mut self, tx: &Arc) { + debug!(target: "txqueue", "[{:?}] Marked as invalid by executor.", tx.hash()); + } + + fn canceled(&mut self, tx: &Arc) { + debug!(target: "txqueue", "[{:?}] Canceled by the user.", tx.hash()); + } + + fn mined(&mut self, tx: &Arc) { + debug!(target: "txqueue", "[{:?}] Mined.", tx.hash()); + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use parking_lot::Mutex; + use transaction; + use txpool::Listener; + + #[test] + fn should_notify_listeners() { + // given + let received = Arc::new(Mutex::new(vec![])); + let r = received.clone(); + let listener = Box::new(move |hashes: &[H256]| { + *r.lock() = hashes.iter().map(|x| *x).collect(); + }); + + let mut tx_listener = Notifier::default(); + tx_listener.add(listener); + + // when + let tx = new_tx(); + tx_listener.added(&tx, None); + assert_eq!(*received.lock(), vec![]); + + // then + tx_listener.notify(); + assert_eq!( + *received.lock(), + vec!["13aff4201ac1dc49daf6a7cf07b558ed956511acbaabf9502bdacc353953766d".parse().unwrap()] + ); + } + + fn new_tx() -> Arc { + let signed = transaction::Transaction { + action: transaction::Action::Create, + data: vec![1, 2, 3], + nonce: 5.into(), + gas: 21_000.into(), + gas_price: 5.into(), + value: 0.into(), + }.fake_sign(5.into()); + + Arc::new(Transaction::from_pending_block_transaction(signed)) + } +} diff --git a/miner/src/pool/local_transactions.rs b/miner/src/pool/local_transactions.rs new file mode 100644 index 0000000000..12ffa84c19 --- /dev/null +++ b/miner/src/pool/local_transactions.rs @@ -0,0 +1,273 @@ +// 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 . + +//! Local Transactions List. + +use std::sync::Arc; + +use ethereum_types::H256; +use linked_hash_map::LinkedHashMap; +use pool::VerifiedTransaction as Transaction; +use txpool::{self, VerifiedTransaction}; + +/// Status of local transaction. +/// Can indicate that the transaction is currently part of the queue (`Pending/Future`) +/// or gives a reason why the transaction was removed. +#[derive(Debug, PartialEq, Clone)] +pub enum Status { + /// The transaction is currently in the transaction queue. + Pending(Arc), + /// Transaction is already mined. + Mined(Arc), + /// Transaction is dropped because of limit + Dropped(Arc), + /// Replaced because of higher gas price of another transaction. + Replaced { + /// Replaced transaction + old: Arc, + /// Transaction that replaced this one. + new: Arc, + }, + /// Transaction was never accepted to the queue. + /// It means that it was too cheap to replace any transaction already in the pool. + Rejected(Arc, String), + /// Transaction is invalid. + Invalid(Arc), + /// Transaction was canceled. + Canceled(Arc), +} + +impl Status { + fn is_pending(&self) -> bool { + match *self { + Status::Pending(_) => true, + _ => false, + } + } +} + +/// Keeps track of local transactions that are in the queue or were mined/dropped recently. +#[derive(Debug)] +pub struct LocalTransactionsList { + max_old: usize, + transactions: LinkedHashMap, + pending: usize, +} + +impl Default for LocalTransactionsList { + fn default() -> Self { + Self::new(10) + } +} + +impl LocalTransactionsList { + /// Create a new list of local transactions. + pub fn new(max_old: usize) -> Self { + LocalTransactionsList { + max_old, + transactions: Default::default(), + pending: 0, + } + } + + /// Returns true if the transaction is already in local transactions. + pub fn contains(&self, hash: &H256) -> bool { + self.transactions.contains_key(hash) + } + + /// Return a map of all currently stored transactions. + pub fn all_transactions(&self) -> &LinkedHashMap { + &self.transactions + } + + /// Returns true if there are pending local transactions. + pub fn has_pending(&self) -> bool { + self.pending > 0 + } + + fn clear_old(&mut self) { + let number_of_old = self.transactions.len() - self.pending; + if self.max_old >= number_of_old { + return; + } + + let to_remove: Vec<_> = self.transactions + .iter() + .filter(|&(_, status)| !status.is_pending()) + .map(|(hash, _)| *hash) + .take(number_of_old - self.max_old) + .collect(); + + for hash in to_remove { + self.transactions.remove(&hash); + } + } + + fn insert(&mut self, hash: H256, status: Status) { + let result = self.transactions.insert(hash, status); + if let Some(old) = result { + if old.is_pending() { + self.pending -= 1; + } + } + } +} + +impl txpool::Listener for LocalTransactionsList { + fn added(&mut self, tx: &Arc, old: Option<&Arc>) { + if !tx.priority().is_local() { + return; + } + + debug!(target: "own_tx", "Imported to the pool (hash {:?})", tx.hash()); + self.clear_old(); + self.insert(*tx.hash(), Status::Pending(tx.clone())); + self.pending += 1; + + if let Some(old) = old { + if self.transactions.contains_key(old.hash()) { + self.insert(*old.hash(), Status::Replaced { + old: old.clone(), + new: tx.clone(), + }); + } + } + } + + fn rejected(&mut self, tx: &Arc, reason: &txpool::ErrorKind) { + if !tx.priority().is_local() { + return; + } + + debug!(target: "own_tx", "Transaction rejected (hash {:?}). {}", tx.hash(), reason); + self.insert(*tx.hash(), Status::Rejected(tx.clone(), format!("{}", reason))); + self.clear_old(); + } + + fn dropped(&mut self, tx: &Arc, new: Option<&Transaction>) { + if !tx.priority().is_local() { + return; + } + + match new { + Some(new) => warn!(target: "own_tx", "Transaction pushed out because of limit (hash {:?}, replacement: {:?})", tx.hash(), new.hash()), + None => warn!(target: "own_tx", "Transaction dropped because of limit (hash: {:?})", tx.hash()), + } + self.insert(*tx.hash(), Status::Dropped(tx.clone())); + self.clear_old(); + } + + fn invalid(&mut self, tx: &Arc) { + if !tx.priority().is_local() { + return; + } + + warn!(target: "own_tx", "Transaction marked invalid (hash {:?})", tx.hash()); + self.insert(*tx.hash(), Status::Invalid(tx.clone())); + self.clear_old(); + } + + fn canceled(&mut self, tx: &Arc) { + if !tx.priority().is_local() { + return; + } + + warn!(target: "own_tx", "Transaction canceled (hash {:?})", tx.hash()); + self.insert(*tx.hash(), Status::Canceled(tx.clone())); + self.clear_old(); + } + + + /// The transaction has been mined. + fn mined(&mut self, tx: &Arc) { + if !tx.priority().is_local() { + return; + } + + info!(target: "own_tx", "Transaction mined (hash {:?})", tx.hash()); + self.insert(*tx.hash(), Status::Mined(tx.clone())); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ethereum_types::U256; + use ethkey::{Random, Generator}; + use transaction; + use txpool::Listener; + + use pool; + + #[test] + fn should_add_transaction_as_pending() { + // given + let mut list = LocalTransactionsList::default(); + let tx1 = new_tx(10); + let tx2 = new_tx(20); + + // when + list.added(&tx1, None); + list.added(&tx2, None); + + // then + assert!(list.contains(tx1.hash())); + assert!(list.contains(tx2.hash())); + let statuses = list.all_transactions().values().cloned().collect::>(); + assert_eq!(statuses, vec![Status::Pending(tx1), Status::Pending(tx2)]); + } + + #[test] + fn should_clear_old_transactions() { + // given + let mut list = LocalTransactionsList::new(1); + let tx1 = new_tx(10); + let tx2 = new_tx(50); + let tx3 = new_tx(51); + + list.added(&tx1, None); + list.invalid(&tx1); + list.dropped(&tx2, None); + assert!(!list.contains(tx1.hash())); + assert!(list.contains(tx2.hash())); + assert!(!list.contains(tx3.hash())); + + // when + list.added(&tx3, Some(&tx1)); + + // then + assert!(!list.contains(tx1.hash())); + assert!(list.contains(tx2.hash())); + assert!(list.contains(tx3.hash())); + } + + fn new_tx>(nonce: T) -> Arc { + let keypair = Random.generate().unwrap(); + let signed = transaction::Transaction { + action: transaction::Action::Create, + value: U256::from(100), + data: Default::default(), + gas: U256::from(10), + gas_price: U256::from(1245), + nonce: nonce.into(), + }.sign(keypair.secret(), None); + + let mut tx = Transaction::from_pending_block_transaction(signed); + tx.priority = pool::Priority::Local; + + Arc::new(tx) + } +} diff --git a/miner/src/pool/mod.rs b/miner/src/pool/mod.rs new file mode 100644 index 0000000000..7950510c6d --- /dev/null +++ b/miner/src/pool/mod.rs @@ -0,0 +1,135 @@ +// 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 . + +//! Transaction Pool + +use ethereum_types::{H256, Address}; +use heapsize::HeapSizeOf; +use transaction; +use txpool; + +mod listener; +mod queue; +mod ready; +mod scoring; + +pub mod client; +pub mod local_transactions; +pub mod verifier; + +#[cfg(test)] +mod tests; + +pub use self::queue::{TransactionQueue, Status as QueueStatus}; +pub use self::txpool::{VerifiedTransaction as PoolVerifiedTransaction, Options}; + +/// How to prioritize transactions in the pool +/// +/// TODO [ToDr] Implement more strategies. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PrioritizationStrategy { + /// Simple gas-price based prioritization. + GasPriceOnly, +} + +/// Transaction priority. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub(crate) enum Priority { + /// Local transactions (high priority) + /// + /// Transactions either from a local account or + /// submitted over local RPC connection via `eth_sendRawTransaction` + Local, + /// Transactions from retracted blocks (medium priority) + /// + /// When block becomes non-canonical we re-import the transactions it contains + /// to the queue and boost their priority. + Retracted, + /// Regular transactions received over the network. (no priority boost) + Regular, +} + +impl Priority { + fn is_local(&self) -> bool { + match *self { + Priority::Local => true, + _ => false, + } + } +} + +/// Verified transaction stored in the pool. +#[derive(Debug, PartialEq, Eq)] +pub struct VerifiedTransaction { + transaction: transaction::PendingTransaction, + // TODO [ToDr] hash and sender should go directly from the transaction + hash: H256, + sender: Address, + priority: Priority, + insertion_id: usize, +} + +impl VerifiedTransaction { + /// Create `VerifiedTransaction` directly from `SignedTransaction`. + /// + /// This method should be used only: + /// 1. for tests + /// 2. In case we are converting pending block transactions that are already in the queue to match the function signature. + pub fn from_pending_block_transaction(tx: transaction::SignedTransaction) -> Self { + let hash = tx.hash(); + let sender = tx.sender(); + VerifiedTransaction { + transaction: tx.into(), + hash, + sender, + priority: Priority::Retracted, + insertion_id: 0, + } + } + + /// Gets transaction priority. + pub(crate) fn priority(&self) -> Priority { + self.priority + } + + /// Gets wrapped `SignedTransaction` + pub fn signed(&self) -> &transaction::SignedTransaction { + &self.transaction + } + + /// Gets wrapped `PendingTransaction` + pub fn pending(&self) -> &transaction::PendingTransaction { + &self.transaction + } +} + +impl txpool::VerifiedTransaction for VerifiedTransaction { + fn hash(&self) -> &H256 { + &self.hash + } + + fn mem_usage(&self) -> usize { + self.transaction.heap_size_of_children() + } + + fn sender(&self) -> &Address { + &self.sender + } + + fn insertion_id(&self) -> u64 { + self.insertion_id as u64 + } +} diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs new file mode 100644 index 0000000000..edc092a119 --- /dev/null +++ b/miner/src/pool/queue.rs @@ -0,0 +1,445 @@ +// 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 . + +//! Ethereum Transaction Queue + +use std::{cmp, fmt}; +use std::sync::Arc; +use std::sync::atomic::{self, AtomicUsize}; +use std::collections::BTreeMap; + +use ethereum_types::{H256, U256, Address}; +use parking_lot::RwLock; +use rayon::prelude::*; +use transaction; +use txpool::{self, Verifier}; + +use pool::{self, scoring, verifier, client, ready, listener, PrioritizationStrategy}; +use pool::local_transactions::LocalTransactionsList; + +type Listener = (LocalTransactionsList, (listener::Notifier, listener::Logger)); +type Pool = txpool::Pool; + +/// Max cache time in milliseconds for pending transactions. +/// +/// Pending transactions are cached and will only be computed again +/// if last cache has been created earler than `TIMESTAMP_CACHE` ms ago. +/// This timeout applies only if there are local pending transactions +/// since it only affects transaction Condition. +const TIMESTAMP_CACHE: u64 = 1000; + +/// Transaction queue status. +#[derive(Debug, Clone, PartialEq)] +pub struct Status { + /// Verifier options. + pub options: verifier::Options, + /// Current status of the transaction pool. + pub status: txpool::LightStatus, + /// Current limits of the transaction pool. + pub limits: txpool::Options, +} + +impl fmt::Display for Status { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + writeln!( + fmt, + "Pool: {current}/{max} ({senders} senders; {mem}/{mem_max} kB) [minGasPrice: {gp} Mwei, maxGas: {max_gas}]", + current = self.status.transaction_count, + max = self.limits.max_count, + senders = self.status.senders, + mem = self.status.mem_usage / 1024, + mem_max = self.limits.max_mem_usage / 1024, + gp = self.options.minimal_gas_price / 1_000_000.into(), + max_gas = cmp::min(self.options.block_gas_limit, self.options.tx_gas_limit), + ) + } +} + +#[derive(Debug)] +struct CachedPending { + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + has_local_pending: bool, + pending: Option>>, +} + +impl CachedPending { + /// Creates new `CachedPending` without cached set. + pub fn none() -> Self { + CachedPending { + block_number: 0, + current_timestamp: 0, + has_local_pending: false, + pending: None, + nonce_cap: None, + } + } + + /// Remove cached pending set. + pub fn clear(&mut self) { + self.pending = None; + } + + /// Returns cached pending set (if any) if it's valid. + pub fn pending( + &self, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option<&U256>, + ) -> Option>> { + // First check if we have anything in cache. + let pending = self.pending.as_ref()?; + + if block_number != self.block_number { + return None; + } + + // In case we don't have any local pending transactions + // there is no need to invalidate the cache because of timestamp. + // Timestamp only affects local `PendingTransactions` with `Condition::Timestamp`. + if self.has_local_pending && current_timestamp > self.current_timestamp + TIMESTAMP_CACHE { + return None; + } + + // It's fine to return limited set even if `nonce_cap` is `None`. + // The worst thing that may happen is that some transactions won't get propagated in current round, + // but they are not really valid in current block anyway. We will propagate them in the next round. + // Also there is no way to have both `Some` with different numbers since it depends on the block number + // and a constant parameter in schedule (`nonce_cap_increment`) + if self.nonce_cap.is_none() && nonce_cap.is_some() { + return None; + } + + Some(pending.clone()) + } +} + +/// Ethereum Transaction Queue +/// +/// Responsible for: +/// - verifying incoming transactions +/// - maintaining a pool of verified transactions. +/// - returning an iterator for transactions that are ready to be included in block (pending) +#[derive(Debug)] +pub struct TransactionQueue { + insertion_id: Arc, + pool: RwLock, + options: RwLock, + cached_pending: RwLock, +} + +impl TransactionQueue { + /// Create new queue with given pool limits and initial verification options. + pub fn new( + limits: txpool::Options, + verification_options: verifier::Options, + strategy: PrioritizationStrategy, + ) -> Self { + TransactionQueue { + insertion_id: Default::default(), + pool: RwLock::new(txpool::Pool::new(Default::default(), scoring::NonceAndGasPrice(strategy), limits)), + options: RwLock::new(verification_options), + cached_pending: RwLock::new(CachedPending::none()), + } + } + + /// Update verification options + /// + /// Some parameters of verification may vary in time (like block gas limit or minimal gas price). + pub fn set_verifier_options(&self, options: verifier::Options) { + *self.options.write() = options; + } + + /// Import a set of transactions to the pool. + /// + /// Given blockchain and state access (Client) + /// verifies and imports transactions to the pool. + pub fn import( + &self, + client: C, + transactions: Vec, + ) -> Vec> { + // Run verification + let _timer = ::trace_time::PerfTimer::new("queue::verifyAndImport"); + let options = self.options.read().clone(); + + let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone()); + let results = transactions + .into_par_iter() + .map(|transaction| verifier.verify_transaction(transaction)) + .map(|result| result.and_then(|verified| { + self.pool.write().import(verified) + .map(|_imported| ()) + .map_err(convert_error) + })) + .collect::>(); + + // Notify about imported transactions. + (self.pool.write().listener_mut().1).0.notify(); + + if results.iter().any(|r| r.is_ok()) { + self.cached_pending.write().clear(); + } + + results + } + + /// Returns all transactions in the queue ordered by priority. + pub fn all_transactions(&self) -> Vec> { + let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready; + self.pool.read().pending(ready).collect() + } + + /// Returns current pneding transactions. + /// + /// NOTE: This may return a cached version of pending transaction set. + /// Re-computing the pending set is possible with `#collect_pending` method, + /// but be aware that it's a pretty expensive operation. + pub fn pending( + &self, + client: C, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + ) -> Vec> where + C: client::NonceClient, + { + + if let Some(pending) = self.cached_pending.read().pending(block_number, current_timestamp, nonce_cap.as_ref()) { + return pending; + } + + // Double check after acquiring write lock + let mut cached_pending = self.cached_pending.write(); + if let Some(pending) = cached_pending.pending(block_number, current_timestamp, nonce_cap.as_ref()) { + return pending; + } + + let pending: Vec<_> = self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| i.collect()); + + *cached_pending = CachedPending { + block_number, + current_timestamp, + nonce_cap, + has_local_pending: self.has_local_pending_transactions(), + pending: Some(pending.clone()), + }; + + pending + } + + /// Collect pending transactions. + /// + /// NOTE This is re-computing the pending set and it might be expensive to do so. + /// Prefer using cached pending set using `#pending` method. + pub fn collect_pending( + &self, + client: C, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + collect: F, + ) -> T where + C: client::NonceClient, + F: FnOnce(txpool::PendingIterator< + pool::VerifiedTransaction, + (ready::Condition, ready::State), + scoring::NonceAndGasPrice, + Listener, + >) -> T, + { + let pending_readiness = ready::Condition::new(block_number, current_timestamp); + // don't mark any transactions as stale at this point. + let stale_id = None; + let state_readiness = ready::State::new(client, stale_id, nonce_cap); + + let ready = (pending_readiness, state_readiness); + + collect(self.pool.read().pending(ready)) + } + + /// Culls all stalled transactions from the pool. + pub fn cull( + &self, + client: C, + ) { + // We don't care about future transactions, so nonce_cap is not important. + let nonce_cap = None; + // We want to clear stale transactions from the queue as well. + // (Transactions that are occuping the queue for a long time without being included) + let stale_id = { + let current_id = self.insertion_id.load(atomic::Ordering::Relaxed) as u64; + // wait at least for half of the queue to be replaced + let gap = self.pool.read().options().max_count / 2; + // but never less than 100 transactions + let gap = cmp::max(100, gap) as u64; + + current_id.checked_sub(gap) + }; + + let state_readiness = ready::State::new(client, stale_id, nonce_cap); + + let removed = self.pool.write().cull(None, state_readiness); + debug!(target: "txqueue", "Removed {} stalled transactions. {}", removed, self.status()); + } + + /// Returns next valid nonce for given sender + /// or `None` if there are no pending transactions from that sender. + pub fn next_nonce( + &self, + client: C, + address: &Address, + ) -> Option { + // Do not take nonce_cap into account when determining next nonce. + let nonce_cap = None; + // Also we ignore stale transactions in the queue. + let stale_id = None; + + let state_readiness = ready::State::new(client, stale_id, nonce_cap); + + self.pool.read().pending_from_sender(state_readiness, address) + .last() + .map(|tx| tx.signed().nonce + 1.into()) + } + + /// Retrieve a transaction from the pool. + /// + /// Given transaction hash looks up that transaction in the pool + /// and returns a shared pointer to it or `None` if it's not present. + pub fn find( + &self, + hash: &H256, + ) -> Option> { + self.pool.read().find(hash) + } + + /// Remove a set of transactions from the pool. + /// + /// Given an iterator of transaction hashes + /// removes them from the pool. + /// That method should be used if invalid transactions are detected + /// or you want to cancel a transaction. + pub fn remove<'a, T: IntoIterator>( + &self, + hashes: T, + is_invalid: bool, + ) -> Vec>> { + let results = { + let mut pool = self.pool.write(); + + hashes + .into_iter() + .map(|hash| pool.remove(hash, is_invalid)) + .collect::>() + }; + + if results.iter().any(Option::is_some) { + self.cached_pending.write().clear(); + } + + results + } + + /// Clear the entire pool. + pub fn clear(&self) { + self.pool.write().clear(); + } + + /// Penalize given senders. + pub fn penalize<'a, T: IntoIterator>(&self, senders: T) { + let mut pool = self.pool.write(); + for sender in senders { + pool.update_scores(sender, ()); + } + } + + /// Returns gas price of currently the worst transaction in the pool. + pub fn current_worst_gas_price(&self) -> U256 { + match self.pool.read().worst_transaction() { + Some(tx) => tx.signed().gas_price, + None => self.options.read().minimal_gas_price, + } + } + + /// Returns a status of the queue. + pub fn status(&self) -> Status { + let pool = self.pool.read(); + let status = pool.light_status(); + let limits = pool.options(); + let options = self.options.read().clone(); + + Status { + options, + status, + limits, + } + } + + /// Check if there are any local transactions in the pool. + /// + /// Returns `true` if there are any transactions in the pool + /// that has been marked as local. + /// + /// Local transactions are the ones from accounts managed by this node + /// and transactions submitted via local RPC (`eth_sendRawTransaction`) + pub fn has_local_pending_transactions(&self) -> bool { + self.pool.read().listener().0.has_pending() + } + + /// Returns status of recently seen local transactions. + pub fn local_transactions(&self) -> BTreeMap { + self.pool.read().listener().0.all_transactions().iter().map(|(a, b)| (*a, b.clone())).collect() + } + + /// Add a callback to be notified about all transactions entering the pool. + pub fn add_listener(&self, f: Box) { + let mut pool = self.pool.write(); + (pool.listener_mut().1).0.add(f); + } +} + + +fn convert_error(err: txpool::Error) -> transaction::Error { + use self::txpool::ErrorKind; + + match *err.kind() { + ErrorKind::AlreadyImported(..) => transaction::Error::AlreadyImported, + ErrorKind::TooCheapToEnter(..) => transaction::Error::LimitReached, + ErrorKind::TooCheapToReplace(..) => transaction::Error::TooCheapToReplace, + ref e => { + warn!(target: "txqueue", "Unknown import error: {:?}", e); + transaction::Error::NotAllowed + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use pool::tests::client::TestClient; + + #[test] + fn should_get_pending_transactions() { + let queue = TransactionQueue::new(txpool::Options::default(), verifier::Options::default(), PrioritizationStrategy::GasPriceOnly); + + let pending: Vec<_> = queue.pending(TestClient::default(), 0, 0, None); + + for tx in pending { + assert!(tx.signed().nonce > 0.into()); + } + } +} diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs new file mode 100644 index 0000000000..54b5aec3a9 --- /dev/null +++ b/miner/src/pool/ready.rs @@ -0,0 +1,212 @@ +// 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 . + +//! Transaction Readiness indicator +//! +//! Transaction readiness is responsible for indicating if +//! particular transaction can be included in the block. +//! +//! Regular transactions are ready iff the current state nonce +//! (obtained from `NonceClient`) equals to the transaction nonce. +//! +//! Let's define `S = state nonce`. Transactions are processed +//! in order, so we first include transaction with nonce `S`, +//! but then we are able to include the one with `S + 1` nonce. +//! So bear in mind that transactions can be included in chains +//! and their readiness is dependent on previous transactions from +//! the same sender. +//! +//! There are three possible outcomes: +//! - The transaction is old (stalled; state nonce > transaction nonce) +//! - The transaction is ready (current; state nonce == transaction nonce) +//! - The transaction is not ready yet (future; state nonce < transaction nonce) +//! +//! NOTE The transactions are always checked for readines in order they are stored within the queue. +//! First `Readiness::Future` response also causes all subsequent transactions from the same sender +//! to be marked as `Future`. + +use std::cmp; +use std::collections::HashMap; + +use ethereum_types::{U256, H160 as Address}; +use transaction; +use txpool::{self, VerifiedTransaction as PoolVerifiedTransaction}; + +use super::client::NonceClient; +use super::VerifiedTransaction; + +/// Checks readiness of transactions by comparing the nonce to state nonce. +#[derive(Debug)] +pub struct State { + nonces: HashMap, + state: C, + max_nonce: Option, + stale_id: Option, +} + +impl State { + /// Create new State checker, given client interface. + pub fn new( + state: C, + stale_id: Option, + max_nonce: Option, + ) -> Self { + State { + nonces: Default::default(), + state, + max_nonce, + stale_id, + } + } +} + +impl txpool::Ready for State { + fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness { + // Check max nonce + match self.max_nonce { + Some(nonce) if tx.transaction.nonce > nonce => { + return txpool::Readiness::Future; + }, + _ => {}, + } + + + let sender = tx.sender(); + let state = &self.state; + let state_nonce = || state.account_nonce(sender); + let nonce = self.nonces.entry(*sender).or_insert_with(state_nonce); + match tx.transaction.nonce.cmp(nonce) { + // Before marking as future check for stale ids + cmp::Ordering::Greater => match self.stale_id { + Some(id) if tx.insertion_id() < id => txpool::Readiness::Stalled, + _ => txpool::Readiness::Future, + }, + cmp::Ordering::Less => txpool::Readiness::Stalled, + cmp::Ordering::Equal => { + *nonce = *nonce + 1.into(); + txpool::Readiness::Ready + }, + } + } +} + +/// Checks readines of Pending transactions by comparing it with current time and block number. +#[derive(Debug)] +pub struct Condition { + block_number: u64, + now: u64, +} + +impl Condition { + /// Create a new condition checker given current block number and UTC timestamp. + pub fn new(block_number: u64, now: u64) -> Self { + Condition { + block_number, + now, + } + } +} + +impl txpool::Ready for Condition { + fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness { + match tx.transaction.condition { + Some(transaction::Condition::Number(block)) if block > self.block_number => txpool::Readiness::Future, + Some(transaction::Condition::Timestamp(time)) if time > self.now => txpool::Readiness::Future, + _ => txpool::Readiness::Ready, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use txpool::Ready; + use pool::tests::client::TestClient; + use pool::tests::tx::{Tx, TxExt}; + + #[test] + fn should_return_correct_state_readiness() { + // given + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + let (tx1, tx2, tx3) = (tx1.verified(), tx2.verified(), tx3.verified()); + + // when + assert_eq!(State::new(TestClient::new(), None, None).is_ready(&tx3), txpool::Readiness::Future); + assert_eq!(State::new(TestClient::new(), None, None).is_ready(&tx2), txpool::Readiness::Future); + + let mut ready = State::new(TestClient::new(), None, None); + + // then + assert_eq!(ready.is_ready(&tx1), txpool::Readiness::Ready); + assert_eq!(ready.is_ready(&tx2), txpool::Readiness::Ready); + assert_eq!(ready.is_ready(&tx3), txpool::Readiness::Ready); + } + + #[test] + fn should_return_future_if_nonce_cap_reached() { + // given + let tx = Tx::default().signed().verified(); + + // when + let res1 = State::new(TestClient::new(), None, Some(10.into())).is_ready(&tx); + let res2 = State::new(TestClient::new(), None, Some(124.into())).is_ready(&tx); + + // then + assert_eq!(res1, txpool::Readiness::Future); + assert_eq!(res2, txpool::Readiness::Ready); + } + + #[test] + fn should_return_stale_if_nonce_does_not_match() { + // given + let tx = Tx::default().signed().verified(); + + // when + let res = State::new(TestClient::new().with_nonce(125), None, None).is_ready(&tx); + + // then + assert_eq!(res, txpool::Readiness::Stalled); + } + + #[test] + fn should_return_stale_for_old_transactions() { + // given + let (_, tx) = Tx::default().signed_pair().verified(); + + // when + let res = State::new(TestClient::new(), Some(1), None).is_ready(&tx); + + // then + assert_eq!(res, txpool::Readiness::Stalled); + } + + #[test] + fn should_check_readiness_of_condition() { + // given + let tx = Tx::default().signed(); + let v = |tx: transaction::PendingTransaction| TestClient::new().verify(tx); + let tx1 = v(transaction::PendingTransaction::new(tx.clone(), transaction::Condition::Number(5).into())); + let tx2 = v(transaction::PendingTransaction::new(tx.clone(), transaction::Condition::Timestamp(3).into())); + let tx3 = v(transaction::PendingTransaction::new(tx.clone(), None)); + + // when/then + assert_eq!(Condition::new(0, 0).is_ready(&tx1), txpool::Readiness::Future); + assert_eq!(Condition::new(0, 0).is_ready(&tx2), txpool::Readiness::Future); + assert_eq!(Condition::new(0, 0).is_ready(&tx3), txpool::Readiness::Ready); + assert_eq!(Condition::new(5, 0).is_ready(&tx1), txpool::Readiness::Ready); + assert_eq!(Condition::new(0, 3).is_ready(&tx2), txpool::Readiness::Ready); + } +} diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs new file mode 100644 index 0000000000..b9f074ecb0 --- /dev/null +++ b/miner/src/pool/scoring.rs @@ -0,0 +1,171 @@ +// 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 . + +//! Transaction Scoring and Ordering +//! +//! Ethereum transactions from the same sender are ordered by `nonce`. +//! Low nonces need to be included first. If there are two transactions from the same sender +//! and with the same `nonce` only one of them can be included. +//! We choose the one with higher gas price, but also require that gas price increment +//! is high enough to prevent attacking miners by requiring them to reshuffle/reexecute +//! the queue too often. +//! +//! Transactions between senders are prioritized using `gas price`. Higher `gas price` +//! yields more profits for miners. Additionally we prioritize transactions that originate +//! from our local node (own transactions). + +use std::cmp; +use std::sync::Arc; + +use ethereum_types::U256; +use txpool; +use super::{PrioritizationStrategy, VerifiedTransaction}; + +/// Transaction with the same (sender, nonce) can be replaced only if +/// `new_gas_price > old_gas_price + old_gas_price >> SHIFT` +const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25% + +/// Simple, gas-price based scoring for transactions. +/// +/// NOTE: Currently penalization does not apply to new transactions that enter the pool. +/// We might want to store penalization status in some persistent state. +#[derive(Debug)] +pub struct NonceAndGasPrice(pub PrioritizationStrategy); + +impl txpool::Scoring for NonceAndGasPrice { + type Score = U256; + type Event = (); + + fn compare(&self, old: &VerifiedTransaction, other: &VerifiedTransaction) -> cmp::Ordering { + old.transaction.nonce.cmp(&other.transaction.nonce) + } + + fn choose(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> txpool::scoring::Choice { + if old.transaction.nonce != new.transaction.nonce { + return txpool::scoring::Choice::InsertNew + } + + let old_gp = old.transaction.gas_price; + let new_gp = new.transaction.gas_price; + + let min_required_gp = old_gp + (old_gp >> GAS_PRICE_BUMP_SHIFT); + + match min_required_gp.cmp(&new_gp) { + cmp::Ordering::Greater => txpool::scoring::Choice::RejectNew, + _ => txpool::scoring::Choice::ReplaceOld, + } + } + + fn update_scores(&self, txs: &[Arc], scores: &mut [U256], change: txpool::scoring::Change) { + use self::txpool::scoring::Change; + + match change { + Change::Culled(_) => {}, + Change::RemovedAt(_) => {} + Change::InsertedAt(i) | Change::ReplacedAt(i) => { + assert!(i < txs.len()); + assert!(i < scores.len()); + + scores[i] = txs[i].transaction.gas_price; + let boost = match txs[i].priority() { + super::Priority::Local => 15, + super::Priority::Retracted => 10, + super::Priority::Regular => 0, + }; + scores[i] = scores[i] << boost; + }, + // We are only sending an event in case of penalization. + // So just lower the priority of all non-local transactions. + Change::Event(_) => { + for (score, tx) in scores.iter_mut().zip(txs) { + // Never penalize local transactions. + if !tx.priority().is_local() { + *score = *score >> 3; + } + } + }, + } + } + + fn should_replace(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> bool { + if old.sender == new.sender { + // prefer earliest transaction + if new.transaction.nonce < old.transaction.nonce { + return true + } + } + + self.choose(old, new) == txpool::scoring::Choice::ReplaceOld + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use pool::tests::tx::{Tx, TxExt}; + use txpool::Scoring; + + #[test] + fn should_calculate_score_correctly() { + // given + let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + let transactions = vec![tx1, tx2, tx3].into_iter().enumerate().map(|(i, tx)| { + let mut verified = tx.verified(); + verified.priority = match i { + 0 => ::pool::Priority::Local, + 1 => ::pool::Priority::Retracted, + _ => ::pool::Priority::Regular, + }; + Arc::new(verified) + }).collect::>(); + let initial_scores = vec![U256::from(0), 0.into(), 0.into()]; + + // No update required + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(0)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(1)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(2)); + assert_eq!(scores, initial_scores); + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(0)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(1)); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(2)); + assert_eq!(scores, initial_scores); + + // Compute score at given index + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(0)); + assert_eq!(scores, vec![32768.into(), 0.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(1)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(2)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]); + + let mut scores = initial_scores.clone(); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(0)); + assert_eq!(scores, vec![32768.into(), 0.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(1)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 0.into()]); + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(2)); + assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]); + + // Check penalization + scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Event(())); + assert_eq!(scores, vec![32768.into(), 128.into(), 0.into()]); + } +} diff --git a/miner/src/pool/tests/client.rs b/miner/src/pool/tests/client.rs new file mode 100644 index 0000000000..7f7be64cc8 --- /dev/null +++ b/miner/src/pool/tests/client.rs @@ -0,0 +1,125 @@ +// 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 . + +use ethereum_types::{U256, H256, Address}; +use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; + +use pool; +use pool::client::AccountDetails; + +#[derive(Debug, Clone)] +pub struct TestClient { + account_details: AccountDetails, + gas_required: U256, + is_service_transaction: bool, + local_address: Address, +} + +impl Default for TestClient { + fn default() -> Self { + TestClient { + account_details: AccountDetails { + nonce: 123.into(), + balance: 63_100.into(), + is_local: false, + }, + gas_required: 21_000.into(), + is_service_transaction: false, + local_address: Default::default(), + } + } +} + +impl TestClient { + pub fn new() -> Self { + TestClient::default() + } + + pub fn with_balance>(mut self, balance: T) -> Self { + self.account_details.balance = balance.into(); + self + } + + pub fn with_nonce>(mut self, nonce: T) -> Self { + self.account_details.nonce = nonce.into(); + self + } + + pub fn with_gas_required>(mut self, gas_required: T) -> Self { + self.gas_required = gas_required.into(); + self + } + + pub fn with_local(mut self, address: &Address) -> Self { + self.local_address = *address; + self + } + + pub fn with_service_transaction(mut self) -> Self { + self.is_service_transaction = true; + self + } + + pub fn verify>(&self, tx: T) -> pool::VerifiedTransaction { + let tx = tx.into(); + pool::VerifiedTransaction { + hash: tx.hash(), + sender: tx.sender(), + priority: pool::Priority::Regular, + transaction: tx, + insertion_id: 1, + } + } +} + +impl pool::client::Client for TestClient { + fn transaction_already_included(&self, _hash: &H256) -> bool { + false + } + + fn verify_transaction(&self, tx: UnverifiedTransaction) + -> Result + { + Ok(SignedTransaction::new(tx)?) + } + + fn account_details(&self, address: &Address) -> AccountDetails { + let mut details = self.account_details.clone(); + if address == &self.local_address { + details.is_local = true; + } + + details + } + + fn required_gas(&self, _tx: &Transaction) -> U256 { + self.gas_required + } + + fn transaction_type(&self, _tx: &SignedTransaction) -> pool::client::TransactionType { + if self.is_service_transaction { + pool::client::TransactionType::Service + } else { + pool::client::TransactionType::Regular + } + } +} + +impl pool::client::NonceClient for TestClient { + fn account_nonce(&self, _address: &Address) -> U256 { + self.account_details.nonce + } +} diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs new file mode 100644 index 0000000000..340cb75158 --- /dev/null +++ b/miner/src/pool/tests/mod.rs @@ -0,0 +1,757 @@ +// 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 . + +use ethereum_types::U256; +use transaction::{self, PendingTransaction}; +use txpool; + +use pool::{verifier, TransactionQueue, PrioritizationStrategy}; + +pub mod tx; +pub mod client; + +use self::tx::{Tx, TxExt, PairExt}; +use self::client::TestClient; + +fn new_queue() -> TransactionQueue { + TransactionQueue::new( + txpool::Options { + max_count: 3, + max_per_sender: 3, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ) +} + +#[test] +fn should_return_correct_nonces_when_dropped_because_of_limit() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 3, + max_per_sender: 1, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let (tx1, tx2) = Tx::gas_price(2).signed_pair(); + let sender = tx1.sender(); + let nonce = tx1.nonce; + + // when + let result = txq.import(TestClient::new(), vec![tx1, tx2].local()); + assert_eq!(result, vec![Ok(()), Err(transaction::Error::LimitReached)]); + assert_eq!(txq.status().status.transaction_count, 1); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1.into())); + + // when + let tx1 = Tx::gas_price(2).signed(); + let tx2 = Tx::gas_price(2).signed(); + let tx3 = Tx::gas_price(1).signed(); + let tx4 = Tx::gas_price(3).signed(); + let res = txq.import(TestClient::new(), vec![tx1, tx2].local()); + let res2 = txq.import(TestClient::new(), vec![tx3, tx4].local()); + + // then + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(res2, vec![Err(transaction::Error::LimitReached), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 3); + // First inserted transacton got dropped because of limit + assert_eq!(txq.next_nonce(TestClient::new(), &sender), None); +} + +#[test] +fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::default().signed_replacement(); + let hash = tx2.hash(); + let client = TestClient::new().with_nonce(122); + + // First insert one transaction to future + let res = txq.import(client.clone(), vec![tx].local()); + assert_eq!(res, vec![Ok(())]); + // next_nonce === None -> transaction is in future + assert_eq!(txq.next_nonce(client.clone(), &tx2.sender()), None); + + // now import second transaction to current + let res = txq.import(TestClient::new(), vec![tx2.local()]); + + // and then there should be only one transaction in current (the one with higher gas_price) + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); +} + +#[test] +fn should_move_all_transactions_from_future() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + let (hash, hash2) = txs.hash(); + let (tx, tx2) = txs; + let client = TestClient::new().with_nonce(122); + + // First insert one transaction to future + let res = txq.import(client.clone(), vec![tx.local()]); + assert_eq!(res, vec![Ok(())]); + // next_nonce === None -> transaction is in future + assert_eq!(txq.next_nonce(client.clone(), &tx2.sender()), None); + + // now import second transaction to current + let res = txq.import(client.clone(), vec![tx2.local()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); + assert_eq!(top[1].hash, hash2); +} + +#[test] +fn should_drop_transactions_from_senders_without_balance() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + let client = TestClient::new().with_balance(1); + + // when + let res = txq.import(client, vec![tx.local()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::InsufficientBalance { + balance: U256::from(1), + cost: U256::from(21_100), + })]); + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_not_import_transaction_below_min_gas_price_threshold_if_external() { + // given + let txq = new_queue(); + let tx = Tx::default(); + txq.set_verifier_options(verifier::Options { + minimal_gas_price: 3.into(), + ..Default::default() + }); + + // when + let res = txq.import(TestClient::new(), vec![tx.signed().unverified()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::InsufficientGasPrice { + minimal: U256::from(3), + got: U256::from(1), + })]); + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_import_transaction_below_min_gas_price_threshold_if_local() { + // given + let txq = new_queue(); + let tx = Tx::default(); + txq.set_verifier_options(verifier::Options { + minimal_gas_price: 3.into(), + ..Default::default() + }); + + // when + let res = txq.import(TestClient::new(), vec![tx.signed().local()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); +} + +#[test] +fn should_import_txs_from_same_sender() { + // given + let txq = new_queue(); + + let txs = Tx::default().signed_pair(); + let (hash, hash2) = txs.hash(); + + // when + txq.import(TestClient::new(), txs.local().into_vec()); + + // then + let top = txq.pending(TestClient::new(), 0 ,0, None); + assert_eq!(top[0].hash, hash); + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_prioritize_local_transactions_within_same_nonce_height() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + // the second one has same nonce but higher `gas_price` + let tx2 = Tx::gas_price(2).signed(); + let (hash, hash2) = (tx.hash(), tx2.hash()); + let client = TestClient::new().with_local(&tx.sender()); + + // when + // first insert the one with higher gas price + let res = txq.import(client.clone(), vec![tx.local(), tx2.unverified()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(client, 0, 0, None); + assert_eq!(top[0].hash, hash); // local should be first + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_prioritize_reimported_transactions_within_same_nonce_height() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + // the second one has same nonce but higher `gas_price` + let tx2 = Tx::gas_price(2).signed(); + let (hash, hash2) = (tx.hash(), tx2.hash()); + + // when + // first insert local one with higher gas price + // then the one with lower gas price, but from retracted block + let res = txq.import(TestClient::new(), vec![tx2.unverified(), tx.retracted()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); // retracted should be first + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_not_prioritize_local_transactions_with_different_nonce_height() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + let (hash, hash2) = txs.hash(); + let (tx, tx2) = txs; + + // when + let res = txq.import(TestClient::new(), vec![tx.unverified(), tx2.local()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top[0].hash, hash); + assert_eq!(top[1].hash, hash2); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_put_transaction_to_futures_if_gap_detected() { + // given + let txq = new_queue(); + let (tx, _, tx2) = Tx::default().signed_triple(); + let hash = tx.hash(); + + // when + let res = txq.import(TestClient::new(), vec![tx, tx2].local()); + + // then + assert_eq!(res, vec![Ok(()), Ok(())]); + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top.len(), 1); + assert_eq!(top[0].hash, hash); +} + +#[test] +fn should_handle_min_block() { + // given + let txq = new_queue(); + + let (tx, tx2) = Tx::default().signed_pair(); + + // when + let res = txq.import(TestClient::new(), vec![ + verifier::Transaction::Local(PendingTransaction::new(tx, transaction::Condition::Number(1).into())), + tx2.local() + ]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top.len(), 0); + let top = txq.pending(TestClient::new(), 1, 0, None); + assert_eq!(top.len(), 2); +} + +#[test] +fn should_correctly_update_futures_when_removing() { + // given + let txq = new_queue(); + let txs= Tx::default().signed_pair(); + + let res = txq.import(TestClient::new().with_nonce(121), txs.local().into_vec()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + + // when + txq.cull(TestClient::new().with_nonce(125)); + // should remove both transactions since they are stalled + + // then + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_move_transactions_if_gap_filled() { + // given + let txq = new_queue(); + let (tx, tx1, tx2) = Tx::default().signed_triple(); + + let res = txq.import(TestClient::new(), vec![tx, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + + // when + let res = txq.import(TestClient::new(), vec![tx1.local()]); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.status().status.transaction_count, 3); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); +} + +#[test] +fn should_remove_transaction() { + // given + let txq = new_queue(); + let (tx, _, tx2) = Tx::default().signed_triple(); + + let res = txq.import(TestClient::default(), vec![tx, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + + // when + txq.cull(TestClient::new().with_nonce(124)); + assert_eq!(txq.status().status.transaction_count, 1); + assert_eq!(txq.pending(TestClient::new().with_nonce(125), 0, 0, None).len(), 1); + txq.cull(TestClient::new().with_nonce(126)); + + // then + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_move_transactions_to_future_if_gap_introduced() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::default().signed_pair(); + let hash = tx.hash(); + let tx3 = Tx::default().signed(); + + let res = txq.import(TestClient::new(), vec![tx3, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + + let res = txq.import(TestClient::new(), vec![tx].local()); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 3); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); + + // when + txq.remove(vec![&hash], true); + + // then + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); +} + +#[test] +fn should_clear_queue() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + + // add + txq.import(TestClient::new(), txs.local().into_vec()); + assert_eq!(txq.status().status.transaction_count, 2); + + // when + txq.clear(); + + // then + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_prefer_current_transactions_when_hitting_the_limit() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 1, + max_per_sender: 2, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let (tx, tx2) = Tx::default().signed_pair(); + let hash = tx.hash(); + let sender = tx.sender(); + + let res = txq.import(TestClient::new(), vec![tx2.unverified()]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + // when + let res = txq.import(TestClient::new(), vec![tx.unverified()]); + + // then + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + let top = txq.pending(TestClient::new(), 0, 0, None); + assert_eq!(top.len(), 1); + assert_eq!(top[0].hash, hash); + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(124.into())); +} + +#[test] +fn should_drop_transactions_with_old_nonces() { + let txq = new_queue(); + let tx = Tx::default().signed(); + + // when + let res = txq.import(TestClient::new().with_nonce(125), vec![tx.unverified()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::Old)]); + assert_eq!(txq.status().status.transaction_count, 0); +} + +#[test] +fn should_not_insert_same_transaction_twice() { + // given + let txq = new_queue(); + let (_tx1, tx2) = Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![tx2.clone().local()]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + // when + let res = txq.import(TestClient::new(), vec![tx2.local()]); + + // then + assert_eq!(res, vec![Err(transaction::Error::AlreadyImported)]); + assert_eq!(txq.status().status.transaction_count, 1); +} + +#[test] +fn should_accept_same_transaction_twice_if_removed() { + // given + let txq = new_queue(); + let txs = Tx::default().signed_pair(); + let (tx1, _) = txs.clone(); + let (hash, _) = txs.hash(); + + + let res = txq.import(TestClient::new(), txs.local().into_vec()); + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); + + // when + txq.remove(vec![&hash], true); + assert_eq!(txq.status().status.transaction_count, 1); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 0); + + let res = txq.import(TestClient::new(), vec![tx1].local()); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); +} + +#[test] +fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::gas_price(20).signed_replacement(); + let (tx3, tx4) = Tx::gas_price(1).signed_replacement(); + let client = TestClient::new().with_balance(1_000_000); + + // when + let res = txq.import(client.clone(), vec![tx, tx3].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + + let res = txq.import(client.clone(), vec![tx2, tx4].local()); + + // then + assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); + assert_eq!(txq.pending(client.clone(), 0, 0, None)[0].signed().gas_price, U256::from(20)); + assert_eq!(txq.pending(client.clone(), 0, 0, None)[1].signed().gas_price, U256::from(2)); +} + +#[test] +fn should_return_none_when_transaction_from_given_address_does_not_exist() { + // given + let txq = new_queue(); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &Default::default()), None); +} + +#[test] +fn should_return_correct_nonce_when_transactions_from_given_address_exist() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + let from = tx.sender(); + let nonce = tx.nonce; + + // when + txq.import(TestClient::new(), vec![tx.local()]); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &from), Some(nonce + 1.into())); +} + +#[test] +fn should_return_valid_last_nonce_after_cull() { + // given + let txq = new_queue(); + let (tx1, _, tx2) = Tx::default().signed_triple(); + let sender = tx1.sender(); + + // when + // Second should go to future + let res = txq.import(TestClient::new(), vec![tx1, tx2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + // Now block is imported + let client = TestClient::new().with_nonce(124); + txq.cull(client.clone()); + // tx2 should be not be promoted to current + assert_eq!(txq.pending(client.clone(), 0, 0, None).len(), 0); + + // then + assert_eq!(txq.next_nonce(client.clone(), &sender), None); + assert_eq!(txq.next_nonce(client.with_nonce(125), &sender), Some(126.into())); +} + +#[test] +fn should_return_true_if_there_is_local_transaction_pending() { + // given + let txq = new_queue(); + let (tx1, tx2) = Tx::default().signed_pair(); + assert_eq!(txq.has_local_pending_transactions(), false); + let client = TestClient::new().with_local(&tx1.sender()); + + // when + let res = txq.import(client.clone(), vec![tx1.unverified(), tx2.local()]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // then + assert_eq!(txq.has_local_pending_transactions(), true); +} + +#[test] +fn should_reject_transactions_below_base_gas() { + // given + let txq = new_queue(); + let tx = Tx::default().signed(); + + // when + let res = txq.import(TestClient::new().with_gas_required(100_001), vec![tx].local()); + + // then + assert_eq!(res, vec![Err(transaction::Error::InsufficientGas { + minimal: 100_001.into(), + got: 21_000.into(), + })]); +} + +#[test] +fn should_remove_out_of_date_transactions_occupying_queue() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 105, + max_per_sender: 3, + max_mem_usage: 5_000_000, + }, + verifier::Options { + minimal_gas_price: 10.into(), + ..Default::default() + }, + PrioritizationStrategy::GasPriceOnly, + ); + // that transaction will be occupying the queue + let (_, tx) = Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![tx.local()]); + assert_eq!(res, vec![Ok(())]); + // This should not clear the transaction (yet) + txq.cull(TestClient::new()); + assert_eq!(txq.status().status.transaction_count, 1); + + // Now insert at least 100 transactions to have the other one marked as future. + for _ in 0..34 { + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + txq.import(TestClient::new(), vec![tx1, tx2, tx3].local()); + } + assert_eq!(txq.status().status.transaction_count, 103); + + // when + txq.cull(TestClient::new()); + + // then + assert_eq!(txq.status().status.transaction_count, 102); +} + +#[test] +fn should_accept_local_transactions_below_min_gas_price() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 3, + max_per_sender: 3, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 10.into(), + ..Default::default() + }, + PrioritizationStrategy::GasPriceOnly, + ); + let tx = Tx::gas_price(1).signed(); + + // when + let res = txq.import(TestClient::new(), vec![tx.local()]); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); +} + +#[test] +fn should_accept_local_service_transaction() { + // given + let txq = new_queue(); + let tx = Tx::gas_price(0).signed(); + + // when + let res = txq.import( + TestClient::new() + .with_local(&tx.sender()), + vec![tx.local()] + ); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); +} + +#[test] +fn should_not_accept_external_service_transaction_if_sender_not_certified() { + // given + let txq = new_queue(); + let tx1 = Tx::gas_price(0).signed().unverified(); + let tx2 = Tx::gas_price(0).signed().retracted(); + let tx3 = Tx::gas_price(0).signed().unverified(); + + // when + let res = txq.import(TestClient::new(), vec![tx1, tx2]); + assert_eq!(res, vec![ + Err(transaction::Error::InsufficientGasPrice { + minimal: 1.into(), + got: 0.into(), + }), + Err(transaction::Error::InsufficientGasPrice { + minimal: 1.into(), + got: 0.into(), + }), + ]); + + // then + let res = txq.import(TestClient::new().with_service_transaction(), vec![tx3]); + assert_eq!(res, vec![Ok(())]); +} + +#[test] +fn should_not_return_transactions_over_nonce_cap() { + // given + let txq = new_queue(); + let (tx1, tx2, tx3) = Tx::default().signed_triple(); + let res = txq.import( + TestClient::new(), + vec![tx1, tx2, tx3].local() + ); + assert_eq!(res, vec![Ok(()), Ok(()), Ok(())]); + + // when + let all = txq.pending(TestClient::new(), 0, 0, None); + // This should invalidate the cache! + let limited = txq.pending(TestClient::new(), 0, 0, Some(123.into())); + + + // then + assert_eq!(all.len(), 3); + assert_eq!(limited.len(), 1); +} + +#[test] +fn should_clear_cache_after_timeout_for_local() { + // given + let txq = new_queue(); + let (tx, tx2) = Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![ + verifier::Transaction::Local(PendingTransaction::new(tx, transaction::Condition::Timestamp(1000).into())), + tx2.local() + ]); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // This should populate cache and set timestamp to 1 + // when + assert_eq!(txq.pending(TestClient::new(), 0, 1, None).len(), 0); + assert_eq!(txq.pending(TestClient::new(), 0, 1000, None).len(), 0); + + // This should invalidate the cache and trigger transaction ready. + // then + assert_eq!(txq.pending(TestClient::new(), 0, 1002, None).len(), 2); +} diff --git a/miner/src/pool/tests/tx.rs b/miner/src/pool/tests/tx.rs new file mode 100644 index 0000000000..ee0a7390ee --- /dev/null +++ b/miner/src/pool/tests/tx.rs @@ -0,0 +1,185 @@ +// 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 . + +use ethereum_types::{U256, H256}; +use ethkey::{Random, Generator}; +use rustc_hex::FromHex; +use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; + +use pool::{verifier, VerifiedTransaction}; + +#[derive(Clone)] +pub struct Tx { + nonce: u64, + gas: u64, + gas_price: u64, +} + +impl Default for Tx { + fn default() -> Self { + Tx { + nonce: 123, + gas: 21_000, + gas_price: 1, + } + } +} + +impl Tx { + pub fn gas_price(gas_price: u64) -> Self { + Tx { + gas_price, + ..Default::default() + } + } + + pub fn signed(self) -> SignedTransaction { + let keypair = Random.generate().unwrap(); + self.unsigned().sign(keypair.secret(), None) + } + + pub fn signed_pair(self) -> (SignedTransaction, SignedTransaction) { + let (tx1, tx2, _) = self.signed_triple(); + (tx1, tx2) + } + + pub fn signed_triple(mut self) -> (SignedTransaction, SignedTransaction, SignedTransaction) { + let keypair = Random.generate().unwrap(); + let tx1 = self.clone().unsigned().sign(keypair.secret(), None); + self.nonce += 1; + let tx2 = self.clone().unsigned().sign(keypair.secret(), None); + self.nonce += 1; + let tx3 = self.unsigned().sign(keypair.secret(), None); + + + (tx1, tx2, tx3) + } + + pub fn signed_replacement(mut self) -> (SignedTransaction, SignedTransaction) { + let keypair = Random.generate().unwrap(); + let tx1 = self.clone().unsigned().sign(keypair.secret(), None); + self.gas_price += 1; + let tx2 = self.unsigned().sign(keypair.secret(), None); + + (tx1, tx2) + } + + pub fn unsigned(self) -> Transaction { + Transaction { + action: transaction::Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: self.gas.into(), + gas_price: self.gas_price.into(), + nonce: self.nonce.into() + } + } +} +pub trait TxExt: Sized { + type Out; + type Verified; + type Hash; + + fn hash(&self) -> Self::Hash; + + fn local(self) -> Self::Out; + + fn retracted(self) -> Self::Out; + + fn unverified(self) -> Self::Out; + + fn verified(self) -> Self::Verified; +} + +impl TxExt for (A, B) where + A: TxExt, + B: TxExt, +{ + type Out = (O, O); + type Verified = (V, V); + type Hash = (H, H); + + fn hash(&self) -> Self::Hash { (self.0.hash(), self.1.hash()) } + fn local(self) -> Self::Out { (self.0.local(), self.1.local()) } + fn retracted(self) -> Self::Out { (self.0.retracted(), self.1.retracted()) } + fn unverified(self) -> Self::Out { (self.0.unverified(), self.1.unverified()) } + fn verified(self) -> Self::Verified { (self.0.verified(), self.1.verified()) } +} + +impl TxExt for SignedTransaction { + type Out = verifier::Transaction; + type Verified = VerifiedTransaction; + type Hash = H256; + + fn hash(&self) -> Self::Hash { + UnverifiedTransaction::hash(self) + } + + fn local(self) -> Self::Out { + verifier::Transaction::Local(self.into()) + } + + fn retracted(self) -> Self::Out { + verifier::Transaction::Retracted(self.into()) + } + + fn unverified(self) -> Self::Out { + verifier::Transaction::Unverified(self.into()) + } + + fn verified(self) -> Self::Verified { + VerifiedTransaction::from_pending_block_transaction(self) + } +} + +impl TxExt for Vec { + type Out = Vec; + type Verified = Vec; + type Hash = Vec; + + fn hash(&self) -> Self::Hash { + self.iter().map(|tx| tx.hash()).collect() + } + + fn local(self) -> Self::Out { + self.into_iter().map(Into::into).map(verifier::Transaction::Local).collect() + } + + fn retracted(self) -> Self::Out { + self.into_iter().map(Into::into).map(verifier::Transaction::Retracted).collect() + } + + fn unverified(self) -> Self::Out { + self.into_iter().map(Into::into).map(verifier::Transaction::Unverified).collect() + } + + fn verified(self) -> Self::Verified { + self.into_iter().map(VerifiedTransaction::from_pending_block_transaction).collect() + } +} + +pub trait PairExt { + type Type; + + fn into_vec(self) -> Vec; +} + +impl PairExt for (A, A) { + type Type = A; + fn into_vec(self) -> Vec { + vec![self.0, self.1] + } +} diff --git a/miner/src/pool/verifier.rs b/miner/src/pool/verifier.rs new file mode 100644 index 0000000000..92d2eb9c86 --- /dev/null +++ b/miner/src/pool/verifier.rs @@ -0,0 +1,288 @@ +// 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 . + +//! Transaction Verifier +//! +//! Responsible for verifying a transaction before importing to the pool. +//! Should make sure that the transaction is structuraly valid. +//! +//! May have some overlap with `Readiness` since we don't want to keep around +//! stalled transactions. + +use std::cmp; +use std::sync::Arc; +use std::sync::atomic::{self, AtomicUsize}; + +use ethereum_types::{U256, H256}; +use transaction; +use txpool; + +use super::client::{Client, TransactionType}; +use super::VerifiedTransaction; + +/// Verification options. +#[derive(Debug, Clone, PartialEq)] +pub struct Options { + /// Minimal allowed gas price. + pub minimal_gas_price: U256, + /// Current block gas limit. + pub block_gas_limit: U256, + /// Maximal gas limit for a single transaction. + pub tx_gas_limit: U256, +} + +#[cfg(test)] +impl Default for Options { + fn default() -> Self { + Options { + minimal_gas_price: 0.into(), + block_gas_limit: U256::max_value(), + tx_gas_limit: U256::max_value(), + } + } +} + +/// Transaction to verify. +pub enum Transaction { + /// Fresh, never verified transaction. + /// + /// We need to do full verification of such transactions + Unverified(transaction::UnverifiedTransaction), + + /// Transaction from retracted block. + /// + /// We could skip some parts of verification of such transactions + Retracted(transaction::UnverifiedTransaction), + + /// Locally signed or retracted transaction. + /// + /// We can skip consistency verifications and just verify readiness. + Local(transaction::PendingTransaction), +} + +impl Transaction { + fn hash(&self) -> H256 { + match *self { + Transaction::Unverified(ref tx) => tx.hash(), + Transaction::Retracted(ref tx) => tx.hash(), + Transaction::Local(ref tx) => tx.hash(), + } + } + + fn gas(&self) -> &U256 { + match *self { + Transaction::Unverified(ref tx) => &tx.gas, + Transaction::Retracted(ref tx) => &tx.gas, + Transaction::Local(ref tx) => &tx.gas, + } + } + + + fn gas_price(&self) -> &U256 { + match *self { + Transaction::Unverified(ref tx) => &tx.gas_price, + Transaction::Retracted(ref tx) => &tx.gas_price, + Transaction::Local(ref tx) => &tx.gas_price, + } + } + + fn transaction(&self) -> &transaction::Transaction { + match *self { + Transaction::Unverified(ref tx) => &*tx, + Transaction::Retracted(ref tx) => &*tx, + Transaction::Local(ref tx) => &*tx, + } + } + + fn is_local(&self) -> bool { + match *self { + Transaction::Local(..) => true, + _ => false, + } + } + + fn is_retracted(&self) -> bool { + match *self { + Transaction::Retracted(..) => true, + _ => false, + } + } +} + +/// Transaction verifier. +/// +/// Verification can be run in parallel for all incoming transactions. +#[derive(Debug)] +pub struct Verifier { + client: C, + options: Options, + id: Arc, +} + +impl Verifier { + /// Creates new transaction verfier with specified options. + pub fn new(client: C, options: Options, id: Arc) -> Self { + Verifier { + client, + options, + id, + } + } +} + +impl txpool::Verifier for Verifier { + type Error = transaction::Error; + type VerifiedTransaction = VerifiedTransaction; + + fn verify_transaction(&self, tx: Transaction) -> Result { + // The checks here should be ordered by cost/complexity. + // Cheap checks should be done as early as possible to discard unneeded transactions early. + + let hash = tx.hash(); + + if self.client.transaction_already_included(&hash) { + trace!(target: "txqueue", "[{:?}] Rejected tx already in the blockchain", hash); + bail!(transaction::Error::AlreadyImported) + } + + let gas_limit = cmp::min(self.options.tx_gas_limit, self.options.block_gas_limit); + if tx.gas() > &gas_limit { + debug!( + target: "txqueue", + "[{:?}] Dropping transaction above gas limit: {} > min({}, {})", + hash, + tx.gas(), + self.options.block_gas_limit, + self.options.tx_gas_limit, + ); + bail!(transaction::Error::GasLimitExceeded { + limit: gas_limit, + got: *tx.gas(), + }); + } + + let minimal_gas = self.client.required_gas(tx.transaction()); + if tx.gas() < &minimal_gas { + trace!(target: "txqueue", + "[{:?}] Dropping transaction with insufficient gas: {} < {}", + hash, + tx.gas(), + minimal_gas, + ); + + bail!(transaction::Error::InsufficientGas { + minimal: minimal_gas, + got: *tx.gas(), + }) + } + + let is_own = tx.is_local(); + // Quick exit for non-service transactions + if tx.gas_price() < &self.options.minimal_gas_price + && !tx.gas_price().is_zero() + && !is_own + { + trace!( + target: "txqueue", + "[{:?}] Rejected tx below minimal gas price threshold: {} < {}", + hash, + tx.gas_price(), + self.options.minimal_gas_price, + ); + bail!(transaction::Error::InsufficientGasPrice { + minimal: self.options.minimal_gas_price, + got: *tx.gas_price(), + }); + } + + // Some more heavy checks below. + // Actually recover sender and verify that transaction + let is_retracted = tx.is_retracted(); + let transaction = match tx { + Transaction::Retracted(tx) | Transaction::Unverified(tx) => match self.client.verify_transaction(tx) { + Ok(signed) => signed.into(), + Err(err) => { + debug!(target: "txqueue", "[{:?}] Rejected tx {:?}", hash, err); + bail!(err) + }, + }, + Transaction::Local(tx) => tx, + }; + + let sender = transaction.sender(); + let account_details = self.client.account_details(&sender); + + if transaction.gas_price < self.options.minimal_gas_price { + let transaction_type = self.client.transaction_type(&transaction); + if let TransactionType::Service = transaction_type { + debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash); + } else if is_own || account_details.is_local { + info!(target: "own_tx", "Local tx {:?} below minimal gas price accepted", hash); + } else { + trace!( + target: "txqueue", + "[{:?}] Rejected tx below minimal gas price threshold: {} < {}", + hash, + transaction.gas_price, + self.options.minimal_gas_price, + ); + bail!(transaction::Error::InsufficientGasPrice { + minimal: self.options.minimal_gas_price, + got: transaction.gas_price, + }); + } + } + + let cost = transaction.value + transaction.gas_price * transaction.gas; + if account_details.balance < cost { + debug!( + target: "txqueue", + "[{:?}] Rejected tx with not enough balance: {} < {}", + hash, + account_details.balance, + cost, + ); + bail!(transaction::Error::InsufficientBalance { + cost: cost, + balance: account_details.balance, + }); + } + + if transaction.nonce < account_details.nonce { + debug!( + target: "txqueue", + "[{:?}] Rejected tx with old nonce ({} < {})", + hash, + transaction.nonce, + account_details.nonce, + ); + bail!(transaction::Error::Old); + } + + let priority = match (is_own || account_details.is_local, is_retracted) { + (true, _) => super::Priority::Local, + (false, false) => super::Priority::Regular, + (false, true) => super::Priority::Retracted, + }; + Ok(VerifiedTransaction { + transaction, + priority, + hash, + sender, + insertion_id: self.id.fetch_add(1, atomic::Ordering::AcqRel), + }) + } +} diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs deleted file mode 100644 index 2be7fc8a3b..0000000000 --- a/miner/src/transaction_queue.rs +++ /dev/null @@ -1,2944 +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 . - -//! Transaction Queue -//! -//! `TransactionQueue` keeps track of all transactions seen by the node (received from other peers) and own transactions -//! and orders them by priority. Top priority transactions are those with low nonce height (difference between -//! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used -//! for comparison (higher gas price = higher priority). -//! -//! # Usage Example -//! -//! ```rust -//! extern crate ethereum_types; -//! extern crate ethcore_miner as miner; -//! extern crate ethcore_transaction as transaction; -//! extern crate ethkey; -//! extern crate rustc_hex; -//! -//! use ethereum_types::{U256, Address}; -//! use ethkey::{Random, Generator}; -//! use miner::transaction_queue::{TransactionQueue, TransactionDetailsProvider, AccountDetails, TransactionOrigin, RemovalReason}; -//! use transaction::*; -//! use rustc_hex::FromHex; -//! -//! #[derive(Default)] -//! struct DummyTransactionDetailsProvider; -//! -//! impl TransactionDetailsProvider for DummyTransactionDetailsProvider { -//! fn fetch_account(&self, _address: &Address) -> AccountDetails { -//! AccountDetails { -//! nonce: U256::from(10), -//! balance: U256::from(1_000_000) -//! } -//! } -//! -//! fn estimate_gas_required(&self, _tx: &SignedTransaction) -> U256 { -//! 2.into() -//! } -//! -//! fn is_service_transaction_acceptable(&self, _tx: &SignedTransaction) -> Result { -//! Ok(true) -//! } -//! } -//! -//! fn main() { -//! let key = Random.generate().unwrap(); -//! let t1 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), -//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(10) }; -//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), -//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) }; -//! -//! let st1 = t1.sign(&key.secret(), None); -//! let st2 = t2.sign(&key.secret(), None); -//! let details_provider = DummyTransactionDetailsProvider::default(); -//! -//! let mut txq = TransactionQueue::default(); -//! txq.add(st2.clone(), TransactionOrigin::External, 0, None, &details_provider).unwrap(); -//! txq.add(st1.clone(), TransactionOrigin::External, 0, None, &details_provider).unwrap(); -//! -//! // Check status -//! assert_eq!(txq.status().pending, 2); -//! // Check top transactions -//! let top = txq.top_transactions(); -//! assert_eq!(top.len(), 2); -//! assert_eq!(top[0], st1); -//! assert_eq!(top[1], st2); -//! -//! // And when transaction is removed (but nonce haven't changed) -//! // it will move subsequent transactions to future -//! txq.remove(&st1.hash(), &|_| 10.into(), RemovalReason::Invalid); -//! assert_eq!(txq.status().pending, 0); -//! assert_eq!(txq.status().future, 1); -//! assert_eq!(txq.top_transactions().len(), 0); -//! } -//! ``` -//! -//! # Maintaing valid state -//! -//! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling). -//! 2. Whenever invalid transaction is removed: -//! - When it's removed from `future` - all `future` transactions heights are recalculated and then -//! we check if the transactions should go to `current` (comparing state nonce) -//! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated. -//! 3. `cull` is used to inform the queue about client (state) nonce changes. -//! - It removes all transactions (either from `current` or `future`) with nonce < client nonce -//! - It moves matching `future` transactions to `current` -//! 4. `remove_old` is used as convenient method to update the state nonce for all senders in the queue. -//! - Invokes `cull` with latest state nonce for all senders. - -use std::cmp::Ordering; -use std::cmp; -use std::collections::{HashSet, HashMap, BTreeSet, BTreeMap}; -use std::ops::Deref; - -use ethereum_types::{H256, U256, Address}; -use heapsize::HeapSizeOf; -use linked_hash_map::LinkedHashMap; -use local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus}; -use table::Table; -use transaction::{self, SignedTransaction, PendingTransaction}; - -type BlockNumber = u64; - -/// Transaction origin -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum TransactionOrigin { - /// Transaction coming from local RPC - Local, - /// External transaction received from network - External, - /// Transactions from retracted blocks - RetractedBlock, -} - -impl PartialOrd for TransactionOrigin { - fn partial_cmp(&self, other: &TransactionOrigin) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TransactionOrigin { - fn cmp(&self, other: &TransactionOrigin) -> Ordering { - if *other == *self { - return Ordering::Equal; - } - - match (*self, *other) { - (TransactionOrigin::RetractedBlock, _) => Ordering::Less, - (_, TransactionOrigin::RetractedBlock) => Ordering::Greater, - (TransactionOrigin::Local, _) => Ordering::Less, - _ => Ordering::Greater, - } - } -} - -impl TransactionOrigin { - fn is_local(&self) -> bool { - *self == TransactionOrigin::Local - } -} - -#[derive(Clone, Debug)] -/// Light structure used to identify transaction and its order -struct TransactionOrder { - /// Primary ordering factory. Difference between transaction nonce and expected nonce in state - /// (e.g. Tx(nonce:5), State(nonce:0) -> height: 5) - /// High nonce_height = Low priority (processed later) - nonce_height: U256, - /// Gas Price of the transaction. - /// Low gas price = Low priority (processed later) - gas_price: U256, - /// Gas usage priority factor. Usage depends on strategy. - /// Represents the linear increment in required gas price for heavy transactions. - /// - /// High gas limit + Low gas price = Very Low priority - /// High gas limit + High gas price = High priority - gas_factor: U256, - /// Gas (limit) of the transaction. Usage depends on strategy. - /// Low gas limit = High priority (processed earlier) - gas: U256, - /// Heap usage of this transaction. - mem_usage: usize, - /// Transaction ordering strategy - strategy: PrioritizationStrategy, - /// Hash to identify associated transaction - hash: H256, - /// Incremental id assigned when transaction is inserted to the queue. - insertion_id: u64, - /// Origin of the transaction - origin: TransactionOrigin, - /// Penalties - penalties: usize, -} - - -impl TransactionOrder { - - fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256, min_gas_price: U256, strategy: PrioritizationStrategy) -> Self { - let factor = (tx.transaction.gas >> 15) * min_gas_price; - TransactionOrder { - nonce_height: tx.nonce() - base_nonce, - gas_price: tx.transaction.gas_price, - gas_factor: factor, - gas: tx.transaction.gas, - mem_usage: tx.transaction.heap_size_of_children(), - strategy: strategy, - hash: tx.hash(), - insertion_id: tx.insertion_id, - origin: tx.origin, - penalties: 0, - } - } - - fn update_height(mut self, nonce: U256, base_nonce: U256) -> Self { - self.nonce_height = nonce - base_nonce; - self - } - - fn penalize(mut self) -> Self { - self.penalties = self.penalties.saturating_add(1); - self - } -} - -impl Eq for TransactionOrder {} -impl PartialEq for TransactionOrder { - fn eq(&self, other: &TransactionOrder) -> bool { - self.cmp(other) == Ordering::Equal - } -} -impl PartialOrd for TransactionOrder { - fn partial_cmp(&self, other: &TransactionOrder) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TransactionOrder { - fn cmp(&self, b: &TransactionOrder) -> Ordering { - // First check number of penalties - if self.penalties != b.penalties { - return self.penalties.cmp(&b.penalties); - } - - // Local transactions should always have priority - if self.origin != b.origin { - return self.origin.cmp(&b.origin); - } - - // Check nonce_height - if self.nonce_height != b.nonce_height { - return self.nonce_height.cmp(&b.nonce_height); - } - - match self.strategy { - PrioritizationStrategy::GasAndGasPrice => { - if self.gas != b.gas { - return self.gas.cmp(&b.gas); - } - }, - PrioritizationStrategy::GasFactorAndGasPrice => { - // avoiding overflows - // (gp1 - g1) > (gp2 - g2) <=> - // (gp1 + g2) > (gp2 + g1) - let f_a = self.gas_price + b.gas_factor; - let f_b = b.gas_price + self.gas_factor; - if f_a != f_b { - return f_b.cmp(&f_a); - } - }, - PrioritizationStrategy::GasPriceOnly => {}, - } - - // Then compare gas_prices - if self.gas_price != b.gas_price { - return b.gas_price.cmp(&self.gas_price); - } - - // Lastly compare insertion_id - self.insertion_id.cmp(&b.insertion_id) - } -} - -/// Verified transaction -#[derive(Debug)] -struct VerifiedTransaction { - /// Transaction. - transaction: SignedTransaction, - /// Transaction origin. - origin: TransactionOrigin, - /// Delay until specified condition is met. - condition: Option, - /// Insertion time - insertion_time: QueuingInstant, - /// ID assigned upon insertion, should be unique. - insertion_id: u64, -} - -impl VerifiedTransaction { - fn new( - transaction: SignedTransaction, - origin: TransactionOrigin, - condition: Option, - insertion_time: QueuingInstant, - insertion_id: u64, - ) -> Self { - VerifiedTransaction { - transaction, - origin, - condition, - insertion_time, - insertion_id, - } - } - - fn hash(&self) -> H256 { - self.transaction.hash() - } - - fn nonce(&self) -> U256 { - self.transaction.nonce - } - - fn sender(&self) -> Address { - self.transaction.sender() - } - - fn cost(&self) -> U256 { - self.transaction.value + self.transaction.gas_price * self.transaction.gas - } -} - -#[derive(Debug, Default)] -struct GasPriceQueue { - backing: BTreeMap>, -} - -impl GasPriceQueue { - /// Insert an item into a BTreeMap/HashSet "multimap". - pub fn insert(&mut self, gas_price: U256, hash: H256) -> bool { - self.backing.entry(gas_price).or_insert_with(Default::default).insert(hash) - } - - /// Remove an item from a BTreeMap/HashSet "multimap". - /// Returns true if the item was removed successfully. - pub fn remove(&mut self, gas_price: &U256, hash: &H256) -> bool { - if let Some(hashes) = self.backing.get_mut(gas_price) { - let only_one_left = hashes.len() == 1; - if !only_one_left { - // Operation may be ok: only if hash is in gas-price's Set. - return hashes.remove(hash); - } - if hash != hashes.iter().next().expect("We know there is only one element in collection, tested above; qed") { - // Operation failed: hash not the single item in gas-price's Set. - return false; - } - } else { - // Operation failed: gas-price not found in Map. - return false; - } - // Operation maybe ok: only if hash not found in gas-price Set. - self.backing.remove(gas_price).is_some() - } -} - -impl Deref for GasPriceQueue { - type Target=BTreeMap>; - - fn deref(&self) -> &Self::Target { - &self.backing - } -} - -/// Holds transactions accessible by (address, nonce) and by priority -/// -/// `TransactionSet` keeps number of entries below limit, but it doesn't -/// automatically happen during `insert/remove` operations. -/// You have to call `enforce_limit` to remove lowest priority transactions from set. -struct TransactionSet { - by_priority: BTreeSet, - by_address: Table, - by_gas_price: GasPriceQueue, - limit: usize, - total_gas_limit: U256, - memory_limit: usize, -} - -impl TransactionSet { - /// Inserts `TransactionOrder` to this set. Transaction does not need to be unique - - /// the same transaction may be validly inserted twice. Any previous transaction that - /// it replaces (i.e. with the same `sender` and `nonce`) should be returned. - fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) -> Option { - if !self.by_priority.insert(order.clone()) { - return Some(order.clone()); - } - let order_hash = order.hash.clone(); - let order_gas_price = order.gas_price.clone(); - let by_address_replaced = self.by_address.insert(sender, nonce, order); - // If transaction was replaced remove it from priority queue - if let Some(ref old_order) = by_address_replaced { - assert!(self.by_priority.remove(old_order), "hash is in `by_address`; all transactions in `by_address` must be in `by_priority`; qed"); - assert!(self.by_gas_price.remove(&old_order.gas_price, &old_order.hash), - "hash is in `by_address`; all transactions' gas_prices in `by_address` must be in `by_gas_limit`; qed"); - } - self.by_gas_price.insert(order_gas_price, order_hash); - assert_eq!(self.by_priority.len(), self.by_address.len()); - assert_eq!(self.by_gas_price.values().map(|v| v.len()).fold(0, |a, b| a + b), self.by_address.len()); - by_address_replaced - } - - /// Remove low priority transactions if there is more than specified by given `limit`. - /// - /// It drops transactions from this set but also removes associated `VerifiedTransaction`. - /// Returns addresses and lowest nonces of transactions removed because of limit. - fn enforce_limit(&mut self, by_hash: &mut HashMap, local: &mut LocalTransactionsList) -> Option> { - let mut count = 0; - let mut mem_usage = 0; - let mut gas: U256 = 0.into(); - let to_drop : Vec<(Address, U256)> = { - self.by_priority - .iter() - .filter(|order| { - // update transaction count and mem usage - count += 1; - mem_usage += order.mem_usage; - - // calculate current gas usage - let r = gas.overflowing_add(order.gas); - if r.1 { return false } - gas = r.0; - - let is_own_or_retracted = order.origin.is_local() || order.origin == TransactionOrigin::RetractedBlock; - // Own and retracted transactions are allowed to go above all limits. - !is_own_or_retracted && (mem_usage > self.memory_limit || count > self.limit || gas > self.total_gas_limit) - }) - .map(|order| by_hash.get(&order.hash) - .expect("All transactions in `self.by_priority` and `self.by_address` are kept in sync with `by_hash`.")) - .map(|tx| (tx.sender(), tx.nonce())) - .collect() - }; - - Some(to_drop.into_iter() - .fold(HashMap::new(), |mut removed, (sender, nonce)| { - let order = self.drop(&sender, &nonce) - .expect("Transaction has just been found in `by_priority`; so it is in `by_address` also."); - trace!(target: "txqueue", "Dropped out of limit transaction: {:?}", order.hash); - - let order = by_hash.remove(&order.hash) - .expect("hash is in `by_priorty`; all hashes in `by_priority` must be in `by_hash`; qed"); - - if order.origin.is_local() { - local.mark_dropped(order.transaction); - } - - let min = removed.get(&sender).map_or(nonce, |val| cmp::min(*val, nonce)); - removed.insert(sender, min); - removed - })) - } - - /// Drop transaction from this set (remove from `by_priority` and `by_address`) - fn drop(&mut self, sender: &Address, nonce: &U256) -> Option { - if let Some(tx_order) = self.by_address.remove(sender, nonce) { - assert!(self.by_gas_price.remove(&tx_order.gas_price, &tx_order.hash), - "hash is in `by_address`; all transactions' gas_prices in `by_address` must be in `by_gas_limit`; qed"); - assert!(self.by_priority.remove(&tx_order), - "hash is in `by_address`; all transactions' gas_prices in `by_address` must be in `by_priority`; qed"); - assert_eq!(self.by_priority.len(), self.by_address.len()); - assert_eq!(self.by_gas_price.values().map(|v| v.len()).fold(0, |a, b| a + b), self.by_address.len()); - return Some(tx_order); - } - assert_eq!(self.by_priority.len(), self.by_address.len()); - assert_eq!(self.by_gas_price.values().map(|v| v.len()).fold(0, |a, b| a + b), self.by_address.len()); - None - } - - /// Drop all transactions. - fn clear(&mut self) { - self.by_priority.clear(); - self.by_address.clear(); - self.by_gas_price.backing.clear(); - } - - /// Sets new limit for number of transactions in this `TransactionSet`. - /// Note the limit is not applied (no transactions are removed) by calling this method. - fn set_limit(&mut self, limit: usize) { - self.limit = limit; - } - - /// Get the minimum gas price that we can accept into this queue that wouldn't cause the transaction to - /// immediately be dropped. 0 if the queue isn't at capacity; 1 plus the lowest if it is. - fn gas_price_entry_limit(&self) -> U256 { - match self.by_gas_price.keys().next() { - Some(k) if self.by_priority.len() >= self.limit => *k + 1.into(), - _ => U256::default(), - } - } -} - -#[derive(Debug)] -/// Current status of the queue -pub struct TransactionQueueStatus { - /// Number of pending transactions (ready to go to block) - pub pending: usize, - /// Number of future transactions (waiting for transactions with lower nonces first) - pub future: usize, -} - -/// Details of account -pub struct AccountDetails { - /// Most recent account nonce - pub nonce: U256, - /// Current account balance - pub balance: U256, -} - -/// Transaction with the same (sender, nonce) can be replaced only if -/// `new_gas_price > old_gas_price + old_gas_price >> SHIFT` -const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25% - -/// Describes the strategy used to prioritize transactions in the queue. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum PrioritizationStrategy { - /// Use only gas price. Disregards the actual computation cost of the transaction. - /// i.e. Higher gas price = Higher priority - GasPriceOnly, - /// Use gas limit and then gas price. - /// i.e. Higher gas limit = Lower priority - GasAndGasPrice, - /// Calculate and use priority based on gas and gas price. - /// PRIORITY = GAS_PRICE - GAS/2^15 * MIN_GAS_PRICE - /// - /// Rationale: - /// Heavy transactions are paying linear cost (GAS * GAS_PRICE) - /// while the computation might be more expensive. - /// - /// i.e. - /// 1M gas tx with `gas_price=30*min` has the same priority - /// as 32k gas tx with `gas_price=min` - GasFactorAndGasPrice, -} - -/// Reason to remove single transaction from the queue. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum RemovalReason { - /// Transaction is invalid - Invalid, - /// Transaction was canceled - Canceled, - /// Transaction is not allowed, - NotAllowed, -} - -/// Point in time when transaction was inserted. -pub type QueuingInstant = BlockNumber; -const DEFAULT_QUEUING_PERIOD: BlockNumber = 128; - -/// `TransactionQueue` transaction details provider. -pub trait TransactionDetailsProvider { - /// Fetch transaction-related account details. - fn fetch_account(&self, address: &Address) -> AccountDetails; - /// Estimate gas required for transaction. - fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256; - /// Check if this service transaction can be accepted by `TransactionQueue`. - fn is_service_transaction_acceptable(&self, tx: &SignedTransaction) -> Result; -} - -/// `TransactionQueue` implementation -pub struct TransactionQueue { - /// Prioritization strategy for this queue - strategy: PrioritizationStrategy, - /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) - minimal_gas_price: U256, - /// The maximum amount of gas any individual transaction may use. - tx_gas_limit: U256, - /// Current gas limit (block gas limit). Transactions above the limit will not be accepted (default to !0) - block_gas_limit: U256, - /// Maximal time transaction may occupy the queue. - /// When we reach `max_time_in_queue / 2^3` we re-validate - /// account balance. - max_time_in_queue: QueuingInstant, - /// Priority queue for transactions that can go to block - current: TransactionSet, - /// Priority queue for transactions that has been received but are not yet valid to go to block - future: TransactionSet, - /// All transactions managed by queue indexed by hash - by_hash: HashMap, - /// Last nonce of transaction in current (to quickly check next expected transaction) - last_nonces: HashMap, - /// List of local transactions and their statuses. - local_transactions: LocalTransactionsList, - /// Next id that should be assigned to a transaction imported to the queue. - next_transaction_id: u64, -} - -impl Default for TransactionQueue { - fn default() -> Self { - TransactionQueue::new(PrioritizationStrategy::GasPriceOnly) - } -} - -impl TransactionQueue { - /// Creates new instance of this Queue - pub fn new(strategy: PrioritizationStrategy) -> Self { - Self::with_limits(strategy, 8192, usize::max_value(), !U256::zero(), !U256::zero()) - } - - /// Create new instance of this Queue with specified limits - pub fn with_limits( - strategy: PrioritizationStrategy, - limit: usize, - memory_limit: usize, - total_gas_limit: U256, - tx_gas_limit: U256, - ) -> Self { - let current = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit, - total_gas_limit, - memory_limit, - }; - - let future = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - total_gas_limit, - limit, - memory_limit, - }; - - TransactionQueue { - strategy, - minimal_gas_price: U256::zero(), - block_gas_limit: !U256::zero(), - tx_gas_limit, - max_time_in_queue: DEFAULT_QUEUING_PERIOD, - current, - future, - by_hash: HashMap::new(), - last_nonces: HashMap::new(), - local_transactions: LocalTransactionsList::default(), - next_transaction_id: 0, - } - } - - /// Set the new limit for `current` and `future` queue. - pub fn set_limit(&mut self, limit: usize) { - self.current.set_limit(limit); - self.future.set_limit(limit); - // And ensure the limits - self.current.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - } - - /// Returns current limit of transactions in the queue. - pub fn limit(&self) -> usize { - self.current.limit - } - - /// Get the minimal gas price. - pub fn minimal_gas_price(&self) -> &U256 { - &self.minimal_gas_price - } - - /// Sets new gas price threshold for incoming transactions. - /// Any transaction already imported to the queue is not affected. - pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) { - self.minimal_gas_price = min_gas_price; - } - - /// Get one more than the lowest gas price in the queue iff the pool is - /// full, otherwise 0. - pub fn effective_minimum_gas_price(&self) -> U256 { - self.current.gas_price_entry_limit() - } - - /// Sets new gas limit. Transactions with gas over the limit will not be accepted. - /// Any transaction already imported to the queue is not affected. - pub fn set_gas_limit(&mut self, gas_limit: U256) { - self.block_gas_limit = gas_limit; - } - - /// Sets new total gas limit. - pub fn set_total_gas_limit(&mut self, total_gas_limit: U256) { - self.current.total_gas_limit = total_gas_limit; - self.future.total_gas_limit = total_gas_limit; - self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - } - - /// Set the new limit for the amount of gas any individual transaction may have. - /// Any transaction already imported to the queue is not affected. - pub fn set_tx_gas_limit(&mut self, limit: U256) { - self.tx_gas_limit = limit; - } - - /// Returns current status for this queue - pub fn status(&self) -> TransactionQueueStatus { - TransactionQueueStatus { - pending: self.current.by_priority.len(), - future: self.future.by_priority.len(), - } - } - - /// Add signed transaction to queue to be verified and imported. - /// - /// NOTE details_provider methods should be cheap to compute - /// otherwise it might open up an attack vector. - pub fn add( - &mut self, - tx: SignedTransaction, - origin: TransactionOrigin, - time: QueuingInstant, - condition: Option, - details_provider: &TransactionDetailsProvider, - ) -> Result { - if origin == TransactionOrigin::Local { - let hash = tx.hash(); - let cloned_tx = tx.clone(); - - let result = self.add_internal(tx, origin, time, condition, details_provider); - match result { - Ok(transaction::ImportResult::Current) => { - self.local_transactions.mark_pending(hash); - }, - Ok(transaction::ImportResult::Future) => { - self.local_transactions.mark_future(hash); - }, - Err(ref err) => { - // Sometimes transactions are re-imported, so - // don't overwrite transactions if they are already on the list - if !self.local_transactions.contains(&hash) { - self.local_transactions.mark_rejected(cloned_tx, err.clone()); - } - }, - } - result - } else { - self.add_internal(tx, origin, time, condition, details_provider) - } - } - - /// Adds signed transaction to the queue. - fn add_internal( - &mut self, - tx: SignedTransaction, - origin: TransactionOrigin, - time: QueuingInstant, - condition: Option, - details_provider: &TransactionDetailsProvider, - ) -> Result { - if origin != TransactionOrigin::Local && tx.gas_price < self.minimal_gas_price { - // if it is non-service-transaction => drop - let is_service_transaction = tx.gas_price.is_zero(); - if !is_service_transaction { - trace!(target: "txqueue", - "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", - tx.hash(), - tx.gas_price, - self.minimal_gas_price - ); - - return Err(transaction::Error::InsufficientGasPrice { - minimal: self.minimal_gas_price, - got: tx.gas_price, - }); - } - - let is_service_transaction_accepted = match details_provider.is_service_transaction_acceptable(&tx) { - Ok(true) => true, - Ok(false) => { - trace!(target: "txqueue", - "Dropping service transaction as sender is not certified to send service transactions: {:?} (sender: {:?})", - tx.hash(), - tx.sender(), - ); - - false - }, - Err(contract_err) => { - trace!(target: "txqueue", - "Dropping service transaction as service contract returned error: {:?} (error: {:?})", - tx.hash(), - contract_err, - ); - - false - }, - }; - - if !is_service_transaction_accepted { - return Err(transaction::Error::InsufficientGasPrice { - minimal: self.minimal_gas_price, - got: tx.gas_price, - }); - } - } - - let full_queues_lowest = self.effective_minimum_gas_price(); - if tx.gas_price < full_queues_lowest && origin != TransactionOrigin::Local { - trace!(target: "txqueue", - "Dropping transaction below lowest gas price in a full queue: {:?} (gp: {} < {})", - tx.hash(), - tx.gas_price, - full_queues_lowest - ); - - return Err(transaction::Error::InsufficientGasPrice { - minimal: full_queues_lowest, - got: tx.gas_price, - }); - } - - let gas_limit = cmp::min(self.tx_gas_limit, self.block_gas_limit); - if tx.gas > gas_limit { - trace!(target: "txqueue", - "Dropping transaction above gas limit: {:?} ({} > min({}, {}))", - tx.hash(), - tx.gas, - self.block_gas_limit, - self.tx_gas_limit - ); - return Err(transaction::Error::GasLimitExceeded { - limit: gas_limit, - got: tx.gas, - }); - } - - let minimal_gas = details_provider.estimate_gas_required(&tx); - if tx.gas < minimal_gas { - trace!(target: "txqueue", - "Dropping transaction with insufficient gas: {:?} ({} > {})", - tx.hash(), - tx.gas, - minimal_gas, - ); - - return Err(transaction::Error::InsufficientGas { - minimal: minimal_gas, - got: tx.gas, - }); - } - - let client_account = details_provider.fetch_account(&tx.sender()); - let cost = tx.value + tx.gas_price * tx.gas; - if client_account.balance < cost { - trace!(target: "txqueue", - "Dropping transaction without sufficient balance: {:?} ({} < {})", - tx.hash(), - client_account.balance, - cost - ); - - return Err(transaction::Error::InsufficientBalance { - cost: cost, - balance: client_account.balance - }); - } - tx.check_low_s()?; - // No invalid transactions beyond this point. - let id = self.next_transaction_id; - self.next_transaction_id += 1; - let vtx = VerifiedTransaction::new(tx, origin, condition, time, id); - let r = self.import_tx(vtx, client_account.nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - r - } - - /// Removes all transactions from particular sender up to (excluding) given client (state) nonce. - /// Client (State) Nonce = next valid nonce for this sender. - pub fn cull(&mut self, sender: Address, client_nonce: U256) { - // Check if there is anything in current... - let should_check_in_current = self.current.by_address.row(&sender) - // If nonce == client_nonce nothing is changed - .and_then(|by_nonce| by_nonce.keys().find(|nonce| *nonce < &client_nonce)) - .map(|_| ()); - // ... or future - let should_check_in_future = self.future.by_address.row(&sender) - // if nonce == client_nonce we need to promote to current - .and_then(|by_nonce| by_nonce.keys().find(|nonce| *nonce <= &client_nonce)) - .map(|_| ()); - - if should_check_in_current.or(should_check_in_future).is_none() { - return; - } - - self.cull_internal(sender, client_nonce); - } - - /// Always updates future and moves transactions from current to future. - fn cull_internal(&mut self, sender: Address, client_nonce: U256) { - // We will either move transaction to future or remove it completely - // so there will be no transactions from this sender in current - self.last_nonces.remove(&sender); - // First update height of transactions in future to avoid collisions - self.update_future(&sender, client_nonce); - // This should move all current transactions to future and remove old transactions - self.move_all_to_future(&sender, client_nonce); - // And now lets check if there is some batch of transactions in future - // that should be placed in current. It should also update last_nonces. - self.move_matching_future_to_current(sender, client_nonce, client_nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - } - - /// Checks the current nonce for all transactions' senders in the queue and removes the old transactions. - pub fn remove_old(&mut self, fetch_account: &F, current_time: QueuingInstant) where - F: Fn(&Address) -> AccountDetails, - { - let senders = self.current.by_address.keys() - .chain(self.future.by_address.keys()) - .map(|sender| (*sender, fetch_account(sender))) - .collect::>(); - - for (sender, details) in senders.iter() { - self.cull(*sender, details.nonce); - } - - let max_time = self.max_time_in_queue; - let balance_check = max_time >> 3; - // Clear transactions occupying the queue too long - let invalid = self.by_hash.iter() - .filter(|&(_, ref tx)| !tx.origin.is_local()) - .map(|(hash, tx)| (hash, tx, current_time.saturating_sub(tx.insertion_time))) - .filter_map(|(hash, tx, time_diff)| { - if time_diff > max_time { - return Some(*hash); - } - - if time_diff > balance_check { - return match senders.get(&tx.sender()) { - Some(details) if tx.cost() > details.balance => { - Some(*hash) - }, - _ => None, - }; - } - - None - }) - .collect::>(); - let fetch_nonce = |a: &Address| senders.get(a) - .expect("We fetch details for all senders from both current and future") - .nonce; - for hash in invalid { - self.remove(&hash, &fetch_nonce, RemovalReason::Invalid); - } - } - - /// Penalize transactions from sender of transaction with given hash. - /// I.e. it should change the priority of the transaction in the queue. - /// - /// NOTE: We need to penalize all transactions from particular sender - /// to avoid breaking invariants in queue (ordered by nonces). - /// Consecutive transactions from this sender would fail otherwise (because of invalid nonce). - pub fn penalize(&mut self, transaction_hash: &H256) { - let transaction = match self.by_hash.get(transaction_hash) { - None => return, - Some(t) => t, - }; - - // Never penalize local transactions - if transaction.origin.is_local() { - return; - } - - let sender = transaction.sender(); - - // Penalize all transactions from this sender - let nonces_from_sender = match self.current.by_address.row(&sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - for k in nonces_from_sender { - let order = self.current.drop(&sender, &k).expect("transaction known to be in self.current; qed"); - self.current.insert(sender, k, order.penalize()); - } - // Same thing for future - let nonces_from_sender = match self.future.by_address.row(&sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - for k in nonces_from_sender { - let order = self.future.drop(&sender, &k).expect("transaction known to be in self.future; qed"); - self.future.insert(sender, k, order.penalize()); - } - } - - /// Removes invalid transaction identified by hash from queue. - /// Assumption is that this transaction nonce is not related to client nonce, - /// so transactions left in queue are processed according to client nonce. - /// - /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &F, reason: RemovalReason) - where F: Fn(&Address) -> U256 { - - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - let transaction = self.by_hash.remove(transaction_hash); - if transaction.is_none() { - // We don't know this transaction - return; - } - - let transaction = transaction.expect("None is tested in early-exit condition above; qed"); - let sender = transaction.sender(); - let nonce = transaction.nonce(); - let current_nonce = fetch_nonce(&sender); - - trace!(target: "txqueue", "Removing invalid transaction: {:?}", transaction.hash()); - - // Mark in locals - if self.local_transactions.contains(transaction_hash) { - match reason { - RemovalReason::Invalid => self.local_transactions.mark_invalid( - transaction.transaction.into() - ), - RemovalReason::NotAllowed => self.local_transactions.mark_invalid( - transaction.transaction.into() - ), - RemovalReason::Canceled => self.local_transactions.mark_canceled( - PendingTransaction::new(transaction.transaction, transaction.condition) - ), - } - } - - // Remove from future - let order = self.future.drop(&sender, &nonce); - if order.is_some() { - self.update_future(&sender, current_nonce); - // And now lets check if there is some chain of transactions in future - // that should be placed in current - self.move_matching_future_to_current(sender, current_nonce, current_nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - return; - } - - // Remove from current - let order = self.current.drop(&sender, &nonce); - if order.is_some() { - // This will keep consistency in queue - // Moves all to future and then promotes a batch from current: - self.cull_internal(sender, current_nonce); - assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len()); - return; - } - } - - /// Marks all transactions from particular sender as local transactions - fn mark_transactions_local(&mut self, sender: &Address) { - fn mark_local(sender: &Address, set: &mut TransactionSet, mut mark: F) { - // Mark all transactions from this sender as local - let nonces_from_sender = set.by_address.row(sender) - .map(|row_map| { - row_map.iter().filter_map(|(nonce, order)| if order.origin.is_local() { - None - } else { - Some(*nonce) - }).collect::>() - }) - .unwrap_or_else(Vec::new); - - for k in nonces_from_sender { - let mut order = set.drop(sender, &k).expect("transaction known to be in self.current/self.future; qed"); - order.origin = TransactionOrigin::Local; - mark(order.hash); - set.insert(*sender, k, order); - } - } - - let local = &mut self.local_transactions; - mark_local(sender, &mut self.current, |hash| local.mark_pending(hash)); - mark_local(sender, &mut self.future, |hash| local.mark_future(hash)); - } - - /// Update height of all transactions in future transactions set. - fn update_future(&mut self, sender: &Address, current_nonce: U256) { - // We need to drain all transactions for current sender from future and reinsert them with updated height - let all_nonces_from_sender = match self.future.by_address.row(sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - for k in all_nonces_from_sender { - let order = self.future.drop(sender, &k).expect("iterating over a collection that has been retrieved above; qed"); - if k >= current_nonce { - self.future.insert(*sender, k, order.update_height(k, current_nonce)); - } else { - trace!(target: "txqueue", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); - // Remove the transaction completely - self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`"); - } - } - } - - /// Drop all transactions from given sender from `current`. - /// Either moves them to `future` or removes them from queue completely. - fn move_all_to_future(&mut self, sender: &Address, current_nonce: U256) { - let all_nonces_from_sender = match self.current.by_address.row(sender) { - Some(row_map) => row_map.keys().cloned().collect::>(), - None => vec![], - }; - - for k in all_nonces_from_sender { - // Goes to future or is removed - let order = self.current.drop(sender, &k).expect("iterating over a collection that has been retrieved above; - qed"); - if k >= current_nonce { - let order = order.update_height(k, current_nonce); - if order.origin.is_local() { - self.local_transactions.mark_future(order.hash); - } - if let Some(old) = self.future.insert(*sender, k, order.clone()) { - Self::replace_orders(*sender, k, old, order, &mut self.future, &mut self.by_hash, &mut self.local_transactions); - } - } else { - trace!(target: "txqueue", "Removing old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); - let tx = self.by_hash.remove(&order.hash).expect("All transactions in `future` are also in `by_hash`"); - if tx.origin.is_local() { - self.local_transactions.mark_mined(tx.transaction); - } - } - } - self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - } - - /// Returns top transactions from the queue ordered by priority. - pub fn top_transactions(&self) -> Vec { - self.top_transactions_at(BlockNumber::max_value(), u64::max_value(), None) - - } - - fn filter_pending_transaction(&self, best_block: BlockNumber, best_timestamp: u64, nonce_cap: Option, mut f: F) - where F: FnMut(&VerifiedTransaction) { - - let mut delayed = HashSet::new(); - for t in self.current.by_priority.iter() { - let tx = self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"); - let sender = tx.sender(); - if delayed.contains(&sender) { - continue; - } - if let Some(max_nonce) = nonce_cap { - if tx.nonce() >= max_nonce { - continue; - } - } - let delay = match tx.condition { - Some(transaction::Condition::Number(n)) => n > best_block, - Some(transaction::Condition::Timestamp(t)) => t > best_timestamp, - None => false, - }; - if delay { - delayed.insert(sender); - continue; - } - f(&tx); - } - } - - /// Returns top transactions from the queue ordered by priority. - pub fn top_transactions_at(&self, best_block: BlockNumber, best_timestamp: u64, nonce_cap: Option) -> Vec { - let mut r = Vec::new(); - self.filter_pending_transaction(best_block, best_timestamp, nonce_cap, |tx| r.push(tx.transaction.clone())); - r - } - - /// Return all ready transactions. - pub fn pending_transactions(&self, best_block: BlockNumber, best_timestamp: u64) -> Vec { - let mut r = Vec::new(); - self.filter_pending_transaction(best_block, best_timestamp, None, |tx| r.push(PendingTransaction::new(tx.transaction.clone(), tx.condition.clone()))); - r - } - - /// Return all future transactions. - pub fn future_transactions(&self) -> Vec { - self.future.by_priority - .iter() - .map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`")) - .map(|t| PendingTransaction { transaction: t.transaction.clone(), condition: t.condition.clone() }) - .collect() - } - - /// Returns local transactions (some of them might not be part of the queue anymore). - pub fn local_transactions(&self) -> &LinkedHashMap { - self.local_transactions.all_transactions() - } - - /// Returns hashes of all transactions from current, ordered by priority. - pub fn pending_hashes(&self) -> Vec { - self.current.by_priority - .iter() - .map(|t| t.hash) - .collect() - } - - /// Returns true if there is at least one local transaction pending - pub fn has_local_pending_transactions(&self) -> bool { - self.current.by_priority.iter().any(|tx| tx.origin == TransactionOrigin::Local) - } - - /// Finds transaction in the queue by hash (if any) - pub fn find(&self, hash: &H256) -> Option { - self.by_hash.get(hash).map(|tx| PendingTransaction { transaction: tx.transaction.clone(), condition: tx.condition.clone() }) - } - - /// Removes all elements (in any state) from the queue - pub fn clear(&mut self) { - self.current.clear(); - self.future.clear(); - self.by_hash.clear(); - self.last_nonces.clear(); - } - - /// Returns highest transaction nonce for given address. - pub fn last_nonce(&self, address: &Address) -> Option { - self.last_nonces.get(address).cloned() - } - - /// Checks if there are any transactions in `future` that should actually be promoted to `current` - /// (because nonce matches). - fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { - let mut update_last_nonce_to = None; - { - let by_nonce = self.future.by_address.row_mut(&address); - if by_nonce.is_none() { - return; - } - let by_nonce = by_nonce.expect("None is tested in early-exit condition above; qed"); - while let Some(order) = by_nonce.remove(¤t_nonce) { - // remove also from priority and gas_price - self.future.by_priority.remove(&order); - self.future.by_gas_price.remove(&order.gas_price, &order.hash); - // Put to current - let order = order.update_height(current_nonce, first_nonce); - if order.origin.is_local() { - self.local_transactions.mark_pending(order.hash); - } - if let Some(old) = self.current.insert(address, current_nonce, order.clone()) { - Self::replace_orders(address, current_nonce, old, order, &mut self.current, &mut self.by_hash, &mut self.local_transactions); - } - update_last_nonce_to = Some(current_nonce); - current_nonce = current_nonce + U256::one(); - } - } - self.future.by_address.clear_if_empty(&address); - if let Some(x) = update_last_nonce_to { - // Update last inserted nonce - self.last_nonces.insert(address, x); - } - } - - /// Adds VerifiedTransaction to this queue. - /// - /// Determines if it should be placed in current or future. When transaction is - /// imported to `current` also checks if there are any `future` transactions that should be promoted because of - /// this. - /// - /// It ignores transactions that has already been imported (same `hash`) and replaces the transaction - /// iff `(address, nonce)` is the same but `gas_price` is higher. - /// - /// Returns `true` when transaction was imported successfuly - fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) -> Result { - - if self.by_hash.get(&tx.hash()).is_some() { - // Transaction is already imported. - trace!(target: "txqueue", "Dropping already imported transaction: {:?}", tx.hash()); - return Err(transaction::Error::AlreadyImported); - } - - let min_gas_price = (self.minimal_gas_price, self.strategy); - let address = tx.sender(); - let nonce = tx.nonce(); - let hash = tx.hash(); - - // The transaction might be old, let's check that. - // This has to be the first test, otherwise calculating - // nonce height would result in overflow. - if nonce < state_nonce { - // Droping transaction - trace!(target: "txqueue", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, state_nonce); - return Err(transaction::Error::Old); - } - - // Update nonces of transactions in future (remove old transactions) - self.update_future(&address, state_nonce); - // State nonce could be updated. Maybe there are some more items waiting in future? - self.move_matching_future_to_current(address, state_nonce, state_nonce); - // Check the next expected nonce (might be updated by move above) - let next_nonce = self.last_nonces - .get(&address) - .cloned() - .map_or(state_nonce, |n| n + U256::one()); - - if tx.origin.is_local() { - self.mark_transactions_local(&address); - } - - // Future transaction - if nonce > next_nonce { - // We have a gap - put to future. - // Insert transaction (or replace old one with lower gas price) - check_too_cheap( - Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.future, &mut self.by_hash, &mut self.local_transactions) - )?; - // Enforce limit in Future - let removed = self.future.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - // Return an error if this transaction was not imported because of limit. - check_if_removed(&address, &nonce, removed)?; - - debug!(target: "txqueue", "Importing transaction to future: {:?}", hash); - debug!(target: "txqueue", "status: {:?}", self.status()); - return Ok(transaction::ImportResult::Future); - } - - // We might have filled a gap - move some more transactions from future - self.move_matching_future_to_current(address, nonce, state_nonce); - self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); - - // Replace transaction if any - check_too_cheap( - Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.current, &mut self.by_hash, &mut self.local_transactions) - )?; - // Keep track of highest nonce stored in current - let new_max = self.last_nonces.get(&address).map_or(nonce, |n| cmp::max(nonce, *n)); - self.last_nonces.insert(address, new_max); - - // Also enforce the limit - let removed = self.current.enforce_limit(&mut self.by_hash, &mut self.local_transactions); - // If some transaction were removed because of limit we need to update last_nonces also. - self.update_last_nonces(&removed); - // Trigger error if the transaction we are importing was removed. - check_if_removed(&address, &nonce, removed)?; - - debug!(target: "txqueue", "Imported transaction to current: {:?}", hash); - debug!(target: "txqueue", "status: {:?}", self.status()); - Ok(transaction::ImportResult::Current) - } - - /// Updates - fn update_last_nonces(&mut self, removed_min_nonces: &Option>) { - if let Some(ref min_nonces) = *removed_min_nonces { - for (sender, nonce) in min_nonces.iter() { - if *nonce == U256::zero() { - self.last_nonces.remove(sender); - } else { - self.last_nonces.insert(*sender, *nonce - U256::one()); - } - } - } - } - - /// Replaces transaction in given set (could be `future` or `current`). - /// - /// If there is already transaction with same `(sender, nonce)` it will be replaced iff `gas_price` is higher. - /// One of the transactions is dropped from set and also removed from queue entirely (from `by_hash`). - /// - /// Returns `true` if transaction actually got to the queue (`false` if there was already a transaction with higher - /// gas_price) - fn replace_transaction( - tx: VerifiedTransaction, - base_nonce: U256, - min_gas_price: (U256, PrioritizationStrategy), - set: &mut TransactionSet, - by_hash: &mut HashMap, - local: &mut LocalTransactionsList, - ) -> bool { - let order = TransactionOrder::for_transaction(&tx, base_nonce, min_gas_price.0, min_gas_price.1); - let hash = tx.hash(); - let address = tx.sender(); - let nonce = tx.nonce(); - - let old_hash = by_hash.insert(hash, tx); - assert!(old_hash.is_none(), "Each hash has to be inserted exactly once."); - - trace!(target: "txqueue", "Inserting: {:?}", order); - - if let Some(old) = set.insert(address, nonce, order.clone()) { - Self::replace_orders(address, nonce, old, order, set, by_hash, local) - } else { - true - } - } - - fn replace_orders( - address: Address, - nonce: U256, - old: TransactionOrder, - order: TransactionOrder, - set: &mut TransactionSet, - by_hash: &mut HashMap, - local: &mut LocalTransactionsList, - ) -> bool { - // There was already transaction in queue. Let's check which one should stay - let old_hash = old.hash; - let new_hash = order.hash; - - let old_gas_price = old.gas_price; - let new_gas_price = order.gas_price; - let min_required_gas_price = old_gas_price + (old_gas_price >> GAS_PRICE_BUMP_SHIFT); - - if min_required_gas_price > new_gas_price { - trace!(target: "txqueue", "Didn't insert transaction because gas price was too low: {:?} ({:?} stays in the queue)", order.hash, old.hash); - // Put back old transaction since it has greater priority (higher gas_price) - set.insert(address, nonce, old); - // and remove new one - let order = by_hash.remove(&order.hash).expect("The hash has been just inserted and no other line is altering `by_hash`."); - if order.origin.is_local() { - local.mark_replaced(order.transaction, old_gas_price, old_hash); - } - false - } else { - trace!(target: "txqueue", "Replaced transaction: {:?} with transaction with higher gas price: {:?}", old.hash, order.hash); - // Make sure we remove old transaction entirely - let old = by_hash.remove(&old.hash).expect("The hash is coming from `future` so it has to be in `by_hash`."); - if old.origin.is_local() { - local.mark_replaced(old.transaction, new_gas_price, new_hash); - } - true - } - } -} - -fn check_too_cheap(is_in: bool) -> Result<(), transaction::Error> { - if is_in { - Ok(()) - } else { - Err(transaction::Error::TooCheapToReplace) - } -} - -fn check_if_removed(sender: &Address, nonce: &U256, dropped: Option>) -> Result<(), - transaction::Error> { - match dropped { - Some(ref dropped) => match dropped.get(sender) { - Some(min) if nonce >= min => { - Err(transaction::Error::LimitReached) - }, - _ => Ok(()), - }, - _ => Ok(()), - } -} - - -#[cfg(test)] -pub mod test { - use ethereum_types::{U256, Address}; - use super::*; - use ethkey::{Random, Generator}; - use rustc_hex::FromHex; - use transaction::Transaction; - - pub struct DummyTransactionDetailsProvider { - account_details: AccountDetails, - gas_required: U256, - service_transactions_check_result: Result, - } - - impl Default for DummyTransactionDetailsProvider { - fn default() -> Self { - DummyTransactionDetailsProvider { - account_details: default_account_details(), - gas_required: U256::zero(), - service_transactions_check_result: Ok(false), - } - } - } - - impl DummyTransactionDetailsProvider { - pub fn with_account(mut self, account_details: AccountDetails) -> Self { - self.account_details = account_details; - self - } - - pub fn with_account_nonce(mut self, nonce: U256) -> Self { - self.account_details.nonce = nonce; - self - } - - pub fn with_tx_gas_required(mut self, gas_required: U256) -> Self { - self.gas_required = gas_required; - self - } - - pub fn service_transaction_checker_returns_error(mut self, error: &str) -> Self { - self.service_transactions_check_result = Err(error.to_owned()); - self - } - - pub fn service_transaction_checker_accepts(mut self, accepts: bool) -> Self { - self.service_transactions_check_result = Ok(accepts); - self - } - } - - impl TransactionDetailsProvider for DummyTransactionDetailsProvider { - fn fetch_account(&self, _address: &Address) -> AccountDetails { - AccountDetails { - nonce: self.account_details.nonce, - balance: self.account_details.balance, - } - } - - fn estimate_gas_required(&self, _tx: &SignedTransaction) -> U256 { - self.gas_required - } - - fn is_service_transaction_acceptable(&self, _tx: &SignedTransaction) -> Result { - self.service_transactions_check_result.clone() - } - } - - fn unwrap_tx_err(err: Result) -> transaction::Error { - err.unwrap_err() - } - - fn default_nonce() -> U256 { 123.into() } - fn default_gas_val() -> U256 { 100_000.into() } - fn default_gas_price() -> U256 { 1.into() } - - fn new_unsigned_tx(nonce: U256, gas: U256, gas_price: U256) -> Transaction { - Transaction { - action: transaction::Action::Create, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: gas, - gas_price: gas_price, - nonce: nonce - } - } - - fn new_tx(nonce: U256, gas_price: U256) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret(), None) - } - - fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction { - let keypair = Random.generate().unwrap(); - new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret(), None) - } - - fn new_tx_default() -> SignedTransaction { - new_tx(default_nonce(), default_gas_price()) - } - - fn default_account_details() -> AccountDetails { - AccountDetails { - nonce: default_nonce(), - balance: !U256::zero() - } - } - - fn default_account_details_for_addr(_a: &Address) -> AccountDetails { - default_account_details() - } - - fn default_tx_provider() -> DummyTransactionDetailsProvider { - DummyTransactionDetailsProvider::default() - } - - fn new_tx_pair(nonce: U256, gas_price: U256, nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { - let tx1 = new_unsigned_tx(nonce, default_gas_val(), gas_price); - let tx2 = new_unsigned_tx(nonce + nonce_increment, default_gas_val(), gas_price + gas_price_increment); - - let keypair = Random.generate().unwrap(); - let secret = &keypair.secret(); - (tx1.sign(secret, None).into(), tx2.sign(secret, None).into()) - } - - /// Returns two consecutive transactions, both with increased gas price - fn new_tx_pair_with_gas_price_increment(gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { - let gas = default_gas_price() + gas_price_increment; - let tx1 = new_unsigned_tx(default_nonce(), default_gas_val(), gas); - let tx2 = new_unsigned_tx(default_nonce() + 1.into(), default_gas_val(), gas); - - let keypair = Random.generate().unwrap(); - let secret = &keypair.secret(); - (tx1.sign(secret, None).into(), tx2.sign(secret, None).into()) - } - - fn new_tx_pair_default(nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { - new_tx_pair(default_nonce(), default_gas_price(), nonce_increment, gas_price_increment) - } - - /// Returns two transactions with identical (sender, nonce) but different gas price/hash. - fn new_similar_tx_pair() -> (SignedTransaction, SignedTransaction) { - new_tx_pair_default(0.into(), 1.into()) - } - - #[test] - fn test_ordering() { - assert_eq!(TransactionOrigin::Local.cmp(&TransactionOrigin::External), Ordering::Less); - assert_eq!(TransactionOrigin::RetractedBlock.cmp(&TransactionOrigin::Local), Ordering::Less); - assert_eq!(TransactionOrigin::RetractedBlock.cmp(&TransactionOrigin::External), Ordering::Less); - - assert_eq!(TransactionOrigin::External.cmp(&TransactionOrigin::Local), Ordering::Greater); - assert_eq!(TransactionOrigin::Local.cmp(&TransactionOrigin::RetractedBlock), Ordering::Greater); - assert_eq!(TransactionOrigin::External.cmp(&TransactionOrigin::RetractedBlock), Ordering::Greater); - } - - fn transaction_order(tx: &VerifiedTransaction, nonce: U256) -> TransactionOrder { - TransactionOrder::for_transaction(tx, nonce, 0.into(), PrioritizationStrategy::GasPriceOnly) - } - - #[test] - fn should_return_correct_nonces_when_dropped_because_of_limit() { - // given - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 2, - usize::max_value(), - !U256::zero(), - !U256::zero(), - ); - let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into()); - let sender = tx1.sender(); - let nonce = tx1.nonce; - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into())); - - // when - let tx = new_tx(123.into(), 1.into()); - let res = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - // No longer the case as we don't even consider a transaction that isn't above a full - // queue's minimum gas price. - // We may want to reconsider this in the near future so leaving this code in as a - // possible alternative. - /* - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.last_nonce(&sender), Some(nonce)); - */ - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientGasPrice { - minimal: 2.into(), - got: 1.into(), - }); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.last_nonce(&sender), Some(tx2.nonce)); - } - - #[test] - fn should_create_transaction_set() { - // given - let mut local = LocalTransactionsList::default(); - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 1, - total_gas_limit: !U256::zero(), - memory_limit: usize::max_value(), - }; - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None, 0, 1); - let mut by_hash = { - let mut x = HashMap::new(); - let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None, 0, 1); - x.insert(tx1.hash(), tx1); - x.insert(tx2.hash(), tx2); - x - }; - // Insert both transactions - let order1 = transaction_order(&tx1, U256::zero()); - set.insert(tx1.sender(), tx1.nonce(), order1.clone()); - let order2 = transaction_order(&tx2, U256::zero()); - set.insert(tx2.sender(), tx2.nonce(), order2.clone()); - assert_eq!(set.by_priority.len(), 2); - assert_eq!(set.by_address.len(), 2); - - // when - set.enforce_limit(&mut by_hash, &mut local); - - // then - assert_eq!(by_hash.len(), 1); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_priority.iter().next().unwrap().clone(), order1); - set.clear(); - assert_eq!(set.by_priority.len(), 0); - assert_eq!(set.by_address.len(), 0); - } - - #[test] - fn should_replace_transaction_in_set() { - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 1, - total_gas_limit: !U256::zero(), - memory_limit: 0, - }; - // Create two transactions with same nonce - // (same hash) - let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into()); - let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None, 0, 1); - let by_hash = { - let mut x = HashMap::new(); - let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None, 0, 0); - let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None, 0, 1); - x.insert(tx1.hash(), tx1); - x.insert(tx2.hash(), tx2); - x - }; - // Insert both transactions - let order1 = transaction_order(&tx1, U256::zero()); - set.insert(tx1.sender(), tx1.nonce(), order1.clone()); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_gas_price.len(), 1); - assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into()); - assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1); - // Two different orders (imagine nonce changed in the meantime) - let order2 = transaction_order(&tx2, U256::one()); - set.insert(tx2.sender(), tx2.nonce(), order2.clone()); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_gas_price.len(), 1); - assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into()); - assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1); - - // then - assert_eq!(by_hash.len(), 1); - assert_eq!(set.by_priority.len(), 1); - assert_eq!(set.by_address.len(), 1); - assert_eq!(set.by_gas_price.len(), 1); - assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into()); - assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1); - assert_eq!(set.by_priority.iter().next().unwrap().clone(), order2); - } - - #[test] - fn should_not_insert_same_transaction_twice_into_set() { - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 2, - total_gas_limit: !U256::zero(), - memory_limit: 0, - }; - let tx = new_tx_default(); - let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None, 0, 0); - let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); - assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none()); - let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External, None, 0, 1); - let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); - assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some()); - } - - #[test] - fn should_give_correct_gas_price_entry_limit() { - let mut set = TransactionSet { - by_priority: BTreeSet::new(), - by_address: Table::new(), - by_gas_price: Default::default(), - limit: 1, - total_gas_limit: !U256::zero(), - memory_limit: 0, - }; - - assert_eq!(set.gas_price_entry_limit(), 0.into()); - let tx = new_tx_default(); - let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None, 0, 0); - let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); - assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none()); - assert_eq!(set.gas_price_entry_limit(), 2.into()); - } - - #[test] - fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_similar_tx_pair(); - let prev_nonce = default_account_details().nonce - U256::one(); - - // First insert one transaction to future - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)); - assert_eq!(res.unwrap(), transaction::ImportResult::Future); - assert_eq!(txq.status().future, 1); - - // now import second transaction to current - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // and then there should be only one transaction in current (the one with higher gas_price) - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.status().pending, 1); - assert_eq!(txq.status().future, 0); - assert_eq!(txq.current.by_priority.len(), 1); - assert_eq!(txq.current.by_address.len(), 1); - let top = txq.top_transactions(); - assert_eq!(top[0], tx2); - } - - #[test] - fn should_move_all_transactions_from_future() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 1.into()); - let prev_nonce = default_account_details().nonce - U256::one(); - - // First insert one transaction to future - let res = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)); - assert_eq!(res.unwrap(), transaction::ImportResult::Future); - assert_eq!(txq.status().future, 1); - - // now import second transaction to current - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.status().pending, 2); - assert_eq!(txq.status().future, 0); - assert_eq!(txq.current.by_priority.len(), 2); - assert_eq!(txq.current.by_address.len(), 2); - let top = txq.top_transactions(); - assert_eq!(top[0], tx); - assert_eq!(top[1], tx2); - } - - #[test] - fn should_import_tx() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - } - - #[test] - fn should_order_by_gas() { - // given - let mut txq = TransactionQueue::new(PrioritizationStrategy::GasAndGasPrice); - let tx1 = new_tx_with_gas(50000.into(), 40.into()); - let tx2 = new_tx_with_gas(40000.into(), 30.into()); - let tx3 = new_tx_with_gas(30000.into(), 10.into()); - let tx4 = new_tx_with_gas(50000.into(), 20.into()); - txq.set_minimal_gas_price(15.into()); - - // when - let res1 = txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res2 = txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res3 = txq.add(tx3, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res4 = txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res1.unwrap(), transaction::ImportResult::Current); - assert_eq!(res2.unwrap(), transaction::ImportResult::Current); - assert_eq!(unwrap_tx_err(res3), transaction::Error::InsufficientGasPrice { - minimal: U256::from(15), - got: U256::from(10), - }); - assert_eq!(res4.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 3); - assert_eq!(txq.top_transactions()[0].gas, 40000.into()); - assert_eq!(txq.top_transactions()[1].gas, 50000.into()); - assert_eq!(txq.top_transactions()[2].gas, 50000.into()); - assert_eq!(txq.top_transactions()[1].gas_price, 40.into()); - assert_eq!(txq.top_transactions()[2].gas_price, 20.into()); - } - - #[test] - fn should_order_by_gas_factor() { - // given - let mut txq = TransactionQueue::new(PrioritizationStrategy::GasFactorAndGasPrice); - - let tx1 = new_tx_with_gas(150_000.into(), 40.into()); - let tx2 = new_tx_with_gas(40_000.into(), 16.into()); - let tx3 = new_tx_with_gas(30_000.into(), 15.into()); - let tx4 = new_tx_with_gas(150_000.into(), 62.into()); - txq.set_minimal_gas_price(15.into()); - - // when - let res1 = txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res2 = txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res3 = txq.add(tx3, TransactionOrigin::External, 0, None, &default_tx_provider()); - let res4 = txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(res1.unwrap(), transaction::ImportResult::Current); - assert_eq!(res2.unwrap(), transaction::ImportResult::Current); - assert_eq!(res3.unwrap(), transaction::ImportResult::Current); - assert_eq!(res4.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 4); - assert_eq!(txq.top_transactions()[0].gas, 30_000.into()); - assert_eq!(txq.top_transactions()[1].gas, 150_000.into()); - assert_eq!(txq.top_transactions()[2].gas, 40_000.into()); - assert_eq!(txq.top_transactions()[3].gas, 150_000.into()); - assert_eq!(txq.top_transactions()[0].gas_price, 15.into()); - assert_eq!(txq.top_transactions()[1].gas_price, 62.into()); - assert_eq!(txq.top_transactions()[2].gas_price, 16.into()); - assert_eq!(txq.top_transactions()[3].gas_price, 40.into()); - } - - #[test] - fn tx_gas_limit_should_never_overflow() { - // given - let mut txq = TransactionQueue::default(); - txq.set_gas_limit(U256::zero()); - assert_eq!(txq.block_gas_limit, U256::zero()); - - // when - txq.set_gas_limit(!U256::zero()); - - // then - assert_eq!(txq.block_gas_limit, !U256::zero()); - } - - #[test] - fn should_not_import_transaction_above_gas_limit() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let gas = tx.gas; - let limit = gas / U256::from(2); - txq.set_gas_limit(limit); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::GasLimitExceeded { - limit: U256::from(50_000), - got: gas, - }); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - - #[test] - fn should_drop_transactions_from_senders_without_balance() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let account = AccountDetails { - nonce: default_account_details().nonce, - balance: U256::one() - }; - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account(account)); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientBalance { - balance: U256::from(1), - cost: U256::from(100_100), - }); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_not_import_transaction_below_min_gas_price_threshold_if_external() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - txq.set_minimal_gas_price(tx.gas_price + U256::one()); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientGasPrice { - minimal: U256::from(2), - got: U256::from(1), - }); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_import_transaction_below_min_gas_price_threshold_if_local() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - txq.set_minimal_gas_price(tx.gas_price + U256::one()); - - // when - let res = txq.add(tx, TransactionOrigin::Local, 0, None, &default_tx_provider()); - - // then - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_import_txs_from_same_sender() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_prioritize_local_transactions_within_same_nonce_height() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - // the second one has same nonce but higher `gas_price` - let (_, tx2) = new_similar_tx_pair(); - - // when - // first insert the one with higher gas price - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - // then the one with lower gas price, but local - txq.add(tx.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); // local should be first - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn when_importing_local_should_mark_others_from_the_same_sender_as_local() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - // the second one has same nonce but higher `gas_price` - let (_, tx0) = new_similar_tx_pair(); - - txq.add(tx0.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - // the one with higher gas price is first - let top = txq.top_transactions(); - assert_eq!(top[0], tx0); - assert_eq!(top[1], tx1); - - // when - // insert second as local - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - // the order should be updated - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], tx2); - assert_eq!(top[2], tx0); - } - - #[test] - fn should_prioritize_reimported_transactions_within_same_nonce_height() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - // the second one has same nonce but higher `gas_price` - let (_, tx2) = new_similar_tx_pair(); - - // when - // first insert local one with higher gas price - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - // then the one with lower gas price, but from retracted block - txq.add(tx.clone(), TransactionOrigin::RetractedBlock, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); // retracted should be first - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_not_prioritize_local_transactions_with_different_nonce_height() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], tx); - assert_eq!(top[1], tx2); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_penalize_transactions_from_sender_in_future() { - // given - let prev_nonce = default_account_details().nonce - U256::one(); - let mut txq = TransactionQueue::default(); - // txa, txb - slightly bigger gas price to have consistent ordering - let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); - let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); - - // insert everything - txq.add(txa.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(txb.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - - assert_eq!(txq.status().future, 4); - - // when - txq.penalize(&tx1.hash()); - - // then - let top: Vec<_> = txq.future_transactions().into_iter().map(|tx| tx.transaction).collect(); - assert_eq!(top[0], txa); - assert_eq!(top[1], txb); - assert_eq!(top[2], tx1); - assert_eq!(top[3], tx2); - assert_eq!(top.len(), 4); - } - - #[test] - fn should_not_penalize_local_transactions() { - // given - let mut txq = TransactionQueue::default(); - // txa, txb - slightly bigger gas price to have consistent ordering - let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); - let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); - - // insert everything - txq.add(txa.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(txb.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], txa); - assert_eq!(top[2], tx2); - assert_eq!(top[3], txb); - assert_eq!(top.len(), 4); - - // when - txq.penalize(&tx1.hash()); - - // then (order is the same) - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], txa); - assert_eq!(top[2], tx2); - assert_eq!(top[3], txb); - assert_eq!(top.len(), 4); - } - - #[test] - fn should_penalize_transactions_from_sender() { - // given - let mut txq = TransactionQueue::default(); - // txa, txb - slightly bigger gas price to have consistent ordering - let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); - let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); - - // insert everything - txq.add(txa.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(txb.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - let top = txq.top_transactions(); - assert_eq!(top[0], tx1); - assert_eq!(top[1], txa); - assert_eq!(top[2], tx2); - assert_eq!(top[3], txb); - assert_eq!(top.len(), 4); - - // when - txq.penalize(&tx1.hash()); - - // then - let top = txq.top_transactions(); - assert_eq!(top[0], txa); - assert_eq!(top[1], txb); - assert_eq!(top[2], tx1); - assert_eq!(top[3], tx2); - assert_eq!(top.len(), 4); - } - - #[test] - fn should_return_pending_hashes() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let top = txq.pending_hashes(); - assert_eq!(top[0], tx.hash()); - assert_eq!(top[1], tx2.hash()); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_put_transaction_to_futures_if_gap_detected() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(2.into(), 0.into()); - - // when - let res1 = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - let res2 = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(res1, transaction::ImportResult::Current); - assert_eq!(res2, transaction::ImportResult::Future); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 1); - let top = txq.top_transactions(); - assert_eq!(top.len(), 1); - assert_eq!(top[0], tx); - } - - #[test] - fn should_handle_min_block() { - // given - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // when - let res1 = txq.add(tx.clone(), TransactionOrigin::External, 0, Some(transaction::Condition::Number(1)), &default_tx_provider()).unwrap(); - let res2 = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(res1, transaction::ImportResult::Current); - assert_eq!(res2, transaction::ImportResult::Current); - let top = txq.top_transactions_at(0, 0, None); - assert_eq!(top.len(), 0); - let top = txq.top_transactions_at(1, 0, None); - assert_eq!(top.len(), 2); - } - - #[test] - fn should_correctly_update_futures_when_removing() { - // given - let prev_nonce = default_account_details().nonce - U256::one(); - let next2_nonce = default_nonce() + U256::from(3); - - let mut txq = TransactionQueue::default(); - - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(); - assert_eq!(txq.status().future, 2); - - // when - txq.cull(tx.sender(), next2_nonce); - // should remove both transactions since they are not valid - - // then - assert_eq!(txq.status().pending, 0); - assert_eq!(txq.status().future, 0); - } - - #[test] - fn should_move_transactions_if_gap_filled() { - // given - let mut txq = TransactionQueue::default(); - let kp = Random.generate().unwrap(); - let secret = kp.secret(); - let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret, None).into(); - let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None).into(); - let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None).into(); - - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 1); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - - // when - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.pending, 3); - assert_eq!(stats.future, 0); - assert_eq!(txq.future.by_priority.len(), 0); - assert_eq!(txq.future.by_address.len(), 0); - assert_eq!(txq.future.by_gas_price.len(), 0); - } - - #[test] - fn should_remove_transaction() { - // given - let mut txq2 = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(3.into(), 0.into()); - txq2.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq2.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq2.status().pending, 1); - assert_eq!(txq2.status().future, 1); - - // when - txq2.cull(tx.sender(), tx.nonce + U256::one()); - txq2.cull(tx2.sender(), tx2.nonce + U256::one()); - - // then - let stats = txq2.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_move_transactions_to_future_if_gap_introduced() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - let tx3 = new_tx_default(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 3); - - // when - txq.remove(&tx.hash(), &|_| default_nonce(), RemovalReason::Invalid); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 1); - assert_eq!(stats.pending, 1); - } - - #[test] - fn should_clear_queue() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - - // add - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - let stats = txq.status(); - assert_eq!(stats.pending, 2); - - // when - txq.clear(); - - // then - let stats = txq.status(); - assert_eq!(stats.pending, 0); - } - - #[test] - fn should_drop_old_transactions_when_hitting_the_limit() { - // given - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 1, - usize::max_value(), - !U256::zero(), - !U256::zero() - ); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - let sender = tx.sender(); - let nonce = tx.nonce; - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 1); - - // when - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - let t = txq.top_transactions(); - assert_eq!(unwrap_tx_err(res), transaction::Error::InsufficientGasPrice { minimal: 2.into(), got: 1.into() }); - assert_eq!(txq.status().pending, 1); - assert_eq!(t.len(), 1); - assert_eq!(t[0], tx); - assert_eq!(txq.last_nonce(&sender), Some(nonce)); - } - - #[test] - fn should_limit_future_transactions() { - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 1, - usize::max_value(), - !U256::zero(), - !U256::zero(), - ); - txq.current.set_limit(10); - let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into()); - let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into()); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 2); - - // when - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx4.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(txq.status().future, 1); - } - - #[test] - fn should_limit_by_gas() { - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 100, - usize::max_value(), - default_gas_val() * U256::from(2), - !U256::zero() - ); - let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); - let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - // limited by gas - txq.add(tx4.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap_err(); - assert_eq!(txq.status().pending, 2); - } - - #[test] - fn should_keep_own_transactions_above_gas_limit() { - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 100, - usize::max_value(), - default_gas_val() * U256::from(2), - !U256::zero() - ); - let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); - let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); - let (tx5, _) = new_tx_pair_default(U256::from(1), U256::from(2)); - txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - // Not accepted because of limit - txq.add(tx5.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap_err(); - txq.add(tx3.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx4.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 4); - } - - #[test] - fn should_drop_transactions_with_old_nonces() { - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let last_nonce = tx.nonce + U256::one(); - - // when - let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(last_nonce)); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::Old); - let stats = txq.status(); - assert_eq!(stats.pending, 0); - assert_eq!(stats.future, 0); - } - - #[test] - fn should_not_insert_same_transaction_twice() { - // given - let nonce = default_account_details().nonce + U256::one(); - let mut txq = TransactionQueue::default(); - let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - assert_eq!(txq.status().pending, 0); - - // when - let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce)); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::AlreadyImported); - let stats = txq.status(); - assert_eq!(stats.future, 1); - assert_eq!(stats.pending, 0); - } - - #[test] - fn should_accept_same_transaction_twice_if_removed() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 2); - - // when - txq.remove(&tx1.hash(), &|_| default_nonce(), RemovalReason::Invalid); - assert_eq!(txq.status().pending, 0); - assert_eq!(txq.status().future, 1); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 2); - } - - #[test] - fn should_not_move_to_future_if_state_nonce_is_higher() { - // given - let mut txq = TransactionQueue::default(); - let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); - let tx3 = new_tx_default(); - txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().pending, 3); - - // when - txq.cull(tx.sender(), default_nonce() + U256::one()); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 2); - } - - #[test] - fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() { - // given - let mut txq = TransactionQueue::default(); - let keypair = Random.generate().unwrap(); - let tx = new_unsigned_tx(123.into(), default_gas_val(), 20.into()).sign(keypair.secret(), None); - let tx2 = { - let mut tx2 = (**tx).clone(); - tx2.gas_price = U256::from(21); - tx2.sign(keypair.secret(), None) - }; - - // when - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - let res = txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()); - - // then - assert_eq!(unwrap_tx_err(res), transaction::Error::TooCheapToReplace); - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 0); - assert_eq!(txq.top_transactions()[0].gas_price, U256::from(20)); - } - - #[test] - fn should_replace_same_transaction_when_has_higher_fee() { - // given - let mut txq = TransactionQueue::default(); - let keypair = Random.generate().unwrap(); - let tx = new_unsigned_tx(123.into(), default_gas_val(), 10.into()).sign(keypair.secret(), None); - let tx2 = { - let mut tx2 = (**tx).clone(); - tx2.gas_price = U256::from(20); - tx2.sign(keypair.secret(), None) - }; - - // when - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.pending, 1); - assert_eq!(stats.future, 0); - assert_eq!(txq.top_transactions()[0].gas_price, U256::from(20)); - } - - #[test] - fn should_replace_same_transaction_when_importing_to_futures() { - // given - let mut txq = TransactionQueue::default(); - let keypair = Random.generate().unwrap(); - let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret(), None); - let tx1 = { - let mut tx1 = (**tx0).clone(); - tx1.nonce = U256::from(124); - tx1.sign(keypair.secret(), None) - }; - let tx2 = { - let mut tx2 = (**tx1).clone(); - tx2.gas_price = U256::from(200); - tx2.sign(keypair.secret(), None) - }; - - // when - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.status().future, 1); - txq.add(tx0, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 2); - assert_eq!(txq.top_transactions()[1].gas_price, U256::from(200)); - } - - #[test] - fn should_recalculate_height_when_removing_from_future() { - // given - let previous_nonce = default_account_details().nonce - U256::one(); - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(previous_nonce)).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(previous_nonce)).unwrap(); - assert_eq!(txq.status().future, 2); - - // when - txq.remove(&tx1.hash(), &|_| default_nonce() + 1.into(), RemovalReason::Invalid); - - // then - let stats = txq.status(); - assert_eq!(stats.future, 0); - assert_eq!(stats.pending, 1); - } - - #[test] - fn should_return_none_when_transaction_from_given_address_does_not_exist() { - // given - let txq = TransactionQueue::default(); - - // then - assert_eq!(txq.last_nonce(&Address::default()), None); - } - - #[test] - fn should_return_correct_nonce_when_transactions_from_given_address_exist() { - // given - let mut txq = TransactionQueue::default(); - let tx = new_tx_default(); - let from = tx.sender(); - let nonce = tx.nonce; - - // when - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce)).unwrap(); - - // then - assert_eq!(txq.last_nonce(&from), Some(nonce)); - } - - #[test] - fn should_remove_old_transaction_even_if_newer_transaction_was_not_known() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let (nonce1, nonce2) = (tx1.nonce, tx2.nonce); - - // Insert first transaction - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce1)).unwrap(); - - // when - txq.cull(tx2.sender(), nonce2 + U256::one()); - - // then - assert!(txq.top_transactions().is_empty()); - } - - #[test] - fn should_return_valid_last_nonce_after_cull() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(4.into(), 0.into()); - let sender = tx1.sender(); - let (nonce1, nonce2) = (tx1.nonce, tx2.nonce); - - // when - // Insert first transaction - assert_eq!(txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce1)).unwrap(), transaction::ImportResult::Current); - // Second should go to future - assert_eq!(txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(nonce1)).unwrap(), transaction::ImportResult::Future); - // Now block is imported - txq.cull(sender, nonce2 - U256::from(1)); - // tx2 should be not be promoted to current - assert_eq!(txq.status().pending, 0); - assert_eq!(txq.status().future, 1); - - // then - assert_eq!(txq.last_nonce(&sender), None); - } - - #[test] - fn should_return_true_if_there_is_local_transaction_pending() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - assert_eq!(txq.has_local_pending_transactions(), false); - - // when - assert_eq!(txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.has_local_pending_transactions(), false); - assert_eq!(txq.add(tx2, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(), - transaction::ImportResult::Current); - - // then - assert_eq!(txq.has_local_pending_transactions(), true); - } - - #[test] - fn should_keep_right_order_in_future() { - // given - let mut txq = TransactionQueue::with_limits( - PrioritizationStrategy::GasPriceOnly, - 1, - usize::max_value(), - !U256::zero(), - !U256::zero() - ); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let prev_nonce = default_account_details().nonce - U256::one(); - - // when - assert_eq!(txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(), transaction::ImportResult::Future); - assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider().with_account_nonce(prev_nonce)).unwrap(), transaction::ImportResult::Future); - - // then - assert_eq!(txq.future.by_priority.len(), 1); - assert_eq!(txq.future.by_priority.iter().next().unwrap().hash, tx1.hash()); - } - - #[test] - fn should_return_correct_last_nonce() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2, tx2_2, tx3) = { - let keypair = Random.generate().unwrap(); - let secret = &keypair.secret(); - let nonce = 123.into(); - let gas = default_gas_val(); - let tx = new_unsigned_tx(nonce, gas, 1.into()); - let tx2 = new_unsigned_tx(nonce + 1.into(), gas, 1.into()); - let tx2_2 = new_unsigned_tx(nonce + 1.into(), gas, 5.into()); - let tx3 = new_unsigned_tx(nonce + 2.into(), gas, 1.into()); - - - (tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None)) - }; - let sender = tx1.sender(); - txq.add(tx1, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.future.by_priority.len(), 0); - assert_eq!(txq.current.by_priority.len(), 3); - - // when - let res = txq.add(tx2_2, TransactionOrigin::Local, 0, None, &default_tx_provider()); - - // then - assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into()); - assert_eq!(res.unwrap(), transaction::ImportResult::Current); - assert_eq!(txq.current.by_priority.len(), 3); - } - - #[test] - fn should_reject_transactions_below_base_gas() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let high_gas = 100_001.into(); - - // when - let res1 = txq.add(tx1, TransactionOrigin::Local, 0, None, &default_tx_provider()); - let res2 = txq.add(tx2, TransactionOrigin::Local, 0, None, &default_tx_provider().with_tx_gas_required(high_gas)); - - // then - assert_eq!(res1.unwrap(), transaction::ImportResult::Current); - assert_eq!(unwrap_tx_err(res2), transaction::Error::InsufficientGas { - minimal: 100_001.into(), - got: 100_000.into(), - }); - - } - - #[test] - fn should_clear_all_old_transactions() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let (tx3, tx4) = new_tx_pair_default(1.into(), 0.into()); - let next_nonce = |_: &Address| - AccountDetails { nonce: default_nonce() + U256::one(), balance: !U256::zero() }; - - // Insert all transactions - txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx3, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.top_transactions().len(), 4); - - // when - txq.remove_old(&next_nonce, 0); - - // then - assert_eq!(txq.top_transactions().len(), 2); - } - - #[test] - fn should_remove_out_of_date_transactions_occupying_queue() { - // given - let mut txq = TransactionQueue::default(); - let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); - let (tx3, tx4) = new_tx_pair_default(2.into(), 0.into()); - - // Insert all transactions - txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 5, None, &default_tx_provider()).unwrap(); - txq.add(tx3.clone(), TransactionOrigin::External, 10, None, &default_tx_provider()).unwrap(); - txq.add(tx4, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - assert_eq!(txq.top_transactions().len(), 3); - assert_eq!(txq.future_transactions().len(), 1); - - // when - txq.remove_old(&default_account_details_for_addr, 9 + super::DEFAULT_QUEUING_PERIOD); - - // then - assert_eq!(txq.top_transactions().len(), 2); - assert_eq!(txq.future_transactions().len(), 0); - assert_eq!(txq.top_transactions(), vec![tx1, tx3]); - } - - #[test] - fn should_accept_local_service_transaction() { - // given - let tx = new_tx(123.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - txq.add(tx, TransactionOrigin::Local, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(txq.top_transactions().len(), 1); - } - - #[test] - fn should_not_accept_external_service_transaction_if_sender_not_certified() { - // given - let tx1 = new_tx(123.into(), 0.into()); - let tx2 = new_tx(456.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - assert_eq!(unwrap_tx_err(txq.add(tx1, TransactionOrigin::External, 0, None, &default_tx_provider())), - transaction::Error::InsufficientGasPrice { - minimal: 100.into(), - got: 0.into(), - }); - assert_eq!(unwrap_tx_err(txq.add(tx2, TransactionOrigin::RetractedBlock, 0, None, &default_tx_provider())), - transaction::Error::InsufficientGasPrice { - minimal: 100.into(), - got: 0.into(), - }); - - // then - assert_eq!(txq.top_transactions().len(), 0); - } - - #[test] - fn should_not_accept_external_service_transaction_if_contract_returns_error() { - // given - let tx = new_tx(123.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - let details_provider = default_tx_provider().service_transaction_checker_returns_error("Contract error"); - assert_eq!(unwrap_tx_err(txq.add(tx, TransactionOrigin::External, 0, None, &details_provider)), - transaction::Error::InsufficientGasPrice { - minimal: 100.into(), - got: 0.into(), - }); - - // then - assert_eq!(txq.top_transactions().len(), 0); - } - - #[test] - fn should_accept_external_service_transaction_if_sender_is_certified() { - // given - let tx = new_tx(123.into(), 0.into()); - let mut txq = TransactionQueue::default(); - txq.set_minimal_gas_price(100.into()); - - // when - let details_provider = default_tx_provider().service_transaction_checker_accepts(true); - txq.add(tx, TransactionOrigin::External, 0, None, &details_provider).unwrap(); - - // then - assert_eq!(txq.top_transactions().len(), 1); - } - - #[test] - fn should_not_order_transactions_by_hash() { - // given - let secret1 = "0000000000000000000000000000000000000000000000000000000000000002".parse().unwrap(); - let secret2 = "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap(); - let tx1 = new_unsigned_tx(123.into(), default_gas_val(), 0.into()).sign(&secret1, None); - let tx2 = new_unsigned_tx(123.into(), default_gas_val(), 0.into()).sign(&secret2, None); - let mut txq = TransactionQueue::default(); - - // when - txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - txq.add(tx2, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - - // then - assert_eq!(txq.top_transactions()[0], tx1); - assert_eq!(txq.top_transactions().len(), 2); - } - - #[test] - fn should_not_return_transactions_over_nonce_cap() { - // given - let keypair = Random.generate().unwrap(); - let mut txq = TransactionQueue::default(); - // when - for nonce in 123..130 { - let tx = new_unsigned_tx(nonce.into(), default_gas_val(), default_gas_price()).sign(keypair.secret(), None); - txq.add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap(); - } - - // then - assert_eq!(txq.top_transactions_at(BlockNumber::max_value(), u64::max_value(), Some(127.into())).len(), 4); - } -} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index c2c6f2aa5c..4a4441b89f 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -390,10 +390,12 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { &snapshot_path, restoration_db_handler, &cmd.dirs.ipc_path(), - Arc::new(Miner::with_spec(&spec)), + // TODO [ToDr] don't use test miner here + // (actually don't require miner at all) + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; // free up the spec in memory. @@ -580,10 +582,12 @@ fn start_client( &snapshot_path, restoration_db_handler, &dirs.ipc_path(), - Arc::new(Miner::with_spec(&spec)), + // It's fine to use test version here, + // since we don't care about miner parameters at all + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; drop(spec); diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index cb6470e9b8..c7c484e2bd 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -721,29 +721,25 @@ usage! { "--gas-cap=[GAS]", "A cap on how large we will raise the gas limit per block due to transaction volume.", - ARG arg_tx_queue_mem_limit: (u32) = 2u32, or |c: &Config| c.mining.as_ref()?.tx_queue_mem_limit.clone(), + ARG arg_tx_queue_mem_limit: (u32) = 4u32, or |c: &Config| c.mining.as_ref()?.tx_queue_mem_limit.clone(), "--tx-queue-mem-limit=[MB]", "Maximum amount of memory that can be used by the transaction queue. Setting this parameter to 0 disables limiting.", - ARG arg_tx_queue_size: (usize) = 8192usize, or |c: &Config| c.mining.as_ref()?.tx_queue_size.clone(), + ARG arg_tx_queue_size: (usize) = 8_192usize, or |c: &Config| c.mining.as_ref()?.tx_queue_size.clone(), "--tx-queue-size=[LIMIT]", "Maximum amount of transactions in the queue (waiting to be included in next block).", + ARG arg_tx_queue_per_sender: (Option) = None, or |c: &Config| c.mining.as_ref()?.tx_queue_per_sender.clone(), + "--tx-queue-per-sender=[LIMIT]", + "Maximum number of transactions per sender in the queue. By default it's 1% of the entire queue, but not less than 16.", + ARG arg_tx_queue_gas: (String) = "off", or |c: &Config| c.mining.as_ref()?.tx_queue_gas.clone(), "--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.", ARG arg_tx_queue_strategy: (String) = "gas_price", or |c: &Config| c.mining.as_ref()?.tx_queue_strategy.clone(), "--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.", - - ARG arg_tx_queue_ban_count: (u16) = 1u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_count.clone(), - "--tx-queue-ban-count=[C]", - "Number of times maximal time for execution (--tx-time-limit) can be exceeded before banning sender/recipient/code.", - - ARG arg_tx_queue_ban_time: (u16) = 180u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_time.clone(), - "--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.", + "Prioritization strategy used to order transactions in the queue. S may be: gas_price - Prioritize txs with high gas price", ARG arg_stratum_interface: (String) = "local", or |c: &Config| c.stratum.as_ref()?.interface.clone(), "--stratum-interface=[IP]", @@ -775,7 +771,7 @@ usage! { ARG arg_tx_time_limit: (Option) = None, or |c: &Config| c.mining.as_ref()?.tx_time_limit.clone(), "--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.", + "Maximal time for processing single transaction. If enabled senders of transactions offending the limit will get other transactions penalized.", ARG arg_extra_data: (Option) = None, or |c: &Config| c.mining.as_ref()?.extra_data.clone(), "--extra-data=[STRING]", @@ -1028,6 +1024,13 @@ usage! { "--cache=[MB]", "Equivalent to --cache-size MB.", + ARG arg_tx_queue_ban_count: (u16) = 1u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_count.clone(), + "--tx-queue-ban-count=[C]", + "Not supported.", + + ARG arg_tx_queue_ban_time: (u16) = 180u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_time.clone(), + "--tx-queue-ban-time=[SEC]", + "Not supported.", } } @@ -1232,6 +1235,7 @@ struct Mining { gas_cap: Option, extra_data: Option, tx_queue_size: Option, + tx_queue_per_sender: Option, tx_queue_mem_limit: Option, tx_queue_gas: Option, tx_queue_strategy: Option, @@ -1654,7 +1658,8 @@ mod tests { arg_gas_cap: "6283184".into(), arg_extra_data: Some("Parity".into()), arg_tx_queue_size: 8192usize, - arg_tx_queue_mem_limit: 2u32, + arg_tx_queue_per_sender: None, + arg_tx_queue_mem_limit: 4u32, arg_tx_queue_gas: "off".into(), arg_tx_queue_strategy: "gas_factor".into(), arg_tx_queue_ban_count: 1u16, @@ -1911,6 +1916,7 @@ mod tests { gas_floor_target: None, gas_cap: None, tx_queue_size: Some(8192), + tx_queue_per_sender: None, tx_queue_mem_limit: None, tx_queue_gas: Some("off".into()), tx_queue_strategy: None, diff --git a/parity/cli/presets/config.mining.toml b/parity/cli/presets/config.mining.toml index f6c39bdd6d..6d22a0f087 100644 --- a/parity/cli/presets/config.mining.toml +++ b/parity/cli/presets/config.mining.toml @@ -19,12 +19,13 @@ force_sealing = true reseal_on_txs = "all" # New pending block will be created only once per 4000 milliseconds. reseal_min_period = 4000 -# Parity will keep/relay at most 2048 transactions in queue. -tx_queue_size = 2048 +# Parity will keep/relay at most 8192 transactions in queue. +tx_queue_size = 8192 +tx_queue_per_sender = 128 [footprint] -# If defined will never use more then 256MB for all caches. (Overrides other cache settings). -cache_size = 256 +# If defined will never use more then 1024MB for all caches. (Overrides other cache settings). +cache_size = 1024 [misc] # Logging pattern (`=`, e.g. `own_tx=trace`). diff --git a/parity/configuration.rs b/parity/configuration.rs index d921c9377b..93cc9a4dd6 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::cmp::{max, min}; use std::time::Duration; use std::io::Read; use std::net::SocketAddr; use std::path::{Path, PathBuf}; use std::collections::BTreeMap; +use std::cmp; use std::str::FromStr; use cli::{Args, ArgsError}; use hash::keccak; @@ -30,15 +30,15 @@ use ansi_term::Colour; use sync::{NetworkConfiguration, validate_node_url, self}; use ethcore::ethstore::ethkey::{Secret, Public}; use ethcore::client::{VMType}; -use ethcore::miner::{MinerOptions, Banning, StratumOptions}; +use ethcore::miner::{stratum, MinerOptions}; use ethcore::verification::queue::VerifierSettings; +use miner::pool; use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}; use rpc_apis::ApiSet; use parity_rpc::NetworkSettings; use cache::CacheConfig; -use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, -to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy, passwords_from_files}; +use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files}; use dir::helpers::{replace_home, replace_home_and_local}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType}; use ethcore_logger::Config as LogConfig; @@ -352,7 +352,6 @@ impl Configuration { daemon: daemon, logger_config: logger_config.clone(), miner_options: self.miner_options()?, - work_notify: self.work_notify(), gas_price_percentile: self.args.arg_gas_price_percentile, ntp_servers: self.ntp_servers(), ws_conf: ws_conf, @@ -411,12 +410,14 @@ impl Configuration { } fn miner_extras(&self) -> Result { + let floor = to_u256(&self.args.arg_gas_floor_target)?; + let ceil = to_u256(&self.args.arg_gas_cap)?; let extras = MinerExtras { author: self.author()?, extra_data: self.extra_data()?, - gas_floor_target: to_u256(&self.args.arg_gas_floor_target)?, - gas_ceil_target: to_u256(&self.args.arg_gas_cap)?, + gas_range_target: (floor, ceil), engine_signer: self.engine_signer()?, + work_notify: self.work_notify(), }; Ok(extras) @@ -471,7 +472,7 @@ impl Configuration { fn max_peers(&self) -> u32 { self.args.arg_max_peers - .or(max(self.args.arg_min_peers, Some(DEFAULT_MAX_PEERS))) + .or(cmp::max(self.args.arg_min_peers, Some(DEFAULT_MAX_PEERS))) .unwrap_or(DEFAULT_MAX_PEERS) as u32 } @@ -484,7 +485,7 @@ impl Configuration { fn min_peers(&self) -> u32 { self.args.arg_min_peers - .or(min(self.args.arg_max_peers, Some(DEFAULT_MIN_PEERS))) + .or(cmp::min(self.args.arg_max_peers, Some(DEFAULT_MIN_PEERS))) .unwrap_or(DEFAULT_MIN_PEERS) as u32 } @@ -514,9 +515,9 @@ impl Configuration { Ok(cfg) } - fn stratum_options(&self) -> Result, String> { + fn stratum_options(&self) -> Result, String> { if self.args.flag_stratum { - Ok(Some(StratumOptions { + Ok(Some(stratum::Options { io_path: self.directories().db, listen_addr: self.stratum_interface(), port: self.args.arg_ports_shift + self.args.arg_stratum_port, @@ -538,36 +539,51 @@ impl Configuration { reseal_on_external_tx: reseal.external, reseal_on_own_tx: reseal.own, reseal_on_uncle: self.args.flag_reseal_on_uncle, - tx_gas_limit: match self.args.arg_tx_gas_limit { - Some(ref d) => to_u256(d)?, - None => U256::max_value(), - }, - tx_queue_size: self.args.arg_tx_queue_size, - tx_queue_memory_limit: if self.args.arg_tx_queue_mem_limit > 0 { - Some(self.args.arg_tx_queue_mem_limit as usize * 1024 * 1024) - } else { None }, - tx_queue_gas_limit: to_gas_limit(&self.args.arg_tx_queue_gas)?, - tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?, - pending_set: to_pending_set(&self.args.arg_relay_set)?, reseal_min_period: Duration::from_millis(self.args.arg_reseal_min_period), reseal_max_period: Duration::from_millis(self.args.arg_reseal_max_period), + + pending_set: to_pending_set(&self.args.arg_relay_set)?, work_queue_size: self.args.arg_work_queue_size, enable_resubmission: !self.args.flag_remove_solved, - tx_queue_banning: match self.args.arg_tx_time_limit { - Some(limit) => Banning::Enabled { - min_offends: self.args.arg_tx_queue_ban_count, - offend_threshold: Duration::from_millis(limit), - ban_duration: Duration::from_secs(self.args.arg_tx_queue_ban_time as u64), - }, - None => Banning::Disabled, - }, - refuse_service_transactions: self.args.flag_refuse_service_transactions, infinite_pending_block: self.args.flag_infinite_pending_block, + + tx_queue_penalization: to_queue_penalization(self.args.arg_tx_time_limit)?, + tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?, + refuse_service_transactions: self.args.flag_refuse_service_transactions, + + pool_limits: self.pool_limits()?, + pool_verification_options: self.pool_verification_options()?, }; Ok(options) } + fn pool_limits(&self) -> Result { + let max_count = self.args.arg_tx_queue_size; + + Ok(pool::Options { + max_count, + max_per_sender: self.args.arg_tx_queue_per_sender.unwrap_or_else(|| cmp::max(16, max_count / 100)), + max_mem_usage: if self.args.arg_tx_queue_mem_limit > 0 { + self.args.arg_tx_queue_mem_limit as usize * 1024 * 1024 + } else { + usize::max_value() + }, + }) + } + + fn pool_verification_options(&self) -> Result{ + Ok(pool::verifier::Options { + // NOTE min_gas_price and block_gas_limit will be overwritten right after start. + minimal_gas_price: U256::from(20_000_000) * 1_000u32, + block_gas_limit: U256::max_value(), + tx_gas_limit: match self.args.arg_tx_gas_limit { + Some(ref d) => to_u256(d)?, + None => U256::max_value(), + }, + }) + } + fn ui_port(&self) -> u16 { self.args.arg_ports_shift + self.args.arg_ui_port } @@ -690,12 +706,7 @@ impl Configuration { let usd_per_tx = to_price(&self.args.arg_usd_per_tx)?; if "auto" == self.args.arg_usd_per_eth.as_str() { - // Just a very rough estimate to avoid accepting - // ZGP transactions before the price is fetched - // if user does not want it. - let last_known_usd_per_eth = 10.0; return Ok(GasPricerConfig::Calibrated { - initial_minimum: wei_per_gas(usd_per_tx, last_known_usd_per_eth), usd_per_tx: usd_per_tx, recalibration_period: to_duration(self.args.arg_price_update_period.as_str())?, }); @@ -1233,7 +1244,7 @@ mod tests { use tempdir::TempDir; use ethcore::client::{VMType, BlockId}; use ethcore::miner::MinerOptions; - use miner::transaction_queue::PrioritizationStrategy; + use miner::pool::PrioritizationStrategy; use parity_rpc::NetworkSettings; use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack}; @@ -1526,7 +1537,6 @@ mod tests { no_hardcoded_sync: false, no_persistent_txqueue: false, whisper: Default::default(), - work_notify: Vec::new(), }; expected.secretstore_conf.enabled = cfg!(feature = "secretstore"); expected.secretstore_conf.http_enabled = cfg!(feature = "secretstore"); @@ -1540,18 +1550,12 @@ mod tests { // when let conf0 = parse(&["parity"]); - let conf1 = parse(&["parity", "--tx-queue-strategy", "gas_factor"]); let conf2 = parse(&["parity", "--tx-queue-strategy", "gas_price"]); - let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]); // then assert_eq!(conf0.miner_options().unwrap(), mining_options); - mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice; - assert_eq!(conf1.miner_options().unwrap(), mining_options); mining_options.tx_queue_strategy = PrioritizationStrategy::GasPriceOnly; assert_eq!(conf2.miner_options().unwrap(), mining_options); - mining_options.tx_queue_strategy = PrioritizationStrategy::GasAndGasPrice; - assert_eq!(conf3.miner_options().unwrap(), mining_options); } #[test] @@ -1883,8 +1887,8 @@ mod tests { assert_eq!(c.miner_options.reseal_on_external_tx, true); assert_eq!(c.miner_options.reseal_on_own_tx, true); assert_eq!(c.miner_options.reseal_min_period, Duration::from_millis(4000)); - assert_eq!(c.miner_options.tx_queue_size, 2048); - assert_eq!(c.cache_config, CacheConfig::new_with_total_cache_size(256)); + assert_eq!(c.miner_options.pool_limits.max_count, 8192); + assert_eq!(c.cache_config, CacheConfig::new_with_total_cache_size(1024)); assert_eq!(c.logger_config.mode.unwrap(), "miner=trace,own_tx=trace"); }, _ => panic!("Should be Cmd::Run"), diff --git a/parity/helpers.rs b/parity/helpers.rs index 0494be40d8..cdd951c2b7 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -23,9 +23,9 @@ use std::path::Path; use ethereum_types::{U256, clean_0x, Address}; use journaldb::Algorithm; use ethcore::client::{Mode, BlockId, VMType, DatabaseCompactionProfile, ClientConfig, VerifierType}; -use ethcore::miner::{PendingSet, GasLimit}; use ethcore::db::NUM_COLUMNS; -use miner::transaction_queue::PrioritizationStrategy; +use ethcore::miner::{PendingSet, Penalization}; +use miner::pool::PrioritizationStrategy; use cache::CacheConfig; use dir::DatabaseDirectories; use dir::helpers::replace_home; @@ -101,23 +101,22 @@ pub fn to_pending_set(s: &str) -> Result { } } -pub fn to_gas_limit(s: &str) -> Result { - match s { - "auto" => Ok(GasLimit::Auto), - "off" => Ok(GasLimit::None), - other => Ok(GasLimit::Fixed(to_u256(other)?)), - } -} - pub fn to_queue_strategy(s: &str) -> Result { match s { - "gas" => Ok(PrioritizationStrategy::GasAndGasPrice), "gas_price" => Ok(PrioritizationStrategy::GasPriceOnly), - "gas_factor" => Ok(PrioritizationStrategy::GasFactorAndGasPrice), other => Err(format!("Invalid queue strategy: {}", other)), } } +pub fn to_queue_penalization(time: Option) -> Result { + Ok(match time { + Some(threshold_ms) => Penalization::Enabled { + offend_threshold: Duration::from_millis(threshold_ms), + }, + None => Penalization::Disabled, + }) +} + pub fn to_address(s: Option) -> Result { match s { Some(ref a) => clean_0x(a).parse().map_err(|_| format!("Invalid address: {:?}", a)), diff --git a/parity/params.rs b/parity/params.rs index 59676108ed..957b280193 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -16,15 +16,16 @@ use std::{str, fs, fmt}; use std::time::Duration; + +use ethcore::client::Mode; +use ethcore::ethereum; +use ethcore::spec::{Spec, SpecParams}; use ethereum_types::{U256, Address}; use futures_cpupool::CpuPool; -use parity_version::version_data; -use journaldb::Algorithm; -use ethcore::spec::{Spec, SpecParams}; -use ethcore::ethereum; -use ethcore::client::Mode; -use ethcore::miner::{GasPricer, GasPriceCalibratorOptions}; use hash_fetch::fetch::Client as FetchClient; +use journaldb::Algorithm; +use miner::gas_pricer::{GasPricer, GasPriceCalibratorOptions}; +use parity_version::version_data; use user_defaults::UserDefaults; #[derive(Debug, PartialEq)] @@ -223,25 +224,14 @@ impl Default for AccountsConfig { pub enum GasPricerConfig { Fixed(U256), Calibrated { - initial_minimum: U256, usd_per_tx: f32, recalibration_period: Duration, } } -impl GasPricerConfig { - pub fn initial_min(&self) -> U256 { - match *self { - GasPricerConfig::Fixed(ref min) => min.clone(), - GasPricerConfig::Calibrated { ref initial_minimum, .. } => initial_minimum.clone(), - } - } -} - impl Default for GasPricerConfig { fn default() -> Self { GasPricerConfig::Calibrated { - initial_minimum: 476190464u64.into(), usd_per_tx: 0.0001f32, recalibration_period: Duration::from_secs(3600), } @@ -269,20 +259,20 @@ impl GasPricerConfig { #[derive(Debug, PartialEq)] pub struct MinerExtras { pub author: Address, - pub extra_data: Vec, - pub gas_floor_target: U256, - pub gas_ceil_target: U256, pub engine_signer: Address, + pub extra_data: Vec, + pub gas_range_target: (U256, U256), + pub work_notify: Vec, } impl Default for MinerExtras { fn default() -> Self { MinerExtras { author: Default::default(), - extra_data: version_data(), - gas_floor_target: U256::from(4_700_000), - gas_ceil_target: U256::from(6_283_184), engine_signer: Default::default(), + extra_data: version_data(), + gas_range_target: (4_700_000.into(), 6_283_184.into()), + work_notify: Default::default(), } } } diff --git a/parity/run.rs b/parity/run.rs index 4cc7b29b04..f4e892b4b9 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -24,11 +24,10 @@ use std::net::{TcpListener}; use ansi_term::{Colour, Style}; use ctrlc::CtrlC; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; -use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient}; +use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; use ethcore::db::NUM_COLUMNS; use ethcore::ethstore::ethkey; -use ethcore::miner::{Miner, MinerService, MinerOptions}; -use ethcore::miner::{StratumOptions, Stratum}; +use ethcore::miner::{stratum, Miner, MinerService, MinerOptions}; use ethcore::snapshot; use ethcore::spec::{SpecParams, OptimizeFor}; use ethcore::verification::queue::VerifierSettings; @@ -128,7 +127,7 @@ pub struct RunCmd { pub ui: bool, pub name: String, pub custom_bootnodes: bool, - pub stratum: Option, + pub stratum: Option, pub no_periodic_snapshot: bool, pub check_seal: bool, pub download_old_blocks: bool, @@ -138,7 +137,6 @@ pub struct RunCmd { pub no_persistent_txqueue: bool, pub whisper: ::whisper::Config, pub no_hardcoded_sync: bool, - pub work_notify: Vec, } pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { @@ -176,11 +174,12 @@ impl ::local_store::NodeInfo for FullNodeInfo { None => return Vec::new(), }; - let local_txs = miner.local_transactions(); - miner.pending_transactions() - .into_iter() - .chain(miner.future_transactions()) - .filter(|tx| local_txs.contains_key(&tx.hash())) + miner.local_transactions() + .values() + .filter_map(|status| match *status { + ::miner::pool::local_transactions::Status::Pending(ref tx) => Some(tx.pending().clone()), + _ => None, + }) .collect() } } @@ -559,19 +558,21 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let fetch = fetch::Client::new().map_err(|e| format!("Error starting fetch client: {:?}", e))?; // create miner - let initial_min_gas_price = cmd.gas_pricer_conf.initial_min(); - let miner = Miner::new(cmd.miner_options, cmd.gas_pricer_conf.to_gas_pricer(fetch.clone(), cpu_pool.clone()), &spec, Some(account_provider.clone())); - miner.set_author(cmd.miner_extras.author); - miner.set_gas_floor_target(cmd.miner_extras.gas_floor_target); - miner.set_gas_ceil_target(cmd.miner_extras.gas_ceil_target); + let miner = Arc::new(Miner::new( + cmd.miner_options, + cmd.gas_pricer_conf.to_gas_pricer(fetch.clone(), cpu_pool.clone()), + &spec, + Some(account_provider.clone()) + )); + miner.set_author(cmd.miner_extras.author, None).expect("Fails only if password is Some; password is None; qed"); + miner.set_gas_range_target(cmd.miner_extras.gas_range_target); miner.set_extra_data(cmd.miner_extras.extra_data); - miner.set_minimal_gas_price(initial_min_gas_price); - miner.recalibrate_minimal_gas_price(); - if !cmd.work_notify.is_empty() { - miner.push_notifier(Box::new(WorkPoster::new(&cmd.work_notify, fetch.clone(), event_loop.remote()))); + if !cmd.miner_extras.work_notify.is_empty() { + miner.add_work_listener(Box::new( + WorkPoster::new(&cmd.miner_extras.work_notify, fetch.clone(), event_loop.remote()) + )); } let engine_signer = cmd.miner_extras.engine_signer; - if engine_signer != Default::default() { // Check if engine signer exists if !account_provider.has_account(engine_signer).unwrap_or(false) { @@ -584,7 +585,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: } // Attempt to sign in the engine signer. - if !passwords.iter().any(|p| miner.set_engine_signer(engine_signer, (*p).clone()).is_ok()) { + if !passwords.iter().any(|p| miner.set_author(engine_signer, Some(p.to_owned())).is_ok()) { return Err(format!("No valid password for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT)); } } @@ -646,6 +647,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // take handle to client let client = service.client(); + // Update miners block gas limit + miner.update_transaction_queue_limits(*client.best_block_header().gas_limit()); + // take handle to private transactions service let private_tx_service = service.private_tx_service(); let private_tx_provider = private_tx_service.provider(); @@ -695,7 +699,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // start stratum if let Some(ref stratum_config) = cmd.stratum { - Stratum::register(stratum_config, miner.clone(), Arc::downgrade(&client)) + stratum::Stratum::register(stratum_config, miner.clone(), Arc::downgrade(&client)) .map_err(|e| format!("Stratum start error: {:?}", e))?; } diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 9096732808..56b166ac62 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -194,10 +194,12 @@ impl SnapshotCommand { &snapshot_path, restoration_db_handler, &self.dirs.ipc_path(), - Arc::new(Miner::with_spec(&spec)), + // TODO [ToDr] don't use test miner here + // (actually don't require miner at all) + Arc::new(Miner::new_for_tests(&spec, None)), Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), - Default::default() + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; Ok(service) diff --git a/price-info/src/lib.rs b/price-info/src/lib.rs index 9685fc7eee..e3594ad2ae 100644 --- a/price-info/src/lib.rs +++ b/price-info/src/lib.rs @@ -98,7 +98,7 @@ impl Client { } /// Gets the current ETH price and calls `set_price` with the result. - pub fn get(&self, set_price: G) { + pub fn get(&self, set_price: G) { let future = self.fetch.get(&self.api_endpoint, fetch::Abort::default()) .from_err() .and_then(|response| { diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index a0639c4ccc..d35a64af9d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -66,8 +66,9 @@ stats = { path = "../util/stats" } vm = { path = "../ethcore/vm" } [dev-dependencies] -pretty_assertions = "0.1" -macros = { path = "../util/macros" } ethcore-network = { path = "../util/network" } -kvdb-memorydb = { path = "../util/kvdb-memorydb" } fake-fetch = { path = "../util/fake-fetch" } +kvdb-memorydb = { path = "../util/kvdb-memorydb" } +macros = { path = "../util/macros" } +pretty_assertions = "0.1" +transaction-pool = { path = "../transaction-pool" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index f3ba68a065..9d97c3c992 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -79,6 +79,8 @@ extern crate serde_derive; #[cfg(test)] extern crate ethjson; +#[cfg(test)] +extern crate transaction_pool as txpool; #[cfg(test)] #[macro_use] diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index b1fc07a22d..1f43ef008e 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -34,8 +34,8 @@ use stats::Corpus; use ethkey::Signature; use sync::LightSync; use ethcore::ids::BlockId; -use ethcore::miner::MinerService; -use ethcore::client::MiningBlockChainClient; +use ethcore::client::BlockChainClient; +use ethcore::miner::{self, MinerService}; use ethcore::account_provider::AccountProvider; use crypto::DEFAULT_MAC; use transaction::{Action, SignedTransaction, PendingTransaction, Transaction}; @@ -117,10 +117,9 @@ impl Clone for FullDispatcher { } } -impl FullDispatcher { +impl FullDispatcher { fn state_nonce(&self, from: &Address) -> U256 { - self.miner.last_nonce(from).map(|nonce| nonce + U256::one()) - .unwrap_or_else(|| self.client.latest_nonce(from)) + self.miner.next_nonce(&*self.client, from) } /// Imports transaction to the miner's queue. @@ -133,7 +132,7 @@ impl FullDispatcher { } } -impl Dispatcher for FullDispatcher { +impl Dispatcher for FullDispatcher { fn fill_optional_fields(&self, request: TransactionRequest, default_sender: Address, force_nonce: bool) -> BoxFuture { @@ -747,7 +746,7 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: S /// Extract the default gas price from a client and miner. pub fn default_gas_price(client: &C, miner: &M, percentile: usize) -> U256 where - C: MiningBlockChainClient, + C: BlockChainClient, M: MinerService, { client.gas_price_corpus(100).percentile(percentile).cloned().unwrap_or_else(|| miner.sensible_gas_price()) diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 6e8836c20d..aa660efc9c 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -391,11 +391,11 @@ pub fn no_light_peers() -> Error { } } -pub fn deprecated>>(message: T) -> Error { +pub fn deprecated, T: Into>>(message: T) -> Error { Error { code: ErrorCode::ServerError(codes::DEPRECATED), message: "Method deprecated".into(), - data: message.into().map(Value::String), + data: message.into().map(Into::into).map(Value::String), } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index c833e3ee7f..37f918466e 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -26,13 +26,12 @@ use parking_lot::Mutex; use ethash::SeedHashCompute; use ethcore::account_provider::{AccountProvider, DappId}; -use ethcore::block::IsBlock; -use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo}; +use ethcore::client::{BlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo}; use ethcore::ethereum::Ethash; use ethcore::filter::Filter as EthcoreFilter; use ethcore::header::{BlockNumber as EthBlockNumber}; use ethcore::log_entry::LogEntry; -use ethcore::miner::MinerService; +use ethcore::miner::{self, MinerService}; use ethcore::snapshot::SnapshotService; use ethcore::encoded; use sync::{SyncProvider}; @@ -92,7 +91,7 @@ impl Default for EthClientOptions { /// Eth rpc implementation. pub struct EthClient where - C: MiningBlockChainClient, + C: miner::BlockChainClient + BlockChainClient, SN: SnapshotService, S: SyncProvider, M: MinerService, @@ -142,7 +141,7 @@ enum PendingTransactionId { } impl EthClient where - C: MiningBlockChainClient + StateClient + Call + EngineInfo, + C: miner::BlockChainClient + BlockChainClient + StateClient + Call + EngineInfo, SN: SnapshotService, S: SyncProvider, M: MinerService, @@ -420,7 +419,7 @@ impl EthClient(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFilter) -> Vec where M: MinerService { - let receipts = miner.pending_receipts(best_block); + let receipts = miner.pending_receipts(best_block).unwrap_or_default(); let pending_logs = receipts.into_iter() .flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::>()) @@ -438,7 +437,7 @@ pub fn pending_logs(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFi result } -fn check_known(client: &C, number: BlockNumber) -> Result<()> where C: MiningBlockChainClient { +fn check_known(client: &C, number: BlockNumber) -> Result<()> where C: BlockChainClient { use ethcore::block_status::BlockStatus; let id = match number { @@ -458,7 +457,7 @@ fn check_known(client: &C, number: BlockNumber) -> Result<()> where C: Mining const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6. impl Eth for EthClient where - C: MiningBlockChainClient + StateClient + Call + EngineInfo + 'static, + C: miner::BlockChainClient + BlockChainClient + StateClient + Call + EngineInfo + 'static, SN: SnapshotService + 'static, S: SyncProvider + 'static, M: MinerService + 'static, @@ -506,7 +505,7 @@ impl Eth for EthClient< fn author(&self, meta: Metadata) -> Result { let dapp = meta.dapp_id(); - let mut miner = self.miner.author(); + let mut miner = self.miner.authoring_params().author; if miner == 0.into() { miner = self.dapp_accounts(dapp.into())?.get(0).cloned().unwrap_or_default(); } @@ -571,16 +570,8 @@ impl Eth for EthClient< let res = match num.unwrap_or_default() { BlockNumber::Pending if self.options.pending_nonce_from_queue => { - let nonce = self.miner.last_nonce(&address) - .map(|n| n + 1.into()) - .or_else(|| self.client.nonce(&address, BlockId::Latest)); - - match nonce { - Some(nonce) => Ok(nonce.into()), - None => Err(errors::database("latest nonce missing")) - } - }, - + Ok(self.miner.next_nonce(&*self.client, &address).into()) + } BlockNumber::Pending => { let info = self.client.chain_info(); let nonce = self.miner @@ -596,7 +587,6 @@ impl Eth for EthClient< None => Err(errors::database("latest nonce missing")) } }, - number => { try_bf!(check_known(&*self.client, number.clone())); match self.client.nonce(&address, block_number_to_id(number)) { @@ -615,13 +605,13 @@ impl Eth for EthClient< } fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture> { + let block_number = self.client.chain_info().best_block_number; + Box::new(future::ok(match num { - BlockNumber::Pending => Some( - self.miner.status().transactions_in_pending_block.into() - ), + BlockNumber::Pending => + self.miner.pending_transactions(block_number).map(|x| x.len().into()), _ => - self.client.block(block_number_to_id(num)) - .map(|block| block.transactions_count().into()) + self.client.block(block_number_to_id(num)).map(|block| block.transactions_count().into()) })) } @@ -665,8 +655,8 @@ impl Eth for EthClient< let hash: H256 = hash.into(); let block_number = self.client.chain_info().best_block_number; let tx = try_bf!(self.transaction(PendingTransactionId::Hash(hash))).or_else(|| { - self.miner.transaction(block_number, &hash) - .map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)) + self.miner.transaction(&hash) + .map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition)) }); Box::new(future::ok(tx)) @@ -745,11 +735,6 @@ impl Eth for EthClient< } fn work(&self, no_new_work_timeout: Trailing) -> Result { - if !self.miner.can_produce_work_package() { - warn!(target: "miner", "Cannot give work package - engine seals internally."); - return Err(errors::no_work_required()) - } - let no_new_work_timeout = no_new_work_timeout.unwrap_or_default(); // check if we're still syncing and return empty strings in that case @@ -768,50 +753,58 @@ impl Eth for EthClient< } } - if self.miner.author().is_zero() { + if self.miner.authoring_params().author.is_zero() { warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!"); return Err(errors::no_author()) } - self.miner.map_sealing_work(&*self.client, |b| { - let pow_hash = b.hash(); - let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); - let seed_hash = self.seed_compute.lock().hash_block_number(b.block().header().number()); - - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs(); - if no_new_work_timeout > 0 && b.block().header().timestamp() + no_new_work_timeout < now { - Err(errors::no_new_work()) - } else if self.options.send_block_number_in_get_work { - let block_number = b.block().header().number(); - Ok(Work { - pow_hash: pow_hash.into(), - seed_hash: seed_hash.into(), - target: target.into(), - number: Some(block_number), - }) - } else { - Ok(Work { - pow_hash: pow_hash.into(), - seed_hash: seed_hash.into(), - target: target.into(), - number: None - }) - } - }).unwrap_or(Err(errors::internal("No work found.", ""))) - } - fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result { - if !self.miner.can_produce_work_package() { - warn!(target: "miner", "Cannot submit work - engine seals internally."); - return Err(errors::no_work_required()) + let work = self.miner.work_package(&*self.client).ok_or_else(|| { + warn!(target: "miner", "Cannot give work package - engine seals internally."); + errors::no_work_required() + })?; + + let (pow_hash, number, timestamp, difficulty) = work; + let target = Ethash::difficulty_to_boundary(&difficulty); + let seed_hash = self.seed_compute.lock().hash_block_number(number); + + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs(); + if no_new_work_timeout > 0 && timestamp + no_new_work_timeout < now { + Err(errors::no_new_work()) + } else if self.options.send_block_number_in_get_work { + Ok(Work { + pow_hash: pow_hash.into(), + seed_hash: seed_hash.into(), + target: target.into(), + number: Some(number), + }) + } else { + Ok(Work { + pow_hash: pow_hash.into(), + seed_hash: seed_hash.into(), + target: target.into(), + number: None + }) } + } + fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result { + // TODO [ToDr] Should disallow submissions in case of PoA? let nonce: H64 = nonce.into(); let pow_hash: H256 = pow_hash.into(); let mix_hash: H256 = mix_hash.into(); trace!(target: "miner", "submit_work: Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash); let seal = vec![rlp::encode(&mix_hash).into_vec(), rlp::encode(&nonce).into_vec()]; - Ok(self.miner.submit_seal(&*self.client, pow_hash, seal).is_ok()) + let import = self.miner.submit_seal(pow_hash, seal) + .and_then(|block| self.client.import_sealed_block(block)); + + match import { + Ok(_) => Ok(true), + Err(err) => { + warn!(target: "miner", "Cannot submit work - {:?}.", err); + Ok(false) + }, + } } fn submit_hashrate(&self, rate: RpcU256, id: RpcH256) -> Result { diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 9e2f2f8887..6ca1c355f3 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use std::collections::HashSet; -use ethcore::miner::MinerService; +use ethcore::miner::{self, MinerService}; use ethcore::filter::Filter as EthcoreFilter; use ethcore::client::{BlockChainClient, BlockId}; use ethereum_types::H256; @@ -42,7 +42,7 @@ pub trait Filterable { fn block_hash(&self, id: BlockId) -> Option; /// pending transaction hashes at the given block. - fn pending_transactions_hashes(&self, block_number: u64) -> Vec; + fn pending_transactions_hashes(&self) -> Vec; /// Get logs that match the given filter. fn logs(&self, filter: EthcoreFilter) -> BoxFuture>; @@ -55,16 +55,13 @@ pub trait Filterable { } /// Eth filter rpc implementation for a full node. -pub struct EthFilterClient where - C: BlockChainClient, - M: MinerService { - +pub struct EthFilterClient { client: Arc, miner: Arc, polls: Mutex>, } -impl EthFilterClient where C: BlockChainClient, M: MinerService { +impl EthFilterClient { /// Creates new Eth filter client. pub fn new(client: Arc, miner: Arc) -> Self { EthFilterClient { @@ -75,7 +72,10 @@ impl EthFilterClient where C: BlockChainClient, M: MinerService { } } -impl Filterable for EthFilterClient where C: BlockChainClient, M: MinerService { +impl Filterable for EthFilterClient where + C: miner::BlockChainClient + BlockChainClient, + M: MinerService, +{ fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number } @@ -84,8 +84,11 @@ impl Filterable for EthFilterClient where C: BlockChainClient, M: Mi self.client.block_hash(id).map(Into::into) } - fn pending_transactions_hashes(&self, best: u64) -> Vec { - self.miner.pending_transactions_hashes(best) + fn pending_transactions_hashes(&self) -> Vec { + self.miner.ready_transactions(&*self.client) + .into_iter() + .map(|tx| tx.signed().hash()) + .collect() } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { @@ -118,8 +121,7 @@ impl EthFilter for T { fn new_pending_transaction_filter(&self) -> Result { let mut polls = self.polls().lock(); - let best_block = self.best_block_number(); - let pending_transactions = self.pending_transactions_hashes(best_block); + let pending_transactions = self.pending_transactions_hashes(); let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); Ok(id.into()) } @@ -143,8 +145,7 @@ impl EthFilter for T { }, PollFilter::PendingTransaction(ref mut previous_hashes) => { // get hashes of pending transactions - let best_block = self.best_block_number(); - let current_hashes = self.pending_transactions_hashes(best_block); + let current_hashes = self.pending_transactions_hashes(); let new_hashes = { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index c617c03b1d..73e041abac 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -533,7 +533,7 @@ impl Filterable for EthClient { self.client.block_hash(id).map(Into::into) } - fn pending_transactions_hashes(&self, _block_number: u64) -> Vec<::ethereum_types::H256> { + fn pending_transactions_hashes(&self) -> Vec<::ethereum_types::H256> { Vec::new() } diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index e1dc8d4d3d..9db7488b6f 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -275,6 +275,21 @@ impl Parity for ParityClient { ) } + fn all_transactions(&self) -> Result> { + let txq = self.light_dispatch.transaction_queue.read(); + let chain_info = self.light_dispatch.client.chain_info(); + + let current = txq.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp); + let future = txq.future_transactions(chain_info.best_block_number, chain_info.best_block_timestamp); + Ok( + current + .into_iter() + .chain(future.into_iter()) + .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) + .collect::>() + ) + } + fn future_transactions(&self) -> Result> { let txq = self.light_dispatch.transaction_queue.read(); let chain_info = self.light_dispatch.client.chain_info(); diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 451556e856..d091d7a999 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -27,9 +27,9 @@ use ethkey::{Brain, Generator}; use ethstore::random_phrase; use sync::{SyncProvider, ManageNetwork}; use ethcore::account_provider::AccountProvider; -use ethcore::client::{MiningBlockChainClient, StateClient, Call}; +use ethcore::client::{BlockChainClient, StateClient, Call}; use ethcore::ids::BlockId; -use ethcore::miner::MinerService; +use ethcore::miner::{self, MinerService}; use ethcore::mode::Mode; use ethcore::state::StateInfo; use ethcore_logger::RotatingLogger; @@ -72,7 +72,7 @@ pub struct ParityClient { } impl ParityClient where - C: MiningBlockChainClient, + C: BlockChainClient, { /// Creates new `ParityClient`. pub fn new( @@ -116,7 +116,7 @@ impl ParityClient where impl Parity for ParityClient where S: StateInfo + 'static, - C: MiningBlockChainClient + StateClient + Call + 'static, + C: miner::BlockChainClient + BlockChainClient + StateClient + Call + 'static, M: MinerService + 'static, U: UpdateService + 'static, { @@ -170,23 +170,23 @@ impl Parity for ParityClient where } fn transactions_limit(&self) -> Result { - Ok(self.miner.transactions_limit()) + Ok(self.miner.queue_status().limits.max_count) } fn min_gas_price(&self) -> Result { - Ok(U256::from(self.miner.minimal_gas_price())) + Ok(self.miner.queue_status().options.minimal_gas_price.into()) } fn extra_data(&self) -> Result { - Ok(Bytes::new(self.miner.extra_data())) + Ok(Bytes::new(self.miner.authoring_params().extra_data)) } fn gas_floor_target(&self) -> Result { - Ok(U256::from(self.miner.gas_floor_target())) + Ok(U256::from(self.miner.authoring_params().gas_range_target.0)) } fn gas_ceil_target(&self) -> Result { - Ok(U256::from(self.miner.gas_ceil_target())) + Ok(U256::from(self.miner.authoring_params().gas_range_target.1)) } fn dev_logs(&self) -> Result> { @@ -315,12 +315,28 @@ impl Parity for ParityClient where fn pending_transactions(&self) -> Result> { let block_number = self.client.chain_info().best_block_number; - Ok(self.miner.pending_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::>()) + let ready_transactions = self.miner.ready_transactions(&*self.client); + + Ok(ready_transactions + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) + .collect() + ) } - fn future_transactions(&self) -> Result> { + fn all_transactions(&self) -> Result> { let block_number = self.client.chain_info().best_block_number; - Ok(self.miner.future_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::>()) + let all_transactions = self.miner.queued_transactions(); + + Ok(all_transactions + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) + .collect() + ) + } + + fn future_transactions(&self) -> Result> { + Err(errors::deprecated("Use `parity_allTransaction` instead.")) } fn pending_transactions_stats(&self) -> Result> { @@ -359,11 +375,7 @@ impl Parity for ParityClient where fn next_nonce(&self, address: H160) -> BoxFuture { let address: Address = address.into(); - Box::new(future::ok(self.miner.last_nonce(&address) - .map(|n| n + 1.into()) - .unwrap_or_else(|| self.client.latest_nonce(&address)) - .into() - )) + Box::new(future::ok(self.miner.next_nonce(&*self.client, &address).into())) } fn mode(&self) -> Result { diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 475f5e0195..612e6aa78b 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -18,8 +18,8 @@ use std::io; use std::sync::Arc; +use ethcore::client::BlockChainClient; use ethcore::miner::MinerService; -use ethcore::client::MiningBlockChainClient; use ethcore::mode::Mode; use sync::ManageNetwork; use fetch::{self, Fetch}; @@ -47,7 +47,7 @@ pub struct ParitySetClient { } impl ParitySetClient - where C: MiningBlockChainClient + 'static, + where C: BlockChainClient + 'static, { /// Creates new `ParitySetClient` with given `Fetch`. pub fn new( @@ -73,24 +73,38 @@ impl ParitySetClient } impl ParitySet for ParitySetClient where - C: MiningBlockChainClient + 'static, + C: BlockChainClient + 'static, M: MinerService + 'static, U: UpdateService + 'static, F: Fetch + 'static, { - fn set_min_gas_price(&self, gas_price: U256) -> Result { - self.miner.set_minimal_gas_price(gas_price.into()); - Ok(true) + fn set_min_gas_price(&self, _gas_price: U256) -> Result { + warn!("setMinGasPrice is deprecated. Ignoring request."); + Ok(false) + } + + fn set_transactions_limit(&self, _limit: usize) -> Result { + warn!("setTransactionsLimit is deprecated. Ignoring request."); + Ok(false) + } + + fn set_tx_gas_limit(&self, _limit: U256) -> Result { + warn!("setTxGasLimit is deprecated. Ignoring request."); + Ok(false) } fn set_gas_floor_target(&self, target: U256) -> Result { - self.miner.set_gas_floor_target(target.into()); + let mut range = self.miner.authoring_params().gas_range_target.clone(); + range.0 = target.into(); + self.miner.set_gas_range_target(range); Ok(true) } fn set_gas_ceil_target(&self, target: U256) -> Result { - self.miner.set_gas_ceil_target(target.into()); + let mut range = self.miner.authoring_params().gas_range_target.clone(); + range.1 = target.into(); + self.miner.set_gas_range_target(range); Ok(true) } @@ -99,23 +113,13 @@ impl ParitySet for ParitySetClient where Ok(true) } - fn set_author(&self, author: H160) -> Result { - self.miner.set_author(author.into()); + fn set_author(&self, address: H160) -> Result { + self.miner.set_author(address.into(), None).map_err(Into::into).map_err(errors::password)?; Ok(true) } fn set_engine_signer(&self, address: H160, password: String) -> Result { - self.miner.set_engine_signer(address.into(), password).map_err(Into::into).map_err(errors::password)?; - Ok(true) - } - - fn set_transactions_limit(&self, limit: usize) -> Result { - self.miner.set_transactions_limit(limit); - Ok(true) - } - - fn set_tx_gas_limit(&self, limit: U256) -> Result { - self.miner.set_tx_gas_limit(limit.into()); + self.miner.set_author(address.into(), Some(password)).map_err(Into::into).map_err(errors::password)?; Ok(true) } @@ -202,6 +206,8 @@ impl ParitySet for ParitySetClient where let block_number = self.client.chain_info().best_block_number; let hash = hash.into(); - Ok(self.miner.remove_pending_transaction(&*self.client, &hash).map(|t| Transaction::from_pending(t, block_number, self.eip86_transition))) + Ok(self.miner.remove_transaction(&hash) + .map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition)) + ) } } diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 0ee1afd5fa..06df83b752 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -18,7 +18,7 @@ use std::sync::Arc; -use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId}; +use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId}; use rlp::UntrustedRlp; use transaction::SignedTransaction; @@ -53,7 +53,7 @@ impl TracesClient { impl Traces for TracesClient where S: StateInfo + 'static, - C: MiningBlockChainClient + StateClient + Call + 'static + C: BlockChainClient + StateClient + Call + 'static { type Metadata = Metadata; diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 747c10200d..6aacbc865d 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -17,15 +17,14 @@ //! rpc integration tests. use std::env; use std::sync::Arc; -use std::time::Duration; -use ethereum_types::{U256, H256, Address}; +use ethereum_types::{H256, Address}; use ethcore::account_provider::AccountProvider; use ethcore::block::Block; use ethcore::client::{BlockChainClient, Client, ClientConfig, ChainInfo, ImportBlock}; use ethcore::ethereum; use ethcore::ids::BlockId; -use ethcore::miner::{MinerOptions, Banning, GasPricer, Miner, PendingSet, GasLimit}; +use ethcore::miner::Miner; use ethcore::spec::{Genesis, Spec}; use ethcore::views::BlockView; use ethjson::blockchain::BlockChain; @@ -33,7 +32,6 @@ use ethjson::state::test::ForkSpec; use io::IoChannel; use kvdb_memorydb; use miner::external::ExternalMiner; -use miner::transaction_queue::PrioritizationStrategy; use parking_lot::Mutex; use jsonrpc_core::IoHandler; @@ -58,30 +56,7 @@ fn sync_provider() -> Arc { } fn miner_service(spec: &Spec, accounts: Arc) -> Arc { - Miner::new( - MinerOptions { - force_sealing: true, - reseal_on_external_tx: true, - reseal_on_own_tx: true, - reseal_on_uncle: false, - tx_queue_size: 1024, - tx_gas_limit: !U256::zero(), - tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, - tx_queue_gas_limit: GasLimit::None, - tx_queue_banning: Banning::Disabled, - tx_queue_memory_limit: None, - pending_set: PendingSet::SealingOrElseQueue, - reseal_min_period: Duration::from_secs(0), - reseal_max_period: Duration::from_secs(120), - work_queue_size: 50, - enable_resubmission: true, - refuse_service_transactions: false, - infinite_pending_block: false, - }, - GasPricer::new_fixed(20_000_000_000u64.into()), - &spec, - Some(accounts), - ) + Arc::new(Miner::new_for_tests(spec, Some(accounts))) } fn snapshot_service() -> Arc { diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index ca9993baea..6781d10b95 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -16,82 +16,68 @@ //! Test implementation of miner service. +use std::sync::Arc; use std::collections::{BTreeMap, HashMap}; -use std::collections::hash_map::Entry; use bytes::Bytes; use ethcore::account_provider::SignError as AccountError; -use ethcore::block::{Block, ClosedBlock}; +use ethcore::block::{Block, SealedBlock, IsBlock}; use ethcore::client::{Nonce, PrepareOpenBlock, StateClient, EngineInfo}; use ethcore::engines::EthEngine; use ethcore::error::Error; use ethcore::header::{BlockNumber, Header}; use ethcore::ids::BlockId; -use ethcore::miner::{MinerService, MinerStatus}; +use ethcore::miner::{MinerService, AuthoringParams}; use ethcore::receipt::{Receipt, RichReceipt}; use ethereum_types::{H256, U256, Address}; -use miner::local_transactions::Status as LocalTransactionStatus; +use miner::pool::local_transactions::Status as LocalTransactionStatus; +use miner::pool::{verifier, VerifiedTransaction, QueueStatus}; use parking_lot::{RwLock, Mutex}; -use transaction::{UnverifiedTransaction, SignedTransaction, PendingTransaction, ImportResult as TransactionImportResult}; +use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; +use txpool; /// Test miner service. pub struct TestMinerService { /// Imported transactions. pub imported_transactions: Mutex>, - /// Latest closed block. - pub latest_closed_block: Mutex>, /// Pre-existed pending transactions pub pending_transactions: Mutex>, /// Pre-existed local transactions pub local_transactions: Mutex>, /// Pre-existed pending receipts pub pending_receipts: Mutex>, - /// Last nonces. - pub last_nonces: RwLock>, + /// Next nonces. + pub next_nonces: RwLock>, /// Password held by Engine. pub password: RwLock, - min_gas_price: RwLock, - gas_range_target: RwLock<(U256, U256)>, - author: RwLock
, - extra_data: RwLock, - limit: RwLock, - tx_gas_limit: RwLock, + authoring_params: RwLock, } impl Default for TestMinerService { fn default() -> TestMinerService { TestMinerService { imported_transactions: Mutex::new(Vec::new()), - latest_closed_block: Mutex::new(None), pending_transactions: Mutex::new(HashMap::new()), local_transactions: Mutex::new(BTreeMap::new()), pending_receipts: Mutex::new(BTreeMap::new()), - last_nonces: RwLock::new(HashMap::new()), - min_gas_price: RwLock::new(U256::from(20_000_000)), - gas_range_target: RwLock::new((U256::from(12345), U256::from(54321))), - author: RwLock::new(Address::zero()), + next_nonces: RwLock::new(HashMap::new()), password: RwLock::new(String::new()), - extra_data: RwLock::new(vec![1, 2, 3, 4]), - limit: RwLock::new(1024), - tx_gas_limit: RwLock::new(!U256::zero()), + authoring_params: RwLock::new(AuthoringParams { + author: Address::zero(), + gas_range_target: (12345.into(), 54321.into()), + extra_data: vec![1, 2, 3, 4], + }), } } } impl TestMinerService { - /// Increments last nonce for given address. - pub fn increment_last_nonce(&self, address: Address) { - let mut last_nonces = self.last_nonces.write(); - match last_nonces.entry(address) { - Entry::Occupied(mut occupied) => { - let val = *occupied.get(); - *occupied.get_mut() = val + 1.into(); - }, - Entry::Vacant(vacant) => { - vacant.insert(0.into()); - }, - } + /// Increments nonce for given address. + pub fn increment_nonce(&self, address: &Address) { + let mut next_nonces = self.next_nonces.write(); + let nonce = next_nonces.entry(*address).or_insert_with(|| 0.into()); + *nonce = *nonce + 1.into(); } } @@ -129,164 +115,112 @@ impl MinerService for TestMinerService { None } - /// Returns miner's status. - fn status(&self) -> MinerStatus { - MinerStatus { - transactions_in_pending_queue: 0, - transactions_in_future_queue: 0, - transactions_in_pending_block: 1 - } - } - - fn set_author(&self, author: Address) { - *self.author.write() = author; + fn authoring_params(&self) -> AuthoringParams { + self.authoring_params.read().clone() } - fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> { - *self.author.write() = address; - *self.password.write() = password; + fn set_author(&self, author: Address, password: Option) -> Result<(), AccountError> { + self.authoring_params.write().author = author; + if let Some(password) = password { + *self.password.write() = password; + } Ok(()) } fn set_extra_data(&self, extra_data: Bytes) { - *self.extra_data.write() = extra_data; - } - - /// Set the lower gas limit we wish to target when sealing a new block. - fn set_gas_floor_target(&self, target: U256) { - self.gas_range_target.write().0 = target; - } - - /// Set the upper gas limit we wish to target when sealing a new block. - fn set_gas_ceil_target(&self, target: U256) { - self.gas_range_target.write().1 = target; - } - - fn set_minimal_gas_price(&self, min_gas_price: U256) { - *self.min_gas_price.write() = min_gas_price; - } - - fn set_transactions_limit(&self, limit: usize) { - *self.limit.write() = limit; - } - - fn set_tx_gas_limit(&self, limit: U256) { - *self.tx_gas_limit.write() = limit; - } - - fn transactions_limit(&self) -> usize { - *self.limit.read() - } - - fn author(&self) -> Address { - *self.author.read() - } - - fn minimal_gas_price(&self) -> U256 { - *self.min_gas_price.read() + self.authoring_params.write().extra_data = extra_data; } - fn extra_data(&self) -> Bytes { - self.extra_data.read().clone() - } - - fn gas_floor_target(&self) -> U256 { - self.gas_range_target.read().0 - } - - fn gas_ceil_target(&self) -> U256 { - self.gas_range_target.read().1 + fn set_gas_range_target(&self, target: (U256, U256)) { + self.authoring_params.write().gas_range_target = target; } /// Imports transactions to transaction queue. - fn import_external_transactions(&self, _chain: &C, transactions: Vec) -> - Vec> { + fn import_external_transactions(&self, chain: &C, transactions: Vec) + -> Vec> + { // lets assume that all txs are valid let transactions: Vec<_> = transactions.into_iter().map(|tx| SignedTransaction::new(tx).unwrap()).collect(); self.imported_transactions.lock().extend_from_slice(&transactions); for sender in transactions.iter().map(|tx| tx.sender()) { - let nonce = self.last_nonce(&sender).expect("last_nonce must be populated in tests"); - self.last_nonces.write().insert(sender, nonce + U256::from(1)); + let nonce = self.next_nonce(chain, &sender); + self.next_nonces.write().insert(sender, nonce); } + transactions .iter() - .map(|_| Ok(TransactionImportResult::Current)) + .map(|_| Ok(())) .collect() } /// Imports transactions to transaction queue. - fn import_own_transaction(&self, chain: &C, pending: PendingTransaction) -> - Result { + fn import_own_transaction(&self, chain: &C, pending: PendingTransaction) + -> Result<(), transaction::Error> { // keep the pending nonces up to date let sender = pending.transaction.sender(); - let nonce = self.last_nonce(&sender).unwrap_or(chain.latest_nonce(&sender)); - self.last_nonces.write().insert(sender, nonce + U256::from(1)); + let nonce = self.next_nonce(chain, &sender); + self.next_nonces.write().insert(sender, nonce); // lets assume that all txs are valid self.imported_transactions.lock().push(pending.transaction); - Ok(TransactionImportResult::Current) - } - - /// Returns hashes of transactions currently in pending - fn pending_transactions_hashes(&self, _best_block: BlockNumber) -> Vec { - vec![] - } - - /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, _chain: &C) { - unimplemented!(); + Ok(()) } /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { + fn chain_new_blocks(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256], _is_internal: bool) { unimplemented!(); } - /// PoW chain - can produce work package - fn can_produce_work_package(&self) -> bool { - true - } - /// New chain head event. Restart mining operation. fn update_sealing(&self, _chain: &C) { unimplemented!(); } - fn map_sealing_work(&self, chain: &C, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { - let open_block = chain.prepare_open_block(self.author(), *self.gas_range_target.write(), self.extra_data()); - Some(f(&open_block.close())) + fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> { + let params = self.authoring_params(); + let open_block = chain.prepare_open_block(params.author, params.gas_range_target, params.extra_data); + let closed = open_block.close(); + let header = closed.header(); + + Some((header.hash(), header.number(), header.timestamp(), *header.difficulty())) } - fn transaction(&self, _best_block: BlockNumber, hash: &H256) -> Option { - self.pending_transactions.lock().get(hash).cloned().map(Into::into) + fn transaction(&self, hash: &H256) -> Option> { + self.pending_transactions.lock().get(hash).cloned().map(|tx| { + Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) + }) } - fn remove_pending_transaction(&self, _chain: &C, hash: &H256) -> Option { - self.pending_transactions.lock().remove(hash).map(Into::into) + fn remove_transaction(&self, hash: &H256) -> Option> { + self.pending_transactions.lock().remove(hash).map(|tx| { + Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) + }) } - fn pending_transactions(&self) -> Vec { - self.pending_transactions.lock().values().cloned().map(Into::into).collect() + fn pending_transactions(&self, _best_block: BlockNumber) -> Option> { + Some(self.pending_transactions.lock().values().cloned().collect()) } fn local_transactions(&self) -> BTreeMap { self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect() } - fn ready_transactions(&self, _best_block: BlockNumber, _best_timestamp: u64) -> Vec { - self.pending_transactions.lock().values().cloned().map(Into::into).collect() + fn ready_transactions(&self, _chain: &C) -> Vec> { + self.queued_transactions() } - fn future_transactions(&self) -> Vec { - vec![] + fn queued_transactions(&self) -> Vec> { + self.pending_transactions.lock().values().cloned().map(|tx| { + Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) + }).collect() } fn pending_receipt(&self, _best_block: BlockNumber, hash: &H256) -> Option { // Not much point implementing this since the logic is complex and the only thing it relies on is pending_receipts, which is already tested. - self.pending_receipts(0).get(hash).map(|r| + self.pending_receipts(0).unwrap().get(hash).map(|r| RichReceipt { transaction_hash: Default::default(), transaction_index: Default::default(), @@ -300,25 +234,49 @@ impl MinerService for TestMinerService { ) } - fn pending_receipts(&self, _best_block: BlockNumber) -> BTreeMap { - self.pending_receipts.lock().clone() + fn pending_receipts(&self, _best_block: BlockNumber) -> Option> { + Some(self.pending_receipts.lock().clone()) } - fn last_nonce(&self, address: &Address) -> Option { - self.last_nonces.read().get(address).cloned() + fn next_nonce(&self, _chain: &C, address: &Address) -> U256 { + self.next_nonces.read().get(address).cloned().unwrap_or_default() } fn is_currently_sealing(&self) -> bool { false } + fn queue_status(&self) -> QueueStatus { + QueueStatus { + options: verifier::Options { + minimal_gas_price: 0x1312d00.into(), + block_gas_limit: 5_000_000.into(), + tx_gas_limit: 5_000_000.into(), + }, + status: txpool::LightStatus { + mem_usage: 1_000, + transaction_count: 52, + senders: 1, + }, + limits: txpool::Options { + max_count: 1_024, + max_per_sender: 16, + max_mem_usage: 5_000, + }, + } + } + /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, _chain: &C, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { + fn submit_seal(&self, _pow_hash: H256, _seal: Vec) -> Result { unimplemented!(); } fn sensible_gas_price(&self) -> U256 { - 20000000000u64.into() + 20_000_000_000u64.into() + } + + fn sensible_gas_limit(&self) -> U256 { + 0x5208.into() } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index c79b02c2d2..badf5bff72 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -368,7 +368,7 @@ fn rpc_eth_author() { for i in 0..20 { let addr = tester.accounts_provider.new_account(&format!("{}", i)).unwrap(); - tester.miner.set_author(addr.clone()); + tester.miner.set_author(addr.clone(), None).unwrap(); assert_eq!(tester.io.handle_request_sync(req), Some(make_res(addr))); } @@ -377,7 +377,7 @@ fn rpc_eth_author() { #[test] fn rpc_eth_mining() { let tester = EthTester::default(); - tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "eth_mining", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; @@ -498,7 +498,7 @@ fn rpc_eth_transaction_count_next_nonce() { let tester = EthTester::new_with_options(EthClientOptions::with(|options| { options.pending_nonce_from_queue = true; })); - tester.miner.increment_last_nonce(1.into()); + tester.miner.increment_nonce(&1.into()); let request1 = r#"{ "jsonrpc": "2.0", @@ -553,7 +553,7 @@ fn rpc_eth_transaction_count_by_number_pending() { "params": ["pending"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x1","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0","id":1}"#; assert_eq!(EthTester::default().io.handle_request_sync(request), Some(response.to_owned())); } @@ -835,7 +835,7 @@ fn rpc_eth_send_transaction() { assert_eq!(tester.io.handle_request_sync(&request), Some(response)); - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); let t = Transaction { nonce: U256::one(), @@ -905,7 +905,7 @@ fn rpc_eth_sign_transaction() { r#""value":"0x9184e72a""# + r#"}},"id":1}"#; - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); assert_eq!(tester.io.handle_request_sync(&request), Some(response)); } @@ -1118,7 +1118,7 @@ fn rpc_get_work_returns_no_work_if_cant_mine() { #[test] fn rpc_get_work_returns_correct_work_package() { let eth_tester = EthTester::default(); - eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x76c7bd86693aee93d1a80a408a09a0585b1a1292afcb56192f171d925ea18e2d","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000","0x1"],"id":1}"#; @@ -1131,7 +1131,7 @@ fn rpc_get_work_should_not_return_block_number() { let eth_tester = EthTester::new_with_options(EthClientOptions::with(|options| { options.send_block_number_in_get_work = false; })); - eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x76c7bd86693aee93d1a80a408a09a0585b1a1292afcb56192f171d925ea18e2d","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000800000000000000000000000000000000000000000000000000000000000"],"id":1}"#; @@ -1142,10 +1142,10 @@ fn rpc_get_work_should_not_return_block_number() { #[test] fn rpc_get_work_should_timeout() { let eth_tester = EthTester::default(); - eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()); + eth_tester.miner.set_author(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(), None).unwrap(); let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() - 1000; // Set latest block to 1000 seconds ago eth_tester.client.set_latest_block_timestamp(timestamp); - let hash = eth_tester.miner.map_sealing_work(&*eth_tester.client, |b| b.hash()).unwrap(); + let hash = eth_tester.miner.work_package(&*eth_tester.client).unwrap().0; // Request without providing timeout. This should work since we're disabling timeout. let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 18f76c6719..5835e2e82c 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -17,13 +17,13 @@ use std::sync::Arc; use ethcore::account_provider::AccountProvider; use ethcore::client::{TestBlockChainClient, Executed}; -use ethcore::miner::LocalTransactionStatus; use ethcore_logger::RotatingLogger; +use ethereum_types::{Address, U256, H256}; use ethstore::ethkey::{Generator, Random}; -use sync::ManageNetwork; +use miner::pool::local_transactions::Status as LocalTransactionStatus; use node_health::{self, NodeHealth}; use parity_reactor; -use ethereum_types::{Address, U256, H256}; +use sync::ManageNetwork; use jsonrpc_core::IoHandler; use v1::{Parity, ParityClient}; @@ -455,7 +455,9 @@ fn rpc_parity_next_nonce() { let address = Address::default(); let io1 = deps.default_client(); let deps = Dependencies::new(); - deps.miner.last_nonces.write().insert(address.clone(), 2.into()); + deps.miner.increment_nonce(&address); + deps.miner.increment_nonce(&address); + deps.miner.increment_nonce(&address); let io2 = deps.default_client(); let request = r#"{ @@ -486,11 +488,20 @@ fn rpc_parity_transactions_stats() { fn rpc_parity_local_transactions() { let deps = Dependencies::new(); let io = deps.default_client(); - deps.miner.local_transactions.lock().insert(10.into(), LocalTransactionStatus::Pending); - deps.miner.local_transactions.lock().insert(15.into(), LocalTransactionStatus::Future); + let tx = ::transaction::Transaction { + value: 5.into(), + gas: 3.into(), + gas_price: 2.into(), + action: ::transaction::Action::Create, + data: vec![1, 2, 3], + nonce: 0.into(), + }.fake_sign(3.into()); + let tx = Arc::new(::miner::pool::VerifiedTransaction::from_pending_block_transaction(tx)); + deps.miner.local_transactions.lock().insert(10.into(), LocalTransactionStatus::Pending(tx.clone())); + deps.miner.local_transactions.lock().insert(15.into(), LocalTransactionStatus::Pending(tx.clone())); let request = r#"{"jsonrpc": "2.0", "method": "parity_localTransactions", "params":[], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":{"0x000000000000000000000000000000000000000000000000000000000000000a":{"status":"pending"},"0x000000000000000000000000000000000000000000000000000000000000000f":{"status":"future"}},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"0x000000000000000000000000000000000000000000000000000000000000000a":{"status":"pending"},"0x000000000000000000000000000000000000000000000000000000000000000f":{"status":"pending"}},"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index af08236fdf..78c73f9479 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -109,10 +109,9 @@ fn rpc_parity_set_min_gas_price() { io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "parity_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.minimal_gas_price(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); } #[test] @@ -129,7 +128,7 @@ fn rpc_parity_set_gas_floor_target() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.gas_floor_target(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); + assert_eq!(miner.authoring_params().gas_range_target.0, U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); } #[test] @@ -146,7 +145,7 @@ fn rpc_parity_set_extra_data() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.extra_data(), "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap()); + assert_eq!(miner.authoring_params().extra_data, "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap()); } #[test] @@ -162,7 +161,7 @@ fn rpc_parity_set_author() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); + assert_eq!(miner.authoring_params().author, Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); } #[test] @@ -178,7 +177,7 @@ fn rpc_parity_set_engine_signer() { let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); + assert_eq!(miner.authoring_params().author, Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); assert_eq!(*miner.password.read(), "password".to_string()); } @@ -193,10 +192,9 @@ fn rpc_parity_set_transactions_limit() { io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "parity_setTransactionsLimit", "params":[10240240], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); - assert_eq!(miner.transactions_limit(), 10_240_240); } #[test] diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 502a590582..c11aca42fb 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -220,7 +220,7 @@ fn sign_and_send_test(method: &str) { assert_eq!(tester.io.handle_request_sync(request.as_ref()), Some(response)); - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); let t = Transaction { nonce: U256::one(), diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 118bbe91ce..3a56c5a0d3 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -327,7 +327,7 @@ fn should_add_sign_transaction_to_the_queue() { r#"}},"id":1}"#; // then - tester.miner.last_nonces.write().insert(address.clone(), U256::zero()); + tester.miner.increment_nonce(&address); let promise = tester.io.handle_request(&request); // the future must be polled at least once before request is queued. diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 81c406fb3a..165cf63d67 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -143,7 +143,13 @@ build_rpc_trait! { #[rpc(name = "parity_pendingTransactions")] fn pending_transactions(&self) -> Result>; - /// Returns all future transactions from transaction queue. + /// Returns all transactions from transaction queue. + /// + /// Some of them might not be ready to be included in a block yet. + #[rpc(name = "parity_allTransactions")] + fn all_transactions(&self) -> Result>; + + /// Returns all future transactions from transaction queue (deprecated) #[rpc(name = "parity_futureTransactions")] fn future_transactions(&self) -> Result>; diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index c5dd63624f..0ac3e37454 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -14,12 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::sync::Arc; + use serde::{Serialize, Serializer}; use serde::ser::SerializeStruct; -use ethcore::miner; use ethcore::{contract_address, CreateContractAddress}; +use miner; use transaction::{LocalizedTransaction, Action, PendingTransaction, SignedTransaction}; -use v1::helpers::errors; use v1::types::{Bytes, H160, H256, U256, H512, U64, TransactionCondition}; /// Transaction @@ -248,17 +249,23 @@ impl Transaction { impl LocalTransactionStatus { /// Convert `LocalTransactionStatus` into RPC `LocalTransactionStatus`. - pub fn from(s: miner::LocalTransactionStatus, block_number: u64, eip86_transition: u64) -> Self { - use ethcore::miner::LocalTransactionStatus::*; + pub fn from(s: miner::pool::local_transactions::Status, block_number: u64, eip86_transition: u64) -> Self { + let convert = |tx: Arc| { + Transaction::from_signed(tx.signed().clone(), block_number, eip86_transition) + }; + use miner::pool::local_transactions::Status::*; match s { - Pending => LocalTransactionStatus::Pending, - Future => LocalTransactionStatus::Future, - Mined(tx) => LocalTransactionStatus::Mined(Transaction::from_signed(tx, block_number, eip86_transition)), - Dropped(tx) => LocalTransactionStatus::Dropped(Transaction::from_signed(tx, block_number, eip86_transition)), - Rejected(tx, err) => LocalTransactionStatus::Rejected(Transaction::from_signed(tx, block_number, eip86_transition), errors::transaction_message(err)), - Replaced(tx, gas_price, hash) => LocalTransactionStatus::Replaced(Transaction::from_signed(tx, block_number, eip86_transition), gas_price.into(), hash.into()), - Invalid(tx) => LocalTransactionStatus::Invalid(Transaction::from_signed(tx, block_number, eip86_transition)), - Canceled(tx) => LocalTransactionStatus::Canceled(Transaction::from_pending(tx, block_number, eip86_transition)), + Pending(_) => LocalTransactionStatus::Pending, + Mined(tx) => LocalTransactionStatus::Mined(convert(tx)), + Dropped(tx) => LocalTransactionStatus::Dropped(convert(tx)), + Rejected(tx, reason) => LocalTransactionStatus::Rejected(convert(tx), reason), + Invalid(tx) => LocalTransactionStatus::Invalid(convert(tx)), + Canceled(tx) => LocalTransactionStatus::Canceled(convert(tx)), + Replaced { old, new } => LocalTransactionStatus::Replaced( + convert(old), + new.signed().gas_price.into(), + new.signed().hash().into(), + ), } } } diff --git a/secret_store/src/trusted_client.rs b/secret_store/src/trusted_client.rs index 5a9efe4b68..94b1c0174d 100644 --- a/secret_store/src/trusted_client.rs +++ b/secret_store/src/trusted_client.rs @@ -74,7 +74,7 @@ impl TrustedClient { let transaction = Transaction { nonce: client.latest_nonce(&self.self_key_pair.address()), action: Action::Call(contract), - gas: miner.gas_floor_target(), + gas: miner.authoring_params().gas_range_target.0, gas_price: miner.sensible_gas_price(), value: Default::default(), data: tx_data, diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index b9db0f6d21..fd19192993 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -9,4 +9,5 @@ authors = ["Parity Technologies "] error-chain = "0.11" log = "0.3" smallvec = "0.4" +trace-time = { path = "../util/trace-time" } ethereum-types = "0.3" diff --git a/transaction-pool/src/error.rs b/transaction-pool/src/error.rs index 706a5b77b1..2e8ac73989 100644 --- a/transaction-pool/src/error.rs +++ b/transaction-pool/src/error.rs @@ -21,17 +21,17 @@ error_chain! { /// Transaction is already imported AlreadyImported(hash: H256) { description("transaction is already in the pool"), - display("[{:?}] transaction already imported", hash) + display("[{:?}] already imported", hash) } /// Transaction is too cheap to enter the queue - TooCheapToEnter(hash: H256) { + TooCheapToEnter(hash: H256, min_score: String) { description("the pool is full and transaction is too cheap to replace any transaction"), - display("[{:?}] transaction too cheap to enter the pool", hash) + display("[{:?}] too cheap to enter the pool. Min score: {}", hash, min_score) } /// Transaction is too cheap to replace existing transaction that occupies the same slot. TooCheapToReplace(old_hash: H256, hash: H256) { description("transaction is too cheap to replace existing transaction in the pool"), - display("[{:?}] transaction too cheap to replace: {:?}", hash, old_hash) + display("[{:?}] too cheap to replace: {:?}", hash, old_hash) } } } @@ -43,7 +43,7 @@ impl PartialEq for ErrorKind { match (self, other) { (&AlreadyImported(ref h1), &AlreadyImported(ref h2)) => h1 == h2, - (&TooCheapToEnter(ref h1), &TooCheapToEnter(ref h2)) => h1 == h2, + (&TooCheapToEnter(ref h1, ref s1), &TooCheapToEnter(ref h2, ref s2)) => h1 == h2 && s1 == s2, (&TooCheapToReplace(ref old1, ref new1), &TooCheapToReplace(ref old2, ref new2)) => old1 == old2 && new1 == new2, _ => false, } diff --git a/transaction-pool/src/lib.rs b/transaction-pool/src/lib.rs index 29353a1000..33d17f4b0f 100644 --- a/transaction-pool/src/lib.rs +++ b/transaction-pool/src/lib.rs @@ -76,6 +76,8 @@ extern crate error_chain; #[macro_use] extern crate log; +extern crate trace_time; + #[cfg(test)] mod tests; @@ -90,6 +92,7 @@ mod verifier; pub mod scoring; +pub use self::error::{Error, ErrorKind}; pub use self::listener::{Listener, NoopListener}; pub use self::options::Options; pub use self::pool::{Pool, PendingIterator}; diff --git a/transaction-pool/src/listener.rs b/transaction-pool/src/listener.rs index 2fc55528fe..728a035e31 100644 --- a/transaction-pool/src/listener.rs +++ b/transaction-pool/src/listener.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::sync::Arc; +use error::ErrorKind; /// Transaction pool listener. /// @@ -28,16 +29,16 @@ pub trait Listener { /// The transaction was rejected from the pool. /// It means that it was too cheap to replace any transaction already in the pool. - fn rejected(&mut self, _tx: T) {} + fn rejected(&mut self, _tx: &Arc, _reason: &ErrorKind) {} - /// The transaction was dropped from the pool because of a limit. - fn dropped(&mut self, _tx: &Arc) {} + /// The transaction was pushed out from the pool because of the limit. + fn dropped(&mut self, _tx: &Arc, _by: Option<&T>) {} /// The transaction was marked as invalid by executor. fn invalid(&mut self, _tx: &Arc) {} - /// The transaction has been cancelled. - fn cancelled(&mut self, _tx: &Arc) {} + /// The transaction has been canceled. + fn canceled(&mut self, _tx: &Arc) {} /// The transaction has been mined. fn mined(&mut self, _tx: &Arc) {} @@ -47,3 +48,38 @@ pub trait Listener { #[derive(Debug)] pub struct NoopListener; impl Listener for NoopListener {} + +impl Listener for (A, B) where + A: Listener, + B: Listener, +{ + fn added(&mut self, tx: &Arc, old: Option<&Arc>) { + self.0.added(tx, old); + self.1.added(tx, old); + } + + fn rejected(&mut self, tx: &Arc, reason: &ErrorKind) { + self.0.rejected(tx, reason); + self.1.rejected(tx, reason); + } + + fn dropped(&mut self, tx: &Arc, by: Option<&T>) { + self.0.dropped(tx, by); + self.1.dropped(tx, by); + } + + fn invalid(&mut self, tx: &Arc) { + self.0.invalid(tx); + self.1.invalid(tx); + } + + fn canceled(&mut self, tx: &Arc) { + self.0.canceled(tx); + self.1.canceled(tx); + } + + fn mined(&mut self, tx: &Arc) { + self.0.mined(tx); + self.1.mined(tx); + } +} diff --git a/transaction-pool/src/options.rs b/transaction-pool/src/options.rs index ddec912864..8ccf8adfd1 100644 --- a/transaction-pool/src/options.rs +++ b/transaction-pool/src/options.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . /// Transaction Pool options. -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct Options { /// Maximal number of transactions in the pool. pub max_count: usize, diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index 4f4a63920f..fa28cdcdfe 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -109,17 +109,17 @@ impl Pool where ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(*transaction.hash())); - // TODO [ToDr] Most likely move this after the transsaction is inserted. + // TODO [ToDr] Most likely move this after the transaction is inserted. // Avoid using should_replace, but rather use scoring for that. { let remove_worst = |s: &mut Self, transaction| { match s.remove_worst(&transaction) { Err(err) => { - s.listener.rejected(transaction); + s.listener.rejected(&Arc::new(transaction), err.kind()); Err(err) }, Ok(removed) => { - s.listener.dropped(&removed); + s.listener.dropped(&removed, Some(&transaction)); s.finalize_remove(removed.hash()); Ok(transaction) }, @@ -127,10 +127,12 @@ impl Pool where }; while self.by_hash.len() + 1 > self.options.max_count { + trace!("Count limit reached: {} > {}", self.by_hash.len() + 1, self.options.max_count); transaction = remove_worst(self, transaction)?; } while self.mem_usage + mem_usage > self.options.max_mem_usage { + trace!("Mem limit reached: {} > {}", self.mem_usage + mem_usage, self.options.max_mem_usage); transaction = remove_worst(self, transaction)?; } } @@ -160,14 +162,14 @@ impl Pool where Ok(new) }, AddResult::TooCheap { new, old } => { - let hash = *new.hash(); - self.listener.rejected(new); - bail!(error::ErrorKind::TooCheapToReplace(*old.hash(), hash)) + let error = error::ErrorKind::TooCheapToReplace(*old.hash(), *new.hash()); + self.listener.rejected(&Arc::new(new), &error); + bail!(error) }, - AddResult::TooCheapToEnter(new) => { - let hash = *new.hash(); - self.listener.rejected(new); - bail!(error::ErrorKind::TooCheapToEnter(hash)) + AddResult::TooCheapToEnter(new, score) => { + let error = error::ErrorKind::TooCheapToEnter(*new.hash(), format!("{:?}", score)); + self.listener.rejected(&Arc::new(new), &error); + bail!(error) } } } @@ -241,14 +243,14 @@ impl Pool where // No elements to remove? and the pool is still full? None => { warn!("The pool is full but there are no transactions to remove."); - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash()).into()); + return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), "unknown".into()).into()); }, Some(old) => if self.scoring.should_replace(&old.transaction, transaction) { // New transaction is better than the worst one so we can replace it. old.clone() } else { // otherwise fail - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash()).into()) + return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), format!("{:?}", old.score)).into()) }, }; @@ -256,6 +258,7 @@ impl Pool where self.remove_from_set(to_remove.transaction.sender(), |set, scoring| { set.remove(&to_remove.transaction, scoring) }); + Ok(to_remove.transaction) } @@ -283,7 +286,7 @@ impl Pool where self.worst_transactions.clear(); for (_hash, tx) in self.by_hash.drain() { - self.listener.dropped(&tx) + self.listener.dropped(&tx, None) } } @@ -298,7 +301,7 @@ impl Pool where if is_invalid { self.listener.invalid(&tx); } else { - self.listener.cancelled(&tx); + self.listener.canceled(&tx); } Some(tx) } else { @@ -345,6 +348,16 @@ impl Pool where removed } + /// Returns a transaction if it's part of the pool or `None` otherwise. + pub fn find(&self, hash: &H256) -> Option> { + self.by_hash.get(hash).cloned() + } + + /// Returns worst transaction in the queue (if any). + pub fn worst_transaction(&self) -> Option> { + self.worst_transactions.iter().next().map(|x| x.transaction.clone()) + } + /// Returns an iterator of pending (ready) transactions. pub fn pending>(&self, ready: R) -> PendingIterator { PendingIterator { @@ -354,6 +367,41 @@ impl Pool where } } + /// Returns pending (ready) transactions from given sender. + pub fn pending_from_sender>(&self, ready: R, sender: &Sender) -> PendingIterator { + let best_transactions = self.transactions.get(sender) + .and_then(|transactions| transactions.worst_and_best()) + .map(|(_, best)| ScoreWithRef::new(best.0, best.1)) + .map(|s| { + let mut set = BTreeSet::new(); + set.insert(s); + set + }) + .unwrap_or_default(); + + PendingIterator { + ready, + best_transactions, + pool: self + } + } + + /// Update score of transactions of a particular sender. + pub fn update_scores(&mut self, sender: &Sender, event: S::Event) { + let res = if let Some(set) = self.transactions.get_mut(sender) { + let prev = set.worst_and_best(); + set.update_scores(&self.scoring, event); + let current = set.worst_and_best(); + Some((prev, current)) + } else { + None + }; + + if let Some((prev, current)) = res { + self.update_senders_worst_and_best(prev, current); + } + } + /// Computes the full status of the pool (including readiness). pub fn status>(&self, mut ready: R) -> Status { let mut status = Status::default(); @@ -383,6 +431,21 @@ impl Pool where senders: self.transactions.len(), } } + + /// Returns current pool options. + pub fn options(&self) -> Options { + self.options.clone() + } + + /// Borrows listener instance. + pub fn listener(&self) -> &L { + &self.listener + } + + /// Borrows listener mutably. + pub fn listener_mut(&mut self) -> &mut L { + &mut self.listener + } } /// An iterator over all pending (ready) transactions. @@ -424,7 +487,7 @@ impl<'a, T, R, S, L> Iterator for PendingIterator<'a, T, R, S, L> where return Some(best.transaction) }, - state => warn!("[{:?}] Ignoring {:?} transaction.", best.transaction.hash(), state), + state => trace!("[{:?}] Ignoring {:?} transaction.", best.transaction.hash(), state), } } diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index e4f923c9b5..4e7a9833a1 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -42,7 +42,7 @@ pub enum Choice { /// The `Scoring` implementations can use this information /// to update the `Score` table more efficiently. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Change { +pub enum Change { /// New transaction has been inserted at given index. /// The Score at that index is initialized with default value /// and needs to be filled in. @@ -56,8 +56,12 @@ pub enum Change { /// The score at that index needs to be update (it contains value from previous transaction). ReplacedAt(usize), /// Given number of stalled transactions has been culled from the beginning. - /// Usually the score will have to be re-computed from scratch. + /// The scores has been removed from the beginning as well. + /// For simple scoring algorithms no action is required here. Culled(usize), + /// Custom event to update the score triggered outside of the pool. + /// Handling this event is up to scoring implementation. + Event(T), } /// A transaction ordering. @@ -69,7 +73,7 @@ pub enum Change { /// Implementation notes: /// - Returned `Score`s should match ordering of `compare` method. /// - `compare` will be called only within a context of transactions from the same sender. -/// - `choose` will be called only if `compare` returns `Ordering::Equal` +/// - `choose` may be called even if `compare` returns `Ordering::Equal` /// - `should_replace` is used to decide if new transaction should push out an old transaction already in the queue. /// - `Score`s and `compare` should align with `Ready` implementation. /// @@ -79,9 +83,11 @@ pub enum Change { /// - `update_scores`: score defined as `gasPrice` if `n==0` and `max(scores[n-1], gasPrice)` if `n>0` /// - `should_replace`: compares `gasPrice` (decides if transaction from a different sender is more valuable) /// -pub trait Scoring { +pub trait Scoring: fmt::Debug { /// A score of a transaction. type Score: cmp::Ord + Clone + Default + fmt::Debug; + /// Custom scoring update event type. + type Event: fmt::Debug; /// Decides on ordering of `T`s from a particular sender. fn compare(&self, old: &T, other: &T) -> cmp::Ordering; @@ -92,7 +98,7 @@ pub trait Scoring { /// Updates the transaction scores given a list of transactions and a change to previous scoring. /// NOTE: you can safely assume that both slices have the same length. /// (i.e. score at index `i` represents transaction at the same index) - fn update_scores(&self, txs: &[Arc], scores: &mut [Self::Score], change: Change); + fn update_scores(&self, txs: &[Arc], scores: &mut [Self::Score], change: Change); /// Decides if `new` should push out `old` transaction from the pool. fn should_replace(&self, old: &T, new: &T) -> bool; diff --git a/transaction-pool/src/status.rs b/transaction-pool/src/status.rs index 5862f75a1e..a03bc6b062 100644 --- a/transaction-pool/src/status.rs +++ b/transaction-pool/src/status.rs @@ -16,7 +16,7 @@ /// Light pool status. /// This status is cheap to compute and can be called frequently. -#[derive(Default, Debug, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct LightStatus { /// Memory usage in bytes. pub mem_usage: usize, @@ -29,7 +29,7 @@ pub struct LightStatus { /// A full queue status. /// To compute this status it is required to provide `Ready`. /// NOTE: To compute the status we need to visit each transaction in the pool. -#[derive(Default, Debug, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Status { /// Number of stalled transactions. pub stalled: usize, diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index 4e03cc8961..ab5b2a334b 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -21,11 +21,12 @@ use ethereum_types::U256; use {scoring, Scoring, Ready, Readiness, Address as Sender}; use super::{Transaction, SharedTransaction}; -#[derive(Default)] +#[derive(Debug, Default)] pub struct DummyScoring; impl Scoring for DummyScoring { type Score = U256; + type Event = (); fn compare(&self, old: &Transaction, new: &Transaction) -> cmp::Ordering { old.nonce.cmp(&new.nonce) @@ -43,9 +44,17 @@ impl Scoring for DummyScoring { } } - fn update_scores(&self, txs: &[SharedTransaction], scores: &mut [Self::Score], _change: scoring::Change) { - for i in 0..txs.len() { - scores[i] = txs[i].gas_price; + fn update_scores(&self, txs: &[SharedTransaction], scores: &mut [Self::Score], change: scoring::Change) { + if let scoring::Change::Event(_) = change { + // In case of event reset all scores to 0 + for i in 0..txs.len() { + scores[i] = 0.into(); + } + } else { + // Set to a gas price otherwise + for i in 0..txs.len() { + scores[i] = txs[i].gas_price; + } } } diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index 05b72284b5..5113a4663c 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -125,7 +125,7 @@ fn should_reject_if_above_count() { let tx2 = b.tx().nonce(1).new(); let hash = *tx2.hash(); txq.import(tx1).unwrap(); - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); txq.clear(); @@ -151,7 +151,7 @@ fn should_reject_if_above_mem_usage() { let tx2 = b.tx().nonce(2).mem_usage(2).new(); let hash = *tx2.hash(); txq.import(tx1).unwrap(); - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); txq.clear(); @@ -177,7 +177,7 @@ fn should_reject_if_above_sender_count() { let tx2 = b.tx().nonce(2).new(); let hash = *tx2.hash(); txq.import(tx1).unwrap(); - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); txq.clear(); @@ -188,7 +188,7 @@ fn should_reject_if_above_sender_count() { let hash = *tx2.hash(); txq.import(tx1).unwrap(); // This results in error because we also compare nonces - assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash)); + assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); } @@ -249,6 +249,66 @@ fn should_construct_pending() { assert_eq!(pending.next(), None); } +#[test] +fn should_update_scoring_correctly() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::default(); + + let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap(); + let tx2 = txq.import(b.tx().nonce(2).new()).unwrap(); + // this transaction doesn't get to the block despite high gas price + // because of block gas limit and simplistic ordering algorithm. + txq.import(b.tx().nonce(3).gas_price(4).new()).unwrap(); + //gap + txq.import(b.tx().nonce(5).new()).unwrap(); + + let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap(); + let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap(); + let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap(); + let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap(); + // gap + txq.import(b.tx().sender(1).nonce(5).new()).unwrap(); + + let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap(); + assert_eq!(txq.light_status().transaction_count, 11); + assert_eq!(txq.status(NonceReady::default()), Status { + stalled: 0, + pending: 9, + future: 2, + }); + assert_eq!(txq.status(NonceReady::new(1)), Status { + stalled: 3, + pending: 6, + future: 2, + }); + + txq.update_scores(&0.into(), ()); + + // when + let mut current_gas = U256::zero(); + let limit = (21_000 * 8).into(); + let mut pending = txq.pending(NonceReady::default()).take_while(|tx| { + let should_take = tx.gas + current_gas <= limit; + if should_take { + current_gas = current_gas + tx.gas + } + should_take + }); + + assert_eq!(pending.next(), Some(tx9)); + assert_eq!(pending.next(), Some(tx5)); + assert_eq!(pending.next(), Some(tx6)); + assert_eq!(pending.next(), Some(tx7)); + assert_eq!(pending.next(), Some(tx8)); + // penalized transactions + assert_eq!(pending.next(), Some(tx0)); + assert_eq!(pending.next(), Some(tx1)); + assert_eq!(pending.next(), Some(tx2)); + assert_eq!(pending.next(), None); +} + #[test] fn should_remove_transaction() { // given @@ -375,6 +435,20 @@ fn should_re_insert_after_cull() { }); } +#[test] +fn should_return_worst_transaction() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::default(); + assert!(txq.worst_transaction().is_none()); + + // when + txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + + // then + assert!(txq.worst_transaction().is_some()); +} + mod listener { use std::cell::RefCell; use std::rc::Rc; @@ -389,11 +463,11 @@ mod listener { self.0.borrow_mut().push(if old.is_some() { "replaced" } else { "added" }); } - fn rejected(&mut self, _tx: Transaction) { + fn rejected(&mut self, _tx: &SharedTransaction, _reason: &error::ErrorKind) { self.0.borrow_mut().push("rejected".into()); } - fn dropped(&mut self, _tx: &SharedTransaction) { + fn dropped(&mut self, _tx: &SharedTransaction, _new: Option<&Transaction>) { self.0.borrow_mut().push("dropped".into()); } @@ -401,8 +475,8 @@ mod listener { self.0.borrow_mut().push("invalid".into()); } - fn cancelled(&mut self, _tx: &SharedTransaction) { - self.0.borrow_mut().push("cancelled".into()); + fn canceled(&mut self, _tx: &SharedTransaction) { + self.0.borrow_mut().push("canceled".into()); } fn mined(&mut self, _tx: &SharedTransaction) { @@ -461,9 +535,9 @@ mod listener { // then txq.remove(&tx1.hash(), false); - assert_eq!(*results.borrow(), &["added", "added", "cancelled"]); + assert_eq!(*results.borrow(), &["added", "added", "canceled"]); txq.remove(&tx2.hash(), true); - assert_eq!(*results.borrow(), &["added", "added", "cancelled", "invalid"]); + assert_eq!(*results.borrow(), &["added", "added", "canceled", "invalid"]); assert_eq!(txq.light_status().transaction_count, 0); } diff --git a/transaction-pool/src/transactions.rs b/transaction-pool/src/transactions.rs index 39fd08e931..c839d9e685 100644 --- a/transaction-pool/src/transactions.rs +++ b/transaction-pool/src/transactions.rs @@ -23,9 +23,9 @@ use ready::{Ready, Readiness}; use scoring::{self, Scoring}; #[derive(Debug)] -pub enum AddResult { +pub enum AddResult { Ok(Arc), - TooCheapToEnter(T), + TooCheapToEnter(T, S), TooCheap { old: Arc, new: T, @@ -93,10 +93,11 @@ impl> Transactions { }) } - fn push_cheapest_transaction(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { + fn push_cheapest_transaction(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { let index = self.transactions.len(); if index == max_count { - AddResult::TooCheapToEnter(tx) + let min_score = self.scores[index - 1].clone(); + AddResult::TooCheapToEnter(tx, min_score) } else { let shared = Arc::new(tx); self.transactions.push(shared.clone()); @@ -107,7 +108,11 @@ impl> Transactions { } } - pub fn add(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { + pub fn update_scores(&mut self, scoring: &S, event: S::Event) { + scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::Event(event)); + } + + pub fn add(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { let index = match self.transactions.binary_search_by(|old| scoring.compare(old, &tx)) { Ok(index) => index, Err(index) => index, @@ -192,6 +197,10 @@ impl> Transactions { } } + if first_non_stalled == 0 { + return result; + } + // reverse the vectors to easily remove first elements. self.transactions.reverse(); self.scores.reverse(); diff --git a/util/table/Cargo.toml b/util/table/Cargo.toml deleted file mode 100644 index f2faca184d..0000000000 --- a/util/table/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "table" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] diff --git a/util/table/src/lib.rs b/util/table/src/lib.rs deleted file mode 100644 index 78b2c646ae..0000000000 --- a/util/table/src/lib.rs +++ /dev/null @@ -1,261 +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 . - -//! A collection associating pair of keys (row and column) with a single value. - -use std::hash::Hash; -use std::collections::HashMap; -use std::collections::hash_map::Keys; - -/// Structure to hold double-indexed values -/// -/// You can obviously use `HashMap<(Row,Col), Val>`, but this structure gives -/// you better access to all `Columns` in Specific `Row`. Namely you can get sub-hashmap -/// `HashMap` for specific `Row` -#[derive(Default, Debug, PartialEq)] -pub struct Table - where Row: Eq + Hash + Clone, - Col: Eq + Hash { - map: HashMap>, -} - -impl Table - where Row: Eq + Hash + Clone, - Col: Eq + Hash { - /// Creates new Table - pub fn new() -> Self { - Table { - map: HashMap::new(), - } - } - - /// Returns keys iterator for this Table. - pub fn keys(&self) -> Keys> { - self.map.keys() - } - - /// Removes all elements from this Table - pub fn clear(&mut self) { - self.map.clear(); - } - - /// Returns length of the Table (number of (row, col, val) tuples) - pub fn len(&self) -> usize { - self.map.values().fold(0, |acc, v| acc + v.len()) - } - - /// Check if there is any element in this Table - pub fn is_empty(&self) -> bool { - self.map.is_empty() || self.map.values().all(|v| v.is_empty()) - } - - /// Get mutable reference for single Table row. - pub fn row_mut(&mut self, row: &Row) -> Option<&mut HashMap> { - self.map.get_mut(row) - } - - /// Checks if row is defined for that table (note that even if defined it might be empty) - pub fn has_row(&self, row: &Row) -> bool { - self.map.contains_key(row) - } - - /// Get immutable reference for single row in this Table - pub fn row(&self, row: &Row) -> Option<&HashMap> { - self.map.get(row) - } - - /// Get element in cell described by `(row, col)` - pub fn get(&self, row: &Row, col: &Col) -> Option<&Val> { - self.map.get(row).and_then(|r| r.get(col)) - } - - /// Remove value from specific cell - /// - /// It will remove the row if it's the last value in it - pub fn remove(&mut self, row: &Row, col: &Col) -> Option { - let (val, is_empty) = { - let row_map = self.map.get_mut(row); - if let None = row_map { - return None; - } - let row_map = row_map.unwrap(); - let val = row_map.remove(col); - (val, row_map.is_empty()) - }; - // Clean row - if is_empty { - self.map.remove(row); - } - val - } - - /// Remove given row from Table if there are no values defined in it - /// - /// When using `#row_mut` it may happen that all values from some row are drained. - /// Table however will not be aware that row is empty. - /// You can use this method to explicitly remove row entry from the Table. - pub fn clear_if_empty(&mut self, row: &Row) { - let is_empty = self.map.get(row).map_or(false, |m| m.is_empty()); - if is_empty { - self.map.remove(row); - } - } - - /// Inserts new value to specified cell - /// - /// Returns previous value (if any) - pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option { - self.map.entry(row).or_insert_with(HashMap::new).insert(col, val) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn should_create_empty_table() { - // when - let table : Table = Table::new(); - - // then - assert!(table.is_empty()); - assert_eq!(table.len(), 0); - } - - #[test] - fn should_insert_elements_and_return_previous_if_any() { - // given - let mut table = Table::new(); - - // when - let r1 = table.insert(5, 4, true); - let r2 = table.insert(10, 4, true); - let r3 = table.insert(10, 10, true); - let r4 = table.insert(10, 10, false); - - // then - assert!(r1.is_none()); - assert!(r2.is_none()); - assert!(r3.is_none()); - assert!(r4.is_some()); - assert!(!table.is_empty()); - assert_eq!(r4.unwrap(), true); - assert_eq!(table.len(), 3); - } - - #[test] - fn should_remove_element() { - // given - let mut table = Table::new(); - table.insert(5, 4, true); - assert!(!table.is_empty()); - assert_eq!(table.len(), 1); - - // when - let r = table.remove(&5, &4); - - // then - assert!(table.is_empty()); - assert_eq!(table.len() ,0); - assert_eq!(r.unwrap(), true); - } - - #[test] - fn should_return_none_if_trying_to_remove_non_existing_element() { - // given - let mut table : Table = Table::new(); - assert!(table.is_empty()); - - // when - let r = table.remove(&5, &4); - - // then - assert!(r.is_none()); - } - - #[test] - fn should_clear_row_if_removing_last_element() { - // given - let mut table = Table::new(); - table.insert(5, 4, true); - assert!(table.has_row(&5)); - - // when - let r = table.remove(&5, &4); - - // then - assert!(r.is_some()); - assert!(!table.has_row(&5)); - } - - #[test] - fn should_return_element_given_row_and_col() { - // given - let mut table = Table::new(); - table.insert(1551, 1234, 123); - - // when - let r1 = table.get(&1551, &1234); - let r2 = table.get(&5, &4); - - // then - assert!(r1.is_some()); - assert!(r2.is_none()); - assert_eq!(r1.unwrap(), &123); - } - - #[test] - fn should_clear_table() { - // given - let mut table = Table::new(); - table.insert(1, 1, true); - table.insert(1, 2, false); - table.insert(2, 2, false); - assert_eq!(table.len(), 3); - - // when - table.clear(); - - // then - assert!(table.is_empty()); - assert_eq!(table.len(), 0); - assert_eq!(table.has_row(&1), false); - assert_eq!(table.has_row(&2), false); - } - - #[test] - fn should_return_mutable_row() { - // given - let mut table = Table::new(); - table.insert(1, 1, true); - table.insert(1, 2, false); - table.insert(2, 2, false); - - // when - { - let row = table.row_mut(&1).unwrap(); - row.remove(&1); - row.remove(&2); - } - assert!(table.has_row(&1)); - table.clear_if_empty(&1); - - // then - assert!(!table.has_row(&1)); - assert_eq!(table.len(), 1); - } -} diff --git a/util/using_queue/src/lib.rs b/util/using_queue/src/lib.rs index 3ce822094a..03862e9c8a 100644 --- a/util/using_queue/src/lib.rs +++ b/util/using_queue/src/lib.rs @@ -82,13 +82,13 @@ impl UsingQueue where T: Clone { /// Returns `Some` item which is the first that `f` returns `true` with a reference to it /// as a parameter or `None` if no such item exists in the queue. - pub fn take_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { + fn take_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { self.in_use.iter().position(|r| predicate(r)).map(|i| self.in_use.remove(i)) } /// Returns `Some` item which is the first that `f` returns `true` with a reference to it /// as a parameter or `None` if no such item exists in the queue. - pub fn clone_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { + fn clone_used_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { self.in_use.iter().find(|r| predicate(r)).cloned() } -- GitLab From 3f677c6168749186fa84bb30728ac573b832339e Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 13 Apr 2018 21:00:14 +0200 Subject: [PATCH 073/263] clarify that windows need perl and yasm (#8402) --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e4a12bf02..bfa7bde7bf 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,11 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do $ rustup default stable-x86_64-pc-windows-msvc ``` -Once you have rustup, install Parity or download and build from source +Once you have rustup installed, then you need to install: +* [Perl](https://www.perl.org) +* [Yasm](http://yasm.tortall.net) + +Make sure that these binaries are in your `PATH`. After that you should be able to build parity from source. ---- -- GitLab From 897a94641e9c9a93be857d054645d064d00d8652 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 14 Apr 2018 03:14:53 +0800 Subject: [PATCH 074/263] Unify and limit rocksdb dependency places (#8371) * secret_store: remove kvdb_rocksdb dependency * cli: init db mod for open dispatch * cli: move db, client_db, restoration_db, secretstore_db to a separate mod * migration: rename to migration-rocksdb and remove ethcore-migrations * ethcore: re-move kvdb-rocksdb dep to test * mark test_helpers as test only and fix migration mod naming * Move restoration_db_handler to test_helpers_internal * Fix missing preambles in test_helpers_internal and rocksdb/helpers * Move test crates downward * Fix missing docs * cli, db::open_db: move each argument to a separate line * Use featuregate instead of dead code for `open_secretstore_db` * Move pathbuf import to open_secretstore_db Because it's only used there behind a feature gate --- Cargo.lock | 12 +-- Cargo.toml | 3 +- ethcore/Cargo.toml | 2 +- ethcore/migrations/Cargo.toml | 7 -- ethcore/src/lib.rs | 6 +- ethcore/src/snapshot/service.rs | 2 +- ethcore/src/snapshot/tests/service.rs | 3 +- ethcore/src/test_helpers.rs | 20 ---- ethcore/src/test_helpers_internal.rs | 39 ++++++++ parity/blockchain.rs | 39 +++----- .../migrations/src/lib.rs => parity/db/mod.rs | 26 ++---- parity/db/rocksdb/helpers.rs | 38 ++++++++ parity/{ => db/rocksdb}/migration.rs | 41 +++++++-- parity/db/rocksdb/mod.rs | 91 +++++++++++++++++++ parity/export_hardcoded_sync.rs | 26 ++---- parity/helpers.rs | 55 +---------- parity/main.rs | 5 +- parity/run.rs | 33 ++----- parity/secretstore.rs | 5 +- parity/snapshot.rs | 10 +- secret_store/Cargo.toml | 2 +- secret_store/src/key_storage.rs | 76 ++++++---------- secret_store/src/lib.rs | 9 +- secret_store/src/types/all.rs | 2 - .../Cargo.toml | 2 +- .../src/lib.rs | 0 .../tests/tests.rs | 2 +- 27 files changed, 295 insertions(+), 261 deletions(-) delete mode 100644 ethcore/migrations/Cargo.toml create mode 100644 ethcore/src/test_helpers_internal.rs rename ethcore/migrations/src/lib.rs => parity/db/mod.rs (56%) create mode 100644 parity/db/rocksdb/helpers.rs rename parity/{ => db/rocksdb}/migration.rs (84%) create mode 100644 parity/db/rocksdb/mod.rs rename util/{migration => migration-rocksdb}/Cargo.toml (91%) rename util/{migration => migration-rocksdb}/src/lib.rs (100%) rename util/{migration => migration-rocksdb}/tests/tests.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 70f7a02661..402327b2e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -641,13 +641,6 @@ dependencies = [ "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethcore-migrations" -version = "0.1.0" -dependencies = [ - "migration 0.1.0", -] - [[package]] name = "ethcore-miner" version = "1.11.0" @@ -1630,7 +1623,7 @@ dependencies = [ ] [[package]] -name = "migration" +name = "migration-rocksdb" version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1933,7 +1926,6 @@ dependencies = [ "ethcore-io 1.11.0", "ethcore-light 1.11.0", "ethcore-logger 1.11.0", - "ethcore-migrations 0.1.0", "ethcore-miner 1.11.0", "ethcore-network 1.11.0", "ethcore-private-tx 1.0.0", @@ -1956,7 +1948,7 @@ dependencies = [ "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", - "migration 0.1.0", + "migration-rocksdb 0.1.0", "node-filter 1.11.0", "node-health 0.1.0", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 5103c2b2b7..9daf4fb558 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,6 @@ ethcore-bytes = { path = "util/bytes" } ethcore-io = { path = "util/io" } ethcore-light = { path = "ethcore/light" } ethcore-logger = { path = "logger" } -ethcore-migrations = { path = "ethcore/migrations" } ethcore-miner = { path = "miner" } ethcore-network = { path = "util/network" } ethcore-private-tx = { path = "ethcore/private-tx" } @@ -64,7 +63,7 @@ path = { path = "util/path" } dir = { path = "util/dir" } panic_hook = { path = "util/panic_hook" } keccak-hash = { path = "util/hash" } -migration = { path = "util/migration" } +migration-rocksdb = { path = "util/migration-rocksdb" } kvdb = { path = "util/kvdb" } kvdb-rocksdb = { path = "util/kvdb-rocksdb" } journaldb = { path = "util/journaldb" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index b8035f0712..6916629758 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -51,7 +51,6 @@ rlp_compress = { path = "../util/rlp_compress" } rlp_derive = { path = "../util/rlp_derive" } kvdb = { path = "../util/kvdb" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } util-error = { path = "../util/error" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } @@ -71,6 +70,7 @@ journaldb = { path = "../util/journaldb" } [dev-dependencies] tempdir = "0.3" trie-standardmap = { path = "../util/trie-standardmap" } +kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } [features] # Display EVM debug traces. diff --git a/ethcore/migrations/Cargo.toml b/ethcore/migrations/Cargo.toml deleted file mode 100644 index 561925be4c..0000000000 --- a/ethcore/migrations/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "ethcore-migrations" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -migration = { path = "../../util/migration" } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index abb680c952..1b0a1e3546 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -92,7 +92,6 @@ extern crate ansi_term; extern crate unexpected; extern crate kvdb; extern crate kvdb_memorydb; -extern crate kvdb_rocksdb; extern crate util_error; extern crate snappy; @@ -128,6 +127,9 @@ extern crate evm; pub extern crate ethstore; +#[cfg(test)] +extern crate kvdb_rocksdb; + pub mod account_provider; pub mod block; pub mod client; @@ -167,6 +169,8 @@ mod tests; #[cfg(test)] #[cfg(feature="json-tests")] mod json_tests; +#[cfg(test)] +mod test_helpers_internal; pub use types::*; pub use executive::contract_address; diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 7d5eea1eff..9cfb2eb63f 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -635,7 +635,7 @@ mod tests { use snapshot::{ManifestData, RestorationStatus, SnapshotService}; use super::*; use tempdir::TempDir; - use test_helpers::restoration_db_handler; + use test_helpers_internal::restoration_db_handler; struct NoopDBRestore; impl DatabaseRestore for NoopDBRestore { diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index d49e6fd63b..3e3087f2bf 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -24,7 +24,8 @@ use ids::BlockId; use snapshot::service::{Service, ServiceParams}; use snapshot::{self, ManifestData, SnapshotService}; use spec::Spec; -use test_helpers::{generate_dummy_client_with_spec_and_data, restoration_db_handler}; +use test_helpers::generate_dummy_client_with_spec_and_data; +use test_helpers_internal::restoration_db_handler; use io::IoChannel; use kvdb_rocksdb::{Database, DatabaseConfig}; diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 8d10e4b3b8..692f029c86 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -35,11 +35,8 @@ use spec::Spec; use state_db::StateDB; use state::*; use std::sync::Arc; -use std::path::Path; use transaction::{Action, Transaction, SignedTransaction}; use views::BlockView; -use kvdb::{KeyValueDB, KeyValueDBHandler}; -use kvdb_rocksdb::{Database, DatabaseConfig}; /// Creates test block with corresponding header pub fn create_test_block(header: &Header) -> Bytes { @@ -402,20 +399,3 @@ impl ChainNotify for TestNotify { self.messages.write().push(data); } } - -/// Creates new instance of KeyValueDBHandler -pub fn restoration_db_handler(config: DatabaseConfig) -> Box { - use kvdb::Error; - - struct RestorationDBHandler { - config: DatabaseConfig, - } - - impl KeyValueDBHandler for RestorationDBHandler { - fn open(&self, db_path: &Path) -> Result, Error> { - Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) - } - } - - Box::new(RestorationDBHandler { config }) -} diff --git a/ethcore/src/test_helpers_internal.rs b/ethcore/src/test_helpers_internal.rs new file mode 100644 index 0000000000..ef98c7c85b --- /dev/null +++ b/ethcore/src/test_helpers_internal.rs @@ -0,0 +1,39 @@ +// 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 . + +//! Internal helpers for client tests + +use std::path::Path; +use std::sync::Arc; +use kvdb::{KeyValueDB, KeyValueDBHandler}; +use kvdb_rocksdb::{Database, DatabaseConfig}; + +/// Creates new instance of KeyValueDBHandler +pub fn restoration_db_handler(config: DatabaseConfig) -> Box { + use kvdb::Error; + + struct RestorationDBHandler { + config: DatabaseConfig, + } + + impl KeyValueDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> Result, Error> { + Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + } + } + + Box::new(RestorationDBHandler { config }) +} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 4a4441b89f..586313ab41 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -27,20 +27,19 @@ use bytes::ToPretty; use rlp::PayloadInfo; use ethcore::account_provider::AccountProvider; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock}; -use ethcore::db::NUM_COLUMNS; use ethcore::error::ImportError; use ethcore::miner::Miner; use ethcore::verification::queue::VerifierSettings; use ethcore_service::ClientService; use cache::CacheConfig; use informant::{Informant, FullNodeInformantData, MillisecondDuration}; -use kvdb_rocksdb::{Database, DatabaseConfig}; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool}; -use helpers::{to_client_config, execute_upgrades, open_client_db, client_db_config, restoration_db_handler, compaction_profile}; +use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; use fdlimit; use ethcore_private_tx; +use db; #[derive(Debug, PartialEq)] pub enum DataFormat { @@ -188,8 +187,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { let client_path = db_dirs.client_path(algorithm); // execute upgrades - let compaction = compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()); - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction)?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(false, false, false)?; @@ -210,19 +208,10 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { config.queue.verifier_settings = cmd.verifier_settings; // initialize database. - let db = { - let db_config = DatabaseConfig { - memory_budget: Some(cmd.cache_config.blockchain() as usize * 1024 * 1024), - compaction: compaction, - wal: cmd.wal, - .. DatabaseConfig::with_columns(NUM_COLUMNS) - }; - - Arc::new(Database::open( - &db_config, - &client_path.to_str().expect("DB path could not be converted to string.") - ).map_err(|e| format!("Failed to open database: {}", e))?) - }; + let db = db::open_db(&client_path.to_str().expect("DB path could not be converted to string."), + &cmd.cache_config, + &cmd.compaction, + cmd.wal)?; // TODO: could epoch signals be avilable at the end of the file? let fetch = ::light::client::fetch::unavailable(); @@ -354,7 +343,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(false, false, false)?; @@ -378,9 +367,8 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { client_config.queue.verifier_settings = cmd.verifier_settings; - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); // build client let service = ClientService::start( @@ -549,7 +537,7 @@ fn start_client( let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&dirs.base, &db_dirs, algorithm, compaction_profile(&compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&dirs.base, &db_dirs, algorithm, &compaction)?; // create dirs used by parity dirs.create_dirs(false, false, false)?; @@ -571,9 +559,8 @@ fn start_client( true, ); - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); let service = ClientService::start( client_config, diff --git a/ethcore/migrations/src/lib.rs b/parity/db/mod.rs similarity index 56% rename from ethcore/migrations/src/lib.rs rename to parity/db/mod.rs index 429c39102c..39f43fd145 100644 --- a/ethcore/migrations/src/lib.rs +++ b/parity/db/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,24 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Database migrations. +//! Database-related operations. -extern crate migration; +#[path="rocksdb/mod.rs"] +mod impls; -use migration::ChangeColumns; +pub use self::impls::{open_db, open_client_db, restoration_db_handler, migrate}; -/// The migration from v10 to v11. -/// Adds a column for node info. -pub const TO_V11: ChangeColumns = ChangeColumns { - pre_columns: Some(6), - post_columns: Some(7), - version: 11, -}; - -/// The migration from v11 to v12. -/// Adds a column for light chain storage. -pub const TO_V12: ChangeColumns = ChangeColumns { - pre_columns: Some(7), - post_columns: Some(8), - version: 12, -}; +#[cfg(feature = "secretstore")] +pub use self::impls::open_secretstore_db; diff --git a/parity/db/rocksdb/helpers.rs b/parity/db/rocksdb/helpers.rs new file mode 100644 index 0000000000..ca685d3e86 --- /dev/null +++ b/parity/db/rocksdb/helpers.rs @@ -0,0 +1,38 @@ +// Copyright 2015-2018 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 . + +use std::path::Path; +use ethcore::db::NUM_COLUMNS; +use ethcore::client::{ClientConfig, DatabaseCompactionProfile}; +use super::kvdb_rocksdb::{CompactionProfile, DatabaseConfig}; + +pub fn compaction_profile(profile: &DatabaseCompactionProfile, db_path: &Path) -> CompactionProfile { + match profile { + &DatabaseCompactionProfile::Auto => CompactionProfile::auto(db_path), + &DatabaseCompactionProfile::SSD => CompactionProfile::ssd(), + &DatabaseCompactionProfile::HDD => CompactionProfile::hdd(), + } +} + +pub fn client_db_config(client_path: &Path, client_config: &ClientConfig) -> DatabaseConfig { + let mut client_db_config = DatabaseConfig::with_columns(NUM_COLUMNS); + + client_db_config.memory_budget = client_config.db_cache_size; + client_db_config.compaction = compaction_profile(&client_config.db_compaction, &client_path); + client_db_config.wal = client_config.db_wal; + + client_db_config +} diff --git a/parity/migration.rs b/parity/db/rocksdb/migration.rs similarity index 84% rename from parity/migration.rs rename to parity/db/rocksdb/migration.rs index bd659cba01..df6a4b5dc9 100644 --- a/parity/migration.rs +++ b/parity/db/rocksdb/migration.rs @@ -18,9 +18,28 @@ use std::fs; use std::io::{Read, Write, Error as IoError, ErrorKind}; use std::path::{Path, PathBuf}; use std::fmt::{Display, Formatter, Error as FmtError}; -use migr::{self, Manager as MigrationManager, Config as MigrationConfig}; -use kvdb_rocksdb::CompactionProfile; -use migrations; +use super::migration_rocksdb::{self, Manager as MigrationManager, Config as MigrationConfig, ChangeColumns}; +use super::kvdb_rocksdb::CompactionProfile; +use ethcore::client::DatabaseCompactionProfile; + +use super::helpers; + +/// The migration from v10 to v11. +/// Adds a column for node info. +pub const TO_V11: ChangeColumns = ChangeColumns { + pre_columns: Some(6), + post_columns: Some(7), + version: 11, +}; + +/// The migration from v11 to v12. +/// Adds a column for light chain storage. +pub const TO_V12: ChangeColumns = ChangeColumns { + pre_columns: Some(7), + post_columns: Some(8), + version: 12, +}; + /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; @@ -43,7 +62,7 @@ pub enum Error { /// Migration is not possible. MigrationImpossible, /// Internal migration error. - Internal(migr::Error), + Internal(migration_rocksdb::Error), /// Migration was completed succesfully, /// but there was a problem with io. Io(IoError), @@ -69,10 +88,10 @@ impl From for Error { } } -impl From for Error { - fn from(err: migr::Error) -> Self { +impl From for Error { + fn from(err: migration_rocksdb::Error) -> Self { match err.into() { - migr::ErrorKind::Io(e) => Error::Io(e), + migration_rocksdb::ErrorKind::Io(e) => Error::Io(e), err => Error::Internal(err.into()), } } @@ -134,8 +153,8 @@ pub fn default_migration_settings(compaction_profile: &CompactionProfile) -> Mig /// Migrations on the consolidated database. fn consolidated_database_migrations(compaction_profile: &CompactionProfile) -> Result { let mut manager = MigrationManager::new(default_migration_settings(compaction_profile)); - manager.add_migration(migrations::TO_V11).map_err(|_| Error::MigrationImpossible)?; - manager.add_migration(migrations::TO_V12).map_err(|_| Error::MigrationImpossible)?; + manager.add_migration(TO_V11).map_err(|_| Error::MigrationImpossible)?; + manager.add_migration(TO_V12).map_err(|_| Error::MigrationImpossible)?; Ok(manager) } @@ -176,7 +195,9 @@ fn exists(path: &Path) -> bool { } /// Migrates the database. -pub fn migrate(path: &Path, compaction_profile: CompactionProfile) -> Result<(), Error> { +pub fn migrate(path: &Path, compaction_profile: &DatabaseCompactionProfile) -> Result<(), Error> { + let compaction_profile = helpers::compaction_profile(&compaction_profile, path); + // read version file. let version = current_version(path)?; diff --git a/parity/db/rocksdb/mod.rs b/parity/db/rocksdb/mod.rs new file mode 100644 index 0000000000..7bfd28f650 --- /dev/null +++ b/parity/db/rocksdb/mod.rs @@ -0,0 +1,91 @@ +// Copyright 2015-2018 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 . + +extern crate kvdb_rocksdb; +extern crate migration_rocksdb; + +use std::sync::Arc; +use std::path::Path; +use ethcore::db::NUM_COLUMNS; +use ethcore::client::{ClientConfig, DatabaseCompactionProfile}; +use kvdb::{KeyValueDB, KeyValueDBHandler}; +use self::kvdb_rocksdb::{Database, DatabaseConfig}; + +use cache::CacheConfig; + +mod migration; +mod helpers; + +pub use self::migration::migrate; + +/// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path. +#[cfg(feature = "secretstore")] +pub fn open_secretstore_db(data_path: &str) -> Result, String> { + use std::path::PathBuf; + + let mut db_path = PathBuf::from(data_path); + db_path.push("db"); + let db_path = db_path.to_str().ok_or_else(|| "Invalid secretstore path".to_string())?; + Ok(Arc::new(Database::open_default(&db_path).map_err(|e| format!("Error opening database: {:?}", e))?)) +} + +/// Open a new client DB. +pub fn open_client_db(client_path: &Path, client_config: &ClientConfig) -> Result, String> { + let client_db_config = helpers::client_db_config(client_path, client_config); + + let client_db = Arc::new(Database::open( + &client_db_config, + &client_path.to_str().expect("DB path could not be converted to string.") + ).map_err(|e| format!("Client service database error: {:?}", e))?); + + Ok(client_db) +} + +/// Create a restoration db handler using the config generated by `client_path` and `client_config`. +pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig) -> Box { + use kvdb::Error; + + let client_db_config = helpers::client_db_config(client_path, client_config); + + struct RestorationDBHandler { + config: DatabaseConfig, + } + + impl KeyValueDBHandler for RestorationDBHandler { + fn open(&self, db_path: &Path) -> Result, Error> { + Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) + } + } + + Box::new(RestorationDBHandler { + config: client_db_config, + }) +} + +/// Open a new main DB. +pub fn open_db(client_path: &str, cache_config: &CacheConfig, compaction: &DatabaseCompactionProfile, wal: bool) -> Result, String> { + let db_config = DatabaseConfig { + memory_budget: Some(cache_config.blockchain() as usize * 1024 * 1024), + compaction: helpers::compaction_profile(&compaction, &Path::new(client_path)), + wal: wal, + .. DatabaseConfig::with_columns(NUM_COLUMNS) + }; + + Ok(Arc::new(Database::open( + &db_config, + client_path + ).map_err(|e| format!("Failed to open database: {}", e))?)) +} diff --git a/parity/export_hardcoded_sync.rs b/parity/export_hardcoded_sync.rs index accb6159fa..3aa2b56149 100644 --- a/parity/export_hardcoded_sync.rs +++ b/parity/export_hardcoded_sync.rs @@ -18,17 +18,16 @@ use std::sync::Arc; use std::time::Duration; use ethcore::client::DatabaseCompactionProfile; -use ethcore::db::NUM_COLUMNS; use ethcore::spec::{SpecParams, OptimizeFor}; -use kvdb_rocksdb::{Database, DatabaseConfig}; use light::client::fetch::Unavailable as UnavailableDataFetcher; use light::Cache as LightDataCache; use params::{SpecType, Pruning}; -use helpers::{execute_upgrades, compaction_profile}; +use helpers::execute_upgrades; use dir::Directories; use cache::CacheConfig; use user_defaults::UserDefaults; +use db; // Number of minutes before a given gas price corpus should expire. // Light client only. @@ -66,10 +65,8 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { // select pruning algorithm let algorithm = cmd.pruning.to_algorithm(&user_defaults); - let compaction = compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()); - // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction.clone())?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(false, false, false)?; @@ -90,19 +87,10 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024; // initialize database. - let db = { - let db_config = DatabaseConfig { - memory_budget: Some(cmd.cache_config.blockchain() as usize * 1024 * 1024), - compaction: compaction, - wal: cmd.wal, - .. DatabaseConfig::with_columns(NUM_COLUMNS) - }; - - Arc::new(Database::open( - &db_config, - &db_dirs.client_path(algorithm).to_str().expect("DB path could not be converted to string.") - ).map_err(|e| format!("Error opening database: {}", e))?) - }; + let db = db::open_db(&db_dirs.client_path(algorithm).to_str().expect("DB path could not be converted to string."), + &cmd.cache_config, + &cmd.compaction, + cmd.wal)?; let service = light_client::Service::start(config, &spec, UnavailableDataFetcher, db, cache) .map_err(|e| format!("Error starting light client: {}", e))?; diff --git a/parity/helpers.rs b/parity/helpers.rs index cdd951c2b7..80ade50983 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -18,22 +18,17 @@ use std::io; use std::io::{Write, BufReader, BufRead}; use std::time::Duration; use std::fs::File; -use std::sync::Arc; -use std::path::Path; use ethereum_types::{U256, clean_0x, Address}; use journaldb::Algorithm; use ethcore::client::{Mode, BlockId, VMType, DatabaseCompactionProfile, ClientConfig, VerifierType}; -use ethcore::db::NUM_COLUMNS; use ethcore::miner::{PendingSet, Penalization}; use miner::pool::PrioritizationStrategy; use cache::CacheConfig; use dir::DatabaseDirectories; use dir::helpers::replace_home; use upgrade::{upgrade, upgrade_data_paths}; -use migration::migrate; use sync::{validate_node_url, self}; -use kvdb::{KeyValueDB, KeyValueDBHandler}; -use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile}; +use db::migrate; use path; pub fn to_duration(s: &str) -> Result { @@ -258,57 +253,11 @@ pub fn to_client_config( client_config } -// We assume client db has similar config as restoration db. -pub fn client_db_config(client_path: &Path, client_config: &ClientConfig) -> DatabaseConfig { - let mut client_db_config = DatabaseConfig::with_columns(NUM_COLUMNS); - - client_db_config.memory_budget = client_config.db_cache_size; - client_db_config.compaction = compaction_profile(&client_config.db_compaction, &client_path); - client_db_config.wal = client_config.db_wal; - - client_db_config -} - -pub fn open_client_db(client_path: &Path, client_db_config: &DatabaseConfig) -> Result, String> { - let client_db = Arc::new(Database::open( - &client_db_config, - &client_path.to_str().expect("DB path could not be converted to string.") - ).map_err(|e| format!("Client service database error: {:?}", e))?); - - Ok(client_db) -} - -pub fn restoration_db_handler(client_db_config: DatabaseConfig) -> Box { - use kvdb::Error; - - struct RestorationDBHandler { - config: DatabaseConfig, - } - - impl KeyValueDBHandler for RestorationDBHandler { - fn open(&self, db_path: &Path) -> Result, Error> { - Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?)) - } - } - - Box::new(RestorationDBHandler { - config: client_db_config, - }) -} - -pub fn compaction_profile(profile: &DatabaseCompactionProfile, db_path: &Path) -> CompactionProfile { - match profile { - &DatabaseCompactionProfile::Auto => CompactionProfile::auto(db_path), - &DatabaseCompactionProfile::SSD => CompactionProfile::ssd(), - &DatabaseCompactionProfile::HDD => CompactionProfile::hdd(), - } -} - pub fn execute_upgrades( base_path: &str, dirs: &DatabaseDirectories, pruning: Algorithm, - compaction_profile: CompactionProfile + compaction_profile: &DatabaseCompactionProfile ) -> Result<(), String> { upgrade_data_paths(base_path, dirs, pruning); diff --git a/parity/main.rs b/parity/main.rs index d7d5b137e3..24b53ae2c9 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -50,7 +50,6 @@ extern crate ethcore_bytes as bytes; extern crate ethcore_io as io; extern crate ethcore_light as light; extern crate ethcore_logger; -extern crate ethcore_migrations as migrations; extern crate ethcore_miner as miner; extern crate ethcore_network as network; extern crate ethcore_private_tx; @@ -60,8 +59,6 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethkey; extern crate kvdb; -extern crate kvdb_rocksdb; -extern crate migration as migr; extern crate node_health; extern crate panic_hook; extern crate parity_hash_fetch as hash_fetch; @@ -112,7 +109,6 @@ mod deprecated; mod helpers; mod informant; mod light_helpers; -mod migration; mod modules; mod params; mod presale; @@ -126,6 +122,7 @@ mod upgrade; mod url; mod user_defaults; mod whisper; +mod db; #[cfg(feature="stratum")] mod stratum; diff --git a/parity/run.rs b/parity/run.rs index f4e892b4b9..6ccd4caf56 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -25,7 +25,6 @@ use ansi_term::{Colour, Style}; use ctrlc::CtrlC; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; -use ethcore::db::NUM_COLUMNS; use ethcore::ethstore::ethkey; use ethcore::miner::{stratum, Miner, MinerService, MinerOptions}; use ethcore::snapshot; @@ -40,7 +39,6 @@ use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; use journaldb::Algorithm; -use kvdb_rocksdb::{Database, DatabaseConfig}; use light::Cache as LightDataCache; use miner::external::ExternalMiner; use node_filter::NodeFilter; @@ -55,7 +53,7 @@ use params::{ SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch, tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool }; -use helpers::{to_client_config, execute_upgrades, passwords_from_files, client_db_config, open_client_db, restoration_db_handler, compaction_profile}; +use helpers::{to_client_config, execute_upgrades, passwords_from_files}; use upgrade::upgrade_key_location; use dir::{Directories, DatabaseDirectories}; use cache::CacheConfig; @@ -68,6 +66,7 @@ use rpc_apis; use secretstore; use signer; use url; +use db; // how often to take periodic snapshots. const SNAPSHOT_PERIOD: u64 = 5000; @@ -210,10 +209,8 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction_profile(&cmd.compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?; @@ -623,9 +611,8 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // set network path. net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); // create client service. let service = ClientService::start( diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 9c130a59a9..168a9b3fcf 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -117,6 +117,7 @@ mod server { use ethcore_secretstore; use ethkey::KeyPair; use ansi_term::Colour::Red; + use db; use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress}; fn into_service_contract_address(address: ContractAddress) -> ethcore_secretstore::ContractAddress { @@ -173,7 +174,6 @@ mod server { service_contract_srv_retr_address: conf.service_contract_srv_retr_address.map(into_service_contract_address), service_contract_doc_store_address: conf.service_contract_doc_store_address.map(into_service_contract_address), service_contract_doc_sretr_address: conf.service_contract_doc_sretr_address.map(into_service_contract_address), - data_path: conf.data_path.clone(), acl_check_enabled: conf.acl_check_enabled, cluster_config: ethcore_secretstore::ClusterConfiguration { threads: 4, @@ -193,7 +193,8 @@ mod server { cconf.cluster_config.nodes.insert(self_secret.public().clone(), cconf.cluster_config.listener_address.clone()); - let key_server = ethcore_secretstore::start(deps.client, deps.sync, deps.miner, self_secret, cconf) + let db = db::open_secretstore_db(&conf.data_path)?; + let key_server = ethcore_secretstore::start(deps.client, deps.sync, deps.miner, self_secret, cconf, db) .map_err(|e| format!("Error starting KeyServer {}: {}", key_server_name, e))?; Ok(KeyServer { diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 56b166ac62..ad93801c0b 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -32,11 +32,12 @@ use ethcore_service::ClientService; use cache::CacheConfig; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool}; -use helpers::{to_client_config, execute_upgrades, client_db_config, open_client_db, restoration_db_handler, compaction_profile}; +use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; use fdlimit; use ethcore_private_tx; +use db; /// Kinds of snapshot commands. #[derive(Debug, PartialEq, Clone, Copy)] @@ -164,7 +165,7 @@ impl SnapshotCommand { let snapshot_path = db_dirs.snapshot_path(); // execute upgrades - execute_upgrades(&self.dirs.base, &db_dirs, algorithm, compaction_profile(&self.compaction, db_dirs.db_root_path().as_path()))?; + execute_upgrades(&self.dirs.base, &db_dirs, algorithm, &self.compaction)?; // prepare client config let client_config = to_client_config( @@ -183,9 +184,8 @@ impl SnapshotCommand { true ); - let client_db_config = client_db_config(&client_path, &client_config); - let client_db = open_client_db(&client_path, &client_db_config)?; - let restoration_db_handler = restoration_db_handler(client_db_config); + let client_db = db::open_client_db(&client_path, &client_config)?; + let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); let service = ClientService::start( client_config, diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index 91889d7012..fee832d069 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -31,7 +31,6 @@ ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } ethereum-types = "0.3" kvdb = { path = "../util/kvdb" } -kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } keccak-hash = { path = "../util/hash" } ethkey = { path = "../ethkey" } lazy_static = "1.0" @@ -41,3 +40,4 @@ ethabi-contract = "5.0" [dev-dependencies] tempdir = "0.3" +kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index 1d4b968c07..fee73c2ae1 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -14,14 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::path::PathBuf; use std::collections::BTreeMap; +use std::sync::Arc; use serde_json; use tiny_keccak::Keccak; use ethereum_types::{H256, Address}; use ethkey::{Secret, Public, public_to_address}; -use kvdb_rocksdb::{Database, DatabaseIterator}; -use types::all::{Error, ServiceConfiguration, ServerKeyId, NodeId}; +use kvdb::KeyValueDB; +use types::all::{Error, ServerKeyId, NodeId}; use serialization::{SerializablePublic, SerializableSecret, SerializableH256, SerializableAddress}; /// Key of version value. @@ -82,17 +82,17 @@ pub trait KeyStorage: Send + Sync { /// Persistent document encryption keys storage pub struct PersistentKeyStorage { - db: Database, + db: Arc, } /// Persistent document encryption keys storage iterator pub struct PersistentKeyStorageIterator<'a> { - iter: Option>, + iter: Box, Box<[u8]>)> + 'a>, } /// V0 of encrypted key share, as it is stored by key storage on the single key server. #[derive(Serialize, Deserialize)] -struct SerializableDocumentKeyShareV0 { +pub struct SerializableDocumentKeyShareV0 { /// Decryption threshold (at least threshold + 1 nodes are required to decrypt data). pub threshold: usize, /// Nodes ids numbers. @@ -172,12 +172,7 @@ type SerializableDocumentKeyShareVersionV3 = SerializableDocumentKeyShareVersion impl PersistentKeyStorage { /// Create new persistent document encryption keys storage - pub fn new(config: &ServiceConfiguration) -> Result { - let mut db_path = PathBuf::from(&config.data_path); - db_path.push("db"); - let db_path = db_path.to_str().ok_or_else(|| Error::Database("Invalid secretstore path".to_owned()))?; - - let db = Database::open_default(&db_path)?; + pub fn new(db: Arc) -> Result { let db = upgrade_db(db)?; Ok(PersistentKeyStorage { @@ -186,14 +181,14 @@ impl PersistentKeyStorage { } } -fn upgrade_db(db: Database) -> Result { +fn upgrade_db(db: Arc) -> Result, Error> { let version = db.get(None, DB_META_KEY_VERSION)?; let version = version.and_then(|v| v.get(0).cloned()).unwrap_or(0); match version { 0 => { let mut batch = db.transaction(); batch.put(None, DB_META_KEY_VERSION, &[CURRENT_VERSION]); - for (db_key, db_value) in db.iter(None).into_iter().flat_map(|inner| inner).filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { + for (db_key, db_value) in db.iter(None).into_iter().filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { let v0_key = serde_json::from_slice::(&db_value).map_err(|e| Error::Database(e.to_string()))?; let current_key = CurrentSerializableDocumentKeyShare { // author is used in separate generation + encrypt sessions. @@ -218,7 +213,7 @@ fn upgrade_db(db: Database) -> Result { 1 => { let mut batch = db.transaction(); batch.put(None, DB_META_KEY_VERSION, &[CURRENT_VERSION]); - for (db_key, db_value) in db.iter(None).into_iter().flat_map(|inner| inner).filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { + for (db_key, db_value) in db.iter(None).into_iter().filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { let v1_key = serde_json::from_slice::(&db_value).map_err(|e| Error::Database(e.to_string()))?; let current_key = CurrentSerializableDocumentKeyShare { author: public_to_address(&v1_key.author).into(), // added in v1 + changed in v3 @@ -241,7 +236,7 @@ fn upgrade_db(db: Database) -> Result { 2 => { let mut batch = db.transaction(); batch.put(None, DB_META_KEY_VERSION, &[CURRENT_VERSION]); - for (db_key, db_value) in db.iter(None).into_iter().flat_map(|inner| inner).filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { + for (db_key, db_value) in db.iter(None).into_iter().filter(|&(ref k, _)| **k != *DB_META_KEY_VERSION) { let v2_key = serde_json::from_slice::(&db_value).map_err(|e| Error::Database(e.to_string()))?; let current_key = CurrentSerializableDocumentKeyShare { author: public_to_address(&v2_key.author).into(), // changed in v3 @@ -319,11 +314,10 @@ impl<'a> Iterator for PersistentKeyStorageIterator<'a> { type Item = (ServerKeyId, DocumentKeyShare); fn next(&mut self) -> Option<(ServerKeyId, DocumentKeyShare)> { - self.iter.as_mut() - .and_then(|iter| iter.next() - .and_then(|(db_key, db_val)| serde_json::from_slice::(&db_val) - .ok() - .map(|key| ((*db_key).into(), key.into())))) + self.iter.as_mut().next() + .and_then(|(db_key, db_val)| serde_json::from_slice::(&db_val) + .ok() + .map(|key| ((*db_key).into(), key.into()))) } } @@ -417,14 +411,15 @@ impl From for DocumentKeyShare { pub mod tests { extern crate tempdir; - use std::collections::{BTreeMap, HashMap}; + use std::collections::HashMap; + use std::sync::Arc; use parking_lot::RwLock; use serde_json; use self::tempdir::TempDir; use ethereum_types::{Address, H256}; use ethkey::{Random, Generator, Public, Secret, public_to_address}; use kvdb_rocksdb::Database; - use types::all::{Error, NodeAddress, ServiceConfiguration, ClusterConfiguration, ServerKeyId}; + use types::all::{Error, ServerKeyId}; use super::{DB_META_KEY_VERSION, CURRENT_VERSION, KeyStorage, PersistentKeyStorage, DocumentKeyShare, DocumentKeyShareVersion, CurrentSerializableDocumentKeyShare, upgrade_db, SerializableDocumentKeyShareV0, SerializableDocumentKeyShareV1, SerializableDocumentKeyShareV2, SerializableDocumentKeyShareVersionV2}; @@ -472,27 +467,6 @@ pub mod tests { #[test] fn persistent_key_storage() { let tempdir = TempDir::new("").unwrap(); - let config = ServiceConfiguration { - listener_address: None, - service_contract_address: None, - service_contract_srv_gen_address: None, - service_contract_srv_retr_address: None, - service_contract_doc_store_address: None, - service_contract_doc_sretr_address: None, - acl_check_enabled: true, - data_path: tempdir.path().display().to_string(), - cluster_config: ClusterConfiguration { - threads: 1, - listener_address: NodeAddress { - address: "0.0.0.0".to_owned(), - port: 8083, - }, - nodes: BTreeMap::new(), - allow_connecting_to_higher_nodes: false, - admin_public: None, - auto_migrate_enabled: false, - }, - }; let key1 = ServerKeyId::from(1); let value1 = DocumentKeyShare { @@ -526,7 +500,9 @@ pub mod tests { }; let key3 = ServerKeyId::from(3); - let key_storage = PersistentKeyStorage::new(&config).unwrap(); + let db = Database::open_default(&tempdir.path().display().to_string()).unwrap(); + + let key_storage = PersistentKeyStorage::new(Arc::new(db)).unwrap(); key_storage.insert(key1.clone(), value1.clone()).unwrap(); key_storage.insert(key2.clone(), value2.clone()).unwrap(); assert_eq!(key_storage.get(&key1), Ok(Some(value1.clone()))); @@ -534,7 +510,9 @@ pub mod tests { assert_eq!(key_storage.get(&key3), Ok(None)); drop(key_storage); - let key_storage = PersistentKeyStorage::new(&config).unwrap(); + let db = Database::open_default(&tempdir.path().display().to_string()).unwrap(); + + let key_storage = PersistentKeyStorage::new(Arc::new(db)).unwrap(); assert_eq!(key_storage.get(&key1), Ok(Some(value1))); assert_eq!(key_storage.get(&key2), Ok(Some(value2))); assert_eq!(key_storage.get(&key3), Ok(None)); @@ -563,7 +541,7 @@ pub mod tests { } // upgrade database - let db = upgrade_db(db).unwrap(); + let db = upgrade_db(Arc::new(db)).unwrap(); // check upgrade assert_eq!(db.get(None, DB_META_KEY_VERSION).unwrap().unwrap()[0], CURRENT_VERSION); @@ -606,7 +584,7 @@ pub mod tests { } // upgrade database - let db = upgrade_db(db).unwrap(); + let db = upgrade_db(Arc::new(db)).unwrap(); // check upgrade assert_eq!(db.get(None, DB_META_KEY_VERSION).unwrap().unwrap()[0], CURRENT_VERSION); @@ -654,7 +632,7 @@ pub mod tests { } // upgrade database - let db = upgrade_db(db).unwrap(); + let db = upgrade_db(Arc::new(db)).unwrap(); // check upgrade assert_eq!(db.get(None, DB_META_KEY_VERSION).unwrap().unwrap()[0], CURRENT_VERSION); diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index dc45f1af36..8e1278e425 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -28,7 +28,6 @@ extern crate futures_cpupool; extern crate hyper; extern crate keccak_hash as hash; extern crate kvdb; -extern crate kvdb_rocksdb; extern crate parking_lot; extern crate rustc_hex; extern crate serde; @@ -54,6 +53,9 @@ extern crate lazy_static; #[macro_use] extern crate log; +#[cfg(test)] +extern crate kvdb_rocksdb; + mod key_server_cluster; mod types; mod helpers; @@ -69,6 +71,7 @@ mod listener; mod trusted_client; use std::sync::Arc; +use kvdb::KeyValueDB; use ethcore::client::Client; use ethcore::miner::Miner; use sync::SyncProvider; @@ -79,7 +82,7 @@ pub use traits::{NodeKeyPair, KeyServer}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; /// Start new key server instance -pub fn start(client: Arc, sync: Arc, miner: Arc, self_key_pair: Arc, config: ServiceConfiguration) -> Result, Error> { +pub fn start(client: Arc, sync: Arc, miner: Arc, self_key_pair: Arc, config: ServiceConfiguration, db: Arc) -> Result, Error> { let trusted_client = trusted_client::TrustedClient::new(self_key_pair.clone(), client.clone(), sync, miner); let acl_storage: Arc = if config.acl_check_enabled { acl_storage::OnChainAclStorage::new(trusted_client.clone())? @@ -89,7 +92,7 @@ pub fn start(client: Arc, sync: Arc, miner: Arc, se let key_server_set = key_server_set::OnChainKeyServerSet::new(trusted_client.clone(), self_key_pair.clone(), config.cluster_config.auto_migrate_enabled, config.cluster_config.nodes.clone())?; - let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(&config)?); + let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(db)?); let key_server = Arc::new(key_server::KeyServerImpl::new(&config.cluster_config, key_server_set.clone(), self_key_pair.clone(), acl_storage.clone(), key_storage.clone())?); let cluster = key_server.cluster(); let key_server: Arc = key_server; diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index 5e28415b18..b994026814 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -91,8 +91,6 @@ pub struct ServiceConfiguration { pub service_contract_doc_sretr_address: Option, /// Is ACL check enabled. If false, everyone has access to all keys. Useful for tests only. pub acl_check_enabled: bool, - /// Data directory path for secret store - pub data_path: String, /// Cluster configuration. pub cluster_config: ClusterConfiguration, } diff --git a/util/migration/Cargo.toml b/util/migration-rocksdb/Cargo.toml similarity index 91% rename from util/migration/Cargo.toml rename to util/migration-rocksdb/Cargo.toml index d938822bac..3f0b8e7520 100644 --- a/util/migration/Cargo.toml +++ b/util/migration-rocksdb/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "migration" +name = "migration-rocksdb" version = "0.1.0" authors = ["Parity Technologies "] diff --git a/util/migration/src/lib.rs b/util/migration-rocksdb/src/lib.rs similarity index 100% rename from util/migration/src/lib.rs rename to util/migration-rocksdb/src/lib.rs diff --git a/util/migration/tests/tests.rs b/util/migration-rocksdb/tests/tests.rs similarity index 99% rename from util/migration/tests/tests.rs rename to util/migration-rocksdb/tests/tests.rs index c1ff8228f8..85c48f12b6 100644 --- a/util/migration/tests/tests.rs +++ b/util/migration-rocksdb/tests/tests.rs @@ -22,7 +22,7 @@ extern crate macros; extern crate tempdir; extern crate kvdb_rocksdb; -extern crate migration; +extern crate migration_rocksdb as migration; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -- GitLab From f6998cb04e63063b64e147a9a87c719dd390c3c6 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 14 Apr 2018 03:15:33 +0800 Subject: [PATCH 075/263] Use tokio::spawn in secret_store listener and fix Uri (#8373) * Directly wait for future to resolve in a threadpool * Ignore return value * Use path.starts_with instead of req_uri.is_absolute The later now means something else in hyper 0.11.. * Use tokio::spawn * typo: remove accidential unsafe impl --- secret_store/src/listener/http_listener.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index 7d4385ccc5..bf293a44eb 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -20,7 +20,7 @@ use hyper::{self, header, Chunk, Uri, Request as HttpRequest, Response as HttpRe use hyper::server::Http; use serde::Serialize; use serde_json; -use tokio::executor::current_thread; +use tokio; use tokio::net::TcpListener; use tokio::runtime::Runtime; use tokio_service::Service; @@ -104,9 +104,7 @@ impl KeyServerHttpListener { warn!("Key server handler error: {:?}", e); }); - // TODO: Change this to tokio::spawn once hyper is Send. - current_thread::spawn(serve); - future::ok(()) + tokio::spawn(serve) }); runtime.spawn(server); @@ -207,7 +205,7 @@ impl Service for KeyServerHttpHandler { type Request = HttpRequest; type Response = HttpResponse; type Error = hyper::Error; - type Future = Box>; + type Future = Box + Send>; fn call(&self, req: HttpRequest) -> Self::Future { if req.headers().has::() { @@ -222,7 +220,7 @@ impl Service for KeyServerHttpHandler { Box::new(req.body().concat2().map(move |body| { let path = req_uri.path().to_string(); - if req_uri.is_absolute() { + if path.starts_with("/") { this.process(req_method, req_uri, &path, &body) } else { warn!(target: "secretstore", "Ignoring invalid {}-request {}", req_method, req_uri); -- GitLab From 90eb61091a875d6c910a5f1dfd4e51cb74e82143 Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Sat, 14 Apr 2018 21:47:52 +0300 Subject: [PATCH 076/263] remove Tendermint extra_info due to seal inconsistencies (#8367) --- ethcore/src/engines/tendermint/mod.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index c9312e9043..14d1ebd585 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -27,7 +27,7 @@ mod params; use std::sync::{Weak, Arc}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; -use std::collections::{HashSet, BTreeMap}; +use std::collections::HashSet; use hash::keccak; use ethereum_types::{H256, H520, U128, U256, Address}; use parking_lot::RwLock; @@ -449,17 +449,6 @@ impl Engine for Tendermint { fn maximum_uncle_age(&self) -> usize { 0 } - /// Additional engine-specific information for the user/developer concerning `header`. - fn extra_info(&self, header: &Header) -> BTreeMap { - let message = ConsensusMessage::new_proposal(header).expect("Invalid header."); - map![ - "signature".into() => message.signature.to_string(), - "height".into() => message.vote_step.height.to_string(), - "view".into() => message.vote_step.view.to_string(), - "block_hash".into() => message.block_hash.as_ref().map(ToString::to_string).unwrap_or("".into()) - ] - } - fn populate_from_parent(&self, header: &mut Header, parent: &Header) { // Chain scoring: total weight is sqrt(U256::max_value())*height - view let new_difficulty = U256::from(U128::max_value()) -- GitLab From fac356c701661699b828737c042baab06ed93f4a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 14 Apr 2018 21:35:58 +0200 Subject: [PATCH 077/263] More code refactoring to integrate Duration (#8322) * More code refactoring to integrate Duration * Fix typo * Fix tests * More test fix --- dapps/src/tests/helpers/fetch.rs | 6 ++-- ethcore/light/src/net/load_timer.rs | 30 +++++++++--------- ethcore/light/src/net/mod.rs | 24 +++++++-------- ethcore/light/src/net/request_credits.rs | 33 ++++++++++++-------- ethcore/service/src/service.rs | 9 +++--- ethcore/src/account_provider/mod.rs | 10 +++--- ethcore/src/engines/authority_round/mod.rs | 9 +++--- ethcore/src/engines/transition.rs | 3 +- ethcore/src/error.rs | 15 ++++++--- ethcore/src/verification/verification.rs | 18 +++++------ ethcore/sync/src/api.rs | 3 +- ethcore/sync/src/chain.rs | 36 +++++++++++----------- ethcore/sync/src/light_sync/mod.rs | 17 +++++----- local-store/src/lib.rs | 5 +-- parity/informant.rs | 2 +- parity/light_helpers/queue_cull.rs | 6 ++-- rpc/src/v1/impls/personal.rs | 5 +-- util/io/src/lib.rs | 6 ++-- util/io/src/service.rs | 20 ++++++------ util/network-devp2p/src/connection.rs | 5 +-- util/network-devp2p/src/handshake.rs | 3 +- util/network-devp2p/src/host.rs | 15 ++++----- util/network-devp2p/src/lib.rs | 3 +- util/network-devp2p/src/session.rs | 16 +++++----- util/network-devp2p/tests/tests.rs | 2 +- util/network/src/lib.rs | 15 ++++----- util/unexpected/src/lib.rs | 12 ++++++++ whisper/src/net/mod.rs | 4 +-- 28 files changed, 185 insertions(+), 147 deletions(-) diff --git a/dapps/src/tests/helpers/fetch.rs b/dapps/src/tests/helpers/fetch.rs index 146163a77f..51c98db531 100644 --- a/dapps/src/tests/helpers/fetch.rs +++ b/dapps/src/tests/helpers/fetch.rs @@ -34,8 +34,8 @@ impl FetchControl { } pub fn wait_for_requests(&self, len: usize) { - const MAX_TIMEOUT_MS: u64 = 5000; - const ATTEMPTS: u64 = 10; + const MAX_TIMEOUT: time::Duration = time::Duration::from_millis(5000); + const ATTEMPTS: u32 = 10; let mut attempts_left = ATTEMPTS; loop { let current = self.fetch.requested.lock().len(); @@ -50,7 +50,7 @@ impl FetchControl { } else { attempts_left -= 1; // Should we handle spurious timeouts better? - thread::park_timeout(time::Duration::from_millis(MAX_TIMEOUT_MS / ATTEMPTS)); + thread::park_timeout(MAX_TIMEOUT / ATTEMPTS); } } } diff --git a/ethcore/light/src/net/load_timer.rs b/ethcore/light/src/net/load_timer.rs index c6e524a441..2846a57384 100644 --- a/ethcore/light/src/net/load_timer.rs +++ b/ethcore/light/src/net/load_timer.rs @@ -48,11 +48,11 @@ pub trait SampleStore: Send + Sync { } // get a hardcoded, arbitrarily determined (but intended overestimate) -// of the time in nanoseconds to serve a request of the given kind. +// of the time it takes to serve a request of the given kind. // // TODO: seed this with empirical data. -fn hardcoded_serve_time(kind: Kind) -> u64 { - match kind { +fn hardcoded_serve_time(kind: Kind) -> Duration { + Duration::new(0, match kind { Kind::Headers => 500_000, Kind::HeaderProof => 500_000, Kind::TransactionIndex => 500_000, @@ -63,7 +63,7 @@ fn hardcoded_serve_time(kind: Kind) -> u64 { Kind::Code => 1_500_000, Kind::Execution => 250, // per gas. Kind::Signal => 500_000, - } + }) } /// A no-op store. @@ -114,10 +114,10 @@ impl LoadDistribution { } } - /// Calculate EMA of load in nanoseconds for a specific request kind. + /// Calculate EMA of load for a specific request kind. /// If there is no data for the given request kind, no EMA will be calculated, /// but a hardcoded time will be returned. - pub fn expected_time_ns(&self, kind: Kind) -> u64 { + pub fn expected_time(&self, kind: Kind) -> Duration { let samples = self.samples.read(); samples.get(&kind).and_then(|s| { if s.len() == 0 { return None } @@ -128,7 +128,9 @@ impl LoadDistribution { (alpha * c as f64) + ((1.0 - alpha) * a) }); - Some(ema as u64) + // TODO: use `Duration::from_nanos` once stable (https://github.com/rust-lang/rust/issues/46507) + let ema = ema as u64; + Some(Duration::new(ema / 1_000_000_000, (ema % 1_000_000_000) as u32)) }).unwrap_or_else(move || hardcoded_serve_time(kind)) } @@ -223,12 +225,12 @@ mod tests { #[test] fn hardcoded_before_data() { let dist = LoadDistribution::load(&NullStore); - assert_eq!(dist.expected_time_ns(Kind::Headers), hardcoded_serve_time(Kind::Headers)); + assert_eq!(dist.expected_time(Kind::Headers), hardcoded_serve_time(Kind::Headers)); dist.update(Kind::Headers, Duration::new(0, 100_000), 100); dist.end_period(&NullStore); - assert_eq!(dist.expected_time_ns(Kind::Headers), 1000); + assert_eq!(dist.expected_time(Kind::Headers), Duration::new(0, 1000)); } #[test] @@ -244,20 +246,20 @@ mod tests { sum += x; if i == 0 { continue } - let moving_average = dist.expected_time_ns(Kind::Headers); + let moving_average = dist.expected_time(Kind::Headers); // should be weighted below the maximum entry. - let arith_average = (sum as f64 / (i + 1) as f64) as u64; - assert!(moving_average < x as u64); + let arith_average = (sum as f64 / (i + 1) as f64) as u32; + assert!(moving_average < Duration::new(0, x)); // when there are only 2 entries, they should be equal due to choice of // ALPHA = 1/N. // otherwise, the weight should be below the arithmetic mean because the much // smaller previous values are discounted less. if i == 1 { - assert_eq!(moving_average, arith_average); + assert_eq!(moving_average, Duration::new(0, arith_average)); } else { - assert!(moving_average < arith_average) + assert!(moving_average < Duration::new(0, arith_average)) } } } diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index abdf91ae44..8299773230 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -61,16 +61,16 @@ pub use self::load_timer::{SampleStore, FileStore}; pub use self::status::{Status, Capabilities, Announcement}; const TIMEOUT: TimerToken = 0; -const TIMEOUT_INTERVAL_MS: u64 = 1000; +const TIMEOUT_INTERVAL: Duration = Duration::from_secs(1); const TICK_TIMEOUT: TimerToken = 1; -const TICK_TIMEOUT_INTERVAL_MS: u64 = 5000; +const TICK_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5); const PROPAGATE_TIMEOUT: TimerToken = 2; -const PROPAGATE_TIMEOUT_INTERVAL_MS: u64 = 5000; +const PROPAGATE_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5); const RECALCULATE_COSTS_TIMEOUT: TimerToken = 3; -const RECALCULATE_COSTS_INTERVAL_MS: u64 = 60 * 60 * 1000; +const RECALCULATE_COSTS_INTERVAL: Duration = Duration::from_secs(60 * 60); // minimum interval between updates. const UPDATE_INTERVAL: Duration = Duration::from_millis(5000); @@ -369,9 +369,9 @@ impl LightProtocol { let sample_store = params.sample_store.unwrap_or_else(|| Box::new(NullStore)); let load_distribution = LoadDistribution::load(&*sample_store); let flow_params = FlowParams::from_request_times( - |kind| load_distribution.expected_time_ns(kind), + |kind| load_distribution.expected_time(kind), params.config.load_share, - params.config.max_stored_seconds, + Duration::from_secs(params.config.max_stored_seconds), ); LightProtocol { @@ -766,9 +766,9 @@ impl LightProtocol { self.load_distribution.end_period(&*self.sample_store); let new_params = Arc::new(FlowParams::from_request_times( - |kind| self.load_distribution.expected_time_ns(kind), + |kind| self.load_distribution.expected_time(kind), self.config.load_share, - self.config.max_stored_seconds, + Duration::from_secs(self.config.max_stored_seconds), )); *self.flow_params.write() = new_params.clone(); @@ -1080,13 +1080,13 @@ fn punish(peer: PeerId, io: &IoContext, e: Error) { impl NetworkProtocolHandler for LightProtocol { fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { - io.register_timer(TIMEOUT, TIMEOUT_INTERVAL_MS) + io.register_timer(TIMEOUT, TIMEOUT_INTERVAL) .expect("Error registering sync timer."); - io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL_MS) + io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL) .expect("Error registering sync timer."); - io.register_timer(PROPAGATE_TIMEOUT, PROPAGATE_TIMEOUT_INTERVAL_MS) + io.register_timer(PROPAGATE_TIMEOUT, PROPAGATE_TIMEOUT_INTERVAL) .expect("Error registering sync timer."); - io.register_timer(RECALCULATE_COSTS_TIMEOUT, RECALCULATE_COSTS_INTERVAL_MS) + io.register_timer(RECALCULATE_COSTS_TIMEOUT, RECALCULATE_COSTS_INTERVAL) .expect("Error registering request timer interval token."); } diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index c35a292227..e1b7455ccc 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -235,23 +235,30 @@ impl FlowParams { /// Create new flow parameters from , /// proportion of total capacity which should be given to a peer, - /// and number of seconds of stored capacity a peer can accumulate. - pub fn from_request_times u64>( - request_time_ns: F, + /// and stored capacity a peer can accumulate. + pub fn from_request_times Duration>( + request_time: F, load_share: f64, - max_stored_seconds: u64 + max_stored: Duration ) -> Self { use request::Kind; let load_share = load_share.abs(); let recharge: u64 = 100_000_000; - let max = recharge.saturating_mul(max_stored_seconds); + let max = { + let sec = max_stored.as_secs().saturating_mul(recharge); + let nanos = (max_stored.subsec_nanos() as u64).saturating_mul(recharge) / 1_000_000_000; + sec + nanos + }; let cost_for_kind = |kind| { // how many requests we can handle per second - let ns = request_time_ns(kind); - let second_duration = 1_000_000_000f64 / ns as f64; + let rq_dur = request_time(kind); + let second_duration = { + let as_ns = rq_dur.as_secs() as f64 * 1_000_000_000f64 + rq_dur.subsec_nanos() as f64; + 1_000_000_000f64 / as_ns + }; // scale by share of the load given to this peer. let serve_per_second = second_duration * load_share; @@ -426,21 +433,21 @@ mod tests { #[test] fn scale_by_load_share_and_time() { let flow_params = FlowParams::from_request_times( - |_| 10_000, + |_| Duration::new(0, 10_000), 0.05, - 60, + Duration::from_secs(60), ); let flow_params2 = FlowParams::from_request_times( - |_| 10_000, + |_| Duration::new(0, 10_000), 0.1, - 60, + Duration::from_secs(60), ); let flow_params3 = FlowParams::from_request_times( - |_| 5_000, + |_| Duration::new(0, 5_000), 0.05, - 60, + Duration::from_secs(60), ); assert_eq!(flow_params2.costs, flow_params3.costs); diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index b57d613e3b..b60d4194c9 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use std::path::Path; +use std::time::Duration; use ansi_term::Colour; use io::{IoContext, TimerToken, IoHandler, IoService, IoError}; @@ -180,13 +181,13 @@ struct ClientIoHandler { const CLIENT_TICK_TIMER: TimerToken = 0; const SNAPSHOT_TICK_TIMER: TimerToken = 1; -const CLIENT_TICK_MS: u64 = 5000; -const SNAPSHOT_TICK_MS: u64 = 10000; +const CLIENT_TICK: Duration = Duration::from_secs(5); +const SNAPSHOT_TICK: Duration = Duration::from_secs(10); impl IoHandler for ClientIoHandler { fn initialize(&self, io: &IoContext) { - io.register_timer(CLIENT_TICK_TIMER, CLIENT_TICK_MS).expect("Error registering client timer"); - io.register_timer(SNAPSHOT_TICK_TIMER, SNAPSHOT_TICK_MS).expect("Error registering snapshot timer"); + io.register_timer(CLIENT_TICK_TIMER, CLIENT_TICK).expect("Error registering client timer"); + io.register_timer(SNAPSHOT_TICK_TIMER, SNAPSHOT_TICK).expect("Error registering snapshot timer"); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 2edb42be1e..9d6b814c6f 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -638,8 +638,8 @@ impl AccountProvider { } /// Unlocks account temporarily with a timeout. - pub fn unlock_account_timed(&self, account: Address, password: String, duration_ms: u32) -> Result<(), Error> { - self.unlock_account(account, password, Unlock::Timed(Instant::now() + Duration::from_millis(duration_ms as u64))) + pub fn unlock_account_timed(&self, account: Address, password: String, duration: Duration) -> Result<(), Error> { + self.unlock_account(account, password, Unlock::Timed(Instant::now() + duration)) } /// Checks if given account is unlocked @@ -834,7 +834,7 @@ impl AccountProvider { #[cfg(test)] mod tests { use super::{AccountProvider, Unlock, DappId}; - use std::time::Instant; + use std::time::{Duration, Instant}; use ethstore::ethkey::{Generator, Random, Address}; use ethstore::{StoreAccountRef, Derivation}; use ethereum_types::H256; @@ -938,8 +938,8 @@ mod tests { let kp = Random.generate().unwrap(); let ap = AccountProvider::transient_provider(); assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); - assert!(ap.unlock_account_timed(kp.address(), "test1".into(), 60000).is_err()); - assert!(ap.unlock_account_timed(kp.address(), "test".into(), 60000).is_ok()); + assert!(ap.unlock_account_timed(kp.address(), "test1".into(), Duration::from_secs(60)).is_err()); + assert!(ap.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60)).is_ok()); assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); ap.unlocked.write().get_mut(&StoreAccountRef::root(kp.address())).unwrap().unlock = Unlock::Timed(Instant::now()); assert!(ap.sign(kp.address(), None, Default::default()).is_err()); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index e3acc5eed9..b8b9ab8b30 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -19,7 +19,7 @@ use std::fmt; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Weak, Arc}; -use std::time::{UNIX_EPOCH, Duration}; +use std::time::{UNIX_EPOCH, SystemTime, Duration}; use std::collections::{BTreeMap, HashSet}; use std::iter::FromIterator; @@ -536,6 +536,7 @@ fn verify_timestamp(step: &Step, header_step: usize) -> Result<(), BlockError> { // NOTE This error might be returned only in early stage of verification (Stage 1). // Returning it further won't recover the sync process. trace!(target: "engine", "verify_timestamp: block too early"); + let oob = oob.map(|n| SystemTime::now() + Duration::from_secs(n)); Err(BlockError::TemporarilyInvalid(oob).into()) }, Ok(_) => Ok(()), @@ -694,8 +695,8 @@ const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; impl IoHandler<()> for TransitionHandler { fn initialize(&self, io: &IoContext<()>) { if let Some(engine) = self.engine.upgrade() { - let remaining = engine.step.duration_remaining(); - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, remaining.as_millis()) + let remaining = engine.step.duration_remaining().as_millis(); + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining)) .unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e)) } } @@ -711,7 +712,7 @@ impl IoHandler<()> for TransitionHandler { } let next_run_at = engine.step.duration_remaining().as_millis() >> 2; - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, next_run_at) + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at)) .unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e)) } } diff --git a/ethcore/src/engines/transition.rs b/ethcore/src/engines/transition.rs index dc745b6e39..a0469b6249 100644 --- a/ethcore/src/engines/transition.rs +++ b/ethcore/src/engines/transition.rs @@ -51,8 +51,7 @@ impl TransitionHandler where S: Sync + Send + Clone { pub const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; fn set_timeout(io: &IoContext, timeout: Duration) { - let ms = timeout.as_secs() * 1_000 + timeout.subsec_nanos() as u64 / 1_000_000; - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, ms) + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, timeout) .unwrap_or_else(|e| warn!(target: "engine", "Failed to set consensus step timeout: {}.", e)) } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index defb301dcb..4c8157a82f 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -17,6 +17,7 @@ //! General error types for use in ethcore. use std::{fmt, error}; +use std::time::SystemTime; use kvdb; use ethereum_types::{H256, U256, Address, Bloom}; use util_error::UtilError; @@ -81,9 +82,9 @@ pub enum BlockError { /// Receipts trie root header field is invalid. InvalidReceiptsRoot(Mismatch), /// Timestamp header field is invalid. - InvalidTimestamp(OutOfBounds), + InvalidTimestamp(OutOfBounds), /// Timestamp header field is too far in future. - TemporarilyInvalid(OutOfBounds), + TemporarilyInvalid(OutOfBounds), /// Log bloom header field is invalid. InvalidLogBloom(Mismatch), /// Number field of header is invalid. @@ -125,8 +126,14 @@ impl fmt::Display for BlockError { InvalidSeal => "Block has invalid seal.".into(), InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob), InvalidReceiptsRoot(ref mis) => format!("Invalid receipts trie root in header: {}", mis), - InvalidTimestamp(ref oob) => format!("Invalid timestamp in header: {}", oob), - TemporarilyInvalid(ref oob) => format!("Future timestamp in header: {}", oob), + InvalidTimestamp(ref oob) => { + let oob = oob.map(|st| st.elapsed().unwrap_or_default().as_secs()); + format!("Invalid timestamp in header: {}", oob) + }, + TemporarilyInvalid(ref oob) => { + let oob = oob.map(|st| st.elapsed().unwrap_or_default().as_secs()); + format!("Future timestamp in header: {}", oob) + }, InvalidLogBloom(ref oob) => format!("Invalid log bloom in header: {}", oob), InvalidNumber(ref mis) => format!("Invalid number in header: {}", mis), RidiculousNumber(ref oob) => format!("Implausible block number. {}", oob), diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index e50eb79194..5b0700bfd9 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -22,7 +22,7 @@ //! 3. Final verification against the blockchain done before enactment. use std::collections::HashSet; -use std::time::{SystemTime, UNIX_EPOCH}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; use bytes::Bytes; use ethereum_types::H256; @@ -284,11 +284,10 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool) } if is_full { - const ACCEPTABLE_DRIFT_SECS: u64 = 15; - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default(); - let max_time = now.as_secs() + ACCEPTABLE_DRIFT_SECS; - let invalid_threshold = max_time + ACCEPTABLE_DRIFT_SECS * 9; - let timestamp = header.timestamp(); + const ACCEPTABLE_DRIFT: Duration = Duration::from_secs(15); + let max_time = SystemTime::now() + ACCEPTABLE_DRIFT; + let invalid_threshold = max_time + ACCEPTABLE_DRIFT * 9; + let timestamp = UNIX_EPOCH + Duration::from_secs(header.timestamp()); if timestamp > invalid_threshold { return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: timestamp }))) @@ -310,7 +309,9 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result let gas_limit_divisor = engine.params().gas_limit_bound_divisor; if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) { - return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() }))) + let min = SystemTime::now() + Duration::from_secs(parent.timestamp() + 1); + let found = SystemTime::now() + Duration::from_secs(header.timestamp()); + return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(min), found }))) } if header.number() != parent.number() + 1 { return Err(From::from(BlockError::InvalidNumber(Mismatch { expected: parent.number() + 1, found: header.number() }))); @@ -679,8 +680,7 @@ mod tests { header = good.clone(); header.set_timestamp(10); - check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), - InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() })); + check_fail_timestamp(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), false); header = good.clone(); header.set_timestamp(2450000000); diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index eeccb46112..6270bcfd59 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeMap}; use std::io; +use std::time::Duration; use bytes::Bytes; use devp2p::{NetworkService, ConnectionFilter}; use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, ProtocolId, @@ -373,7 +374,7 @@ struct SyncProtocolHandler { impl NetworkProtocolHandler for SyncProtocolHandler { fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { if io.subprotocol_name() != WARP_SYNC_PROTOCOL_ID { - io.register_timer(0, 1000).expect("Error registering sync timer"); + io.register_timer(0, Duration::from_secs(1)).expect("Error registering sync timer"); } } diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index 44ab1971a9..014302d7fe 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -91,7 +91,7 @@ use std::sync::Arc; use std::collections::{HashSet, HashMap}; use std::cmp; -use std::time::Instant; +use std::time::{Duration, Instant}; use hash::keccak; use heapsize::HeapSizeOf; use ethereum_types::{H256, U256}; @@ -177,14 +177,14 @@ pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; -const WAIT_PEERS_TIMEOUT_SEC: u64 = 5; -const STATUS_TIMEOUT_SEC: u64 = 5; -const HEADERS_TIMEOUT_SEC: u64 = 15; -const BODIES_TIMEOUT_SEC: u64 = 20; -const RECEIPTS_TIMEOUT_SEC: u64 = 10; -const FORK_HEADER_TIMEOUT_SEC: u64 = 3; -const SNAPSHOT_MANIFEST_TIMEOUT_SEC: u64 = 5; -const SNAPSHOT_DATA_TIMEOUT_SEC: u64 = 120; +const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); +const STATUS_TIMEOUT: Duration = Duration::from_secs(5); +const HEADERS_TIMEOUT: Duration = Duration::from_secs(15); +const BODIES_TIMEOUT: Duration = Duration::from_secs(20); +const RECEIPTS_TIMEOUT: Duration = Duration::from_secs(10); +const FORK_HEADER_TIMEOUT: Duration = Duration::from_secs(3); +const SNAPSHOT_MANIFEST_TIMEOUT: Duration = Duration::from_secs(5); +const SNAPSHOT_DATA_TIMEOUT: Duration = Duration::from_secs(120); #[derive(Copy, Clone, Eq, PartialEq, Debug)] /// Sync state @@ -573,7 +573,7 @@ impl ChainSync { (best_hash, max_peers, snapshot_peers) }; - let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed().as_secs() > WAIT_PEERS_TIMEOUT_SEC); + let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed() > WAIT_PEERS_TIMEOUT); if let (Some(hash), Some(peers)) = (best_hash, best_hash.map_or(None, |h| snapshot_peers.get(&h))) { if max_peers >= SNAPSHOT_MIN_PEERS { @@ -1825,15 +1825,15 @@ impl ChainSync { let tick = Instant::now(); let mut aborting = Vec::new(); for (peer_id, peer) in &self.peers { - let elapsed = (tick - peer.ask_time).as_secs(); + let elapsed = tick - peer.ask_time; let timeout = match peer.asking { - PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT_SEC, - PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT_SEC, - PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT_SEC, + PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT, + PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT, + PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT, PeerAsking::Nothing => false, - PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT_SEC, - PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT_SEC, - PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT_SEC, + PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT, + PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT, + PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, }; if timeout { trace!(target:"sync", "Timeout {}", peer_id); @@ -1848,7 +1848,7 @@ impl ChainSync { // Check for handshake timeouts for (peer, &ask_time) in &self.handshaking_peers { let elapsed = (tick - ask_time) / 1_000_000_000; - if elapsed.as_secs() > STATUS_TIMEOUT_SEC { + if elapsed > STATUS_TIMEOUT { trace!(target:"sync", "Status timeout {}", peer); io.disconnect_peer(*peer); } diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index df76d25ccc..0f6660e179 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -58,12 +58,12 @@ mod sync_round; #[cfg(test)] mod tests; -// Base number of milliseconds for the header request timeout. -const REQ_TIMEOUT_MILLISECS_BASE: u64 = 7000; -// Additional number of milliseconds for each requested header. +// Base value for the header request timeout. +const REQ_TIMEOUT_BASE: Duration = Duration::from_secs(7); +// Additional value for each requested header. // If we request N headers, then the timeout will be: -// REQ_TIMEOUT_MILLISECS_BASE + N * REQ_TIMEOUT_MILLISECS_PER_HEADER -const REQ_TIMEOUT_MILLISECS_PER_HEADER: u64 = 10; +// REQ_TIMEOUT_BASE + N * REQ_TIMEOUT_PER_HEADER +const REQ_TIMEOUT_PER_HEADER: Duration = Duration::from_millis(10); /// Peer chain info. #[derive(Debug, Clone, PartialEq, Eq)] @@ -585,11 +585,12 @@ impl LightSync { if requested_from.contains(peer) { continue } match ctx.request_from(*peer, request.clone()) { Ok(id) => { - let timeout_ms = REQ_TIMEOUT_MILLISECS_BASE + - req.max * REQ_TIMEOUT_MILLISECS_PER_HEADER; + assert!(req.max <= u32::max_value() as u64, + "requesting more than 2^32 headers at a time would overflow"); + let timeout = REQ_TIMEOUT_BASE + REQ_TIMEOUT_PER_HEADER * req.max as u32; self.pending_reqs.lock().insert(id.clone(), PendingReq { started: Instant::now(), - timeout: Duration::from_millis(timeout_ms), + timeout, }); requested_from.insert(peer.clone()); diff --git a/local-store/src/lib.rs b/local-store/src/lib.rs index 9120b8694a..2ebc6a69ce 100644 --- a/local-store/src/lib.rs +++ b/local-store/src/lib.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use std::fmt; +use std::time::Duration; use transaction::{ SignedTransaction, PendingTransaction, UnverifiedTransaction, @@ -50,7 +51,7 @@ extern crate kvdb_memorydb; const LOCAL_TRANSACTIONS_KEY: &'static [u8] = &*b"LOCAL_TXS"; const UPDATE_TIMER: ::io::TimerToken = 0; -const UPDATE_TIMEOUT_MS: u64 = 15 * 60 * 1000; // once every 15 minutes. +const UPDATE_TIMEOUT: Duration = Duration::from_secs(15 * 60); // once every 15 minutes. /// Errors which can occur while using the local data store. #[derive(Debug)] @@ -205,7 +206,7 @@ impl LocalDataStore { impl IoHandler for LocalDataStore { fn initialize(&self, io: &::io::IoContext) { - if let Err(e) = io.register_timer(UPDATE_TIMER, UPDATE_TIMEOUT_MS) { + if let Err(e) = io.register_timer(UPDATE_TIMER, UPDATE_TIMEOUT) { warn!(target: "local_store", "Error registering local store update timer: {}", e); } } diff --git a/parity/informant.rs b/parity/informant.rs index fddcadebd8..896e80ec53 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -399,7 +399,7 @@ const INFO_TIMER: TimerToken = 0; impl IoHandler for Informant { fn initialize(&self, io: &IoContext) { - io.register_timer(INFO_TIMER, 5000).expect("Error registering timer"); + io.register_timer(INFO_TIMER, Duration::from_secs(5)).expect("Error registering timer"); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index e072540619..b6be59e2ce 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -35,10 +35,10 @@ use parking_lot::RwLock; // Attepmt to cull once every 10 minutes. const TOKEN: TimerToken = 1; -const TIMEOUT_MS: u64 = 1000 * 60 * 10; +const TIMEOUT: Duration = Duration::from_secs(60 * 10); // But make each attempt last only 9 minutes -const PURGE_TIMEOUT: Duration = Duration::from_millis(1000 * 60 * 9); +const PURGE_TIMEOUT: Duration = Duration::from_secs(60 * 9); /// Periodically culls the transaction queue of mined transactions. pub struct QueueCull { @@ -56,7 +56,7 @@ pub struct QueueCull { impl IoHandler for QueueCull { fn initialize(&self, io: &IoContext) { - io.register_timer(TOKEN, TIMEOUT_MS).expect("Error registering timer"); + io.register_timer(TOKEN, TIMEOUT).expect("Error registering timer"); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index c3560fe9df..03495fd37f 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -16,6 +16,7 @@ //! Account management (personal) rpc implementation use std::sync::Arc; +use std::time::Duration; use bytes::{Bytes, ToPretty}; use ethcore::account_provider::AccountProvider; @@ -130,8 +131,8 @@ impl Personal for PersonalClient { Some("Restart your client with --geth flag or use personal_sendTransaction instead."), )), (true, Some(0)) => store.unlock_account_permanently(account, account_pass), - (true, Some(d)) => store.unlock_account_timed(account, account_pass, d * 1000), - (true, None) => store.unlock_account_timed(account, account_pass, 300_000), + (true, Some(d)) => store.unlock_account_timed(account, account_pass, Duration::from_secs(d.into())), + (true, None) => store.unlock_account_timed(account, account_pass, Duration::from_secs(300)), }; match r { Ok(_) => Ok(true), diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index 22241a2f5d..20b908ac91 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -22,6 +22,7 @@ //! extern crate ethcore_io; //! use ethcore_io::*; //! use std::sync::Arc; +//! use std::time::Duration; //! //! struct MyHandler; //! @@ -32,7 +33,7 @@ //! //! impl IoHandler for MyHandler { //! fn initialize(&self, io: &IoContext) { -//! io.register_timer(0, 1000).unwrap(); +//! io.register_timer(0, Duration::from_secs(1)).unwrap(); //! } //! //! fn timeout(&self, _io: &IoContext, timer: TimerToken) { @@ -147,6 +148,7 @@ pub use service::TOKENS_PER_HANDLER; mod tests { use std::sync::Arc; + use std::time::Duration; use super::*; struct MyHandler; @@ -158,7 +160,7 @@ mod tests { impl IoHandler for MyHandler { fn initialize(&self, io: &IoContext) { - io.register_timer(0, 1000).unwrap(); + io.register_timer(0, Duration::from_secs(1)).unwrap(); } fn timeout(&self, _io: &IoContext, timer: TimerToken) { diff --git a/util/io/src/service.rs b/util/io/src/service.rs index baa279cabd..19f2d4b3bb 100644 --- a/util/io/src/service.rs +++ b/util/io/src/service.rs @@ -54,7 +54,7 @@ pub enum IoMessage where Message: Send + Clone + Sized { AddTimer { handler_id: HandlerId, token: TimerToken, - delay: u64, + delay: Duration, once: bool, }, RemoveTimer { @@ -93,10 +93,10 @@ impl IoContext where Message: Send + Clone + Sync + 'static { } /// Register a new recurring IO timer. 'IoHandler::timeout' will be called with the token. - pub fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), IoError> { + pub fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { self.channel.send_io(IoMessage::AddTimer { - token: token, - delay: ms, + token, + delay, handler_id: self.handler, once: false, })?; @@ -104,10 +104,10 @@ impl IoContext where Message: Send + Clone + Sync + 'static { } /// Register a new IO timer once. 'IoHandler::timeout' will be called with the token. - pub fn register_timer_once(&self, token: TimerToken, ms: u64) -> Result<(), IoError> { + pub fn register_timer_once(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { self.channel.send_io(IoMessage::AddTimer { - token: token, - delay: ms, + token, + delay, handler_id: self.handler, once: true, })?; @@ -173,7 +173,7 @@ impl IoContext where Message: Send + Clone + Sync + 'static { #[derive(Clone)] struct UserTimer { - delay: u64, + delay: Duration, timeout: Timeout, once: bool, } @@ -252,7 +252,7 @@ impl Handler for IoManager where Message: Send + Clone + Sync self.timers.write().remove(&token_id); event_loop.clear_timeout(&timer.timeout); } else { - event_loop.timeout(token, Duration::from_millis(timer.delay)).expect("Error re-registering user timer"); + event_loop.timeout(token, timer.delay).expect("Error re-registering user timer"); } self.worker_channel.push(Work { work_type: WorkType::Timeout, token: token_id, handler: handler.clone(), handler_id: handler_index }); self.work_ready.notify_all(); @@ -283,7 +283,7 @@ impl Handler for IoManager where Message: Send + Clone + Sync }, IoMessage::AddTimer { handler_id, token, delay, once } => { let timer_id = token + handler_id * TOKENS_PER_HANDLER; - let timeout = event_loop.timeout(Token(timer_id), Duration::from_millis(delay)).expect("Error registering user timer"); + let timeout = event_loop.timeout(Token(timer_id), delay).expect("Error registering user timer"); self.timers.write().insert(timer_id, UserTimer { delay: delay, timeout: timeout, once: once }); }, IoMessage::RemoveTimer { handler_id, token } => { diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 4d775b215f..12c38b3a24 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -17,6 +17,7 @@ use std::collections::VecDeque; use std::net::SocketAddr; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; +use std::time::Duration; use hash::{keccak, write_keccak}; use mio::{Token, Ready, PollOpt}; use mio::deprecated::{Handler, EventLoop, TryRead, TryWrite}; @@ -37,7 +38,7 @@ use crypto; use network::{Error, ErrorKind}; const ENCRYPTED_HEADER_LEN: usize = 32; -const RECIEVE_PAYLOAD_TIMEOUT: u64 = 30000; +const RECEIVE_PAYLOAD: Duration = Duration::from_secs(30); pub const MAX_PAYLOAD_SIZE: usize = (1 << 24) - 1; pub trait GenericSocket : Read + Write { @@ -447,7 +448,7 @@ impl EncryptedConnection { if let EncryptedConnectionState::Header = self.read_state { if let Some(data) = self.connection.readable()? { self.read_header(&data)?; - io.register_timer(self.connection.token, RECIEVE_PAYLOAD_TIMEOUT)?; + io.register_timer(self.connection.token, RECEIVE_PAYLOAD)?; } }; if let EncryptedConnectionState::Payload = self.read_state { diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 020b65477b..d7818b64d9 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::time::Duration; use rand::random; use hash::write_keccak; use mio::tcp::*; @@ -73,7 +74,7 @@ pub struct Handshake { const V4_AUTH_PACKET_SIZE: usize = 307; const V4_ACK_PACKET_SIZE: usize = 210; -const HANDSHAKE_TIMEOUT: u64 = 5000; +const HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(5); const PROTOCOL_VERSION: u64 = 4; // Amount of bytes added when encrypting with encryptECIES. const ECIES_OVERHEAD: usize = 113; diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 7056c67f6c..73ca2aca4b 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -24,6 +24,7 @@ use std::cmp::{min, max}; use std::path::{Path, PathBuf}; use std::io::{Read, Write, self}; use std::fs; +use std::time::Duration; use ethkey::{KeyPair, Secret, Random, Generator}; use hash::keccak; use mio::*; @@ -67,13 +68,13 @@ const SYS_TIMER: TimerToken = LAST_SESSION + 1; // Timeouts // for IDLE TimerToken -const MAINTENANCE_TIMEOUT: u64 = 1000; +const MAINTENANCE_TIMEOUT: Duration = Duration::from_secs(1); // for DISCOVERY_REFRESH TimerToken -const DISCOVERY_REFRESH_TIMEOUT: u64 = 60_000; +const DISCOVERY_REFRESH_TIMEOUT: Duration = Duration::from_secs(60); // for DISCOVERY_ROUND TimerToken -const DISCOVERY_ROUND_TIMEOUT: u64 = 300; +const DISCOVERY_ROUND_TIMEOUT: Duration = Duration::from_millis(300); // for NODE_TABLE TimerToken -const NODE_TABLE_TIMEOUT: u64 = 300_000; +const NODE_TABLE_TIMEOUT: Duration = Duration::from_secs(300); #[derive(Debug, PartialEq, Eq)] /// Protocol info @@ -165,10 +166,10 @@ impl<'s> NetworkContextTrait for NetworkContext<'s> { self.session.as_ref().map_or(false, |s| s.lock().expired()) } - fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), Error> { + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error> { self.io.message(NetworkIoMessage::AddTimer { - token: token, - delay: ms, + token, + delay, protocol: self.protocol, }).unwrap_or_else(|e| warn!("Error sending network IO message: {:?}", e)); Ok(()) diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index f326ff4b1e..8faf21e465 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -24,12 +24,13 @@ //! use net::*; //! use devp2p::NetworkService; //! use std::sync::Arc; +//! use std::time::Duration; //! //! struct MyHandler; //! //! impl NetworkProtocolHandler for MyHandler { //! fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { -//! io.register_timer(0, 1000); +//! io.register_timer(0, Duration::from_secs(1)); //! } //! //! fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index 6353a90946..c1e09a2525 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -34,8 +34,8 @@ use node_table::NodeId; use snappy; // Timeout must be less than (interval - 1). -const PING_TIMEOUT_SEC: Duration = Duration::from_secs(60); -const PING_INTERVAL_SEC: Duration = Duration::from_secs(120); +const PING_TIMEOUT: Duration = Duration::from_secs(60); +const PING_INTERVAL: Duration = Duration::from_secs(120); const MIN_PROTOCOL_VERSION: u32 = 4; const MIN_COMPRESSION_PROTOCOL_VERSION: u32 = 5; @@ -116,7 +116,7 @@ impl Session { protocol_version: 0, capabilities: Vec::new(), peer_capabilities: Vec::new(), - ping_ms: None, + ping: None, originated: originated, remote_address: "Handshake".to_owned(), local_address: local_addr, @@ -298,12 +298,12 @@ impl Session { return true; } let timed_out = if let Some(pong) = self.pong_time { - pong.duration_since(self.ping_time) > PING_TIMEOUT_SEC + pong.duration_since(self.ping_time) > PING_TIMEOUT } else { - self.ping_time.elapsed() > PING_TIMEOUT_SEC + self.ping_time.elapsed() > PING_TIMEOUT }; - if !timed_out && self.ping_time.elapsed() > PING_INTERVAL_SEC { + if !timed_out && self.ping_time.elapsed() > PING_INTERVAL { if let Err(e) = self.send_ping(io) { debug!("Error sending ping message: {:?}", e); } @@ -368,9 +368,7 @@ impl Session { PACKET_PONG => { let time = Instant::now(); self.pong_time = Some(time); - let ping_elapsed = time.duration_since(self.ping_time); - self.info.ping_ms = Some(ping_elapsed.as_secs() * 1_000 + - ping_elapsed.subsec_nanos() as u64 / 1_000_000); + self.info.ping = Some(time.duration_since(self.ping_time)); Ok(SessionData::Continue) }, PACKET_GET_PEERS => Ok(SessionData::None), //TODO; diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index 3aed1b9fc4..4788e0d442 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -71,7 +71,7 @@ impl TestProtocol { impl NetworkProtocolHandler for TestProtocol { fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { - io.register_timer(0, 10).unwrap(); + io.register_timer(0, Duration::from_millis(10)).unwrap(); } fn read(&self, _io: &NetworkContext, _peer: &PeerId, packet_id: u8, data: &[u8]) { diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 55c31dd2e6..1a0c88e4ca 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -37,6 +37,7 @@ use std::collections::HashMap; use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr}; use std::str::{self, FromStr}; use std::sync::Arc; +use std::time::Duration; use ipnetwork::{IpNetwork, IpNetworkError}; use io::IoChannel; use ethkey::Secret; @@ -74,8 +75,8 @@ pub enum NetworkIoMessage { protocol: ProtocolId, /// Timer token. token: TimerToken, - /// Timer delay in milliseconds. - delay: u64, + /// Timer delay. + delay: Duration, }, /// Initliaze public interface. InitPublicInterface, @@ -100,8 +101,8 @@ pub struct SessionInfo { pub capabilities: Vec, /// Peer protocol capabilities pub peer_capabilities: Vec, - /// Peer ping delay in milliseconds - pub ping_ms: Option, + /// Peer ping delay + pub ping: Option, /// True if this session was originated by us. pub originated: bool, /// Remote endpoint address of the session @@ -271,7 +272,7 @@ pub trait NetworkContext { fn is_expired(&self) -> bool; /// Register a new IO timer. 'IoHandler::timeout' will be called with the token. - fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), Error>; + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error>; /// Returns peer identification string fn peer_client_version(&self, peer: PeerId) -> String; @@ -315,8 +316,8 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { (**self).is_expired() } - fn register_timer(&self, token: TimerToken, ms: u64) -> Result<(), Error> { - (**self).register_timer(token, ms) + fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error> { + (**self).register_timer(token, delay) } fn peer_client_version(&self, peer: PeerId) -> String { diff --git a/util/unexpected/src/lib.rs b/util/unexpected/src/lib.rs index e34b2326cf..4cf8448bd4 100644 --- a/util/unexpected/src/lib.rs +++ b/util/unexpected/src/lib.rs @@ -44,6 +44,18 @@ pub struct OutOfBounds { pub found: T, } +impl OutOfBounds { + pub fn map(self, map: F) -> OutOfBounds + where F: Fn(T) -> U + { + OutOfBounds { + min: self.min.map(&map), + max: self.max.map(&map), + found: map(self.found), + } + } +} + impl fmt::Display for OutOfBounds { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let msg = match (self.min.as_ref(), self.max.as_ref()) { diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index 28f3fee55a..dd5e345bcd 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -36,7 +36,7 @@ mod tests; // how often periodic relays are. when messages are imported // we directly broadcast. const RALLY_TOKEN: TimerToken = 1; -const RALLY_TIMEOUT_MS: u64 = 2500; +const RALLY_TIMEOUT: Duration = Duration::from_millis(2500); /// Current protocol version. pub const PROTOCOL_VERSION: usize = 6; @@ -685,7 +685,7 @@ impl Network { impl ::network::NetworkProtocolHandler for Network { fn initialize(&self, io: &NetworkContext, host_info: &HostInfo) { // set up broadcast timer (< 1s) - io.register_timer(RALLY_TOKEN, RALLY_TIMEOUT_MS) + io.register_timer(RALLY_TOKEN, RALLY_TIMEOUT) .expect("Failed to initialize message rally timer"); *self.node_key.write() = host_info.id().clone(); -- GitLab From db7a8c4ac734ab015480a99a2c4138e10a658c29 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 16 Apr 2018 13:02:23 +0300 Subject: [PATCH 078/263] tokio-core v0.1.16 -> v0.1.17 (#8408) --- Cargo.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 402327b2e2..e78a947eaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -786,7 +786,7 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -823,7 +823,7 @@ dependencies = [ "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1045,7 +1045,7 @@ dependencies = [ "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1217,7 +1217,7 @@ dependencies = [ "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1233,7 +1233,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-rustls 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1260,7 +1260,7 @@ dependencies = [ "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1390,7 +1390,7 @@ dependencies = [ "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2119,7 +2119,7 @@ name = "parity-reactor" version = "0.1.0" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2215,7 +2215,7 @@ dependencies = [ "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes)", "tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3189,7 +3189,7 @@ dependencies = [ [[package]] name = "tokio-core" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3198,11 +3198,11 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3231,7 +3231,7 @@ dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3247,7 +3247,7 @@ dependencies = [ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3272,7 +3272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3364,7 +3364,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3963,7 +3963,7 @@ dependencies = [ "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" "checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" -"checksum tokio-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "799492ccba3d8ed5e41f2520a7cfd504cb65bbfe5fbbbd0012e335ae5f188051" +"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" "checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a" "checksum tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes)" = "" -- GitLab From a04c5b180a821c709b0ea24c7d4f21c9c2511839 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 16 Apr 2018 14:52:12 +0100 Subject: [PATCH 079/263] Replace legacy Rlp with UntrustedRlp and use in ethcore rlp views (#8316) * WIP * Replace Rlp with UntrustedRlp in views, explicity unwrap with expect First pass to get it to compile. Need to figure out whether to do this or to propogate Errors upstream, which would require many more changes to dependent code. If we do this way we are assuming that the views are always used in a context where the rlp is trusted to be valid e.g. when reading from our own DB. So need to fid out whether views are used with data received from an untrusted (e.g. extrernal peer). * Remove original Rlp impl, rename UntrustedRlp -> Rlp * Create rlp views with view! macro to record debug info Views are assumed to be over valid rlp, so if there is a decoding error we record where the view was created in the first place and report it in the expect * Use $crate in view! macro to avoid import, fix tests * Expect valid rlp in decode functions for now * Replace spaces with tabs in new file * Add doc tests for creating views with macro * Update rlp docs to reflect removing of UntrustedRlp * Replace UntrustedRlp usages in private-tx merge --- ethcore/light/src/cht.rs | 4 +- ethcore/light/src/client/header_chain.rs | 6 +- ethcore/light/src/net/mod.rs | 20 +- ethcore/light/src/net/request_credits.rs | 4 +- ethcore/light/src/net/status.rs | 30 +- ethcore/light/src/net/tests/mod.rs | 8 +- ethcore/light/src/on_demand/request.rs | 4 +- ethcore/light/src/types/request/mod.rs | 36 +- ethcore/private-tx/src/lib.rs | 6 +- ethcore/src/block.rs | 14 +- ethcore/src/blockchain/blockchain.rs | 32 +- ethcore/src/blockchain/generator.rs | 2 +- ethcore/src/client/client.rs | 10 +- ethcore/src/client/test_client.rs | 14 +- ethcore/src/encoded.rs | 18 +- ethcore/src/engines/authority_round/mod.rs | 18 +- ethcore/src/engines/basic_authority.rs | 4 +- ethcore/src/engines/epoch.rs | 6 +- ethcore/src/engines/tendermint/message.rs | 18 +- ethcore/src/engines/tendermint/mod.rs | 11 +- .../engines/validator_set/safe_contract.rs | 10 +- ethcore/src/ethereum/ethash.rs | 6 +- ethcore/src/ethereum/mod.rs | 4 +- ethcore/src/header.rs | 6 +- ethcore/src/json_tests/transaction.rs | 4 +- ethcore/src/lib.rs | 4 +- ethcore/src/snapshot/account.rs | 18 +- ethcore/src/snapshot/block.rs | 10 +- ethcore/src/snapshot/consensus/authority.rs | 6 +- ethcore/src/snapshot/consensus/work.rs | 6 +- ethcore/src/snapshot/io.rs | 4 +- ethcore/src/snapshot/mod.rs | 6 +- ethcore/src/spec/spec.rs | 2 +- ethcore/src/test_helpers.rs | 2 +- ethcore/src/tests/client.rs | 12 +- ethcore/src/tests/trace.rs | 4 +- ethcore/src/trace/types/error.rs | 4 +- ethcore/src/trace/types/flat.rs | 4 +- ethcore/src/trace/types/trace.rs | 10 +- ethcore/src/verification/queue/kind.rs | 2 +- ethcore/src/verification/queue/mod.rs | 6 +- ethcore/src/verification/verification.rs | 28 +- ethcore/src/views/block.rs | 59 +- ethcore/src/views/body.rs | 56 +- ethcore/src/views/header.rs | 42 +- ethcore/src/views/mod.rs | 14 + ethcore/src/views/transaction.rs | 35 +- ethcore/src/views/view_rlp.rs | 130 +++++ ethcore/sync/src/block_sync.rs | 12 +- ethcore/sync/src/blocks.rs | 25 +- ethcore/sync/src/chain.rs | 96 ++-- ethcore/sync/src/lib.rs | 1 + ethcore/transaction/src/transaction.rs | 6 +- ethcore/types/src/receipt.rs | 4 +- ethcore/types/src/snapshot_manifest.rs | 4 +- ethcore/vm/src/call_type.rs | 4 +- local-store/src/lib.rs | 4 +- parity/blockchain.rs | 2 +- rpc/src/lib.rs | 1 + rpc/src/v1/impls/eth.rs | 4 +- rpc/src/v1/impls/light/eth.rs | 4 +- rpc/src/v1/impls/private.rs | 6 +- rpc/src/v1/impls/signer.rs | 4 +- rpc/src/v1/impls/traces.rs | 4 +- rpc/src/v1/tests/eth.rs | 2 +- util/journaldb/src/overlaydb.rs | 4 +- util/journaldb/src/overlayrecentdb.rs | 4 +- util/journaldb/src/util.rs | 6 +- util/network-devp2p/src/connection.rs | 4 +- util/network-devp2p/src/discovery.rs | 16 +- util/network-devp2p/src/handshake.rs | 6 +- util/network-devp2p/src/node_table.rs | 4 +- util/network-devp2p/src/session.rs | 8 +- util/network/src/lib.rs | 4 +- util/patricia_trie/src/node.rs | 6 +- util/patricia_trie/src/triedbmut.rs | 4 +- util/rlp/src/impls.rs | 20 +- util/rlp/src/lib.rs | 14 +- util/rlp/src/rlpin.rs | 533 +++++++++++------- util/rlp/src/traits.rs | 4 +- util/rlp/src/untrusted_rlp.rs | 406 ------------- util/rlp/tests/tests.rs | 18 +- util/rlp_compress/src/lib.rs | 8 +- util/rlp_derive/src/de.rs | 4 +- whisper/src/message.rs | 18 +- whisper/src/net/mod.rs | 12 +- 86 files changed, 967 insertions(+), 1078 deletions(-) create mode 100644 ethcore/src/views/view_rlp.rs delete mode 100644 util/rlp/src/untrusted_rlp.rs diff --git a/ethcore/light/src/cht.rs b/ethcore/light/src/cht.rs index 6f5ebf808e..ffb7841f45 100644 --- a/ethcore/light/src/cht.rs +++ b/ethcore/light/src/cht.rs @@ -26,7 +26,7 @@ use hashdb::HashDB; use memorydb::MemoryDB; use bytes::Bytes; use trie::{self, TrieMut, TrieDBMut, Trie, TrieDB, Recorder}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; // encode a key. macro_rules! key { @@ -150,7 +150,7 @@ pub fn check_proof(proof: &[Bytes], num: u64, root: H256) -> Option<(H256, U256) let res = match TrieDB::new(&db, &root) { Err(_) => return None, Ok(trie) => trie.get_with(&key!(num), |val: &[u8]| { - let rlp = UntrustedRlp::new(val); + let rlp = Rlp::new(val); rlp.val_at::(0) .and_then(|h| rlp.val_at::(1).map(|td| (h, td))) .ok() diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 84b7916eef..7bd13a6c09 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -41,7 +41,7 @@ use ethcore::engines::epoch::{ PendingTransition as PendingEpochTransition }; -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; use plain_hasher::H256FastMap; @@ -125,7 +125,7 @@ impl Encodable for Entry { } impl Decodable for Entry { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let mut candidates = SmallVec::<[Candidate; 3]>::new(); for item in rlp.iter() { @@ -186,7 +186,7 @@ fn encode_canonical_transition(header: &Header, proof: &[u8]) -> Vec { // decode last canonical transition entry. fn decode_canonical_transition(t: &[u8]) -> Result<(Header, &[u8]), DecoderError> { - let rlp = UntrustedRlp::new(t); + let rlp = Rlp::new(t); Ok((rlp.val_at(0)?, rlp.at(1)?.data()?)) } diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 8299773230..d58d90fac4 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -22,7 +22,7 @@ use transaction::UnverifiedTransaction; use io::TimerToken; use network::{HostInfo, NetworkProtocolHandler, NetworkContext, PeerId}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; use kvdb::DBValue; use parking_lot::{Mutex, RwLock}; @@ -528,7 +528,7 @@ impl LightProtocol { // - check whether peer exists // - check whether request was made // - check whether request kinds match - fn pre_verify_response(&self, peer: &PeerId, raw: &UntrustedRlp) -> Result { + fn pre_verify_response(&self, peer: &PeerId, raw: &Rlp) -> Result { let req_id = ReqId(raw.val_at(0)?); let cur_credits: U256 = raw.val_at(1)?; @@ -572,7 +572,7 @@ impl LightProtocol { /// Packet data is _untrusted_, which means that invalid data won't lead to /// issues. pub fn handle_packet(&self, io: &IoContext, peer: &PeerId, packet_id: u8, data: &[u8]) { - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); trace!(target: "pip", "Incoming packet {} from peer {}", packet_id, peer); @@ -794,7 +794,7 @@ impl LightProtocol { impl LightProtocol { // Handle status message from peer. - fn status(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { + fn status(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> { let pending = match self.pending_peers.write().remove(peer) { Some(pending) => pending, None => { @@ -855,7 +855,7 @@ impl LightProtocol { } // Handle an announcement. - fn announcement(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { + fn announcement(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> { if !self.peers.read().contains_key(peer) { debug!(target: "pip", "Ignoring announcement from unknown peer"); return Ok(()) @@ -900,7 +900,7 @@ impl LightProtocol { } // Receive requests from a peer. - fn request(&self, peer_id: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + fn request(&self, peer_id: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> { // the maximum amount of requests we'll fill in a single packet. const MAX_REQUESTS: usize = 256; @@ -968,7 +968,7 @@ impl LightProtocol { } // handle a packet with responses. - fn response(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + fn response(&self, peer: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> { let (req_id, responses) = { let id_guard = self.pre_verify_response(peer, &raw)?; let responses: Vec = raw.list_at(2)?; @@ -987,7 +987,7 @@ impl LightProtocol { } // handle an update of request credits parameters. - fn update_credits(&self, peer_id: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> { + fn update_credits(&self, peer_id: &PeerId, io: &IoContext, raw: Rlp) -> Result<(), Error> { let peers = self.peers.read(); let peer = peers.get(peer_id).ok_or(Error::UnknownPeer)?; @@ -1022,7 +1022,7 @@ impl LightProtocol { } // handle an acknowledgement of request credits update. - fn acknowledge_update(&self, peer_id: &PeerId, _io: &IoContext, _raw: UntrustedRlp) -> Result<(), Error> { + fn acknowledge_update(&self, peer_id: &PeerId, _io: &IoContext, _raw: Rlp) -> Result<(), Error> { let peers = self.peers.read(); let peer = peers.get(peer_id).ok_or(Error::UnknownPeer)?; let mut peer = peer.lock(); @@ -1041,7 +1041,7 @@ impl LightProtocol { } // Receive a set of transactions to relay. - fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> { + fn relay_transactions(&self, peer: &PeerId, io: &IoContext, data: Rlp) -> Result<(), Error> { const MAX_TRANSACTIONS: usize = 256; let txs: Vec<_> = data.iter() diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index e1b7455ccc..abe609dabb 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -29,7 +29,7 @@ use request::{self, Request}; use super::error::Error; -use rlp::{UntrustedRlp, RlpStream, Decodable, Encodable, DecoderError}; +use rlp::{Rlp, RlpStream, Decodable, Encodable, DecoderError}; use ethereum_types::U256; use std::time::{Duration, Instant}; @@ -162,7 +162,7 @@ impl Encodable for CostTable { } impl Decodable for CostTable { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let base = rlp.val_at(0)?; let mut headers = None; diff --git a/ethcore/light/src/net/status.rs b/ethcore/light/src/net/status.rs index 0f811bbe40..c9ee3d760f 100644 --- a/ethcore/light/src/net/status.rs +++ b/ethcore/light/src/net/status.rs @@ -16,7 +16,7 @@ //! Peer status and capabilities. -use rlp::{DecoderError, Encodable, Decodable, RlpStream, UntrustedRlp}; +use rlp::{DecoderError, Encodable, Decodable, RlpStream, Rlp}; use ethereum_types::{H256, U256}; use super::request_credits::FlowParams; @@ -85,7 +85,7 @@ impl Key { // helper for decoding key-value pairs in the handshake or an announcement. struct Parser<'a> { pos: usize, - rlp: UntrustedRlp<'a>, + rlp: Rlp<'a>, } impl<'a> Parser<'a> { @@ -97,7 +97,7 @@ impl<'a> Parser<'a> { // expect a specific next key, and get the value's RLP. // if the key isn't found, the position isn't advanced. - fn expect_raw(&mut self, key: Key) -> Result, DecoderError> { + fn expect_raw(&mut self, key: Key) -> Result, DecoderError> { trace!(target: "les", "Expecting key {}", key.as_str()); let pre_pos = self.pos; if let Some((k, val)) = self.get_next()? { @@ -109,7 +109,7 @@ impl<'a> Parser<'a> { } // get the next key and value RLP. - fn get_next(&mut self) -> Result)>, DecoderError> { + fn get_next(&mut self) -> Result)>, DecoderError> { while self.pos < self.rlp.item_count()? { let pair = self.rlp.at(self.pos)?; let k: String = pair.val_at(0)?; @@ -208,7 +208,7 @@ impl Capabilities { /// - chain status /// - serving capabilities /// - request credit parameters -pub fn parse_handshake(rlp: UntrustedRlp) -> Result<(Status, Capabilities, Option), DecoderError> { +pub fn parse_handshake(rlp: Rlp) -> Result<(Status, Capabilities, Option), DecoderError> { let mut parser = Parser { pos: 0, rlp: rlp, @@ -304,7 +304,7 @@ pub struct Announcement { } /// Parse an announcement. -pub fn parse_announcement(rlp: UntrustedRlp) -> Result { +pub fn parse_announcement(rlp: Rlp) -> Result { let mut last_key = None; let mut announcement = Announcement { @@ -374,7 +374,7 @@ mod tests { use super::*; use super::super::request_credits::FlowParams; use ethereum_types::{U256, H256}; - use rlp::{RlpStream, UntrustedRlp}; + use rlp::{RlpStream, Rlp}; #[test] fn full_handshake() { @@ -404,7 +404,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, Some(&flow_params)); let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&handshake)).unwrap(); + = parse_handshake(Rlp::new(&handshake)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); @@ -439,7 +439,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, Some(&flow_params)); let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&handshake)).unwrap(); + = parse_handshake(Rlp::new(&handshake)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); @@ -473,7 +473,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, Some(&flow_params)); let interleaved = { - let handshake = UntrustedRlp::new(&handshake); + let handshake = Rlp::new(&handshake); let mut stream = RlpStream::new_list(handshake.item_count().unwrap_or(0) * 3); for item in handshake.iter() { @@ -489,7 +489,7 @@ mod tests { }; let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&interleaved)).unwrap(); + = parse_handshake(Rlp::new(&interleaved)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); @@ -510,7 +510,7 @@ mod tests { }; let serialized = write_announcement(&announcement); - let read = parse_announcement(UntrustedRlp::new(&serialized)).unwrap(); + let read = parse_announcement(Rlp::new(&serialized)).unwrap(); assert_eq!(read, announcement); } @@ -529,7 +529,7 @@ mod tests { .append_raw(&encode_flag(Key::ServeHeaders), 1); let out = stream.drain(); - assert!(parse_announcement(UntrustedRlp::new(&out)).is_err()); + assert!(parse_announcement(Rlp::new(&out)).is_err()); let mut stream = RlpStream::new_list(6); stream @@ -541,7 +541,7 @@ mod tests { .append_raw(&encode_pair(Key::ServeStateSince, &44u64), 1); let out = stream.drain(); - assert!(parse_announcement(UntrustedRlp::new(&out)).is_ok()); + assert!(parse_announcement(Rlp::new(&out)).is_ok()); } #[test] @@ -566,7 +566,7 @@ mod tests { let handshake = write_handshake(&status, &capabilities, None); let (read_status, read_capabilities, read_flow) - = parse_handshake(UntrustedRlp::new(&handshake)).unwrap(); + = parse_handshake(Rlp::new(&handshake)).unwrap(); assert_eq!(read_status, status); assert_eq!(read_capabilities, capabilities); diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index 397576ae42..3c04c0ffba 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -31,7 +31,7 @@ use provider::Provider; use request; use request::*; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use ethereum_types::{H256, U256, Address}; use std::sync::Arc; @@ -688,7 +688,7 @@ fn id_guard() { stream.begin_list(2).append(&125usize).append(&3usize); let packet = stream.out(); - assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_err()); + assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_err()); } // next, do an unexpected response. @@ -699,7 +699,7 @@ fn id_guard() { stream.begin_list(0); let packet = stream.out(); - assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_err()); + assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_err()); } // lastly, do a valid (but empty) response. @@ -710,7 +710,7 @@ fn id_guard() { stream.begin_list(0); let packet = stream.out(); - assert!(proto.response(&peer_id, &Expect::Nothing, UntrustedRlp::new(&packet)).is_ok()); + assert!(proto.response(&peer_id, &Expect::Nothing, Rlp::new(&packet)).is_ok()); } let peers = proto.peers.read(); diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 8b184cc1d8..18a309ae96 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -30,7 +30,7 @@ use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY, KECCAK_EMPTY_LIST_RLP, keccak}; use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256, Address}; use parking_lot::Mutex; use hashdb::HashDB; @@ -831,7 +831,7 @@ impl Account { match TrieDB::new(&db, &state_root).and_then(|t| t.get(&keccak(&self.address)))? { Some(val) => { - let rlp = UntrustedRlp::new(&val); + let rlp = Rlp::new(&val); Ok(Some(BasicAccount { nonce: rlp.val_at(0)?, balance: rlp.val_at(1)?, diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index bd68c6a0a2..8d911d3f55 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -16,7 +16,7 @@ //! Light protocol request types. -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::H256; mod batch; @@ -148,7 +148,7 @@ impl From for Field { } impl Decodable for Field { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.val_at::(0)? { 0 => Ok(Field::Scalar(rlp.val_at::(1)?)), 1 => Ok({ @@ -224,7 +224,7 @@ impl From for HashOrNumber { } impl Decodable for HashOrNumber { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.as_val::().map(HashOrNumber::Hash) .or_else(|_| rlp.as_val().map(HashOrNumber::Number)) } @@ -331,7 +331,7 @@ impl Request { } impl Decodable for Request { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.val_at::(0)? { Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)), Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)), @@ -493,7 +493,7 @@ pub enum Kind { } impl Decodable for Kind { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.as_val::()? { 0 => Ok(Kind::Headers), 1 => Ok(Kind::HeaderProof), @@ -578,7 +578,7 @@ impl Response { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.val_at::(0)? { Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)), Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)), @@ -673,7 +673,7 @@ pub trait ResponseLike { pub mod header { use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output}; use ethcore::encoded; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; /// Potentially incomplete headers request. #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] @@ -754,7 +754,7 @@ pub mod header { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use ethcore::header::Header as FullHeader; let mut headers = Vec::new(); @@ -785,7 +785,7 @@ pub mod header { /// Request and response for header proofs. pub mod header_proof { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::{H256, U256}; use bytes::Bytes; @@ -859,7 +859,7 @@ pub mod header_proof { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Response { proof: rlp.list_at(0)?, hash: rlp.val_at(1)?, @@ -1027,7 +1027,7 @@ pub mod block_receipts { pub mod block_body { use super::{Field, NoSuchOutput, OutputKind, Output}; use ethcore::encoded; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::H256; /// Potentially incomplete block body request. @@ -1092,7 +1092,7 @@ pub mod block_body { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use ethcore::header::Header as FullHeader; use transaction::UnverifiedTransaction; @@ -1411,7 +1411,7 @@ pub mod contract_code { pub mod execution { use super::{Field, NoSuchOutput, OutputKind, Output}; use transaction::Action; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; + use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::{H256, U256, Address}; use kvdb::DBValue; use bytes::Bytes; @@ -1508,7 +1508,7 @@ pub mod execution { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let mut items = Vec::new(); for raw_item in rlp.iter() { let mut item = DBValue::new(); @@ -1536,7 +1536,7 @@ 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 rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use ethereum_types::H256; use bytes::Bytes; @@ -1548,7 +1548,7 @@ pub mod epoch_signal { } impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Incomplete { block_hash: rlp.val_at(0)?, }) @@ -1617,7 +1617,7 @@ pub mod epoch_signal { } impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Response { signal: rlp.as_val()?, @@ -1891,7 +1891,7 @@ mod tests { stream.append(&100usize).append_list(&reqs); let out = stream.out(); - let rlp = UntrustedRlp::new(&out); + let rlp = Rlp::new(&out); assert_eq!(rlp.val_at::(0).unwrap(), 100usize); assert_eq!(rlp.list_at::(1).unwrap(), reqs); } diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index e28dd7c331..80510938cf 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -238,14 +238,14 @@ impl Provider where { fn extract_original_transaction(&self, private: PrivateTransaction, contract: &Address) -> Result { let encrypted_transaction = private.encrypted; let transaction_bytes = self.decrypt(contract, &encrypted_transaction)?; - let original_transaction: UnverifiedTransaction = UntrustedRlp::new(&transaction_bytes).as_val()?; + let original_transaction: UnverifiedTransaction = Rlp::new(&transaction_bytes).as_val()?; Ok(original_transaction) } /// Process received private transaction pub fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { trace!("Private transaction received"); - let private_tx: PrivateTransaction = UntrustedRlp::new(rlp).as_val()?; + let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?; let contract = private_tx.contract; let contract_validators = self.get_validators(BlockId::Latest, &contract)?; @@ -356,7 +356,7 @@ impl Provider where { /// Add signed private transaction into the store /// Creates corresponding public transaction if last required singature collected and sends it to the chain pub fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { - let tx: SignedPrivateTransaction = UntrustedRlp::new(rlp).as_val()?; + let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?; trace!("Signature for private transaction received: {:?}", tx); let private_hash = tx.private_transaction_hash(); let desc = match self.transactions_for_signing.lock().get(&private_hash) { diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 4cbc0bac9f..e3622c293d 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -22,7 +22,7 @@ use std::collections::HashSet; use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; use triehash::ordered_trie_root; -use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError, encode_list}; +use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list}; use ethereum_types::{H256, U256, Address, Bloom}; use bytes::Bytes; use unexpected::{Mismatch, OutOfBounds}; @@ -54,7 +54,7 @@ pub struct Block { impl Block { /// Returns true if the given bytes form a valid encoding of a block in RLP. pub fn is_good(b: &[u8]) -> bool { - UntrustedRlp::new(b).as_val::().is_ok() + Rlp::new(b).as_val::().is_ok() } /// Get the RLP-encoding of the block with the seal. @@ -68,7 +68,7 @@ impl Block { } impl Decodable for Block { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.as_raw().len() != rlp.payload_info()?.total() { return Err(DecoderError::RlpIsTooBig); } @@ -622,7 +622,7 @@ pub fn enact_verified( // Remove state root from transaction receipts to make them EIP-98 compatible. strip_receipts: bool, ) -> Result { - let view = BlockView::new(&block.bytes); + let view = view!(BlockView, &block.bytes); enact( block.header, @@ -664,7 +664,7 @@ mod tests { last_hashes: Arc, factories: Factories, ) -> Result { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header(); let transactions: Result, Error> = block .transactions() @@ -715,7 +715,7 @@ mod tests { last_hashes: Arc, factories: Factories, ) -> Result { - let header = BlockView::new(block_bytes).header_view(); + let header = view!(BlockView, block_bytes).header_view(); Ok(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)?.seal(engine, header.seal())?) } @@ -781,7 +781,7 @@ mod tests { let bytes = e.rlp_bytes(); assert_eq!(bytes, orig_bytes); - let uncles = BlockView::new(&bytes).uncles(); + let uncles = view!(BlockView, &bytes).uncles(); assert_eq!(uncles[1].extra_data(), b"uncle2"); let db = e.drain(); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 5dffc9ec37..6ad8bf8111 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -25,11 +25,11 @@ use heapsize::HeapSizeOf; use ethereum_types::{H256, Bloom, U256}; use parking_lot::{Mutex, RwLock}; use bytes::Bytes; -use rlp::{Rlp, RlpStream}; +use rlp::RlpStream; use rlp_compress::{compress, decompress, blocks_swapper}; use header::*; use transaction::*; -use views::*; +use views::{BlockView, HeaderView}; use log_entry::{LogEntry, LocalizedLogEntry}; use receipt::Receipt; use blooms::{BloomGroup, GroupPosition}; @@ -231,13 +231,7 @@ impl BlockProvider for BlockChain { fn block(&self, hash: &H256) -> Option { let header = self.block_header_data(hash)?; let body = self.block_body(hash)?; - - let mut block = RlpStream::new_list(3); - let body_rlp = body.rlp(); - block.append_raw(header.rlp().as_raw(), 1); - block.append_raw(body_rlp.at(0).as_raw(), 1); - block.append_raw(body_rlp.at(1).as_raw(), 1); - Some(encoded::Block::new(block.out())) + Some(encoded::Block::new_from_header_and_body(&header.view(), &body.view())) } /// Get block header data @@ -499,7 +493,7 @@ impl BlockChain { None => { // best block does not exist // we need to insert genesis into the cache - let block = BlockView::new(genesis); + let block = view!(BlockView, genesis); let header = block.header_view(); let hash = block.hash(); @@ -701,7 +695,7 @@ impl BlockChain { /// Supply a dummy parent total difficulty when the parent block may not be in the chain. /// Returns true if the block is disconnected. pub fn insert_unordered_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, parent_td: Option, is_best: bool, is_ancient: bool) -> bool { - let block = BlockView::new(bytes); + let block = view!(BlockView, bytes); let header = block.header_view(); let hash = header.hash(); @@ -898,7 +892,7 @@ impl BlockChain { /// If the block is already known, does nothing. pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec) -> ImportRoute { // create views onto rlp - let block = BlockView::new(bytes); + let block = view!(BlockView, bytes); let header = block.header_view(); let hash = header.hash(); @@ -1138,7 +1132,7 @@ impl BlockChain { /// This function returns modified block hashes. fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let mut block_hashes = HashMap::new(); - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header_view(); let number = header.number(); @@ -1165,7 +1159,7 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); @@ -1197,7 +1191,7 @@ impl BlockChain { /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap> { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let transaction_hashes = block.transaction_hashes(); match info.location { @@ -1265,7 +1259,7 @@ impl BlockChain { /// to bloom location in database (BlocksBloomLocation). /// fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { - let block = BlockView::new(block_bytes); + let block = view!(BlockView, block_bytes); let header = block.header_view(); let log_blooms = match info.location { @@ -1384,9 +1378,9 @@ impl BlockChain { /// Create a block body from a block. pub fn block_to_body(block: &[u8]) -> Bytes { let mut body = RlpStream::new_list(2); - let block_rlp = Rlp::new(block); - body.append_raw(block_rlp.at(1).as_raw(), 1); - body.append_raw(block_rlp.at(2).as_raw(), 1); + let block_view = view!(BlockView, block); + body.append_raw(block_view.transactions_rlp().as_raw(), 1); + body.append_raw(block_view.uncles_rlp().as_raw(), 1); body.out() } diff --git a/ethcore/src/blockchain/generator.rs b/ethcore/src/blockchain/generator.rs index 5f990a4d98..e767f2211c 100644 --- a/ethcore/src/blockchain/generator.rs +++ b/ethcore/src/blockchain/generator.rs @@ -41,7 +41,7 @@ impl Block { #[inline] pub fn hash(&self) -> H256 { - BlockView::new(&self.encoded()).header_view().hash() + view!(BlockView, &self.encoded()).header_view().hash() } #[inline] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index fb3f07e41e..d2b63b6cdb 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -62,7 +62,7 @@ use ethcore_miner::pool::VerifiedTransaction; use parking_lot::{Mutex, RwLock}; use rand::OsRng; use receipt::{Receipt, LocalizedReceipt}; -use rlp::UntrustedRlp; +use rlp::Rlp; use snapshot::{self, io as snapshot_io}; use spec::Spec; use state_db::StateDB; @@ -446,7 +446,7 @@ impl Importer { /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. fn import_old_block(&self, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { - let block = BlockView::new(&block_bytes); + let block = view!(BlockView, &block_bytes); let header = block.header(); let receipts = ::rlp::decode_list(&receipts_bytes); let hash = header.hash(); @@ -514,7 +514,7 @@ impl Importer { let receipts = block.receipts().to_owned(); let traces = block.traces().clone().drain(); - assert_eq!(header.hash(), BlockView::new(block_data).header_view().hash()); + assert_eq!(header.hash(), view!(BlockView, block_data).header_view().hash()); //let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new)); @@ -988,7 +988,7 @@ impl Client { let txs: Vec = transactions .iter() - .filter_map(|bytes| UntrustedRlp::new(bytes).as_val().ok()) + .filter_map(|bytes| Rlp::new(bytes).as_val().ok()) .collect(); self.notify(|notify| { @@ -1423,7 +1423,7 @@ impl ImportBlock for Client { fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { { // check block order - let header = BlockView::new(&block_bytes).header_view(); + let header = view!(BlockView, &block_bytes).header_view(); if self.chain.read().is_known(&header.hash()) { return Err(BlockImportError::Import(ImportError::AlreadyInChain)); } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 02067afd00..c2e06009b6 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -29,7 +29,7 @@ use journaldb; use kvdb::DBValue; use kvdb_memorydb; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use ethkey::{Generator, Random}; use ethcore_miner::pool::VerifiedTransaction; use transaction::{self, Transaction, LocalizedTransaction, SignedTransaction, Action}; @@ -471,7 +471,7 @@ impl ChainInfo for TestBlockChainClient { impl BlockInfo for TestBlockChainClient { fn block_header(&self, id: BlockId) -> Option { self.block_hash(id) - .and_then(|hash| self.blocks.read().get(&hash).map(|r| BlockView::new(r).header_rlp().as_raw().to_vec())) + .and_then(|hash| self.blocks.read().get(&hash).map(|r| view!(BlockView, r).header_rlp().as_raw().to_vec())) .map(encoded::Header::new) } @@ -513,7 +513,7 @@ impl RegistryInfo for TestBlockChainClient { impl ImportBlock for TestBlockChainClient { fn import_block(&self, b: Bytes) -> Result { - let header = BlockView::new(&b).header(); + let header = view!(BlockView, &b).header(); let h = header.hash(); let number: usize = header.number() as usize; if number > self.blocks.read().len() { @@ -522,7 +522,7 @@ impl ImportBlock for TestBlockChainClient { if number > 0 { match self.blocks.read().get(header.parent_hash()) { Some(parent) => { - let parent = BlockView::new(parent).header(); + let parent = view!(BlockView, parent).header(); if parent.number() != (header.number() - 1) { panic!("Unexpected block parent"); } @@ -547,7 +547,7 @@ impl ImportBlock for TestBlockChainClient { while n > 0 && self.numbers.read()[&n] != parent_hash { *self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone(); n -= 1; - parent_hash = BlockView::new(&self.blocks.read()[&parent_hash]).header().parent_hash().clone(); + parent_hash = view!(BlockView, &self.blocks.read()[&parent_hash]).header().parent_hash().clone(); } } } @@ -692,7 +692,7 @@ impl BlockChainClient for TestBlockChainClient { fn block_body(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| { - let block = BlockView::new(r); + let block = view!(BlockView, r); let mut stream = RlpStream::new_list(2); stream.append_raw(block.transactions_rlp().as_raw(), 1); stream.append_raw(block.uncles_rlp().as_raw(), 1); @@ -811,7 +811,7 @@ impl BlockChainClient for TestBlockChainClient { fn queue_transactions(&self, transactions: Vec, _peer_id: usize) { // import right here - let txs = transactions.into_iter().filter_map(|bytes| UntrustedRlp::new(&bytes).as_val().ok()).collect(); + let txs = transactions.into_iter().filter_map(|bytes| Rlp::new(&bytes).as_val().ok()).collect(); self.miner.import_external_transactions(self, txs); } diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 5d3d316063..1f627666a9 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -26,12 +26,12 @@ use block::Block as FullBlock; use header::{BlockNumber, Header as FullHeader}; use transaction::UnverifiedTransaction; -use views; use hash::keccak; use heapsize::HeapSizeOf; use ethereum_types::{H256, Bloom, U256, Address}; use rlp::{Rlp, RlpStream}; +use views::{self, BlockView, HeaderView, BodyView}; /// Owning header view. #[derive(Debug, Clone, PartialEq, Eq)] @@ -52,7 +52,7 @@ impl Header { /// Get a borrowed header view onto the data. #[inline] - pub fn view(&self) -> views::HeaderView { views::HeaderView::new(&self.0) } + pub fn view(&self) -> HeaderView { view!(HeaderView, &self.0) } /// Get the rlp of the header. #[inline] @@ -125,7 +125,7 @@ impl Body { /// Get a borrowed view of the data within. #[inline] - pub fn view(&self) -> views::BodyView { views::BodyView::new(&self.0) } + pub fn view(&self) -> BodyView { view!(BodyView, &self.0) } /// Fully decode this block body. pub fn decode(&self) -> (Vec, Vec) { @@ -145,7 +145,7 @@ impl Body { // forwarders to borrowed view. impl Body { /// Get raw rlp of transactions - pub fn transactions_rlp(&self) -> Rlp { self.view().transactions_rlp() } + pub fn transactions_rlp(&self) -> Rlp { self.view().transactions_rlp().rlp } /// Get a vector of all transactions. pub fn transactions(&self) -> Vec { self.view().transactions() } @@ -160,7 +160,7 @@ impl Body { pub fn transaction_hashes(&self) -> Vec { self.view().transaction_hashes() } /// Get raw rlp of uncle headers - pub fn uncles_rlp(&self) -> Rlp { self.view().uncles_rlp() } + pub fn uncles_rlp(&self) -> Rlp { self.view().uncles_rlp().rlp } /// Decode uncle headers. pub fn uncles(&self) -> Vec { self.view().uncles() } @@ -198,20 +198,20 @@ impl Block { /// Get a borrowed view of the whole block. #[inline] - pub fn view(&self) -> views::BlockView { views::BlockView::new(&self.0) } + pub fn view(&self) -> BlockView { view!(BlockView, &self.0) } /// Get a borrowed view of the block header. #[inline] - pub fn header_view(&self) -> views::HeaderView { self.view().header_view() } + pub fn header_view(&self) -> HeaderView { self.view().header_view() } /// Decode to a full block. pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0) } /// Decode the header. - pub fn decode_header(&self) -> FullHeader { self.rlp().val_at(0) } + pub fn decode_header(&self) -> FullHeader { self.view().rlp().val_at(0) } /// Clone the encoded header. - pub fn header(&self) -> Header { Header(self.rlp().at(0).as_raw().to_vec()) } + pub fn header(&self) -> Header { Header(self.view().rlp().at(0).as_raw().to_vec()) } /// Get the rlp of this block. #[inline] diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index b8b9ab8b30..013445ba35 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -41,7 +41,7 @@ use self::finality::RollingFinality; use ethkey::{self, Signature}; use io::{IoContext, IoHandler, TimerToken, IoService}; use itertools::{self, Itertools}; -use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; +use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, Rlp}; use ethereum_types::{H256, H520, Address, U128, U256}; use parking_lot::{Mutex, RwLock}; use unexpected::{Mismatch, OutOfBounds}; @@ -325,7 +325,7 @@ impl Encodable for EmptyStep { } impl Decodable for EmptyStep { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let signature = rlp.val_at(0)?; let empty_step_rlp = rlp.at(1)?; @@ -366,7 +366,7 @@ impl Encodable for SealedEmptyStep { } impl Decodable for SealedEmptyStep { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let signature = rlp.val_at(0)?; let step = rlp.val_at(1)?; @@ -415,7 +415,7 @@ impl super::EpochVerifier for EpochVerifier { let mut finality_checker = RollingFinality::blank(self.subchain_validators.clone().into_inner()); let mut finalized = Vec::new(); - let headers: Vec

= UntrustedRlp::new(proof).as_list().ok()?; + let headers: Vec
= Rlp::new(proof).as_list().ok()?; { let mut push_header = |parent_header: &Header, header: Option<&Header>| { @@ -479,13 +479,13 @@ fn header_expected_seal_fields(header: &Header, empty_steps_transition: u64) -> fn header_step(header: &Header, empty_steps_transition: u64) -> Result { let expected_seal_fields = header_expected_seal_fields(header, empty_steps_transition); - UntrustedRlp::new(&header.seal().get(0).expect( + Rlp::new(&header.seal().get(0).expect( &format!("was either checked with verify_block_basic or is genesis; has {} fields; qed (Make sure the spec file has a correct genesis seal)", expected_seal_fields))).as_val() } fn header_signature(header: &Header, empty_steps_transition: u64) -> Result { let expected_seal_fields = header_expected_seal_fields(header, empty_steps_transition); - UntrustedRlp::new(&header.seal().get(1).expect( + Rlp::new(&header.seal().get(1).expect( &format!("was checked with verify_block_basic; has {} fields; qed", expected_seal_fields))).as_val::().map(Into::into) } @@ -498,7 +498,7 @@ fn header_empty_steps_raw(header: &Header) -> &[u8] { // extracts the empty steps from the header seal. should only be called when there are 3 fields in the seal // (i.e. header.number() >= self.empty_steps_transition). fn header_empty_steps(header: &Header) -> Result, ::rlp::DecoderError> { - let empty_steps = UntrustedRlp::new(header_empty_steps_raw(header)).as_list::()?; + let empty_steps = Rlp::new(header_empty_steps_raw(header)).as_list::()?; Ok(empty_steps.into_iter().map(|s| EmptyStep::from_sealed(s, header.parent_hash())).collect()) } @@ -575,7 +575,7 @@ fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof: } fn destructure_proofs(combined: &[u8]) -> Result<(BlockNumber, &[u8], &[u8]), Error> { - let rlp = UntrustedRlp::new(combined); + let rlp = Rlp::new(combined); Ok(( rlp.at(0)?.as_val()?, rlp.at(1)?.data()?, @@ -801,7 +801,7 @@ impl Engine for AuthorityRound { EngineError::MalformedMessage(format!("{:?}", x)) } - let rlp = UntrustedRlp::new(rlp); + let rlp = Rlp::new(rlp); let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;; if empty_step.verify(&*self.validators).unwrap_or(false) { diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 768cde3d5e..bbefddccb7 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -57,10 +57,10 @@ impl super::EpochVerifier for EpochVerifier { } fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Error> { - use rlp::UntrustedRlp; + use rlp::Rlp; // Check if the signature belongs to a validator, can depend on parent state. - let sig = UntrustedRlp::new(&header.seal()[0]).as_val::()?; + let sig = Rlp::new(&header.seal()[0]).as_val::()?; let signer = ethkey::public_to_address(ðkey::recover(&sig.into(), &header.bare_hash())?); if *header.author() != signer { diff --git a/ethcore/src/engines/epoch.rs b/ethcore/src/engines/epoch.rs index dffc822cbf..6975e8898b 100644 --- a/ethcore/src/engines/epoch.rs +++ b/ethcore/src/engines/epoch.rs @@ -18,7 +18,7 @@ use ethereum_types::H256; -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; /// A full epoch transition. #[derive(Debug, Clone)] @@ -41,7 +41,7 @@ impl Encodable for Transition { } impl Decodable for Transition { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(Transition { block_hash: rlp.val_at(0)?, block_number: rlp.val_at(1)?, @@ -64,7 +64,7 @@ impl Encodable for PendingTransition { } impl Decodable for PendingTransition { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { Ok(PendingTransition { proof: rlp.as_val()?, }) diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index eac08df9bc..17b79a80b8 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -23,7 +23,7 @@ use bytes::Bytes; use super::{Height, View, BlockHash, Step}; use error::Error; use header::Header; -use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; +use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError}; use ethkey::{recover, public_to_address}; use super::super::vote_collector::Message; @@ -61,12 +61,12 @@ impl VoteStep { /// Header consensus view. pub fn consensus_view(header: &Header) -> Result { let view_rlp = header.seal().get(0).expect("seal passed basic verification; seal has 3 fields; qed"); - UntrustedRlp::new(view_rlp.as_slice()).as_val() + Rlp::new(view_rlp.as_slice()).as_val() } /// Proposal signature. pub fn proposal_signature(header: &Header) -> Result { - UntrustedRlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val() + Rlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val() } impl Message for ConsensusMessage { @@ -100,7 +100,7 @@ impl ConsensusMessage { pub fn verify(&self) -> Result { let full_rlp = ::rlp::encode(self); - let block_info = UntrustedRlp::new(&full_rlp).at(1)?; + let block_info = Rlp::new(&full_rlp).at(1)?; let public_key = recover(&self.signature.into(), &keccak(block_info.as_raw()))?; Ok(public_to_address(&public_key)) } @@ -142,7 +142,7 @@ impl Step { } impl Decodable for Step { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { match rlp.as_val()? { 0u8 => Ok(Step::Propose), 1 => Ok(Step::Prevote), @@ -160,7 +160,7 @@ impl Encodable for Step { /// (signature, (height, view, step, block_hash)) impl Decodable for ConsensusMessage { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let m = rlp.at(1)?; let block_message: H256 = m.val_at(3)?; Ok(ConsensusMessage { @@ -234,7 +234,7 @@ mod tests { }; let raw_rlp = ::rlp::encode(&message).into_vec(); let rlp = Rlp::new(&raw_rlp); - assert_eq!(message, rlp.as_val()); + assert_eq!(Ok(message), rlp.as_val()); let message = ConsensusMessage { signature: H520::default(), @@ -247,7 +247,7 @@ mod tests { }; let raw_rlp = ::rlp::encode(&message); let rlp = Rlp::new(&raw_rlp); - assert_eq!(message, rlp.as_val()); + assert_eq!(Ok(message), rlp.as_val()); } #[test] @@ -260,7 +260,7 @@ mod tests { let raw_rlp = message_full_rlp(&tap.sign(addr, None, keccak(&mi)).unwrap().into(), &mi); - let rlp = UntrustedRlp::new(&raw_rlp); + let rlp = Rlp::new(&raw_rlp); let message: ConsensusMessage = rlp.as_val().unwrap(); match message.verify() { Ok(a) if a == addr => {}, _ => panic!(), }; } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 14d1ebd585..5021ef9865 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -36,7 +36,7 @@ use client::EngineClient; use bytes::Bytes; use error::{Error, BlockError}; use header::{Header, BlockNumber}; -use rlp::UntrustedRlp; +use rlp::Rlp; use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; use block::*; @@ -118,7 +118,7 @@ impl super::EpochVerifier for EpochVerifier let mut addresses = HashSet::new(); let ref header_signatures_field = header.seal().get(2).ok_or(BlockError::InvalidSeal)?; - for rlp in UntrustedRlp::new(header_signatures_field).iter() { + for rlp in Rlp::new(header_signatures_field).iter() { let signature: H520 = rlp.as_val()?; let address = (self.recover)(&signature.into(), &message)?; @@ -154,7 +154,7 @@ fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof: } fn destructure_proofs(combined: &[u8]) -> Result<(BlockNumber, &[u8], &[u8]), Error> { - let rlp = UntrustedRlp::new(combined); + let rlp = Rlp::new(combined); Ok(( rlp.at(0)?.as_val()?, rlp.at(1)?.data()?, @@ -503,7 +503,8 @@ impl Engine for Tendermint { fn fmt_err(x: T) -> EngineError { EngineError::MalformedMessage(format!("{:?}", x)) } - let rlp = UntrustedRlp::new(rlp); + + let rlp = Rlp::new(rlp); let message: ConsensusMessage = rlp.as_val().map_err(fmt_err)?; if !self.votes.is_old_or_known(&message) { let msg_hash = keccak(rlp.at(1).map_err(fmt_err)?.as_raw()); @@ -595,7 +596,7 @@ impl Engine for Tendermint { let precommit_hash = message_hash(vote_step.clone(), header.bare_hash()); let ref signatures_field = header.seal().get(2).expect("block went through verify_block_basic; block has .seal_fields() fields; qed"); let mut origins = HashSet::new(); - for rlp in UntrustedRlp::new(signatures_field).iter() { + for rlp in Rlp::new(signatures_field).iter() { let precommit = ConsensusMessage { signature: rlp.as_val()?, block_hash: Some(header.bare_hash()), diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 5c73cb28d1..f132a0bf9d 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -25,7 +25,7 @@ use parking_lot::RwLock; use bytes::Bytes; use memory_cache::MemoryLruCache; use unexpected::Mismatch; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use kvdb::DBValue; use client::EngineClient; @@ -63,7 +63,7 @@ impl ::engines::StateDependentProof for StateProof { } fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> { - let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof)) + let (header, state_items) = decode_first_proof(&Rlp::new(proof)) .map_err(|e| format!("proof incorrectly encoded: {}", e))?; if &header != &self.header { return Err("wrong header in proof".into()); @@ -145,7 +145,7 @@ fn check_first_proof(machine: &EthereumMachine, provider: &validator_set::Valida }).map_err(|err| err.to_string()) } -fn decode_first_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec), ::error::Error> { +fn decode_first_proof(rlp: &Rlp) -> Result<(Header, Vec), ::error::Error> { let header = rlp.val_at(0)?; let state_items = rlp.at(1)?.iter().map(|x| { let mut val = DBValue::new(); @@ -165,7 +165,7 @@ fn encode_proof(header: &Header, receipts: &[Receipt]) -> Bytes { stream.drain().into_vec() } -fn decode_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec), ::error::Error> { +fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec), ::error::Error> { Ok((rlp.val_at(0)?, rlp.list_at(1)?)) } @@ -357,7 +357,7 @@ impl ValidatorSet for ValidatorSafeContract { fn epoch_set(&self, first: bool, machine: &EthereumMachine, _number: ::header::BlockNumber, proof: &[u8]) -> Result<(SimpleList, Option), ::error::Error> { - let rlp = UntrustedRlp::new(proof); + let rlp = Rlp::new(proof); if first { trace!(target: "engine", "Recovering initial epoch set"); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 41ab777d4a..7d43395286 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -27,7 +27,7 @@ use error::{BlockError, Error}; use header::{Header, BlockNumber}; use engines::{self, Engine}; use ethjson; -use rlp::UntrustedRlp; +use rlp::Rlp; use machine::EthereumMachine; /// Number of blocks in an ethash snapshot. @@ -59,8 +59,8 @@ impl Seal { ).into()); } - let mix_hash = UntrustedRlp::new(seal[0].as_ref()).as_val::()?; - let nonce = UntrustedRlp::new(seal[1].as_ref()).as_val::()?; + let mix_hash = Rlp::new(seal[0].as_ref()).as_val::()?; + let nonce = Rlp::new(seal[1].as_ref()).as_val::()?; let seal = Seal { mix_hash, nonce, diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 71cf2e86af..5cf6462686 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -174,7 +174,7 @@ mod tests { assert_eq!(morden.state_root(), "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".into()); let genesis = morden.genesis_block(); - assert_eq!(BlockView::new(&genesis).header_view().hash(), "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303".into()); + assert_eq!(view!(BlockView, &genesis).header_view().hash(), "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303".into()); let _ = morden.engine; } @@ -185,7 +185,7 @@ mod tests { assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into()); let genesis = frontier.genesis_block(); - assert_eq!(BlockView::new(&genesis).header_view().hash(), "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3".into()); + assert_eq!(view!(BlockView, &genesis).header_view().hash(), "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3".into()); let _ = frontier.engine; } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 50529c7201..a31aa029b3 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -21,7 +21,7 @@ use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak}; use heapsize::HeapSizeOf; use ethereum_types::{H256, U256, Address, Bloom}; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable}; +use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable}; pub use types::BlockNumber; @@ -177,7 +177,7 @@ impl Header { /// Get the seal field with RLP-decoded values as bytes. pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(&'a self) -> Result { self.seal.iter().map(|rlp| { - UntrustedRlp::new(rlp).data() + Rlp::new(rlp).data() }).collect() } @@ -327,7 +327,7 @@ fn change_field(hash: &mut Option, field: &mut T, value: T) where T: Pa impl Decodable for Header { - fn decode(r: &UntrustedRlp) -> Result { + fn decode(r: &Rlp) -> Result { let mut blockheader = Header { parent_hash: r.val_at(0)?, uncles_hash: r.val_at(1)?, diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index b7445c51ad..1be4900b12 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -17,7 +17,7 @@ use super::test_common::*; use evm; use ethjson; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::{Action, UnverifiedTransaction, SignedTransaction}; fn do_json_test(json_data: &[u8]) -> Vec { @@ -40,7 +40,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { let allow_unsigned = number.map_or(false, |n| n >= 3_000_000); let rlp: Vec = test.rlp.into(); - let res = UntrustedRlp::new(&rlp) + let res = Rlp::new(&rlp) .as_val() .map_err(::error::Error::from) .and_then(|t: UnverifiedTransaction| { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 1b0a1e3546..65be24dec0 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -127,6 +127,9 @@ extern crate evm; pub extern crate ethstore; +#[macro_use] +pub mod views; + #[cfg(test)] extern crate kvdb_rocksdb; @@ -152,7 +155,6 @@ pub mod state_db; pub mod test_helpers; pub mod trace; pub mod verification; -pub mod views; mod cache_manager; mod blooms; diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 222875b842..6c9e0f3d6e 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -25,7 +25,7 @@ use ethereum_types::{H256, U256}; use hashdb::HashDB; use bytes::Bytes; use trie::{TrieDB, Trie}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use std::collections::HashSet; @@ -148,7 +148,7 @@ pub fn to_fat_rlps(account_hash: &H256, acc: &BasicAccount, acct_db: &AccountDB, // if it exists. pub fn from_fat_rlp( acct_db: &mut AccountDBMut, - rlp: UntrustedRlp, + rlp: Rlp, mut storage_root: H256, ) -> Result<(BasicAccount, Option), Error> { use trie::{TrieDBMut, TrieMut}; @@ -217,7 +217,7 @@ mod tests { use ethereum_types::{H256, Address}; use hashdb::HashDB; use kvdb::DBValue; - use rlp::UntrustedRlp; + use rlp::Rlp; use std::collections::HashSet; @@ -239,7 +239,7 @@ mod tests { assert_eq!(::rlp::decode::(&thin_rlp), account); let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); - let fat_rlp = UntrustedRlp::new(&fat_rlps[0]).at(1).unwrap(); + let fat_rlp = Rlp::new(&fat_rlps[0]).at(1).unwrap(); assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account); } @@ -264,7 +264,7 @@ mod tests { assert_eq!(::rlp::decode::(&thin_rlp), account); let fat_rlp = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); - let fat_rlp = UntrustedRlp::new(&fat_rlp[0]).at(1).unwrap(); + let fat_rlp = Rlp::new(&fat_rlp[0]).at(1).unwrap(); assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account); } @@ -292,7 +292,7 @@ mod tests { let mut root = KECCAK_NULL_RLP; let mut restored_account = None; for rlp in fat_rlps { - let fat_rlp = UntrustedRlp::new(&rlp).at(1).unwrap(); + let fat_rlp = Rlp::new(&rlp).at(1).unwrap(); restored_account = Some(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, root).unwrap().0); root = restored_account.as_ref().unwrap().storage_root.clone(); } @@ -336,8 +336,8 @@ mod tests { let fat_rlp2 = to_fat_rlps(&keccak(&addr2), &account2, &AccountDB::new(db.as_hashdb(), &addr2), &mut used_code, usize::max_value(), usize::max_value()).unwrap(); assert_eq!(used_code.len(), 1); - let fat_rlp1 = UntrustedRlp::new(&fat_rlp1[0]).at(1).unwrap(); - let fat_rlp2 = UntrustedRlp::new(&fat_rlp2[0]).at(1).unwrap(); + let fat_rlp1 = Rlp::new(&fat_rlp1[0]).at(1).unwrap(); + let fat_rlp2 = Rlp::new(&fat_rlp2[0]).at(1).unwrap(); let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2, H256::zero()).unwrap(); assert!(maybe_code.is_none()); @@ -351,6 +351,6 @@ mod tests { #[test] fn encoding_empty_acc() { let mut db = get_temp_state_db(); - assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None)); + assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), Rlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None)); } } diff --git a/ethcore/src/snapshot/block.rs b/ethcore/src/snapshot/block.rs index aa946fd703..a47c504d8f 100644 --- a/ethcore/src/snapshot/block.rs +++ b/ethcore/src/snapshot/block.rs @@ -21,7 +21,7 @@ use header::Header; use hash::keccak; use views::BlockView; -use rlp::{DecoderError, RlpStream, UntrustedRlp}; +use rlp::{DecoderError, RlpStream, Rlp}; use ethereum_types::H256; use bytes::Bytes; use triehash::ordered_trie_root; @@ -89,7 +89,7 @@ impl AbridgedBlock { /// /// Will fail if contains invalid rlp. pub fn to_block(&self, parent_hash: H256, number: u64, receipts_root: H256) -> Result { - let rlp = UntrustedRlp::new(&self.rlp); + let rlp = Rlp::new(&self.rlp); let mut header: Header = Default::default(); header.set_parent_hash(parent_hash); @@ -151,7 +151,7 @@ mod tests { let receipts_root = b.header.receipts_root().clone(); let encoded = encode_block(&b); - let abridged = AbridgedBlock::from_block_view(&BlockView::new(&encoded)); + let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded)); assert_eq!(abridged.to_block(H256::new(), 0, receipts_root).unwrap(), b); } @@ -162,7 +162,7 @@ mod tests { let receipts_root = b.header.receipts_root().clone(); let encoded = encode_block(&b); - let abridged = AbridgedBlock::from_block_view(&BlockView::new(&encoded)); + let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded)); assert_eq!(abridged.to_block(H256::new(), 2, receipts_root).unwrap(), b); } @@ -198,7 +198,7 @@ mod tests { let encoded = encode_block(&b); - let abridged = AbridgedBlock::from_block_view(&BlockView::new(&encoded[..])); + let abridged = AbridgedBlock::from_block_view(&view!(BlockView, &encoded[..])); assert_eq!(abridged.to_block(H256::new(), 0, receipts_root).unwrap(), b); } } diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index d3184a0810..474f5d350c 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -33,7 +33,7 @@ use receipt::Receipt; use snapshot::{Error, ManifestData}; use itertools::{Position, Itertools}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; use kvdb::KeyValueDB; use bytes::Bytes; @@ -182,7 +182,7 @@ impl ChunkRebuilder { fn verify_transition( &mut self, last_verifier: &mut Option>>, - transition_rlp: UntrustedRlp, + transition_rlp: Rlp, engine: &EthEngine, ) -> Result { use engines::ConstructedVerifier; @@ -242,7 +242,7 @@ impl Rebuilder for ChunkRebuilder { engine: &EthEngine, abort_flag: &AtomicBool, ) -> Result<(), ::error::Error> { - let rlp = UntrustedRlp::new(chunk); + let rlp = Rlp::new(chunk); let is_last_chunk: bool = rlp.val_at(0)?; let num_items = rlp.item_count()?; diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index 7f90e327c0..5414ed5963 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -33,7 +33,7 @@ use snapshot::block::AbridgedBlock; use ethereum_types::H256; use kvdb::KeyValueDB; use bytes::Bytes; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use rand::OsRng; /// Snapshot creation and restoration for PoW chains. @@ -225,7 +225,7 @@ impl Rebuilder for PowRebuilder { use ethereum_types::U256; use triehash::ordered_trie_root; - let rlp = UntrustedRlp::new(chunk); + let rlp = Rlp::new(chunk); let item_count = rlp.item_count()?; let num_blocks = (item_count - 3) as u64; @@ -284,7 +284,7 @@ impl Rebuilder for PowRebuilder { self.db.write_buffered(batch); self.chain.commit(); - parent_hash = BlockView::new(&block_bytes).hash(); + parent_hash = view!(BlockView, &block_bytes).hash(); cur_number += 1; } diff --git a/ethcore/src/snapshot/io.rs b/ethcore/src/snapshot/io.rs index 7e38177ea5..84faa19b48 100644 --- a/ethcore/src/snapshot/io.rs +++ b/ethcore/src/snapshot/io.rs @@ -27,7 +27,7 @@ use std::path::{Path, PathBuf}; use bytes::Bytes; use ethereum_types::H256; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use super::ManifestData; @@ -238,7 +238,7 @@ impl PackedReader { file.seek(SeekFrom::Start(manifest_off))?; file.read_exact(&mut manifest_buf)?; - let rlp = UntrustedRlp::new(&manifest_buf); + let rlp = Rlp::new(&manifest_buf); let (start, version) = if rlp.item_count()? == 5 { (0, 1) diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 6b751bf2c4..fbf0c5ca5e 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -39,7 +39,7 @@ use parking_lot::Mutex; use journaldb::{self, Algorithm, JournalDB}; use kvdb::KeyValueDB; use trie::{TrieDB, TrieDBMut, Trie, TrieMut}; -use rlp::{RlpStream, UntrustedRlp}; +use rlp::{RlpStream, Rlp}; use bloom_journal::Bloom; use self::io::SnapshotWriter; @@ -327,7 +327,7 @@ impl StateRebuilder { /// Feed an uncompressed state chunk into the rebuilder. pub fn feed(&mut self, chunk: &[u8], flag: &AtomicBool) -> Result<(), ::error::Error> { - let rlp = UntrustedRlp::new(chunk); + let rlp = Rlp::new(chunk); let empty_rlp = StateAccount::new_basic(U256::zero(), U256::zero()).rlp(); let mut pairs = Vec::with_capacity(rlp.item_count()?); @@ -415,7 +415,7 @@ struct RebuiltStatus { // returns a status detailing newly-loaded code and accounts missing code. fn rebuild_accounts( db: &mut HashDB, - account_fat_rlps: UntrustedRlp, + account_fat_rlps: Rlp, out_chunk: &mut [(H256, Bytes)], known_code: &HashMap, known_storage_roots: &mut HashMap, diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index ec1b5edf3d..c1fda86672 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -913,7 +913,7 @@ mod tests { ); let genesis = test_spec.genesis_block(); assert_eq!( - BlockView::new(&genesis).header_view().hash(), + view!(BlockView, &genesis).header_view().hash(), "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303".into() ); } diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 692f029c86..32b8beab83 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -171,7 +171,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun panic!("error importing block which is valid by definition: {:?}", e); } - last_header = BlockView::new(&b.rlp_bytes()).header(); + last_header = view!(BlockView, &b.rlp_bytes()).header(); db = b.drain(); } client.flush_queue(); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index fc5f84bfae..0b8200e938 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -141,7 +141,7 @@ fn query_bad_block() { fn returns_chain_info() { let dummy_block = get_good_dummy_block(); let client = get_test_client_with_blocks(vec![dummy_block.clone()]); - let block = BlockView::new(&dummy_block); + let block = view!(BlockView, &dummy_block); let info = client.chain_info(); assert_eq!(info.best_block_hash, block.header().hash()); } @@ -178,12 +178,12 @@ fn returns_logs_with_limit() { fn returns_block_body() { let dummy_block = get_good_dummy_block(); let client = get_test_client_with_blocks(vec![dummy_block.clone()]); - let block = BlockView::new(&dummy_block); + let block = view!(BlockView, &dummy_block); let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap(); let body = body.rlp(); - assert_eq!(body.item_count(), 2); - assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]); - assert_eq!(body.at(1).as_raw()[..], block.rlp().at(2).as_raw()[..]); + assert_eq!(body.item_count().unwrap(), 2); + assert_eq!(body.at(0).unwrap().as_raw()[..], block.rlp().at(1).as_raw()[..]); + assert_eq!(body.at(1).unwrap().as_raw()[..], block.rlp().at(2).as_raw()[..]); } #[test] @@ -259,7 +259,7 @@ fn can_mine() { let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).close(); - assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().hash()); + assert_eq!(*b.block().header().parent_hash(), view!(BlockView, &dummy_blocks[0]).header_view().hash()); } #[test] diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 1626e828cc..72d0d47371 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -97,7 +97,7 @@ fn can_trace_block_and_uncle_reward() { panic!("error importing block which is valid by definition: {:?}", e); } - last_header = BlockView::new(&root_block.rlp_bytes()).header(); + last_header = view!(BlockView, &root_block.rlp_bytes()).header(); let root_header = last_header.clone(); db = root_block.drain(); @@ -125,7 +125,7 @@ fn can_trace_block_and_uncle_reward() { panic!("error importing block which is valid by definition: {:?}", e); } - last_header = BlockView::new(&parent_block.rlp_bytes()).header(); + last_header = view!(BlockView,&parent_block.rlp_bytes()).header(); db = parent_block.drain(); last_hashes.push(last_header.hash()); diff --git a/ethcore/src/trace/types/error.rs b/ethcore/src/trace/types/error.rs index 70a3c315ad..f2fa192d33 100644 --- a/ethcore/src/trace/types/error.rs +++ b/ethcore/src/trace/types/error.rs @@ -17,7 +17,7 @@ //! Trace errors. use std::fmt; -use rlp::{Encodable, RlpStream, Decodable, DecoderError, UntrustedRlp}; +use rlp::{Encodable, RlpStream, Decodable, DecoderError, Rlp}; use vm::Error as VmError; /// Trace evm errors. @@ -115,7 +115,7 @@ impl Encodable for Error { } impl Decodable for Error { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use self::Error::*; let value: u8 = rlp.as_val()?; match value { diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index e3f66e170b..e2746ca7f7 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -17,7 +17,7 @@ //! Flat trace module use std::collections::VecDeque; -use rlp::{UntrustedRlp, RlpStream, Decodable, Encodable, DecoderError}; +use rlp::{Rlp, RlpStream, Decodable, Encodable, DecoderError}; use heapsize::HeapSizeOf; use ethereum_types::Bloom; use super::trace::{Action, Res}; @@ -63,7 +63,7 @@ impl Encodable for FlatTrace { } impl Decodable for FlatTrace { - fn decode(d: &UntrustedRlp) -> Result { + fn decode(d: &Rlp) -> Result { let v: Vec = d.list_at(3)?; let res = FlatTrace { action: d.val_at(0)?, diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index e6db17603d..06f24efac3 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -18,7 +18,7 @@ use ethereum_types::{U256, Address, Bloom, BloomInput}; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable}; +use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable}; use vm::ActionParams; use evm::CallType; @@ -154,7 +154,7 @@ impl Encodable for RewardType { } impl Decodable for RewardType { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.as_val().and_then(|v| Ok(match v { 0u32 => RewardType::Block, 1 => RewardType::Uncle, @@ -191,7 +191,7 @@ impl Encodable for Reward { } impl Decodable for Reward { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let res = Reward { author: rlp.val_at(0)?, value: rlp.val_at(1)?, @@ -263,7 +263,7 @@ impl Encodable for Action { } impl Decodable for Action { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let action_type: u8 = rlp.val_at(0)?; match action_type { 0 => rlp.val_at(1).map(Action::Call), @@ -334,7 +334,7 @@ impl Encodable for Res { } impl Decodable for Res { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let action_type: u8 = rlp.val_at(0)?; match action_type { 0 => rlp.val_at(1).map(Res::Call), diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index 898435eb26..223de30f75 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -122,7 +122,7 @@ pub mod blocks { pub fn new(bytes: Bytes) -> Self { use views::BlockView; - let header = BlockView::new(&bytes).header(); + let header = view!(BlockView, &bytes).header(); Unverified { header: header, bytes: bytes, diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index b6e60d042a..d50bd1cb34 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -733,7 +733,7 @@ mod tests { use super::kind::blocks::Unverified; use test_helpers::{get_good_dummy_block_seq, get_good_dummy_block}; use error::*; - use views::*; + use views::BlockView; // create a test block queue. // auto_scaling enables verifier adjustment. @@ -785,7 +785,7 @@ mod tests { fn returns_total_difficulty() { let queue = get_test_queue(false); let block = get_good_dummy_block(); - let hash = BlockView::new(&block).header().hash().clone(); + let hash = view!(BlockView, &block).header().hash().clone(); if let Err(e) = queue.import(Unverified::new(block)) { panic!("error importing block that is valid by definition({:?})", e); } @@ -801,7 +801,7 @@ mod tests { fn returns_ok_for_drained_duplicates() { let queue = get_test_queue(false); let block = get_good_dummy_block(); - let hash = BlockView::new(&block).header().hash().clone(); + let hash = view!(BlockView, &block).header().hash().clone(); if let Err(e) = queue.import(Unverified::new(block)) { panic!("error importing block that is valid by definition({:?})", e); } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 5b0700bfd9..d0bfcc0c7c 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -28,7 +28,7 @@ use bytes::Bytes; use ethereum_types::H256; use hash::keccak; use heapsize::HeapSizeOf; -use rlp::UntrustedRlp; +use rlp::Rlp; use triehash::ordered_trie_root; use unexpected::{Mismatch, OutOfBounds}; @@ -63,13 +63,13 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &EthEngine) -> verify_header_params(&header, engine, true)?; verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash())?; engine.verify_block_basic(&header)?; - for u in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { + for u in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { let u = u?; verify_header_params(&u, engine, false)?; engine.verify_block_basic(&u)?; } - for t in UntrustedRlp::new(bytes).at(1)?.iter().map(|rlp| rlp.as_val::()) { + for t in Rlp::new(bytes).at(1)?.iter().map(|rlp| rlp.as_val::()) { engine.verify_transaction_basic(&t?, &header)?; } Ok(()) @@ -81,7 +81,7 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &EthEngine) -> pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine, check_seal: bool) -> Result { if check_seal { engine.verify_block_unordered(&header)?; - for u in UntrustedRlp::new(&bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { + for u in Rlp::new(&bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { engine.verify_block_unordered(&u?)?; } } @@ -91,7 +91,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine, Some((engine.params().nonce_cap_increment * header.number()).into()) } else { None }; { - let v = BlockView::new(&bytes); + let v = view!(BlockView, &bytes); for t in v.transactions() { let t = engine.verify_transaction_unordered(t, &header)?; if let Some(max_nonce) = nonce_cap { @@ -145,7 +145,7 @@ pub fn verify_block_family(header: &Header, parent: } fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> { - let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?; + let num_uncles = Rlp::new(bytes).at(2)?.item_count()?; let max_uncles = engine.maximum_uncle_count(header.number()); if num_uncles != 0 { if num_uncles > max_uncles { @@ -174,7 +174,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth } let mut verified = HashSet::new(); - for uncle in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { + for uncle in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::
()) { let uncle = uncle?; if excluded.contains(&uncle.hash()) { return Err(From::from(BlockError::UncleInChain(uncle.hash()))) @@ -333,7 +333,7 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result /// Verify block data against header: transactions root and uncles hash. fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), Error> { - let block = UntrustedRlp::new(block); + let block = Rlp::new(block); let tx = block.at(1)?; let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw())); if expected_root != transactions_root { @@ -408,8 +408,8 @@ mod tests { } pub fn insert(&mut self, bytes: Bytes) { - let number = BlockView::new(&bytes).header_view().number(); - let hash = BlockView::new(&bytes).header_view().hash(); + let number = view!(BlockView, &bytes).header_view().number(); + let hash = view!(BlockView, &bytes).header_view().hash(); self.blocks.insert(hash.clone(), bytes); self.numbers.insert(number, hash.clone()); } @@ -448,7 +448,7 @@ mod tests { /// Get the familial details concerning a block. fn block_details(&self, hash: &H256) -> Option { self.blocks.get(hash).map(|bytes| { - let header = BlockView::new(bytes).header(); + let header = view!(BlockView, bytes).header(); BlockDetails { number: header.number(), total_difficulty: header.difficulty().clone(), @@ -482,12 +482,12 @@ mod tests { } fn basic_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> { - let header = BlockView::new(bytes).header(); + let header = view!(BlockView, bytes).header(); verify_block_basic(&header, bytes, engine) } fn family_test(bytes: &[u8], engine: &EthEngine, bc: &BC) -> Result<(), Error> where BC: BlockProvider { - let view = BlockView::new(bytes); + let view = view!(BlockView, bytes); let header = view.header(); let transactions: Vec<_> = view.transactions() .into_iter() @@ -514,7 +514,7 @@ mod tests { } fn unordered_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> { - let header = BlockView::new(bytes).header(); + let header = view!(BlockView, bytes).header(); verify_block_unordered(header, bytes.to_vec(), engine, false)?; Ok(()) } diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index f6bb92873c..f610504d85 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -20,25 +20,34 @@ use bytes::Bytes; use ethereum_types::H256; use hash::keccak; use header::Header; -use rlp::Rlp; use transaction::{UnverifiedTransaction, LocalizedTransaction}; use views::{TransactionView, HeaderView}; +use super::ViewRlp; /// View onto block rlp. pub struct BlockView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } -impl<'a> BlockView<'a> { - /// Creates new view onto block from raw bytes. - pub fn new(bytes: &'a [u8]) -> BlockView<'a> { - BlockView { - rlp: Rlp::new(bytes) - } - } +impl<'a> BlockView<'a> { /// Creates new view onto block from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> { + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{BlockView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let block_view = view!(BlockView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> BlockView<'a> { BlockView { rlp: rlp } @@ -50,7 +59,7 @@ impl<'a> BlockView<'a> { } /// Return reference to underlaying rlp. - pub fn rlp(&self) -> &Rlp<'a> { + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } @@ -60,13 +69,13 @@ impl<'a> BlockView<'a> { } /// Return header rlp. - pub fn header_rlp(&self) -> Rlp { + pub fn header_rlp(&self) -> ViewRlp<'a> { self.rlp.at(0) } /// Create new header view obto block head rlp. pub fn header_view(&self) -> HeaderView<'a> { - HeaderView::new_from_rlp(self.rlp.at(0)) + HeaderView::new(self.header_rlp()) } /// Return List of transactions in given block. @@ -92,28 +101,28 @@ impl<'a> BlockView<'a> { } /// Return the raw rlp for the transactions in the given block. - pub fn transactions_rlp(&self) -> Rlp<'a> { + pub fn transactions_rlp(&self) -> ViewRlp<'a> { self.rlp.at(1) } /// Return number of transactions in given block, without deserializing them. pub fn transactions_count(&self) -> usize { - self.rlp.at(1).iter().count() + self.transactions_rlp().iter().count() } /// Return List of transactions in given block. pub fn transaction_views(&self) -> Vec> { - self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect() + self.transactions_rlp().iter().map(TransactionView::new).collect() } /// Return transaction hashes. pub fn transaction_hashes(&self) -> Vec { - self.rlp.at(1).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.transactions_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Returns transaction at given index without deserializing unnecessary data. pub fn transaction_at(&self, index: usize) -> Option { - self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val()) + self.transactions_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Returns localized transaction at given index. @@ -131,7 +140,7 @@ impl<'a> BlockView<'a> { } /// Returns raw rlp for the uncles in the given block - pub fn uncles_rlp(&self) -> Rlp<'a> { + pub fn uncles_rlp(&self) -> ViewRlp<'a> { self.rlp.at(2) } @@ -142,27 +151,27 @@ impl<'a> BlockView<'a> { /// Return number of uncles in given block, without deserializing them. pub fn uncles_count(&self) -> usize { - self.rlp.at(2).iter().count() + self.uncles_rlp().iter().count() } /// Return List of transactions in given block. pub fn uncle_views(&self) -> Vec> { - self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect() + self.uncles_rlp().iter().map(HeaderView::new).collect() } /// Return list of uncle hashes of given block. pub fn uncle_hashes(&self) -> Vec { - self.rlp.at(2).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.uncles_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Return nth uncle. pub fn uncle_at(&self, index: usize) -> Option
{ - self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Return nth uncle rlp. pub fn uncle_rlp_at(&self, index: usize) -> Option { - self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) } } @@ -176,7 +185,7 @@ mod tests { // that's rlp of block created with ethash engine. let rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap(); - let view = BlockView::new(&rlp); + let view = view!(BlockView, &rlp); assert_eq!(view.hash(), "2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259".into()); assert_eq!(view.transactions_count(), 1); assert_eq!(view.uncles_count(), 0); diff --git a/ethcore/src/views/body.rs b/ethcore/src/views/body.rs index d23f1a1d77..d2864b9725 100644 --- a/ethcore/src/views/body.rs +++ b/ethcore/src/views/body.rs @@ -20,32 +20,40 @@ use bytes::Bytes; use ethereum_types::H256; use hash::keccak; use header::{Header, BlockNumber}; -use rlp::Rlp; use transaction::{LocalizedTransaction, UnverifiedTransaction}; use views::{TransactionView, HeaderView}; +use super::ViewRlp; /// View onto block rlp. pub struct BodyView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } impl<'a> BodyView<'a> { - /// Creates new view onto block from raw bytes. - pub fn new(bytes: &'a [u8]) -> BodyView<'a> { - BodyView { - rlp: Rlp::new(bytes) - } - } - - /// Creates new view onto block from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> BodyView<'a> { + /// Creates new view onto block body from rlp. + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{BodyView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let body_view = view!(BodyView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> BodyView<'a> { BodyView { rlp: rlp } } /// Return reference to underlaying rlp. - pub fn rlp(&self) -> &Rlp<'a> { + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } @@ -69,27 +77,27 @@ impl<'a> BodyView<'a> { } /// Return the raw rlp for the transactions in the given block. - pub fn transactions_rlp(&self) -> Rlp<'a> { + pub fn transactions_rlp(&self) -> ViewRlp<'a> { self.rlp.at(0) } /// Return number of transactions in given block, without deserializing them. pub fn transactions_count(&self) -> usize { - self.rlp.at(0).item_count() + self.transactions_rlp().item_count() } /// Return List of transactions in given block. pub fn transaction_views(&self) -> Vec> { - self.rlp.at(0).iter().map(TransactionView::new_from_rlp).collect() + self.transactions_rlp().iter().map(TransactionView::new).collect() } /// Return transaction hashes. pub fn transaction_hashes(&self) -> Vec { - self.rlp.at(0).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.transactions_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Returns transaction at given index without deserializing unnecessary data. pub fn transaction_at(&self, index: usize) -> Option { - self.rlp.at(0).iter().nth(index).map(|rlp| rlp.as_val()) + self.transactions_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Returns localized transaction at given index. @@ -104,7 +112,7 @@ impl<'a> BodyView<'a> { } /// Returns raw rlp for the uncles in the given block - pub fn uncles_rlp(&self) -> Rlp<'a> { + pub fn uncles_rlp(&self) -> ViewRlp<'a> { self.rlp.at(1) } @@ -115,27 +123,27 @@ impl<'a> BodyView<'a> { /// Return number of uncles in given block, without deserializing them. pub fn uncles_count(&self) -> usize { - self.rlp.at(1).item_count() + self.uncles_rlp().item_count() } /// Return List of transactions in given block. pub fn uncle_views(&self) -> Vec> { - self.rlp.at(1).iter().map(HeaderView::new_from_rlp).collect() + self.uncles_rlp().iter().map(HeaderView::new).collect() } /// Return list of uncle hashes of given block. pub fn uncle_hashes(&self) -> Vec { - self.rlp.at(1).iter().map(|rlp| keccak(rlp.as_raw())).collect() + self.uncles_rlp().iter().map(|rlp| keccak(rlp.as_raw())).collect() } /// Return nth uncle. pub fn uncle_at(&self, index: usize) -> Option
{ - self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_val()) } /// Return nth uncle rlp. pub fn uncle_rlp_at(&self, index: usize) -> Option { - self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) + self.uncles_rlp().iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) } } @@ -150,7 +158,7 @@ mod tests { // that's rlp of block created with ethash engine. let rlp = "f90261f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba03a347e72953c860f32b1eb2c78a680d8734b2ea08085d949d729479796f218d5a047ea6239d9e31ccac8af3366f5ca37184d26e7646e3191a3aeb81c4cf74de500c0".from_hex().unwrap(); let body = BlockChain::block_to_body(&rlp); - let view = BodyView::new(&body); + let view = view!(BodyView, &body); assert_eq!(view.transactions_count(), 1); assert_eq!(view.uncles_count(), 0); } diff --git a/ethcore/src/views/header.rs b/ethcore/src/views/header.rs index cce4eee828..8d407f0a1b 100644 --- a/ethcore/src/views/header.rs +++ b/ethcore/src/views/header.rs @@ -20,35 +20,44 @@ use bytes::Bytes; use ethereum_types::{H256, Bloom, U256, Address}; use hash::keccak; use header::BlockNumber; -use rlp::{self, Rlp}; +use rlp::{self}; +use super::ViewRlp; /// View onto block header rlp. pub struct HeaderView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } impl<'a> HeaderView<'a> { - /// Creates new view onto header from raw bytes. - pub fn new(bytes: &'a [u8]) -> HeaderView<'a> { + /// Creates a new Header view from valid ViewRlp + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{HeaderView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let tx_view = view!(HeaderView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> HeaderView<'a> { HeaderView { - rlp: Rlp::new(bytes) - } - } - - /// Creates new view onto header from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> HeaderView<'a> { - HeaderView { - rlp: rlp + rlp } } /// Returns header hash. pub fn hash(&self) -> H256 { - keccak(self.rlp.as_raw()) + keccak(self.rlp.rlp.as_raw()) } /// Returns raw rlp. - pub fn rlp(&self) -> &Rlp<'a> { &self.rlp } + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } /// Returns parent hash. pub fn parent_hash(&self) -> H256 { self.rlp.val_at(0) } @@ -102,9 +111,10 @@ impl<'a> HeaderView<'a> { pub fn decode_seal(&self) -> Result, rlp::DecoderError> { let seal = self.seal(); seal.into_iter() - .map(|s| rlp::UntrustedRlp::new(&s).data().map(|x| x.to_vec())) + .map(|s| rlp::Rlp::new(&s).data().map(|x| x.to_vec())) .collect() } + } #[cfg(test)] @@ -120,7 +130,7 @@ mod tests { let mix_hash = "a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd".from_hex().unwrap(); let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap(); - let view = HeaderView::new(&rlp); + let view = view!(HeaderView, &rlp); assert_eq!(view.hash(), "2c9747e804293bd3f1a986484343f23bc88fd5be75dfe9d5c2860aff61e6f259".into()); assert_eq!(view.parent_hash(), "d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7".into()); assert_eq!(view.uncles_hash(), "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".into()); diff --git a/ethcore/src/views/mod.rs b/ethcore/src/views/mod.rs index 5d3cc8cdcc..b9cbad8889 100644 --- a/ethcore/src/views/mod.rs +++ b/ethcore/src/views/mod.rs @@ -16,12 +16,26 @@ //! Block oriented views onto rlp. +#[macro_use] +mod view_rlp; mod block; mod body; mod header; mod transaction; +pub use self::view_rlp::ViewRlp; pub use self::block::BlockView; pub use self::body::BodyView; pub use self::header::HeaderView; pub use self::transaction::TransactionView; + +#[cfg(test)] +mod tests { + use super::HeaderView; + + #[test] + #[should_panic(expected="View rlp is trusted and should be valid. Constructed in ethcore/src/views/mod.rs on line 39: RlpExpectedToBeList")] + fn should_include_file_line_number_in_panic_for_invalid_rlp() { + let _ = view!(HeaderView, &[]).parent_hash(); + } +} \ No newline at end of file diff --git a/ethcore/src/views/transaction.rs b/ethcore/src/views/transaction.rs index 92bd49c276..5607482b30 100644 --- a/ethcore/src/views/transaction.rs +++ b/ethcore/src/views/transaction.rs @@ -18,30 +18,39 @@ use bytes::Bytes; use ethereum_types::{H256, U256}; use hash::keccak; -use rlp::Rlp; +// use rlp::{Rlp, Decodable}; +use super::ViewRlp; /// View onto transaction rlp. pub struct TransactionView<'a> { - rlp: Rlp<'a> + rlp: ViewRlp<'a> } impl<'a> TransactionView<'a> { - /// Creates new view onto block from raw bytes. - pub fn new(bytes: &'a [u8]) -> TransactionView<'a> { - TransactionView { - rlp: Rlp::new(bytes) - } - } - - /// Creates new view onto block from rlp. - pub fn new_from_rlp(rlp: Rlp<'a>) -> TransactionView<'a> { + /// Creates new view onto valid transaction rlp. + /// Use the `view!` macro to create this view in order to capture debugging info. + /// + /// # Example + /// + /// ``` + /// #[macro_use] + /// extern crate ethcore; + /// + /// use ethcore::views::{TransactionView}; + /// + /// fn main() { + /// let bytes : &[u8] = &[]; + /// let tx_view = view!(TransactionView, bytes); + /// } + /// ``` + pub fn new(rlp: ViewRlp<'a>) -> TransactionView<'a> { TransactionView { rlp: rlp } } /// Return reference to underlaying rlp. - pub fn rlp(&self) -> &Rlp<'a> { + pub fn rlp(&self) -> &ViewRlp<'a> { &self.rlp } @@ -84,7 +93,7 @@ mod tests { fn test_transaction_view() { let rlp = "f87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804".from_hex().unwrap(); - let view = TransactionView::new(&rlp); + let view = view!(TransactionView, &rlp); assert_eq!(view.nonce(), 0.into()); assert_eq!(view.gas_price(), 1.into()); assert_eq!(view.gas(), 0x61a8.into()); diff --git a/ethcore/src/views/view_rlp.rs b/ethcore/src/views/view_rlp.rs new file mode 100644 index 0000000000..6afdb3af8c --- /dev/null +++ b/ethcore/src/views/view_rlp.rs @@ -0,0 +1,130 @@ +// 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 . + +//! Wrapper for view rlp expected to be valid with debug info + +use rlp::{Rlp, Decodable, DecoderError}; + +/// Wrapper for trusted rlp, which is expected to be valid, for use in views +/// When created with view!, records the file and line where it was created for debugging +pub struct ViewRlp<'a> { + /// Wrapped Rlp, expected to be valid + pub rlp: Rlp<'a>, + file: &'a str, + line: u32, +} + +impl<'a, 'view> ViewRlp<'a> where 'a : 'view { + #[doc(hidden)] + pub fn new(bytes: &'a [u8], file: &'a str, line: u32) -> Self { + ViewRlp { + rlp: Rlp::new(bytes), + file, + line + } + } + + /// Returns a new instance replacing existing rlp with new rlp, maintaining debug info + fn new_from_rlp(&self, rlp: Rlp<'a>) -> Self { + ViewRlp { + rlp, + file: self.file, + line: self.line + } + } + + fn maybe_at(&self, index: usize) -> Option> { + self.rlp.at(index) + .map(|rlp| self.new_from_rlp(rlp)) + .ok() + } + + fn expect_valid_rlp(&self, r: Result) -> T { + r.expect(&format!("View rlp is trusted and should be valid. Constructed in {} on line {}", self.file, self.line)) + } + + /// Returns rlp at the given index, panics if no rlp at that index + pub fn at(&self, index: usize) -> ViewRlp<'a> { + let rlp = self.expect_valid_rlp(self.rlp.at(index)); + self.new_from_rlp(rlp) + } + + /// Returns an iterator over all rlp values + pub fn iter(&'view self) -> ViewRlpIterator<'a, 'view> { + self.into_iter() + } + + /// Returns decoded value of this rlp, panics if rlp not valid + pub fn as_val(&self) -> T where T: Decodable { + self.expect_valid_rlp(self.rlp.as_val()) + } + + /// Returns decoded value at the given index, panics not present or valid at that index + pub fn val_at(&self, index: usize) -> T where T : Decodable { + self.expect_valid_rlp(self.rlp.val_at(index)) + } + + /// Returns decoded list of values, panics if rlp is invalid + pub fn list_at(&self, index: usize) -> Vec where T: Decodable { + self.expect_valid_rlp(self.rlp.list_at(index)) + } + + /// Returns the number of items in the rlp, panics if it is not a list of rlp values + pub fn item_count(&self) -> usize { + self.expect_valid_rlp(self.rlp.item_count()) + } + + /// Returns raw rlp bytes + pub fn as_raw(&'view self) -> &'a [u8] { + self.rlp.as_raw() + } +} + +/// Iterator over rlp-slice list elements. +pub struct ViewRlpIterator<'a, 'view> where 'a: 'view { + rlp: &'view ViewRlp<'a>, + index: usize, +} + +impl<'a, 'view> IntoIterator for &'view ViewRlp<'a> where 'a: 'view { + type Item = ViewRlp<'a>; + type IntoIter = ViewRlpIterator<'a, 'view>; + + fn into_iter(self) -> Self::IntoIter { + ViewRlpIterator { + rlp: self, + index: 0, + } + } +} + +impl<'a, 'view> Iterator for ViewRlpIterator<'a, 'view> { + type Item = ViewRlp<'a>; + + fn next(&mut self) -> Option> { + let index = self.index; + let result = self.rlp.maybe_at(index); + self.index += 1; + result + } +} + +#[macro_export] +macro_rules! view { + ($view: ident, $bytes: expr) => { + $view::new($crate::views::ViewRlp::new($bytes, file!(), line!())) + }; +} \ No newline at end of file diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index 5cf81b2e86..f7626b0efd 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -22,8 +22,8 @@ use std::collections::{HashSet, VecDeque}; use std::cmp; use heapsize::HeapSizeOf; use ethereum_types::H256; -use rlp::UntrustedRlp; -use ethcore::views::{BlockView}; +use rlp::Rlp; +use ethcore::views::BlockView; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockStatus, BlockId, BlockImportError}; use ethcore::block::Block; @@ -216,7 +216,7 @@ impl BlockDownloader { } /// Add new block headers. - pub fn import_headers(&mut self, io: &mut SyncIo, r: &UntrustedRlp, expected_hash: Option) -> Result { + pub fn import_headers(&mut self, io: &mut SyncIo, r: &Rlp, expected_hash: Option) -> Result { let item_count = r.item_count().unwrap_or(0); if self.state == State::Idle { trace!(target: "sync", "Ignored unexpected block headers"); @@ -316,7 +316,7 @@ impl BlockDownloader { } /// Called by peer once it has new block bodies - pub fn import_bodies(&mut self, _io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), BlockDownloaderImportError> { + pub fn import_bodies(&mut self, _io: &mut SyncIo, r: &Rlp) -> Result<(), BlockDownloaderImportError> { let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); @@ -342,7 +342,7 @@ impl BlockDownloader { } /// Called by peer once it has new block bodies - pub fn import_receipts(&mut self, _io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), BlockDownloaderImportError> { + pub fn import_receipts(&mut self, _io: &mut SyncIo, r: &Rlp) -> Result<(), BlockDownloaderImportError> { let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); @@ -478,7 +478,7 @@ impl BlockDownloader { let block = block_and_receipts.block; let receipts = block_and_receipts.receipts; let (h, number, parent) = { - let header = BlockView::new(&block).header_view(); + let header = view!(BlockView, &block).header_view(); (header.hash(), header.number(), header.parent_hash()) }; diff --git a/ethcore/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs index 37aa579ef9..321c783b4d 100644 --- a/ethcore/sync/src/blocks.rs +++ b/ethcore/sync/src/blocks.rs @@ -22,7 +22,7 @@ use heapsize::HeapSizeOf; use ethereum_types::H256; use triehash::ordered_trie_root; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Rlp, RlpStream, DecoderError}; use network; use ethcore::encoded::Block; use ethcore::views::{HeaderView, BodyView}; @@ -292,8 +292,9 @@ impl BlockCollection { } for block in blocks { - let body = BodyView::new(block.body.as_ref().expect("blocks contains only full blocks; qed")); - let block_view = Block::new_from_header_and_body(&HeaderView::new(&block.header), &body); + let body = view!(BodyView, block.body.as_ref().expect("blocks contains only full blocks; qed")); + let header = view!(HeaderView, &block.header); + let block_view = Block::new_from_header_and_body(&header, &body); drained.push(BlockAndReceipts { block: block_view.rlp().as_raw().to_vec(), receipts: block.receipts.clone(), @@ -340,7 +341,7 @@ impl BlockCollection { fn insert_body(&mut self, b: Bytes) -> Result<(), network::Error> { let header_id = { - let body = UntrustedRlp::new(&b); + let body = Rlp::new(&b); let tx = body.at(0)?; let tx_root = ordered_trie_root(tx.iter().map(|r| r.as_raw())); let uncles = keccak(body.at(1)?.as_raw()); @@ -375,7 +376,7 @@ impl BlockCollection { fn insert_receipt(&mut self, r: Bytes) -> Result<(), network::Error> { let receipt_root = { - let receipts = UntrustedRlp::new(&r); + let receipts = Rlp::new(&r); ordered_trie_root(receipts.iter().map(|r| r.as_raw())) }; self.downloading_receipts.remove(&receipt_root); @@ -403,7 +404,7 @@ impl BlockCollection { } fn insert_header(&mut self, header: Bytes) -> Result { - let info: BlockHeader = UntrustedRlp::new(&header).as_val()?; + let info: BlockHeader = Rlp::new(&header).as_val()?; let hash = info.hash(); if self.blocks.contains_key(&hash) { return Ok(hash); @@ -525,8 +526,8 @@ mod test { let blocks: Vec<_> = (0..nblocks) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner()) .collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); bc.reset_to(heads); assert!(!bc.is_empty()); @@ -580,8 +581,8 @@ mod test { let blocks: Vec<_> = (0..nblocks) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner()) .collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); bc.reset_to(heads); @@ -604,8 +605,8 @@ mod test { let blocks: Vec<_> = (0..nblocks) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner()) .collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); bc.reset_to(heads); diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index 014302d7fe..bc8e35ed49 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -98,7 +98,7 @@ use ethereum_types::{H256, U256}; use plain_hasher::H256FastMap; use parking_lot::RwLock; use bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream, DecoderError, Encodable}; +use rlp::{Rlp, RlpStream, DecoderError, Encodable}; use network::{self, PeerId, PacketId}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo}; @@ -632,7 +632,7 @@ impl ChainSync { } /// Called by peer to report status - fn on_peer_status(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_status(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { self.handshaking_peers.remove(&peer_id); let protocol_version: u8 = r.val_at(0)?; let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer_id) != 0; @@ -702,7 +702,7 @@ impl ChainSync { } /// Called by peer once it has new block headers during sync - fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { let confirmed = match self.peers.get_mut(&peer_id) { Some(ref mut peer) if peer.asking == PeerAsking::ForkHeader => { peer.asking = PeerAsking::Nothing; @@ -803,7 +803,7 @@ impl ChainSync { } /// Called by peer once it has new block bodies - fn on_peer_block_bodies(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_bodies(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { self.clear_peer_download(peer_id); let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); if !self.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { @@ -857,7 +857,7 @@ impl ChainSync { } /// Called by peer once it has new block receipts - fn on_peer_block_receipts(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_block_receipts(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { self.clear_peer_download(peer_id); let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); if !self.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { @@ -911,7 +911,7 @@ impl ChainSync { } /// Called by peer once it has new block bodies - fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id); return Ok(()); @@ -978,7 +978,7 @@ impl ChainSync { } /// Handles `NewHashes` packet. Initiates headers download for any unknown hashes. - fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id); return Ok(()); @@ -1053,7 +1053,7 @@ impl ChainSync { } /// Called when snapshot manifest is downloaded from a peer. - fn on_snapshot_manifest(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_snapshot_manifest(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring snapshot manifest from unconfirmed peer {}", peer_id); return Ok(()); @@ -1097,7 +1097,7 @@ impl ChainSync { } /// Called when snapshot data is downloaded from a peer. - fn on_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "Ignoring snapshot data from unconfirmed peer {}", peer_id); return Ok(()); @@ -1501,7 +1501,7 @@ impl ChainSync { } /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { // Accept transactions only when fully synced if !io.is_chain_queue_empty() || (self.state != SyncState::Idle && self.state != SyncState::NewBlocks) { trace!(target: "sync", "{} Ignoring transactions while syncing", peer_id); @@ -1555,7 +1555,7 @@ impl ChainSync { } /// Respond to GetBlockHeaders request - fn return_block_headers(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_block_headers(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { // Packet layout: // [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ] let max_headers: usize = r.val_at(1)?; @@ -1628,7 +1628,7 @@ impl ChainSync { } /// Respond to GetBlockBodies request - fn return_block_bodies(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_block_bodies(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let mut count = r.item_count().unwrap_or(0); if count == 0 { debug!(target: "sync", "Empty GetBlockBodies request, ignoring."); @@ -1650,7 +1650,7 @@ impl ChainSync { } /// Respond to GetNodeData request - fn return_node_data(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_node_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let mut count = r.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetNodeData: {} entries", peer_id, count); if count == 0 { @@ -1674,7 +1674,7 @@ impl ChainSync { Ok(Some((NODE_DATA_PACKET, rlp))) } - fn return_receipts(io: &SyncIo, rlp: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_receipts(io: &SyncIo, rlp: &Rlp, peer_id: PeerId) -> RlpResponseResult { let mut count = rlp.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetReceipts: {} entries", peer_id, count); if count == 0 { @@ -1699,7 +1699,7 @@ impl ChainSync { } /// Respond to GetSnapshotManifest request - fn return_snapshot_manifest(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let count = r.item_count().unwrap_or(0); trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); if count != 0 { @@ -1722,7 +1722,7 @@ impl ChainSync { } /// Respond to GetSnapshotData request - fn return_snapshot_data(io: &SyncIo, r: &UntrustedRlp, peer_id: PeerId) -> RlpResponseResult { + fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let hash: H256 = r.val_at(0)?; trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); let rlp = match io.snapshot_service().chunk(hash) { @@ -1739,8 +1739,8 @@ impl ChainSync { Ok(Some((SNAPSHOT_DATA_PACKET, rlp))) } - fn return_rlp(io: &mut SyncIo, rlp: &UntrustedRlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> - where FRlp : Fn(&SyncIo, &UntrustedRlp, PeerId) -> RlpResponseResult, + fn return_rlp(io: &mut SyncIo, rlp: &Rlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> + where FRlp : Fn(&SyncIo, &Rlp, PeerId) -> RlpResponseResult, FError : FnOnce(network::Error) -> String { let response = rlp_func(io, rlp, peer); @@ -1757,7 +1757,7 @@ impl ChainSync { /// Dispatch incoming requests and responses pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); let result = match packet_id { GET_BLOCK_BODIES_PACKET => ChainSync::return_rlp(io, &rlp, peer, ChainSync::return_block_bodies, @@ -1798,7 +1798,7 @@ impl ChainSync { debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); return; } - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); let result = match packet_id { STATUS_PACKET => self.on_peer_status(io, peer, &rlp), TRANSACTIONS_PACKET => self.on_peer_transactions(io, peer, &rlp), @@ -2233,7 +2233,7 @@ impl ChainSync { } /// Called when peer sends us new consensus packet - fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { trace!(target: "sync", "Received consensus packet from {:?}", peer_id); io.chain().queue_consensus_message(r.as_raw().to_vec()); Ok(()) @@ -2249,7 +2249,7 @@ impl ChainSync { } /// Called when peer sends us new private transaction packet - fn on_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); return Ok(()); @@ -2273,7 +2273,7 @@ impl ChainSync { } /// Called when peer sends us signed private transaction packet - fn on_signed_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + fn on_signed_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); return Ok(()); @@ -2324,7 +2324,7 @@ mod tests { use ethereum_types::{H256, U256, Address}; use parking_lot::RwLock; use bytes::Bytes; - use rlp::{Rlp, RlpStream, UntrustedRlp}; + use rlp::{Rlp, RlpStream}; use super::*; use ::SyncConfig; use super::{PeerInfo, PeerAsking}; @@ -2421,7 +2421,7 @@ mod tests { let ss = TestSnapshotService::new(); let io = TestIo::new(&mut client, &ss, &queue, None); - let result = ChainSync::return_receipts(&io, &UntrustedRlp::new(&[0xc0]), 0); + let result = ChainSync::return_receipts(&io, &Rlp::new(&[0xc0]), 0); assert!(result.is_ok()); } @@ -2442,7 +2442,7 @@ mod tests { let receipts_request = receipt_list.out(); // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_receipts(&io, &UntrustedRlp::new(&receipts_request.clone()), 0); + let result = ChainSync::return_receipts(&io, &Rlp::new(&receipts_request.clone()), 0); assert!(result.is_ok()); let rlp_result = result.unwrap(); @@ -2484,41 +2484,41 @@ mod tests { client.add_blocks(100, EachBlockWith::Nothing); let blocks: Vec<_> = (0 .. 100) .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).hash()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); let queue = RwLock::new(VecDeque::new()); let ss = TestSnapshotService::new(); let io = TestIo::new(&mut client, &ss, &queue, None); let unknown: H256 = H256::new(); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); assert!(to_header_vec(result).is_empty()); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); assert!(to_header_vec(result).is_empty()); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(2, 1, 0, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(2, 1, 0, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0); assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(50, 3, 5, false)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - let result = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&make_num_req(50, 3, 5, true)), 0); + let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0); assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); } @@ -2537,7 +2537,7 @@ mod tests { let node_request = node_list.out(); // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_node_data(&io, &UntrustedRlp::new(&node_request.clone()), 0); + let result = ChainSync::return_node_data(&io, &Rlp::new(&node_request.clone()), 0); assert!(result.is_ok()); let rlp_result = result.unwrap(); @@ -2546,7 +2546,7 @@ mod tests { // the length of one rlp-encoded hashe let rlp = rlp_result.unwrap().1.out(); let rlp = Rlp::new(&rlp); - assert_eq!(1, rlp.item_count()); + assert_eq!(Ok(1), rlp.item_count()); io.sender = Some(2usize); @@ -2891,7 +2891,7 @@ mod tests { return None; } - let rlp = UntrustedRlp::new(&*p.data); + let rlp = Rlp::new(&*p.data); let item_count = rlp.item_count().unwrap_or(0); if item_count != 1 { return None; @@ -2918,7 +2918,7 @@ mod tests { let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); - let block = UntrustedRlp::new(&block_data); + let block = Rlp::new(&block_data); let result = sync.on_peer_new_block(&mut io, 0, &block); @@ -2937,7 +2937,7 @@ mod tests { let ss = TestSnapshotService::new(); let mut io = TestIo::new(&mut client, &ss, &queue, None); - let block = UntrustedRlp::new(&block_data); + let block = Rlp::new(&block_data); let result = sync.on_peer_new_block(&mut io, 0, &block); @@ -2954,7 +2954,7 @@ mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); let empty_data = vec![]; - let block = UntrustedRlp::new(&empty_data); + let block = Rlp::new(&empty_data); let result = sync.on_peer_new_block(&mut io, 0, &block); @@ -2971,7 +2971,7 @@ mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); let hashes_data = get_dummy_hashes(); - let hashes_rlp = UntrustedRlp::new(&hashes_data); + let hashes_rlp = Rlp::new(&hashes_data); let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); @@ -2988,7 +2988,7 @@ mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); let empty_hashes_data = vec![]; - let hashes_rlp = UntrustedRlp::new(&empty_hashes_data); + let hashes_rlp = Rlp::new(&empty_hashes_data); let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); @@ -3011,7 +3011,7 @@ mod tests { sync.propagate_new_hashes(&chain_info, &mut io, &peers); let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(data)); + let result = sync.on_peer_new_hashes(&mut io, 0, &Rlp::new(data)); assert!(result.is_ok()); } @@ -3031,7 +3031,7 @@ mod tests { sync.propagate_blocks(&chain_info, &mut io, &[], &peers); let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(data)); + let result = sync.on_peer_new_block(&mut io, 0, &Rlp::new(data)); assert!(result.is_ok()); } diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index a6e0c7db24..bf3b475fc6 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -26,6 +26,7 @@ extern crate ethcore_network_devp2p as devp2p; extern crate ethcore_bytes as bytes; extern crate ethcore_io as io; extern crate ethcore_transaction as transaction; +#[macro_use] extern crate ethcore; extern crate ethereum_types; extern crate env_logger; diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 6e8e78cc48..571dec3fae 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -24,7 +24,7 @@ use ethkey::{self, Signature, Secret, Public, recover, public_to_address}; use evm::Schedule; use hash::keccak; use heapsize::HeapSizeOf; -use rlp::{self, RlpStream, UntrustedRlp, DecoderError, Encodable}; +use rlp::{self, RlpStream, Rlp, DecoderError, Encodable}; type Bytes = Vec; type BlockNumber = u64; @@ -50,7 +50,7 @@ impl Default for Action { } impl rlp::Decodable for Action { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.is_empty() { Ok(Action::Create) } else { @@ -291,7 +291,7 @@ impl Deref for UnverifiedTransaction { } impl rlp::Decodable for UnverifiedTransaction { - fn decode(d: &UntrustedRlp) -> Result { + fn decode(d: &Rlp) -> Result { if d.item_count()? != 9 { return Err(DecoderError::RlpIncorrectListLen); } diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index 8aee993653..c1defbc151 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -18,7 +18,7 @@ use ethereum_types::{H256, U256, Address, Bloom}; use heapsize::HeapSizeOf; -use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError}; +use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError}; use {BlockNumber}; use log_entry::{LogEntry, LocalizedLogEntry}; @@ -81,7 +81,7 @@ impl Encodable for Receipt { } impl Decodable for Receipt { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.item_count()? == 3 { Ok(Receipt { outcome: TransactionOutcome::Unknown, diff --git a/ethcore/types/src/snapshot_manifest.rs b/ethcore/types/src/snapshot_manifest.rs index 7f41f9994d..c59402023a 100644 --- a/ethcore/types/src/snapshot_manifest.rs +++ b/ethcore/types/src/snapshot_manifest.rs @@ -17,7 +17,7 @@ //! Snapshot manifest type definition use ethereum_types::H256; -use rlp::{UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Rlp, RlpStream, DecoderError}; use bytes::Bytes; /// Manifest data. @@ -53,7 +53,7 @@ impl ManifestData { /// Try to restore manifest data from raw bytes, interpreted as RLP. pub fn from_rlp(raw: &[u8]) -> Result { - let decoder = UntrustedRlp::new(raw); + let decoder = Rlp::new(raw); let (start, version) = if decoder.item_count()? == 5 { (0, 1) } else { diff --git a/ethcore/vm/src/call_type.rs b/ethcore/vm/src/call_type.rs index 08a004053f..83260825f3 100644 --- a/ethcore/vm/src/call_type.rs +++ b/ethcore/vm/src/call_type.rs @@ -1,6 +1,6 @@ //! EVM call types. -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; /// The type of the call-like instruction. #[derive(Debug, PartialEq, Clone)] @@ -31,7 +31,7 @@ impl Encodable for CallType { } impl Decodable for CallType { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.as_val().and_then(|v| Ok(match v { 0u32 => CallType::None, 1 => CallType::Call, diff --git a/local-store/src/lib.rs b/local-store/src/lib.rs index 2ebc6a69ce..078dff36ed 100644 --- a/local-store/src/lib.rs +++ b/local-store/src/lib.rs @@ -26,7 +26,7 @@ use transaction::{ }; use ethcore::client::ClientIoMessage; use io::IoHandler; -use rlp::UntrustedRlp; +use rlp::Rlp; use kvdb::KeyValueDB; extern crate ethcore; @@ -103,7 +103,7 @@ struct TransactionEntry { impl TransactionEntry { fn into_pending(self) -> Option { - let tx: UnverifiedTransaction = match UntrustedRlp::new(&self.rlp_bytes).as_val() { + let tx: UnverifiedTransaction = match Rlp::new(&self.rlp_bytes).as_val() { Err(e) => { warn!(target: "local_store", "Invalid persistent transaction stored: {}", e); return None diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 586313ab41..439f13ba39 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -247,7 +247,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { let do_import = |bytes: Vec| { while client.queue_info().is_full() { sleep(Duration::from_secs(1)); } - let header: ::ethcore::header::Header = ::rlp::UntrustedRlp::new(&bytes).val_at(0) + let header: ::ethcore::header::Header = ::rlp::Rlp::new(&bytes).val_at(0) .map_err(|e| format!("Bad block: {}", e))?; if client.best_block_header().number() >= header.number() { return Ok(()) } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 9d97c3c992..7b5cc36447 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -44,6 +44,7 @@ extern crate jsonrpc_ipc_server as ipc; extern crate jsonrpc_pubsub; extern crate ethash; +#[cfg_attr(test, macro_use)] extern crate ethcore; extern crate ethcore_bytes as bytes; extern crate ethcore_crypto as crypto; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 37f918466e..c894f16dfc 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -20,7 +20,7 @@ use std::thread; use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH}; use std::sync::Arc; -use rlp::{self, UntrustedRlp}; +use rlp::{self, Rlp}; use ethereum_types::{U256, H64, H160, H256, Address}; use parking_lot::Mutex; @@ -813,7 +813,7 @@ impl Eth for EthClient< } fn send_raw_transaction(&self, raw: Bytes) -> Result { - UntrustedRlp::new(&raw.into_vec()).as_val() + Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction)) .and_then(|signed_transaction| { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 73e041abac..eeef12da6e 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -36,7 +36,7 @@ use sync::LightSync; use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; use ethereum_types::U256; use parking_lot::{RwLock, Mutex}; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::SignedTransaction; use v1::impls::eth_filter::Filterable; @@ -373,7 +373,7 @@ impl Eth for EthClient { fn send_raw_transaction(&self, raw: Bytes) -> Result { let best_header = self.client.best_block_header().decode(); - UntrustedRlp::new(&raw.into_vec()).as_val() + Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| { self.client.engine().verify_transaction_basic(&tx, &best_header) diff --git a/rpc/src/v1/impls/private.rs b/rpc/src/v1/impls/private.rs index bf797d5a58..ab5866e4a7 100644 --- a/rpc/src/v1/impls/private.rs +++ b/rpc/src/v1/impls/private.rs @@ -18,7 +18,7 @@ use std::sync::Arc; -use rlp::UntrustedRlp; +use rlp::Rlp; use ethcore_private_tx::Provider as PrivateTransactionManager; use ethereum_types::Address; @@ -56,7 +56,7 @@ impl Private for PrivateClient { type Metadata = Metadata; fn send_transaction(&self, request: Bytes) -> Result { - let signed_transaction = UntrustedRlp::new(&request.into_vec()).as_val() + let signed_transaction = Rlp::new(&request.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))?; let client = self.unwrap_manager()?; @@ -65,7 +65,7 @@ impl Private for PrivateClient { } fn compose_deployment_transaction(&self, block_number: BlockNumber, request: Bytes, validators: Vec, gas_price: U256) -> Result { - let signed_transaction = UntrustedRlp::new(&request.into_vec()).as_val() + let signed_transaction = Rlp::new(&request.into_vec()).as_val() .map_err(errors::rlp) .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))?; let client = self.unwrap_manager()?; diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index ce3f13b976..2e8d41c4ac 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -22,7 +22,7 @@ use ethcore::account_provider::AccountProvider; use ethkey; use parity_reactor::Remote; use parking_lot::Mutex; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::{SignedTransaction, PendingTransaction}; use jsonrpc_core::{Result, BoxFuture, Error}; @@ -127,7 +127,7 @@ impl SignerClient { fn verify_transaction(bytes: Bytes, request: FilledTransactionRequest, process: F) -> Result where F: FnOnce(PendingTransaction) -> Result, { - let signed_transaction = UntrustedRlp::new(&bytes.0).as_val().map_err(errors::rlp)?; + let signed_transaction = Rlp::new(&bytes.0).as_val().map_err(errors::rlp)?; let signed_transaction = SignedTransaction::new(signed_transaction).map_err(|e| errors::invalid_params("Invalid signature.", e))?; let sender = signed_transaction.sender(); diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 06df83b752..bf4dc83beb 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId}; -use rlp::UntrustedRlp; +use rlp::Rlp; use transaction::SignedTransaction; use jsonrpc_core::Result; @@ -139,7 +139,7 @@ impl Traces for TracesClient where fn raw_transaction(&self, raw_transaction: Bytes, flags: TraceOptions, block: Trailing) -> Result { let block = block.unwrap_or_default(); - let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?; + let tx = Rlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?; let signed = SignedTransaction::new(tx).map_err(errors::transaction)?; let id = match block { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 6aacbc865d..4b83710bc0 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -411,7 +411,7 @@ fn verify_transaction_counts(name: String, chain: BlockChain) { let tester = EthTester::from_chain(&chain); let mut id = 1; - for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| BlockView::new(b)) { + for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| view!(BlockView, b)) { let count = b.transactions_count(); let hash = b.hash(); diff --git a/util/journaldb/src/overlaydb.rs b/util/journaldb/src/overlaydb.rs index 6ff1b97e8b..fa7ff04596 100644 --- a/util/journaldb/src/overlaydb.rs +++ b/util/journaldb/src/overlaydb.rs @@ -21,7 +21,7 @@ use std::collections::HashMap; use std::collections::hash_map::Entry; use error::{Result, BaseDataError}; use ethereum_types::H256; -use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode}; +use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode}; use hashdb::*; use memorydb::*; use kvdb::{KeyValueDB, DBTransaction}; @@ -64,7 +64,7 @@ impl Encodable for Payload { } impl Decodable for Payload { - fn decode(rlp: &UntrustedRlp) -> ::std::result::Result { + fn decode(rlp: &Rlp) -> ::std::result::Result { let payload = Payload { count: rlp.val_at(0)?, value: DBValue::from_slice(rlp.at(1)?.data()?), diff --git a/util/journaldb/src/overlayrecentdb.rs b/util/journaldb/src/overlayrecentdb.rs index 9ac8a4e294..fdc178350e 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -21,7 +21,7 @@ use std::collections::hash_map::Entry; use std::sync::Arc; use parking_lot::RwLock; use heapsize::HeapSizeOf; -use rlp::{UntrustedRlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable}; +use rlp::{Rlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable}; use hashdb::*; use memorydb::*; use super::{DB_PREFIX_LEN, LATEST_ERA_KEY}; @@ -78,7 +78,7 @@ struct DatabaseValue { } impl Decodable for DatabaseValue { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let id = rlp.val_at(0)?; let inserts = rlp.at(1)?.iter().map(|r| { let k = r.val_at(0)?; diff --git a/util/journaldb/src/util.rs b/util/journaldb/src/util.rs index 52dbad7e1d..e99be458e5 100644 --- a/util/journaldb/src/util.rs +++ b/util/journaldb/src/util.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use ethereum_types::H256; -use rlp::{RlpStream, Encodable, UntrustedRlp, DecoderError}; +use rlp::{RlpStream, Encodable, Rlp, DecoderError}; const PADDING : [u8; 10] = [ 0u8; 10 ]; @@ -34,13 +34,13 @@ impl Encodable for DatabaseKey { } pub struct DatabaseValueView<'a> { - rlp: UntrustedRlp<'a>, + rlp: Rlp<'a>, } impl<'a> DatabaseValueView<'a> { pub fn from_rlp(data: &'a [u8]) -> Self { DatabaseValueView { - rlp: UntrustedRlp::new(data), + rlp: Rlp::new(data), } } diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 12c38b3a24..2b390baf75 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -24,7 +24,7 @@ use mio::deprecated::{Handler, EventLoop, TryRead, TryWrite}; use mio::tcp::*; use ethereum_types::{H128, H256, H512}; use ethcore_bytes::*; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use std::io::{self, Cursor, Read, Write}; use io::{IoContext, StreamToken}; use handshake::Handshake; @@ -391,7 +391,7 @@ impl EncryptedConnection { self.decoder.decrypt(&mut RefReadBuffer::new(&header[0..16]), &mut RefWriteBuffer::new(&mut hdec), false).expect("Invalid length or padding"); let length = ((((hdec[0] as u32) << 8) + (hdec[1] as u32)) << 8) + (hdec[2] as u32); - let header_rlp = UntrustedRlp::new(&hdec[3..6]); + let header_rlp = Rlp::new(&hdec[3..6]); let protocol_id = header_rlp.val_at::(0)?; self.payload_len = length as usize; diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index 2828b8f19f..f14cd5ba6f 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -25,7 +25,7 @@ use mio::deprecated::{Handler, EventLoop}; use mio::udp::*; use hash::keccak; use ethereum_types::{H256, H520}; -use rlp::{UntrustedRlp, RlpStream, encode_list}; +use rlp::{Rlp, RlpStream, encode_list}; use node_table::*; use network::{Error, ErrorKind}; use io::{StreamToken, IoContext}; @@ -259,7 +259,7 @@ impl Discovery { fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) -> Result<(), Error> { let mut rlp = RlpStream::new(); rlp.append_raw(&[packet_id], 1); - let source = UntrustedRlp::new(payload); + let source = Rlp::new(payload); rlp.begin_list(source.item_count()? + 1); for i in 0 .. source.item_count()? { rlp.append_raw(source.at(i)?.as_raw(), 1); @@ -382,7 +382,7 @@ impl Discovery { let node_id = recover(&signature.into(), &keccak(signed))?; let packet_id = signed[0]; - let rlp = UntrustedRlp::new(&signed[1..]); + let rlp = Rlp::new(&signed[1..]); match packet_id { PACKET_PING => self.on_ping(&rlp, &node_id, &from, &hash_signed), PACKET_PONG => self.on_pong(&rlp, &node_id, &from), @@ -409,7 +409,7 @@ impl Discovery { entry.endpoint.is_allowed(&self.ip_filter) && entry.id != self.id } - fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr, echo_hash: &[u8]) -> Result, Error> { + fn on_ping(&mut self, rlp: &Rlp, node: &NodeId, from: &SocketAddr, echo_hash: &[u8]) -> Result, Error> { trace!(target: "discovery", "Got Ping from {:?}", &from); let source = NodeEndpoint::from_rlp(&rlp.at(1)?)?; let dest = NodeEndpoint::from_rlp(&rlp.at(2)?)?; @@ -433,7 +433,7 @@ impl Discovery { Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) } - fn on_pong(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, Error> { + fn on_pong(&mut self, rlp: &Rlp, node: &NodeId, from: &SocketAddr) -> Result, Error> { trace!(target: "discovery", "Got Pong from {:?}", &from); // TODO: validate pong packet in rlp.val_at(1) let dest = NodeEndpoint::from_rlp(&rlp.at(0)?)?; @@ -448,7 +448,7 @@ impl Discovery { Ok(None) } - fn on_find_node(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { + fn on_find_node(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { trace!(target: "discovery", "Got FindNode from {:?}", &from); let target: NodeId = rlp.val_at(0)?; let timestamp: u64 = rlp.val_at(1)?; @@ -481,7 +481,7 @@ impl Discovery { packets.collect() } - fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { + fn on_neighbours(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result, Error> { // TODO: validate packet let mut added = HashMap::new(); trace!(target: "discovery", "Got {} Neighbours from {:?}", rlp.at(0)?.item_count()?, &from); @@ -725,7 +725,7 @@ mod tests { discovery2.on_packet(&ping_data.payload, ep1.address.clone()).ok(); let pong_data = discovery2.send_queue.pop_front().unwrap(); let data = &pong_data.payload[(32 + 65)..]; - let rlp = UntrustedRlp::new(&data[1..]); + let rlp = Rlp::new(&data[1..]); assert_eq!(ping_data.payload[0..32], rlp.val_at::>(1).unwrap()[..]) } } diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index d7818b64d9..37c39eb618 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -20,7 +20,7 @@ use hash::write_keccak; use mio::tcp::*; use ethereum_types::{H256, H520}; use ethcore_bytes::Bytes; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use connection::{Connection}; use node_table::NodeId; use io::{IoContext, StreamToken}; @@ -205,7 +205,7 @@ impl Handshake { trace!(target: "network", "Received EIP8 handshake auth from {:?}", self.connection.remote_addr_str()); self.auth_cipher.extend_from_slice(data); let auth = ecies::decrypt(secret, &self.auth_cipher[0..2], &self.auth_cipher[2..])?; - let rlp = UntrustedRlp::new(&auth); + let rlp = Rlp::new(&auth); let signature: H520 = rlp.val_at(0)?; let remote_public: Public = rlp.val_at(1)?; let remote_nonce: H256 = rlp.val_at(2)?; @@ -248,7 +248,7 @@ impl Handshake { trace!(target: "network", "Received EIP8 handshake auth from {:?}", self.connection.remote_addr_str()); self.ack_cipher.extend_from_slice(data); let ack = ecies::decrypt(secret, &self.ack_cipher[0..2], &self.ack_cipher[2..])?; - let rlp = UntrustedRlp::new(&ack); + let rlp = Rlp::new(&ack); self.remote_ephemeral = rlp.val_at(0)?; self.remote_nonce = rlp.val_at(1)?; self.remote_version = rlp.val_at(2)?; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 470bf5cde0..fd18c10a12 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -22,7 +22,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::{fs, mem, slice}; use ethereum_types::H512; -use rlp::{UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Rlp, RlpStream, DecoderError}; use network::{Error, ErrorKind, AllowIP, IpFilter}; use discovery::{TableUpdates, NodeEntry}; use ip_utils::*; @@ -66,7 +66,7 @@ impl NodeEndpoint { } } - pub fn from_rlp(rlp: &UntrustedRlp) -> Result { + pub fn from_rlp(rlp: &Rlp) -> Result { let tcp_port = rlp.val_at::(2)?; let udp_port = rlp.val_at::(1)?; let addr_bytes = rlp.at(0)?.data()?; diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index c1e09a2525..47eb2cf728 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -23,7 +23,7 @@ use mio::*; use mio::deprecated::{Handler, EventLoop}; use mio::tcp::*; use ethereum_types::H256; -use rlp::{UntrustedRlp, RlpStream, EMPTY_LIST_RLP}; +use rlp::{Rlp, RlpStream, EMPTY_LIST_RLP}; use connection::{EncryptedConnection, Packet, Connection, MAX_PAYLOAD_SIZE}; use handshake::Handshake; use io::{IoContext, StreamToken}; @@ -349,12 +349,12 @@ impl Session { }; match packet_id { PACKET_HELLO => { - let rlp = UntrustedRlp::new(&data); //TODO: validate rlp expected size + let rlp = Rlp::new(&data); //TODO: validate rlp expected size self.read_hello(io, &rlp, host)?; Ok(SessionData::Ready) }, PACKET_DISCONNECT => { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let reason: u8 = rlp.val_at(0)?; if self.had_hello { debug!(target:"network", "Disconnected: {}: {:?}", self.token(), DisconnectReason::from_u8(reason)); @@ -419,7 +419,7 @@ impl Session { self.send(io, &rlp.drain()) } - fn read_hello(&mut self, io: &IoContext, rlp: &UntrustedRlp, host: &HostInfo) -> Result<(), Error> + fn read_hello(&mut self, io: &IoContext, rlp: &Rlp, host: &HostInfo) -> Result<(), Error> where Message: Send + Sync + Clone { let protocol = rlp.val_at::(0)?; let client_version = rlp.val_at::(1)?; diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 1a0c88e4ca..5077a953d4 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -42,7 +42,7 @@ use ipnetwork::{IpNetwork, IpNetworkError}; use io::IoChannel; use ethkey::Secret; use ethereum_types::{H256, H512}; -use rlp::{Decodable, DecoderError, UntrustedRlp}; +use rlp::{Decodable, DecoderError, Rlp}; /// Protocol handler level packet id pub type PacketId = u8; @@ -118,7 +118,7 @@ pub struct PeerCapabilityInfo { } impl Decodable for PeerCapabilityInfo { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let p: Vec = rlp.val_at(0)?; if p.len() != 3 { return Err(DecoderError::Custom("Invalid subprotocol string length. Should be 3")); diff --git a/util/patricia_trie/src/node.rs b/util/patricia_trie/src/node.rs index 47807940fe..0b99acded3 100644 --- a/util/patricia_trie/src/node.rs +++ b/util/patricia_trie/src/node.rs @@ -19,7 +19,7 @@ use elastic_array::ElasticArray36; use nibbleslice::NibbleSlice; use nibblevec::NibbleVec; use bytes::*; -use rlp::{UntrustedRlp, RlpStream, Prototype, DecoderError}; +use rlp::{Rlp, RlpStream, Prototype, DecoderError}; use hashdb::DBValue; /// Partial node key type. @@ -41,7 +41,7 @@ pub enum Node<'a> { impl<'a> Node<'a> { /// Decode the `node_rlp` and return the Node. pub fn decoded(node_rlp: &'a [u8]) -> Result { - let r = UntrustedRlp::new(node_rlp); + let r = Rlp::new(node_rlp); match r.prototype()? { // either leaf or extension - decode first item with NibbleSlice::??? // and use is_leaf return to figure out which. @@ -105,7 +105,7 @@ impl<'a> Node<'a> { } pub fn try_decode_hash(node_data: &[u8]) -> Option { - let r = UntrustedRlp::new(node_data); + let r = Rlp::new(node_data); if r.is_data() && r.size() == 32 { Some(r.as_val().expect("Hash is the correct size of 32 bytes; qed")) } else { diff --git a/util/patricia_trie/src/triedbmut.rs b/util/patricia_trie/src/triedbmut.rs index 98215de012..b8d919deea 100644 --- a/util/patricia_trie/src/triedbmut.rs +++ b/util/patricia_trie/src/triedbmut.rs @@ -24,7 +24,7 @@ use super::node::NodeKey; use hashdb::HashDB; use bytes::ToPretty; use nibbleslice::NibbleSlice; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use hashdb::DBValue; use std::collections::{HashSet, VecDeque}; @@ -107,7 +107,7 @@ impl Node { RlpNode::Branch(ref children_rlp, val) => { let mut child = |i| { let raw = children_rlp[i]; - let child_rlp = UntrustedRlp::new(raw); + let child_rlp = Rlp::new(raw); if !child_rlp.is_empty() { Some(Self::inline_or_hash(raw, db, storage)) } else { diff --git a/util/rlp/src/impls.rs b/util/rlp/src/impls.rs index 7cb6572fec..573f2c0781 100644 --- a/util/rlp/src/impls.rs +++ b/util/rlp/src/impls.rs @@ -11,7 +11,7 @@ use byteorder::{ByteOrder, BigEndian}; use bigint::{U128, U256, H64, H128, H160, H256, H512, H520, Bloom}; use traits::{Encodable, Decodable}; use stream::RlpStream; -use {UntrustedRlp, DecoderError}; +use {Rlp, DecoderError}; pub fn decode_usize(bytes: &[u8]) -> Result { match bytes.len() { @@ -41,7 +41,7 @@ impl Encodable for bool { } impl Decodable for bool { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match bytes.len() { 0 => Ok(false), @@ -65,7 +65,7 @@ impl Encodable for Vec { } impl Decodable for Vec { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { Ok(bytes.to_vec()) }) @@ -87,7 +87,7 @@ impl Encodable for Option where T: Encodable { } impl Decodable for Option where T: Decodable { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { let items = rlp.item_count()?; match items { 1 => rlp.val_at(0).map(Some), @@ -108,7 +108,7 @@ impl Encodable for u8 { } impl Decodable for u8 { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match bytes.len() { 1 if bytes[0] != 0 => Ok(bytes[0]), @@ -136,7 +136,7 @@ macro_rules! impl_encodable_for_u { macro_rules! impl_decodable_for_u { ($name: ident) => { impl Decodable for $name { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match bytes.len() { 0 | 1 => u8::decode(rlp).map(|v| v as $name), @@ -174,7 +174,7 @@ impl Encodable for usize { } impl Decodable for usize { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { u64::decode(rlp).map(|value| value as usize) } } @@ -192,7 +192,7 @@ macro_rules! impl_encodable_for_hash { macro_rules! impl_decodable_for_hash { ($name: ident, $size: expr) => { impl Decodable for $name { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$size) { cmp::Ordering::Less => Err(DecoderError::RlpIsTooShort), cmp::Ordering::Greater => Err(DecoderError::RlpIsTooBig), @@ -239,7 +239,7 @@ macro_rules! impl_encodable_for_uint { macro_rules! impl_decodable_for_uint { ($name: ident, $size: expr) => { impl Decodable for $name { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { if !bytes.is_empty() && bytes[0] == 0 { Err(DecoderError::RlpInvalidIndirection) @@ -273,7 +273,7 @@ impl Encodable for String { } impl Decodable for String { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match str::from_utf8(bytes) { Ok(s) => Ok(s.to_owned()), diff --git a/util/rlp/src/lib.rs b/util/rlp/src/lib.rs index a5889a4efc..a6754e22de 100644 --- a/util/rlp/src/lib.rs +++ b/util/rlp/src/lib.rs @@ -27,12 +27,6 @@ //! * You encode a big set of data. //! //!### Use `Rlp` when: -//! * You are working on trusted data (not corrupted). -//! * You want to get view onto rlp-slice. -//! * You don't want to decode whole rlp at once. -//! -//!### Use `UntrustedRlp` when: -//! * You are working on untrusted data (~corrupted). //! * You need to handle data corruption errors. //! * You are working on input data. //! * You want to get view onto rlp-slice. @@ -46,7 +40,6 @@ extern crate rustc_hex; mod traits; mod error; mod rlpin; -mod untrusted_rlp; mod stream; mod impls; @@ -55,8 +48,7 @@ use elastic_array::ElasticArray1024; pub use error::DecoderError; pub use traits::{Decodable, Encodable}; -pub use untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; -pub use rlpin::{Rlp, RlpIterator}; +pub use rlpin::{Rlp, RlpIterator, PayloadInfo, Prototype}; pub use stream::RlpStream; /// The RLP encoded empty data (used to mean "null value"). @@ -77,12 +69,12 @@ pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; /// ``` pub fn decode(bytes: &[u8]) -> T where T: Decodable { let rlp = Rlp::new(bytes); - rlp.as_val() + rlp.as_val().expect("trusted rlp should be valid") } pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable { let rlp = Rlp::new(bytes); - rlp.as_list() + rlp.as_list().expect("trusted rlp should be valid") } /// Shortcut function to encode structure into rlp. diff --git a/util/rlp/src/rlpin.rs b/util/rlp/src/rlpin.rs index c967959130..a55b4f7907 100644 --- a/util/rlp/src/rlpin.rs +++ b/util/rlp/src/rlpin.rs @@ -6,246 +6,295 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::cell::Cell; use std::fmt; -use {UntrustedRlp, PayloadInfo, Prototype, Decodable}; +use rustc_hex::ToHex; +use impls::decode_usize; +use {Decodable, DecoderError}; -impl<'a> From> for Rlp<'a> { - fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { - Rlp { rlp: rlp } +/// rlp offset +#[derive(Copy, Clone, Debug)] +struct OffsetCache { + index: usize, + offset: usize, +} + +impl OffsetCache { + fn new(index: usize, offset: usize) -> OffsetCache { + OffsetCache { + index: index, + offset: offset, + } + } +} + +#[derive(Debug)] +/// RLP prototype +pub enum Prototype { + /// Empty + Null, + /// Value + Data(usize), + /// List + List(usize), +} + +/// Stores basic information about item +pub struct PayloadInfo { + /// Header length in bytes + pub header_len: usize, + /// Value length in bytes + pub value_len: usize, +} + +fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result { + let header_len = 1 + len_of_len; + match header_bytes.get(1) { + Some(&0) => return Err(DecoderError::RlpDataLenWithZeroPrefix), + None => return Err(DecoderError::RlpIsTooShort), + _ => (), } + if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); } + let value_len = decode_usize(&header_bytes[1..header_len])?; + Ok(PayloadInfo::new(header_len, value_len)) } -/// Data-oriented view onto trusted rlp-slice. +impl PayloadInfo { + fn new(header_len: usize, value_len: usize) -> PayloadInfo { + PayloadInfo { + header_len: header_len, + value_len: value_len, + } + } + + /// Total size of the RLP. + pub fn total(&self) -> usize { self.header_len + self.value_len } + + /// Create a new object from the given bytes RLP. The bytes + pub fn from(header_bytes: &[u8]) -> Result { + match header_bytes.first().cloned() { + None => Err(DecoderError::RlpIsTooShort), + Some(0...0x7f) => Ok(PayloadInfo::new(0, 1)), + Some(l @ 0x80...0xb7) => Ok(PayloadInfo::new(1, l as usize - 0x80)), + Some(l @ 0xb8...0xbf) => { + let len_of_len = l as usize - 0xb7; + calculate_payload_info(header_bytes, len_of_len) + } + Some(l @ 0xc0...0xf7) => Ok(PayloadInfo::new(1, l as usize - 0xc0)), + Some(l @ 0xf8...0xff) => { + let len_of_len = l as usize - 0xf7; + calculate_payload_info(header_bytes, len_of_len) + }, + // we cant reach this place, but rust requires _ to be implemented + _ => { unreachable!(); } + } + } +} + +/// Data-oriented view onto rlp-slice. +/// +/// This is an immutable structure. No operations change it. /// -/// Unlikely to `UntrustedRlp` doesn't bother you with error -/// handling. It assumes that you know what you are doing. +/// Should be used in places where, error handling is required, +/// eg. on input #[derive(Debug)] pub struct Rlp<'a> { - rlp: UntrustedRlp<'a> + bytes: &'a [u8], + offset_cache: Cell, + count_cache: Cell>, +} + +impl<'a> Clone for Rlp<'a> { + fn clone(&self) -> Rlp<'a> { + Rlp { + bytes: self.bytes, + offset_cache: self.offset_cache.clone(), + count_cache: self.count_cache.clone(), + } + } } impl<'a> fmt::Display for Rlp<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "{}", self.rlp) + match self.prototype() { + Ok(Prototype::Null) => write!(f, "null"), + Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex()), + Ok(Prototype::List(len)) => { + write!(f, "[")?; + for i in 0..len-1 { + write!(f, "{}, ", self.at(i).unwrap())?; + } + write!(f, "{}", self.at(len - 1).unwrap())?; + write!(f, "]") + }, + Err(err) => write!(f, "{:?}", err) + } } } impl<'a, 'view> Rlp<'a> where 'a: 'view { - /// Create a new instance of `Rlp` pub fn new(bytes: &'a [u8]) -> Rlp<'a> { Rlp { - rlp: UntrustedRlp::new(bytes) + bytes: bytes, + offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), + count_cache: Cell::new(None) } } - /// The raw data of the RLP as slice. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog = rlp.at(1).as_raw(); - /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']); - /// } - /// ``` pub fn as_raw(&'view self) -> &'a [u8] { - self.rlp.as_raw() - } - - /// Get the prototype of the RLP. - pub fn prototype(&self) -> Prototype { - self.rlp.prototype().unwrap() - } - - /// Get payload info. - pub fn payload_info(&self) -> PayloadInfo { - self.rlp.payload_info().unwrap() - } - - /// Get underlieing data. - pub fn data(&'view self) -> &'a [u8] { - self.rlp.data().unwrap() - } - - /// Returns number of RLP items. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.item_count(), 2); - /// let view = rlp.at(1); - /// assert_eq!(view.item_count(), 0); - /// } - /// ``` - pub fn item_count(&self) -> usize { - self.rlp.item_count().unwrap_or(0) - } - - /// Returns the number of bytes in the data, or zero if it isn't data. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.size(), 0); - /// let view = rlp.at(1); - /// assert_eq!(view.size(), 3); - /// } - /// ``` + self.bytes + } + + pub fn prototype(&self) -> Result { + // optimize? && return appropriate errors + if self.is_data() { + Ok(Prototype::Data(self.size())) + } else if self.is_list() { + self.item_count().map(Prototype::List) + } else { + Ok(Prototype::Null) + } + } + + pub fn payload_info(&self) -> Result { + BasicDecoder::payload_info(self.bytes) + } + + pub fn data(&'view self) -> Result<&'a [u8], DecoderError> { + let pi = BasicDecoder::payload_info(self.bytes)?; + Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) + } + + pub fn item_count(&self) -> Result { + match self.is_list() { + true => match self.count_cache.get() { + Some(c) => Ok(c), + None => { + let c = self.iter().count(); + self.count_cache.set(Some(c)); + Ok(c) + } + }, + false => Err(DecoderError::RlpExpectedToBeList), + } + } + pub fn size(&self) -> usize { - self.rlp.size() - } - - /// Get view onto RLP-slice at index. - /// - /// Caches offset to given index, so access to successive - /// slices is faster. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog: String = rlp.at(1).as_val(); - /// assert_eq!(dog, "dog".to_string()); - /// } - /// ``` - pub fn at(&'view self, index: usize) -> Rlp<'a> { - From::from(self.rlp.at(index).unwrap()) - } - - /// No value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_null()); - /// } - /// ``` + match self.is_data() { + // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. + true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0), + false => 0 + } + } + + pub fn at(&'view self, index: usize) -> Result, DecoderError> { + if !self.is_list() { + return Err(DecoderError::RlpExpectedToBeList); + } + + // move to cached position if its index is less or equal to + // current search index, otherwise move to beginning of list + let c = self.offset_cache.get(); + let (mut bytes, to_skip) = match c.index <= index { + true => (Rlp::consume(self.bytes, c.offset)?, index - c.index), + false => (self.consume_list_payload()?, index), + }; + + // skip up to x items + bytes = Rlp::consume_items(bytes, to_skip)?; + + // update the cache + self.offset_cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len())); + + // construct new rlp + let found = BasicDecoder::payload_info(bytes)?; + Ok(Rlp::new(&bytes[0..found.header_len + found.value_len])) + } + pub fn is_null(&self) -> bool { - self.rlp.is_null() - } - - /// Contains a zero-length string or zero-length list. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc0]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_empty()); - /// } - /// ``` + self.bytes.len() == 0 + } + pub fn is_empty(&self) -> bool { - self.rlp.is_empty() - } - - /// List value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_list()); - /// } - /// ``` + !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) + } + pub fn is_list(&self) -> bool { - self.rlp.is_list() - } - - /// String value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.at(1).is_data()); - /// } - /// ``` + !self.is_null() && self.bytes[0] >= 0xc0 + } + pub fn is_data(&self) -> bool { - self.rlp.is_data() - } - - /// Int value - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc1, 0x10]; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.is_int(), false); - /// assert_eq!(rlp.at(0).is_int(), true); - /// } - /// ``` + !self.is_null() && self.bytes[0] < 0xc0 + } + pub fn is_int(&self) -> bool { - self.rlp.is_int() - } - - /// Get iterator over rlp-slices - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let strings: Vec = rlp.iter().map(| i | i.as_val()).collect(); - /// } - /// ``` + if self.is_null() { + return false; + } + + match self.bytes[0] { + 0...0x80 => true, + 0x81...0xb7 => self.bytes[1] != 0, + b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0, + _ => false + } + } + pub fn iter(&'view self) -> RlpIterator<'a, 'view> { self.into_iter() } - /// Decode data into an object - pub fn as_val(&self) -> T where T: Decodable { - self.rlp.as_val().expect("Unexpected rlp error") + pub fn as_val(&self) -> Result where T: Decodable { + T::decode(self) } - pub fn as_list(&self) -> Vec where T: Decodable { + pub fn as_list(&self) -> Result, DecoderError> where T: Decodable { self.iter().map(|rlp| rlp.as_val()).collect() } - /// Decode data at given list index into an object - pub fn val_at(&self, index: usize) -> T where T: Decodable { - self.at(index).as_val() + pub fn val_at(&self, index: usize) -> Result where T: Decodable { + self.at(index)?.as_val() + } + + pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable { + self.at(index)?.as_list() } - pub fn list_at(&self, index: usize) -> Vec where T: Decodable { - self.at(index).as_list() + pub fn decoder(&self) -> BasicDecoder { + BasicDecoder::new(self.clone()) + } + + /// consumes first found prefix + fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> { + let item = BasicDecoder::payload_info(self.bytes)?; + let bytes = Rlp::consume(self.bytes, item.header_len)?; + Ok(bytes) + } + + /// consumes fixed number of items + fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> { + let mut result = bytes; + for _ in 0..items { + let i = BasicDecoder::payload_info(result)?; + result = Rlp::consume(result, i.header_len + i.value_len)?; + } + Ok(result) + } + + + /// consumes slice prefix of length `len` + fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { + match bytes.len() >= len { + true => Ok(&bytes[len..]), + false => Err(DecoderError::RlpIsTooShort), + } } } -/// Iterator over trusted rlp-slice list elements. +/// Iterator over rlp-slice list elements. pub struct RlpIterator<'a, 'view> where 'a: 'view { rlp: &'view Rlp<'a>, - index: usize + index: usize, } impl<'a, 'view> IntoIterator for &'view Rlp<'a> where 'a: 'view { @@ -265,19 +314,93 @@ impl<'a, 'view> Iterator for RlpIterator<'a, 'view> { fn next(&mut self) -> Option> { let index = self.index; - let result = self.rlp.rlp.at(index).ok().map(From::from); + let result = self.rlp.at(index).ok(); self.index += 1; result } } -#[test] -fn break_it() { - use rustc_hex::FromHex; - use bigint::U256; +pub struct BasicDecoder<'a> { + rlp: Rlp<'a> +} + +impl<'a> BasicDecoder<'a> { + pub fn new(rlp: Rlp<'a>) -> BasicDecoder<'a> { + BasicDecoder { + rlp: rlp + } + } + + /// Return first item info. + fn payload_info(bytes: &[u8]) -> Result { + let item = PayloadInfo::from(bytes)?; + match item.header_len.checked_add(item.value_len) { + Some(x) if x <= bytes.len() => Ok(item), + _ => Err(DecoderError::RlpIsTooShort), + } + } + + pub fn decode_value(&self, f: F) -> Result + where F: Fn(&[u8]) -> Result { + + let bytes = self.rlp.as_raw(); + + match bytes.first().cloned() { + // RLP is too short. + None => Err(DecoderError::RlpIsTooShort), + // Single byte value. + Some(l @ 0...0x7f) => Ok(f(&[l])?), + // 0-55 bytes + Some(l @ 0x80...0xb7) => { + let last_index_of = 1 + l as usize - 0x80; + if bytes.len() < last_index_of { + return Err(DecoderError::RlpInconsistentLengthAndData); + } + let d = &bytes[1..last_index_of]; + if l == 0x81 && d[0] < 0x80 { + return Err(DecoderError::RlpInvalidIndirection); + } + Ok(f(d)?) + }, + // Longer than 55 bytes. + Some(l @ 0xb8...0xbf) => { + let len_of_len = l as usize - 0xb7; + let begin_of_value = 1 as usize + len_of_len; + if bytes.len() < begin_of_value { + return Err(DecoderError::RlpInconsistentLengthAndData); + } + let len = decode_usize(&bytes[1..begin_of_value])?; + + let last_index_of_value = begin_of_value.checked_add(len) + .ok_or(DecoderError::RlpInvalidLength)?; + if bytes.len() < last_index_of_value { + return Err(DecoderError::RlpInconsistentLengthAndData); + } + Ok(f(&bytes[begin_of_value..last_index_of_value])?) + } + // We are reading value, not a list! + _ => Err(DecoderError::RlpExpectedToBeData) + } + } +} + +#[cfg(test)] +mod tests { + use {Rlp, DecoderError}; - let h: Vec = FromHex::from_hex("f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap(); - let r: Rlp = Rlp::new(&h); - let u: U256 = r.val_at(1); - assert_eq!(format!("{}", u), "19526463837540678066"); + #[test] + fn test_rlp_display() { + use rustc_hex::FromHex; + let data = "f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".from_hex().unwrap(); + let rlp = Rlp::new(&data); + assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); + } + + #[test] + fn length_overflow() { + let bs = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; + let rlp = Rlp::new(&bs); + let res: Result = rlp.as_val(); + assert_eq!(Err(DecoderError::RlpInvalidLength), res); + } } diff --git a/util/rlp/src/traits.rs b/util/rlp/src/traits.rs index 193d0bf84a..1596009e75 100644 --- a/util/rlp/src/traits.rs +++ b/util/rlp/src/traits.rs @@ -8,12 +8,12 @@ //! Common RLP traits use elastic_array::ElasticArray1024; -use {DecoderError, UntrustedRlp, RlpStream}; +use {DecoderError, Rlp, RlpStream}; /// RLP decodable trait pub trait Decodable: Sized { /// Decode a value from RLP bytes - fn decode(rlp: &UntrustedRlp) -> Result; + fn decode(rlp: &Rlp) -> Result; } /// Structure encodable to RLP diff --git a/util/rlp/src/untrusted_rlp.rs b/util/rlp/src/untrusted_rlp.rs deleted file mode 100644 index 7f95ce2efe..0000000000 --- a/util/rlp/src/untrusted_rlp.rs +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cell::Cell; -use std::fmt; -use rustc_hex::ToHex; -use impls::decode_usize; -use {Decodable, DecoderError}; - -/// rlp offset -#[derive(Copy, Clone, Debug)] -struct OffsetCache { - index: usize, - offset: usize, -} - -impl OffsetCache { - fn new(index: usize, offset: usize) -> OffsetCache { - OffsetCache { - index: index, - offset: offset, - } - } -} - -#[derive(Debug)] -/// RLP prototype -pub enum Prototype { - /// Empty - Null, - /// Value - Data(usize), - /// List - List(usize), -} - -/// Stores basic information about item -pub struct PayloadInfo { - /// Header length in bytes - pub header_len: usize, - /// Value length in bytes - pub value_len: usize, -} - -fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result { - let header_len = 1 + len_of_len; - match header_bytes.get(1) { - Some(&0) => return Err(DecoderError::RlpDataLenWithZeroPrefix), - None => return Err(DecoderError::RlpIsTooShort), - _ => (), - } - if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); } - let value_len = decode_usize(&header_bytes[1..header_len])?; - Ok(PayloadInfo::new(header_len, value_len)) -} - -impl PayloadInfo { - fn new(header_len: usize, value_len: usize) -> PayloadInfo { - PayloadInfo { - header_len: header_len, - value_len: value_len, - } - } - - /// Total size of the RLP. - pub fn total(&self) -> usize { self.header_len + self.value_len } - - /// Create a new object from the given bytes RLP. The bytes - pub fn from(header_bytes: &[u8]) -> Result { - match header_bytes.first().cloned() { - None => Err(DecoderError::RlpIsTooShort), - Some(0...0x7f) => Ok(PayloadInfo::new(0, 1)), - Some(l @ 0x80...0xb7) => Ok(PayloadInfo::new(1, l as usize - 0x80)), - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - calculate_payload_info(header_bytes, len_of_len) - } - Some(l @ 0xc0...0xf7) => Ok(PayloadInfo::new(1, l as usize - 0xc0)), - Some(l @ 0xf8...0xff) => { - let len_of_len = l as usize - 0xf7; - calculate_payload_info(header_bytes, len_of_len) - }, - // we cant reach this place, but rust requires _ to be implemented - _ => { unreachable!(); } - } - } -} - -/// Data-oriented view onto rlp-slice. -/// -/// This is an immutable structure. No operations change it. -/// -/// Should be used in places where, error handling is required, -/// eg. on input -#[derive(Debug)] -pub struct UntrustedRlp<'a> { - bytes: &'a [u8], - offset_cache: Cell, - count_cache: Cell>, -} - -impl<'a> Clone for UntrustedRlp<'a> { - fn clone(&self) -> UntrustedRlp<'a> { - UntrustedRlp { - bytes: self.bytes, - offset_cache: self.offset_cache.clone(), - count_cache: self.count_cache.clone(), - } - } -} - -impl<'a> fmt::Display for UntrustedRlp<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.prototype() { - Ok(Prototype::Null) => write!(f, "null"), - Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex()), - Ok(Prototype::List(len)) => { - write!(f, "[")?; - for i in 0..len-1 { - write!(f, "{}, ", self.at(i).unwrap())?; - } - write!(f, "{}", self.at(len - 1).unwrap())?; - write!(f, "]") - }, - Err(err) => write!(f, "{:?}", err) - } - } -} - -impl<'a, 'view> UntrustedRlp<'a> where 'a: 'view { - pub fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> { - UntrustedRlp { - bytes: bytes, - offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), - count_cache: Cell::new(None) - } - } - - pub fn as_raw(&'view self) -> &'a [u8] { - self.bytes - } - - pub fn prototype(&self) -> Result { - // optimize? && return appropriate errors - if self.is_data() { - Ok(Prototype::Data(self.size())) - } else if self.is_list() { - self.item_count().map(Prototype::List) - } else { - Ok(Prototype::Null) - } - } - - pub fn payload_info(&self) -> Result { - BasicDecoder::payload_info(self.bytes) - } - - pub fn data(&'view self) -> Result<&'a [u8], DecoderError> { - let pi = BasicDecoder::payload_info(self.bytes)?; - Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) - } - - pub fn item_count(&self) -> Result { - match self.is_list() { - true => match self.count_cache.get() { - Some(c) => Ok(c), - None => { - let c = self.iter().count(); - self.count_cache.set(Some(c)); - Ok(c) - } - }, - false => Err(DecoderError::RlpExpectedToBeList), - } - } - - pub fn size(&self) -> usize { - match self.is_data() { - // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. - true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0), - false => 0 - } - } - - pub fn at(&'view self, index: usize) -> Result, DecoderError> { - if !self.is_list() { - return Err(DecoderError::RlpExpectedToBeList); - } - - // move to cached position if its index is less or equal to - // current search index, otherwise move to beginning of list - let c = self.offset_cache.get(); - let (mut bytes, to_skip) = match c.index <= index { - true => (UntrustedRlp::consume(self.bytes, c.offset)?, index - c.index), - false => (self.consume_list_payload()?, index), - }; - - // skip up to x items - bytes = UntrustedRlp::consume_items(bytes, to_skip)?; - - // update the cache - self.offset_cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len())); - - // construct new rlp - let found = BasicDecoder::payload_info(bytes)?; - Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len])) - } - - pub fn is_null(&self) -> bool { - self.bytes.len() == 0 - } - - pub fn is_empty(&self) -> bool { - !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) - } - - pub fn is_list(&self) -> bool { - !self.is_null() && self.bytes[0] >= 0xc0 - } - - pub fn is_data(&self) -> bool { - !self.is_null() && self.bytes[0] < 0xc0 - } - - pub fn is_int(&self) -> bool { - if self.is_null() { - return false; - } - - match self.bytes[0] { - 0...0x80 => true, - 0x81...0xb7 => self.bytes[1] != 0, - b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0, - _ => false - } - } - - pub fn iter(&'view self) -> UntrustedRlpIterator<'a, 'view> { - self.into_iter() - } - - pub fn as_val(&self) -> Result where T: Decodable { - T::decode(self) - } - - pub fn as_list(&self) -> Result, DecoderError> where T: Decodable { - self.iter().map(|rlp| rlp.as_val()).collect() - } - - pub fn val_at(&self, index: usize) -> Result where T: Decodable { - self.at(index)?.as_val() - } - - pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable { - self.at(index)?.as_list() - } - - pub fn decoder(&self) -> BasicDecoder { - BasicDecoder::new(self.clone()) - } - - /// consumes first found prefix - fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> { - let item = BasicDecoder::payload_info(self.bytes)?; - let bytes = UntrustedRlp::consume(self.bytes, item.header_len)?; - Ok(bytes) - } - - /// consumes fixed number of items - fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> { - let mut result = bytes; - for _ in 0..items { - let i = BasicDecoder::payload_info(result)?; - result = UntrustedRlp::consume(result, i.header_len + i.value_len)?; - } - Ok(result) - } - - - /// consumes slice prefix of length `len` - fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { - match bytes.len() >= len { - true => Ok(&bytes[len..]), - false => Err(DecoderError::RlpIsTooShort), - } - } -} - -/// Iterator over rlp-slice list elements. -pub struct UntrustedRlpIterator<'a, 'view> where 'a: 'view { - rlp: &'view UntrustedRlp<'a>, - index: usize, -} - -impl<'a, 'view> IntoIterator for &'view UntrustedRlp<'a> where 'a: 'view { - type Item = UntrustedRlp<'a>; - type IntoIter = UntrustedRlpIterator<'a, 'view>; - - fn into_iter(self) -> Self::IntoIter { - UntrustedRlpIterator { - rlp: self, - index: 0, - } - } -} - -impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> { - type Item = UntrustedRlp<'a>; - - fn next(&mut self) -> Option> { - let index = self.index; - let result = self.rlp.at(index).ok(); - self.index += 1; - result - } -} - -pub struct BasicDecoder<'a> { - rlp: UntrustedRlp<'a> -} - -impl<'a> BasicDecoder<'a> { - pub fn new(rlp: UntrustedRlp<'a>) -> BasicDecoder<'a> { - BasicDecoder { - rlp: rlp - } - } - - /// Return first item info. - fn payload_info(bytes: &[u8]) -> Result { - let item = PayloadInfo::from(bytes)?; - match item.header_len.checked_add(item.value_len) { - Some(x) if x <= bytes.len() => Ok(item), - _ => Err(DecoderError::RlpIsTooShort), - } - } - - pub fn decode_value(&self, f: F) -> Result - where F: Fn(&[u8]) -> Result { - - let bytes = self.rlp.as_raw(); - - match bytes.first().cloned() { - // RLP is too short. - None => Err(DecoderError::RlpIsTooShort), - // Single byte value. - Some(l @ 0...0x7f) => Ok(f(&[l])?), - // 0-55 bytes - Some(l @ 0x80...0xb7) => { - let last_index_of = 1 + l as usize - 0x80; - if bytes.len() < last_index_of { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - let d = &bytes[1..last_index_of]; - if l == 0x81 && d[0] < 0x80 { - return Err(DecoderError::RlpInvalidIndirection); - } - Ok(f(d)?) - }, - // Longer than 55 bytes. - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - let begin_of_value = 1 as usize + len_of_len; - if bytes.len() < begin_of_value { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - let len = decode_usize(&bytes[1..begin_of_value])?; - - let last_index_of_value = begin_of_value.checked_add(len) - .ok_or(DecoderError::RlpInvalidLength)?; - if bytes.len() < last_index_of_value { - return Err(DecoderError::RlpInconsistentLengthAndData); - } - Ok(f(&bytes[begin_of_value..last_index_of_value])?) - } - // We are reading value, not a list! - _ => Err(DecoderError::RlpExpectedToBeData) - } - } -} - -#[cfg(test)] -mod tests { - use {UntrustedRlp, DecoderError}; - - #[test] - fn test_rlp_display() { - use rustc_hex::FromHex; - let data = "f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".from_hex().unwrap(); - let rlp = UntrustedRlp::new(&data); - assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); - } - - #[test] - fn length_overflow() { - let bs = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; - let rlp = UntrustedRlp::new(&bs); - let res: Result = rlp.as_val(); - assert_eq!(Err(DecoderError::RlpInvalidLength), res); - } -} diff --git a/util/rlp/tests/tests.rs b/util/rlp/tests/tests.rs index 03151c5bf7..6ff426a773 100644 --- a/util/rlp/tests/tests.rs +++ b/util/rlp/tests/tests.rs @@ -11,13 +11,13 @@ extern crate rlp; use std::{fmt, cmp}; use bigint::{U256, H160}; -use rlp::{Encodable, Decodable, UntrustedRlp, RlpStream, DecoderError}; +use rlp::{Encodable, Decodable, Rlp, RlpStream, DecoderError}; #[test] fn rlp_at() { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); assert!(rlp.is_list()); let animals: Vec = rlp.as_list().unwrap(); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); @@ -43,7 +43,7 @@ fn rlp_at() { fn rlp_at_err() { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o']; { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); assert!(rlp.is_list()); let cat_err = rlp.at(0).unwrap_err(); @@ -58,7 +58,7 @@ fn rlp_at_err() { fn rlp_iter() { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; { - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let mut iter = rlp.iter(); let cat = iter.next().unwrap(); @@ -337,7 +337,7 @@ fn decode_untrusted_vector_str() { fn test_rlp_data_length_check() { let data = vec![0x84, b'c', b'a', b't']; - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); @@ -351,7 +351,7 @@ fn test_rlp_long_data_length_check() data.push(b'c'); } - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); @@ -365,7 +365,7 @@ fn test_the_exact_long_string() data.push(b'c'); } - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert!(as_val.is_ok()); @@ -379,7 +379,7 @@ fn test_rlp_2bytes_data_length_check() data.push(b'c'); } - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); @@ -396,7 +396,7 @@ fn test_rlp_nested_empty_list_encode() { #[test] fn test_rlp_list_length_overflow() { let data: Vec = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00]; - let rlp = UntrustedRlp::new(&data); + let rlp = Rlp::new(&data); let as_val: Result = rlp.val_at(0); assert_eq!(Err(DecoderError::RlpIsTooShort), as_val); } diff --git a/util/rlp_compress/src/lib.rs b/util/rlp_compress/src/lib.rs index 89c5e83283..b895e1ce1a 100644 --- a/util/rlp_compress/src/lib.rs +++ b/util/rlp_compress/src/lib.rs @@ -16,7 +16,7 @@ mod common; use std::cmp; use std::collections::HashMap; use elastic_array::ElasticArray1024; -use rlp::{UntrustedRlp, RlpStream}; +use rlp::{Rlp, RlpStream}; use common::{SNAPSHOT_SWAPPER, BLOCKS_SWAPPER}; pub fn snapshot_swapper() -> &'static Swapper<'static> { @@ -41,7 +41,7 @@ pub trait Decompressor { /// Call this function to compress rlp. pub fn compress(c: &[u8], swapper: &Compressor) -> ElasticArray1024 { - let rlp = UntrustedRlp::new(c); + let rlp = Rlp::new(c); if rlp.is_data() { ElasticArray1024::from_slice(swapper.compressed(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw())) } else { @@ -51,7 +51,7 @@ pub fn compress(c: &[u8], swapper: &Compressor) -> ElasticArray1024 { /// Call this function to decompress rlp. pub fn decompress(c: &[u8], swapper: &Decompressor) -> ElasticArray1024 { - let rlp = UntrustedRlp::new(c); + let rlp = Rlp::new(c); if rlp.is_data() { ElasticArray1024::from_slice(swapper.decompressed(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw())) } else { @@ -59,7 +59,7 @@ pub fn decompress(c: &[u8], swapper: &Decompressor) -> ElasticArray1024 { } } -fn map_rlp ElasticArray1024>(rlp: &UntrustedRlp, f: F) -> ElasticArray1024 { +fn map_rlp ElasticArray1024>(rlp: &Rlp, f: F) -> ElasticArray1024 { let mut stream = RlpStream::new_list(rlp.item_count().unwrap_or_default()); for subrlp in rlp.iter() { stream.append_raw(&f(&subrlp), 1); diff --git a/util/rlp_derive/src/de.rs b/util/rlp_derive/src/de.rs index 7432d3e2e8..dac4e34cdb 100644 --- a/util/rlp_derive/src/de.rs +++ b/util/rlp_derive/src/de.rs @@ -35,7 +35,7 @@ pub fn impl_decodable(ast: &syn::DeriveInput) -> quote::Tokens { let dummy_const: syn::Ident = format!("_IMPL_RLP_DECODABLE_FOR_{}", name).into(); let impl_block = quote! { impl rlp::Decodable for #name { - fn decode(rlp: &rlp::UntrustedRlp) -> Result { + fn decode(rlp: &rlp::Rlp) -> Result { let result = #name { #(#stmts)* }; @@ -75,7 +75,7 @@ pub fn impl_decodable_wrapper(ast: &syn::DeriveInput) -> quote::Tokens { let dummy_const: syn::Ident = format!("_IMPL_RLP_DECODABLE_FOR_{}", name).into(); let impl_block = quote! { impl rlp::Decodable for #name { - fn decode(rlp: &rlp::UntrustedRlp) -> Result { + fn decode(rlp: &rlp::Rlp) -> Result { let result = #name { #stmt }; diff --git a/whisper/src/message.rs b/whisper/src/message.rs index 126acebd25..fbf2faf3fd 100644 --- a/whisper/src/message.rs +++ b/whisper/src/message.rs @@ -20,7 +20,7 @@ use std::fmt; use std::time::{self, SystemTime, Duration, Instant}; use ethereum_types::{H256, H512}; -use rlp::{self, DecoderError, RlpStream, UntrustedRlp}; +use rlp::{self, DecoderError, RlpStream, Rlp}; use smallvec::SmallVec; use tiny_keccak::{keccak256, Keccak}; @@ -85,7 +85,7 @@ impl rlp::Encodable for Topic { } impl rlp::Decodable for Topic { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { use std::cmp; rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&4) { @@ -145,7 +145,7 @@ fn append_topics<'a>(s: &'a mut RlpStream, topics: &[Topic]) -> &'a mut RlpStrea } } -fn decode_topics(rlp: UntrustedRlp) -> Result, DecoderError> { +fn decode_topics(rlp: Rlp) -> Result, DecoderError> { if rlp.is_list() { rlp.iter().map(|r| r.as_val::()).collect() } else { @@ -212,7 +212,7 @@ impl rlp::Encodable for Envelope { } impl rlp::Decodable for Envelope { - fn decode(rlp: &UntrustedRlp) -> Result { + fn decode(rlp: &Rlp) -> Result { if rlp.item_count()? != 5 { return Err(DecoderError::RlpIncorrectListLen) } Ok(Envelope { @@ -332,7 +332,7 @@ impl Message { } /// Decode message from RLP and check for validity against system time. - pub fn decode(rlp: UntrustedRlp, now: SystemTime) -> Result { + pub fn decode(rlp: Rlp, now: SystemTime) -> Result { let envelope: Envelope = rlp.as_val()?; let encoded_size = rlp.as_raw().len(); let hash = H256(keccak256(rlp.as_raw())); @@ -418,7 +418,7 @@ impl Message { mod tests { use super::*; use std::time::{self, Duration, SystemTime}; - use rlp::UntrustedRlp; + use rlp::Rlp; use smallvec::SmallVec; fn unix_time(x: u64) -> SystemTime { @@ -481,7 +481,7 @@ mod tests { for i in 0..30 { let now = unix_time(100_000 - i); - Message::decode(UntrustedRlp::new(&*encoded), now).unwrap(); + Message::decode(Rlp::new(&*encoded), now).unwrap(); } } @@ -499,7 +499,7 @@ mod tests { let encoded = ::rlp::encode(&envelope); let now = unix_time(100_000 - 1_000); - Message::decode(UntrustedRlp::new(&*encoded), now).unwrap(); + Message::decode(Rlp::new(&*encoded), now).unwrap(); } #[test] @@ -516,6 +516,6 @@ mod tests { let encoded = ::rlp::encode(&envelope); let now = unix_time(95_000); - Message::decode(UntrustedRlp::new(&*encoded), now).unwrap(); + Message::decode(Rlp::new(&*encoded), now).unwrap(); } } diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index dd5e345bcd..fc6138cf1d 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -26,7 +26,7 @@ use ethereum_types::{H256, H512}; use network::{self, HostInfo, NetworkContext, NodeId, PeerId, ProtocolId, TimerToken}; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock}; -use rlp::{DecoderError, RlpStream, UntrustedRlp}; +use rlp::{DecoderError, RlpStream, Rlp}; use message::{Message, Error as MessageError}; @@ -506,7 +506,7 @@ impl Network { } // handle status packet from peer. - fn on_status(&self, peer: &PeerId, _status: UntrustedRlp) + fn on_status(&self, peer: &PeerId, _status: Rlp) -> Result<(), Error> { let peers = self.peers.read(); @@ -523,7 +523,7 @@ impl Network { } } - fn on_messages(&self, peer: &PeerId, message_packet: UntrustedRlp) + fn on_messages(&self, peer: &PeerId, message_packet: Rlp) -> Result<(), Error> { let mut messages_vec = { @@ -568,7 +568,7 @@ impl Network { Ok(()) } - fn on_pow_requirement(&self, peer: &PeerId, requirement: UntrustedRlp) + fn on_pow_requirement(&self, peer: &PeerId, requirement: Rlp) -> Result<(), Error> { use byteorder::{ByteOrder, BigEndian}; @@ -604,7 +604,7 @@ impl Network { Ok(()) } - fn on_topic_filter(&self, peer: &PeerId, filter: UntrustedRlp) + fn on_topic_filter(&self, peer: &PeerId, filter: Rlp) -> Result<(), Error> { let peers = self.peers.read(); @@ -661,7 +661,7 @@ impl Network { } fn on_packet(&self, io: &C, peer: &PeerId, packet_id: u8, data: &[u8]) { - let rlp = UntrustedRlp::new(data); + let rlp = Rlp::new(data); let res = match packet_id { packet::STATUS => self.on_status(peer, rlp), packet::MESSAGES => self.on_messages(peer, rlp), -- GitLab From 9e09d5b6bf0842b4ddad61976250a6007abcfa8b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 02:14:42 +0800 Subject: [PATCH 080/263] Fix TODO comments (#8413) --- rpc/src/v1/types/block.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index d9c1b247c3..2b3a085ca5 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -55,8 +55,7 @@ pub struct Block { pub uncles_hash: H256, /// Authors address pub author: H160, - // TODO: get rid of this one - /// ? + /// Alias of `author` pub miner: H160, /// State root hash #[serde(rename="stateRoot")] -- GitLab From cb31220a4a8ce50ce8c4191b955fabcecd2201d6 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 19 Apr 2018 10:53:14 +0200 Subject: [PATCH 081/263] update zip to 0.3 (#8381) * update zip to 0.3 * enable zip deflate feature --- Cargo.lock | 62 ++++++++++++++++++++++++++++++++++++------------ dapps/Cargo.toml | 2 +- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e78a947eaa..def760f7b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,8 @@ +[[package]] +name = "adler32" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aho-corasick" version = "0.6.4" @@ -168,6 +173,11 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.2.1" @@ -250,6 +260,14 @@ dependencies = [ "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam" version = "0.3.2" @@ -1062,11 +1080,11 @@ dependencies = [ [[package]] name = "flate2" -version = "0.2.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1654,12 +1672,23 @@ dependencies = [ ] [[package]] -name = "miniz-sys" -version = "0.1.10" +name = "miniz_oxide" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide_c_api" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1714,12 +1743,11 @@ dependencies = [ [[package]] name = "msdos_time" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2019,7 +2047,7 @@ dependencies = [ "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3723,16 +3751,17 @@ dependencies = [ [[package]] name = "zip" -version = "0.1.19" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] +"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" @@ -3754,6 +3783,7 @@ dependencies = [ "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" "checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" @@ -3761,6 +3791,7 @@ dependencies = [ "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" +"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" @@ -3790,7 +3821,7 @@ dependencies = [ "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" -"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423" +"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" @@ -3846,12 +3877,13 @@ dependencies = [ "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" "checksum mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e3d709ffbb330e1566dc2f2a3c9b58a5ad4a381f740b810cd305dc3f089bc160" "checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae" -"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" +"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398" +"checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" "checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "" "checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "65ba9d75bcea84e07812618fedf284a64776c2f2ea0cad6bca7f69739695a958" +"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" "checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" @@ -4012,4 +4044,4 @@ dependencies = [ "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9cfb54ca6b8f17d2377219ce485b134d53561b77e1393c7ea416f543a527431" -"checksum zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c0deac03fc7d43abcf19f2c2db6bd9289f9ea3d31f350e26eb0ed8b4117983c1" +"checksum zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "10931e278527cea65682696481e6d840371d581079df529ebfee186e0eaad719" diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index fdd497763f..8e35b213e0 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -22,7 +22,7 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" unicase = "1.4" -zip = { version = "0.1", default-features = false } +zip = { version = "0.3", default-features = false, features = ["deflate"] } itertools = "0.5" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } -- GitLab From 941f2380c427b5c604da228d83556f13c6e238a7 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 19 Apr 2018 17:24:19 +0800 Subject: [PATCH 082/263] typo, docs parity_chainId: empty string -> None (#8434) --- rpc/src/v1/traits/parity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 165cf63d67..83d8b19811 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -178,7 +178,7 @@ build_rpc_trait! { fn mode(&self) -> Result; /// Returns the chain ID used for transaction signing at the - /// current best block. An empty string is returned if not + /// current best block. None is returned if not /// available. #[rpc(name = "parity_chainId")] fn chain_id(&self) -> Result>; -- GitLab From 461b2d48531bac522ddb0b7eb532ebb70427f7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 19 Apr 2018 11:25:15 +0200 Subject: [PATCH 083/263] Fix receipts stripping. (#8414) --- ethcore/src/block.rs | 28 ++++++++++++++++++---------- ethcore/src/client/client.rs | 13 ++++++++++--- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index e3622c293d..d9f3d27afb 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -491,6 +491,24 @@ impl ClosedBlock { } impl LockedBlock { + + /// Removes outcomes from receipts and updates the receipt root. + /// + /// This is done after the block is enacted for historical reasons. + /// We allow inconsistency in receipts for some chains if `validate_receipts_transition` + /// is set to non-zero value, so the check only happens if we detect + /// unmatching root first and then fall back to striped receipts. + pub fn strip_receipts_outcomes(&mut self) { + for receipt in &mut self.block.receipts { + receipt.outcome = TransactionOutcome::Unknown; + } + self.block.header.set_receipts_root( + ordered_trie_root(self.block.receipts.iter().map(|r| r.rlp_bytes())) + ); + // compute hash and cache it. + self.block.header.compute_hash(); + } + /// Get the hash of the header without seal arguments. pub fn hash(&self) -> H256 { self.header().bare_hash() } @@ -570,7 +588,6 @@ fn enact( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, - strip_receipts: bool, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { @@ -600,12 +617,6 @@ fn enact( b.push_uncle(u)?; } - if strip_receipts { - for receipt in &mut b.block.receipts { - receipt.outcome = TransactionOutcome::Unknown; - } - } - Ok(b.close_and_lock()) } @@ -619,8 +630,6 @@ pub fn enact_verified( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, - // Remove state root from transaction receipts to make them EIP-98 compatible. - strip_receipts: bool, ) -> Result { let view = view!(BlockView, &block.bytes); @@ -635,7 +644,6 @@ pub fn enact_verified( last_hashes, factories, is_epoch_begin, - strip_receipts, ) } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d2b63b6cdb..bb7f5894b8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -415,7 +415,6 @@ impl Importer { let db = client.state_db.read().boxed_clone_canon(header.parent_hash()); let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some(); - let strip_receipts = header.number() < engine.params().validate_receipts_transition; let enact_result = enact_verified( block, engine, @@ -425,13 +424,21 @@ impl Importer { last_hashes, client.factories.clone(), is_epoch_begin, - strip_receipts, ); - let locked_block = enact_result.map_err(|e| { + let mut locked_block = enact_result.map_err(|e| { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); })?; + // Strip receipts for blocks before validate_receipts_transition, + // if the expected receipts root header does not match. + // (i.e. allow inconsistency in receipts outcome before the transition block) + if header.number() < engine.params().validate_receipts_transition + && header.receipts_root() != locked_block.block().header().receipts_root() + { + locked_block.strip_receipts_outcomes(); + } + // Final Verification if let Err(e) = self.verifier.verify_block_final(&header, locked_block.block().header()) { warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); -- GitLab From 2257bc8e2f336495873e85062af97188036cab55 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Thu, 19 Apr 2018 11:26:55 +0200 Subject: [PATCH 084/263] Changelogs for 1.9.6 and 1.10.1 (#8411) * Add changelog for 1.9.6 * Add Changelog for 1.10.1 --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ docs/CHANGELOG-1.9.md | 27 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0f438696b..2f42b78188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,44 @@ +## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) + +Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. + +The full list of included changes: + +- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350)) + - Bump beta to 1.10.1 + - Unflag critical release +- Backports ([#8346](https://github.com/paritytech/parity/pull/8346)) + - Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) + - Warp-only sync with warp-after [blocknumber] flag. + - Fix tests. + - Fix configuration tests. + - Rename to warp barrier. + - Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) + - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) + - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) + - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) + - Include suicided accounts in state diff + - Shorten form match -> if let + - Test suicide trace diff in State + - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) + - Replace_home for password_files, reserved_peers and log_file + - Typo: arg_log_file is Option + - Enable UI by default, but only display info page. + - Fix test. + - Fix naming and remove old todo. + - Change "wallet" with "browser UI" +- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205)) + - Change name Wallet -> UI + - Make warning bold +- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132)) +- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220)) + - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) + - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203)) +- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181)) + - Updated jsonrpc to include latest backports + - Update dependencies. + ## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22) This is the Parity 1.10.0-beta release! Cool! diff --git a/docs/CHANGELOG-1.9.md b/docs/CHANGELOG-1.9.md index ddb7e9cee1..0351d61135 100644 --- a/docs/CHANGELOG-1.9.md +++ b/docs/CHANGELOG-1.9.md @@ -1,3 +1,30 @@ +## Parity [v1.9.6](https://github.com/paritytech/parity/releases/tag/v1.9.6) (2018-04-16) + +Parity 1.9.6 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Bump app_dirs, fixes [#8315](https://github.com/paritytech/parity/issues/8315) ([#8355](https://github.com/paritytech/parity/pull/8355)) +- Fix Cargo lock +- Backports ([#8352](https://github.com/paritytech/parity/pull/8352)) + - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) + - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) + - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) + - Include suicided accounts in state diff + - Shorten form match -> if let + - Test suicide trace diff in State + - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) + - Replace_home for password_files, reserved_peers and log_file + - Typo: arg_log_file is Option + - Bump version in util/version +- Bump stable to 1.9.6 ([#8348](https://github.com/paritytech/parity/pull/8348)) +- WASM libraries bump ([#8219](https://github.com/paritytech/parity/pull/8219)) + - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) + - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Updated jsonrpc to include latest backports (1.9) ([#8182](https://github.com/paritytech/parity/pull/8182)) + - Updated jsonrpc to include latest backports (1.9) + - Update dependencies. + ## Parity [v1.9.5](https://github.com/paritytech/parity/releases/tag/v1.9.5) (2018-03-21) Parity 1.9.5 is a bug-fix release to improve performance and stability. This release marks the 1.9 track _stable_. -- GitLab From 14361cc7b154af46ea0efca79d1c297d32181b40 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 19 Apr 2018 10:52:54 +0100 Subject: [PATCH 085/263] Move ethcore::Error to error_chain (#8386) * WIP * Convert Ethcore error to use error_chain * Use error_chain for ImportError and BlockImportError * Fix error pattern matches for error_chain in miner * Implement explicit From for AccountsError * Fix pattern matches for ErrorKinds * Handle ethcore error_chain in light client * Explicitly define Result type to avoid shadowing * Fix remaining Error pattern matches * Fix tab space formatting * Helps if the tests compile * Fix error chain matching after merge --- Cargo.lock | 2 + ethcore/Cargo.toml | 1 + ethcore/light/Cargo.toml | 1 + ethcore/light/src/client/header_chain.rs | 15 +- ethcore/light/src/lib.rs | 2 + ethcore/src/client/client.rs | 10 +- ethcore/src/client/mod.rs | 2 +- ethcore/src/engines/authority_round/mod.rs | 8 +- ethcore/src/engines/mod.rs | 8 +- ethcore/src/engines/tendermint/mod.rs | 18 +- ethcore/src/error.rs | 311 ++++++++------------ ethcore/src/ethereum/ethash.rs | 18 +- ethcore/src/executed.rs | 8 +- ethcore/src/lib.rs | 6 + ethcore/src/miner/miner.rs | 16 +- ethcore/src/snapshot/tests/proof_of_work.rs | 4 +- ethcore/src/snapshot/tests/state.rs | 4 +- ethcore/src/verification/queue/kind.rs | 4 +- ethcore/src/verification/queue/mod.rs | 10 +- ethcore/src/verification/verification.rs | 9 +- ethcore/sync/src/block_sync.rs | 14 +- ethcore/sync/src/chain.rs | 8 +- ethcore/sync/src/light_sync/mod.rs | 6 +- ethcore/transaction/src/error.rs | 8 +- ethkey/src/error.rs | 8 +- parity/blockchain.rs | 6 +- rpc/src/v1/helpers/errors.rs | 10 +- 27 files changed, 246 insertions(+), 271 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index def760f7b5..72c163e4d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,6 +512,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -613,6 +614,7 @@ name = "ethcore-light" version = "1.11.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", "ethcore-io 1.11.0", diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 6916629758..c9db7cf9f6 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -20,6 +20,7 @@ fetch = { path = "../util/fetch" } hashdb = { path = "../util/hashdb" } memorydb = { path = "../util/memorydb" } patricia-trie = { path = "../util/patricia_trie" } +error-chain = { version = "0.11", default-features = false } ethcore-io = { path = "../util/io" } ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index 9de1ceb9e7..ba76dc3b10 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -35,6 +35,7 @@ keccak-hash = { path = "../../util/hash" } triehash = { path = "../../util/triehash" } kvdb = { path = "../../util/kvdb" } memory-cache = { path = "../../util/memory_cache" } +error-chain = { version = "0.11", default-features = false } [dev-dependencies] kvdb-memorydb = { path = "../../util/kvdb-memorydb" } diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 7bd13a6c09..abcb04c366 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -31,7 +31,7 @@ use std::sync::Arc; use cht; use ethcore::block_status::BlockStatus; -use ethcore::error::{Error, BlockImportError, BlockError}; +use ethcore::error::{Error, ErrorKind, BlockImportError, BlockImportErrorKind, BlockError}; use ethcore::encoded; use ethcore::header::Header; use ethcore::ids::BlockId; @@ -260,7 +260,7 @@ impl HeaderChain { let best_block = { let era = match candidates.get(&curr.best_num) { Some(era) => era, - None => return Err(Error::Database("Database corrupt: highest block referenced but no data.".into())), + None => bail!(ErrorKind::Database("Database corrupt: highest block referenced but no data.".into())), }; let best = &era.candidates[0]; @@ -332,8 +332,7 @@ impl HeaderChain { // 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() - .map_err(|s| Error::Database(s.into()))?; + let genesis_data = spec.genesis_epoch_data()?; { let mut batch = chain.db.transaction(); @@ -411,7 +410,7 @@ impl HeaderChain { .and_then(|entry| entry.candidates.iter().find(|c| c.hash == parent_hash)) .map(|c| c.total_difficulty) .ok_or_else(|| BlockError::UnknownParent(parent_hash)) - .map_err(BlockImportError::Block)? + .map_err(BlockImportErrorKind::Block)? }; parent_td + *header.difficulty() @@ -580,7 +579,7 @@ impl HeaderChain { } else { let msg = format!("header of block #{} not found in DB ; database in an \ inconsistent state", h_num); - return Err(Error::Database(msg.into())); + bail!(ErrorKind::Database(msg.into())); }; let decoded = header.decode(); @@ -590,7 +589,7 @@ impl HeaderChain { .ok_or_else(|| { let msg = format!("entry for era #{} not found in DB ; database \ in an inconsistent state", h_num); - Error::Database(msg.into()) + ErrorKind::Database(msg.into()) })?; ::rlp::decode(&bytes) }; @@ -600,7 +599,7 @@ impl HeaderChain { .ok_or_else(|| { let msg = "no candidate matching block found in DB ; database in an \ inconsistent state"; - Error::Database(msg.into()) + ErrorKind::Database(msg.into()) })? .total_difficulty; diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index 1ffe0079c1..9723854b8d 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -80,6 +80,8 @@ extern crate keccak_hash as hash; extern crate triehash; extern crate kvdb; extern crate memory_cache; +#[macro_use] +extern crate error_chain; #[cfg(test)] extern crate kvdb_memorydb; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index bb7f5894b8..6ec318a03f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -49,7 +49,7 @@ use client::{ }; use encoded; use engines::{EthEngine, EpochTransition}; -use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; +use error::{ImportErrorKind, BlockImportErrorKind, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use vm::{EnvInfo, LastHashes}; use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; @@ -1417,11 +1417,11 @@ impl ImportBlock for Client { { if self.chain.read().is_known(&unverified.hash()) { - return Err(BlockImportError::Import(ImportError::AlreadyInChain)); + bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } let status = self.block_status(BlockId::Hash(unverified.parent_hash())); if status == BlockStatus::Unknown || status == BlockStatus::Pending { - return Err(BlockImportError::Block(BlockError::UnknownParent(unverified.parent_hash()))); + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash()))); } } Ok(self.importer.block_queue.import(unverified)?) @@ -1432,11 +1432,11 @@ impl ImportBlock for Client { // check block order let header = view!(BlockView, &block_bytes).header_view(); if self.chain.read().is_known(&header.hash()) { - return Err(BlockImportError::Import(ImportError::AlreadyInChain)); + bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } let status = self.block_status(BlockId::Hash(header.parent_hash())); if status == BlockStatus::Unknown || status == BlockStatus::Pending { - return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash()))); + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(header.parent_hash()))); } } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 8f6b624a5e..1e4ccba585 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -48,7 +48,7 @@ pub use types::call_analytics::CallAnalytics; pub use executive::{Executed, Executive, TransactOptions}; pub use vm::{LastHashes, EnvInfo}; -pub use error::{BlockImportError, TransactionImportError}; +pub use error::{BlockImportError, BlockImportErrorKind, TransactionImportError}; pub use verification::VerifierType; mod traits; diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 013445ba35..387dafd50a 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1339,7 +1339,7 @@ mod tests { use transaction::{Action, Transaction}; use engines::{Seal, Engine, EngineError, EthEngine}; use engines::validator_set::TestSet; - use error::Error; + use error::{Error, ErrorKind}; use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep}; #[test] @@ -1842,7 +1842,7 @@ mod tests { ]); assert!(match engine.verify_block_family(&header, &parent_header) { - Err(Error::Engine(EngineError::InsufficientProof(ref s))) + Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _)) if s.contains("invalid step") => true, _ => false, }); @@ -1856,7 +1856,7 @@ mod tests { ]); assert!(match engine.verify_block_family(&header, &parent_header) { - Err(Error::Engine(EngineError::InsufficientProof(ref s))) + Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _)) if s.contains("invalid empty step proof") => true, _ => false, }); @@ -1871,7 +1871,7 @@ mod tests { ]); assert!(match engine.verify_block_family(&header, &parent_header) { - Err(Error::Engine(EngineError::InsufficientProof(ref s))) + Err(Error(ErrorKind::Engine(EngineError::InsufficientProof(ref s)), _)) if s.contains("invalid empty step proof") => true, _ => false, }); diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 4d22bd1f76..3412c48367 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -37,7 +37,7 @@ pub use self::tendermint::Tendermint; use std::sync::{Weak, Arc}; use std::collections::{BTreeMap, HashMap}; -use std::fmt; +use std::{fmt, error}; use self::epoch::PendingTransition; @@ -102,6 +102,12 @@ impl fmt::Display for EngineError { } } +impl error::Error for EngineError { + fn description(&self) -> &str { + "Engine error" + } +} + /// Seal type. #[derive(Debug, PartialEq, Eq)] pub enum Seal { diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 5021ef9865..289beaad0c 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -768,7 +768,7 @@ mod tests { use ethereum_types::Address; use bytes::Bytes; use block::*; - use error::{Error, BlockError}; + use error::{Error, ErrorKind, BlockError}; use header::Header; use client::ChainInfo; use miner::MinerService; @@ -855,7 +855,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidSealArity(_)), _)) => {}, Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -885,7 +885,7 @@ mod tests { header.set_seal(seal); // Bad proposer. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::NotProposer(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::NotProposer(_)), _)) => {}, _ => panic!(), } @@ -895,7 +895,7 @@ mod tests { header.set_seal(seal); // Not authority. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::NotAuthorized(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::NotAuthorized(_)), _)) => {}, _ => panic!(), }; engine.stop(); @@ -925,7 +925,7 @@ mod tests { // One good signature is not enough. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::BadSealFieldSize(_)), _)) => {}, _ => panic!(), } @@ -945,7 +945,7 @@ mod tests { // One good and one bad signature. match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::NotAuthorized(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::NotAuthorized(_)), _)) => {}, _ => panic!(), }; engine.stop(); @@ -1092,7 +1092,7 @@ mod tests { } else if *s == signature0 { Ok(voter) } else { - Err(Error::Ethkey(EthkeyError::InvalidSignature)) + Err(ErrorKind::Ethkey(EthkeyError::InvalidSignature).into()) } } }, @@ -1100,7 +1100,7 @@ mod tests { // One good signature is not enough. match epoch_verifier.verify_light(&header) { - Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {}, + Err(Error(ErrorKind::Engine(EngineError::BadSealFieldSize(_)), _)) => {}, _ => panic!(), } @@ -1117,7 +1117,7 @@ mod tests { // One good and one bad signature. match epoch_verifier.verify_light(&header) { - Err(Error::Ethkey(EthkeyError::InvalidSignature)) => {}, + Err(Error(ErrorKind::Ethkey(EthkeyError::InvalidSignature), _)) => {}, _ => panic!(), }; diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 4c8157a82f..b68bf35534 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -20,7 +20,7 @@ use std::{fmt, error}; use std::time::SystemTime; use kvdb; use ethereum_types::{H256, U256, Address, Bloom}; -use util_error::UtilError; +use util_error::{self, UtilError}; use snappy::InvalidInput; use unexpected::{Mismatch, OutOfBounds}; use trie::TrieError; @@ -147,45 +147,66 @@ impl fmt::Display for BlockError { } } -#[derive(Debug, Clone, Copy, PartialEq)] -/// Import to the block queue result -pub enum ImportError { - /// Already in the block chain. - AlreadyInChain, - /// Already in the block queue. - AlreadyQueued, - /// Already marked as bad from a previous import (could mean parent is bad). - KnownBad, +impl error::Error for BlockError { + fn description(&self) -> &str { + "Block error" + } } -impl fmt::Display for ImportError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg = match *self { - ImportError::AlreadyInChain => "block already in chain", - ImportError::AlreadyQueued => "block already in the block queue", - ImportError::KnownBad => "block known to be bad", - }; +error_chain! { + types { + ImportError, ImportErrorKind, ImportErrorResultExt, ImportErrorResult; + } + + errors { + #[doc = "Already in the block chain."] + AlreadyInChain { + description("Block already in chain") + display("Block already in chain") + } + + #[doc = "Already in the block queue"] + AlreadyQueued { + description("block already in the block queue") + display("block already in the block queue") + } - f.write_fmt(format_args!("Block import error ({})", msg)) + #[doc = "Already marked as bad from a previous import (could mean parent is bad)."] + KnownBad { + description("block known to be bad") + display("block known to be bad") + } } } -/// Error dedicated to import block function -#[derive(Debug)] -pub enum BlockImportError { - /// Import error - Import(ImportError), - /// Block error - Block(BlockError), - /// Other error - Other(String), + +error_chain! { + types { + BlockImportError, BlockImportErrorKind, BlockImportErrorResultExt; + } + + links { + Import(ImportError, ImportErrorKind) #[doc = "Import error"]; + } + + foreign_links { + Block(BlockError) #[doc = "Block error"]; + } + + errors { + #[doc = "Other error"] + Other(err: String) { + description("Other error") + display("Other error {}", err) + } + } } impl From for BlockImportError { fn from(e: Error) -> Self { match e { - Error::Block(block_error) => BlockImportError::Block(block_error), - Error::Import(import_error) => BlockImportError::Import(import_error), - _ => BlockImportError::Other(format!("other block import error: {:?}", e)), + Error(ErrorKind::Block(block_error), _) => BlockImportErrorKind::Block(block_error).into(), + Error(ErrorKind::Import(import_error), _) => BlockImportErrorKind::Import(import_error.into()).into(), + _ => BlockImportErrorKind::Other(format!("other block import error: {:?}", e)).into(), } } } @@ -202,203 +223,121 @@ pub enum TransactionImportError { impl From for TransactionImportError { fn from(e: Error) -> Self { match e { - Error::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error), + Error(ErrorKind::Transaction(transaction_error), _) => TransactionImportError::Transaction(transaction_error), _ => TransactionImportError::Other(format!("other block import error: {:?}", e)), } } } -#[derive(Debug)] -/// General error type which should be capable of representing all errors in ethcore. -pub enum Error { - /// Client configuration error. - Client(ClientError), - /// Database error. - Database(kvdb::Error), - /// Error concerning a utility. - Util(UtilError), - /// Error concerning block processing. - Block(BlockError), - /// Unknown engine given. - UnknownEngineName(String), - /// Error concerning EVM code execution. - Execution(ExecutionError), - /// Error concerning transaction processing. - Transaction(TransactionError), - /// Error concerning block import. - Import(ImportError), - /// PoW hash is invalid or out of date. - PowHashInvalid, - /// The value of the nonce or mishash is invalid. - PowInvalid, - /// Error concerning TrieDBs - Trie(TrieError), - /// Io crate error. - Io(IoError), - /// Standard io error. - StdIo(::std::io::Error), - /// Snappy error. - Snappy(InvalidInput), - /// Snapshot error. - Snapshot(SnapshotError), - /// Consensus vote error. - Engine(EngineError), - /// Ethkey error. - Ethkey(EthkeyError), - /// Account Provider error. - AccountProvider(AccountsError), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Client(ref err) => err.fmt(f), - Error::Database(ref err) => err.fmt(f), - Error::Util(ref err) => err.fmt(f), - Error::Io(ref err) => err.fmt(f), - Error::Block(ref err) => err.fmt(f), - Error::Execution(ref err) => err.fmt(f), - Error::Transaction(ref err) => err.fmt(f), - Error::Import(ref err) => err.fmt(f), - Error::UnknownEngineName(ref name) => - f.write_fmt(format_args!("Unknown engine name ({})", name)), - Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."), - Error::PowInvalid => f.write_str("Invalid nonce or mishash"), - Error::Trie(ref err) => err.fmt(f), - Error::StdIo(ref err) => err.fmt(f), - Error::Snappy(ref err) => err.fmt(f), - Error::Snapshot(ref err) => err.fmt(f), - Error::Engine(ref err) => err.fmt(f), - Error::Ethkey(ref err) => err.fmt(f), - Error::AccountProvider(ref err) => err.fmt(f), - } +error_chain! { + types { + Error, ErrorKind, ErrorResultExt, EthcoreResult; } -} -impl error::Error for Error { - fn description(&self) -> &str { - // improve description - "ethcore error" + links { + Database(kvdb::Error, kvdb::ErrorKind) #[doc = "Database error."]; + Util(UtilError, util_error::ErrorKind) #[doc = "Error concerning a utility"]; + Import(ImportError, ImportErrorKind) #[doc = "Error concerning block import." ]; } -} - -/// Result of import block operation. -pub type ImportResult = Result; - -impl From for Error { - fn from(err: ClientError) -> Error { - match err { - ClientError::Trie(err) => Error::Trie(err), - _ => Error::Client(err) - } + + foreign_links { + Io(IoError) #[doc = "Io create error"]; + StdIo(::std::io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; + Trie(TrieError) #[doc = "Error concerning TrieDBs."]; + Execution(ExecutionError) #[doc = "Error concerning EVM code execution."]; + Block(BlockError) #[doc = "Error concerning block processing."]; + Transaction(TransactionError) #[doc = "Error concerning transaction processing."]; + Snappy(InvalidInput) #[doc = "Snappy error."]; + Engine(EngineError) #[doc = "Consensus vote error."]; + Ethkey(EthkeyError) #[doc = "Ethkey error."]; } -} -impl From for Error { - fn from(err: kvdb::Error) -> Error { - Error::Database(err) - } -} + errors { + #[doc = "Client configuration error."] + Client(err: ClientError) { + description("Client configuration error.") + display("Client configuration error {}", err) + } -impl From for Error { - fn from(err: TransactionError) -> Error { - Error::Transaction(err) - } -} + #[doc = "Snapshot error."] + Snapshot(err: SnapshotError) { + description("Snapshot error.") + display("Snapshot error {}", err) + } -impl From for Error { - fn from(err: ImportError) -> Error { - Error::Import(err) - } -} + #[doc = "Account Provider error"] + AccountProvider(err: AccountsError) { + description("Accounts Provider error") + display("Accounts Provider error {}", err) + } -impl From for Error { - fn from(err: BlockError) -> Error { - Error::Block(err) - } -} + #[doc = "PoW hash is invalid or out of date."] + PowHashInvalid { + description("PoW hash is invalid or out of date.") + display("PoW hash is invalid or out of date.") + } + + #[doc = "The value of the nonce or mishash is invalid."] + PowInvalid { + description("The value of the nonce or mishash is invalid.") + display("The value of the nonce or mishash is invalid.") + } -impl From for Error { - fn from(err: ExecutionError) -> Error { - Error::Execution(err) + #[doc = "Unknown engine given"] + UnknownEngineName(name: String) { + description("Unknown engine name") + display("Unknown engine name ({})", name) + } } } -impl From<::rlp::DecoderError> for Error { - fn from(err: ::rlp::DecoderError) -> Error { - Error::Util(UtilError::from(err)) - } -} -impl From for Error { - fn from(err: UtilError) -> Error { - Error::Util(err) - } -} +/// Result of import block operation. +pub type ImportResult = EthcoreResult; -impl From for Error { - fn from(err: IoError) -> Error { - Error::Io(err) +impl From for Error { + fn from(err: ClientError) -> Error { + match err { + ClientError::Trie(err) => ErrorKind::Trie(err).into(), + _ => ErrorKind::Client(err).into() + } } } -impl From for Error { - fn from(err: TrieError) -> Error { - Error::Trie(err) - } -} +impl From for Error { + fn from(err: AccountsError) -> Error { + ErrorKind::AccountProvider(err).into() + } +} -impl From<::std::io::Error> for Error { - fn from(err: ::std::io::Error) -> Error { - Error::StdIo(err) +impl From<::rlp::DecoderError> for Error { + fn from(err: ::rlp::DecoderError) -> Error { + UtilError::from(err).into() } } impl From for Error { fn from(err: BlockImportError) -> Error { match err { - BlockImportError::Block(e) => Error::Block(e), - BlockImportError::Import(e) => Error::Import(e), - BlockImportError::Other(s) => Error::Util(UtilError::from(s)), + BlockImportError(BlockImportErrorKind::Block(e), _) => ErrorKind::Block(e).into(), + BlockImportError(BlockImportErrorKind::Import(e), _) => ErrorKind::Import(e).into(), + BlockImportError(BlockImportErrorKind::Other(s), _) => UtilError::from(s).into(), + _ => ErrorKind::Msg(format!("other block import error: {:?}", err)).into(), } } } -impl From<::snappy::InvalidInput> for Error { - fn from(err: ::snappy::InvalidInput) -> Error { - Error::Snappy(err) - } -} - impl From for Error { fn from(err: SnapshotError) -> Error { match err { - SnapshotError::Io(err) => Error::StdIo(err), - SnapshotError::Trie(err) => Error::Trie(err), + SnapshotError::Io(err) => ErrorKind::StdIo(err).into(), + SnapshotError::Trie(err) => ErrorKind::Trie(err).into(), SnapshotError::Decoder(err) => err.into(), - other => Error::Snapshot(other), + other => ErrorKind::Snapshot(other).into(), } } } -impl From for Error { - fn from(err: EngineError) -> Error { - Error::Engine(err) - } -} - -impl From for Error { - fn from(err: EthkeyError) -> Error { - Error::Ethkey(err) - } -} - -impl From for Error { - fn from(err: AccountsError) -> Error { - Error::AccountProvider(err) - } -} - impl From> for Error where Error: From { fn from(err: Box) -> Error { Error::from(*err) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 7d43395286..09e9caf727 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -488,7 +488,7 @@ mod tests { use ethereum_types::{H64, H256, U256, Address}; use block::*; use test_helpers::get_temp_state_db; - use error::{BlockError, Error}; + use error::{BlockError, Error, ErrorKind}; use header::Header; use spec::Spec; use engines::Engine; @@ -640,7 +640,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidSealArity(_)), _)) => {}, Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -655,7 +655,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::DifficultyOutOfBounds(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::DifficultyOutOfBounds(_)), _)) => {}, Err(_) => { panic!("should be block difficulty error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -671,7 +671,7 @@ mod tests { let verify_result = engine.verify_block_basic(&header); match verify_result { - Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidProofOfWork(_)), _)) => {}, Err(_) => { panic!("should be invalid proof of work error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -685,7 +685,7 @@ mod tests { let verify_result = engine.verify_block_unordered(&header); match verify_result { - Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidSealArity(_)), _)) => {}, Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -710,7 +710,7 @@ mod tests { let verify_result = engine.verify_block_unordered(&header); match verify_result { - Err(Error::Block(BlockError::MismatchedH256SealElement(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::MismatchedH256SealElement(_)), _)) => {}, Err(_) => { panic!("should be invalid 256-bit seal fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -726,7 +726,7 @@ mod tests { let verify_result = engine.verify_block_unordered(&header); match verify_result { - Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidProofOfWork(_)), _)) => {}, Err(_) => { panic!("should be invalid proof-of-work fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -741,7 +741,7 @@ mod tests { let verify_result = engine.verify_block_family(&header, &parent_header); match verify_result { - Err(Error::Block(BlockError::RidiculousNumber(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::RidiculousNumber(_)), _)) => {}, Err(_) => { panic!("should be invalid block number fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } @@ -758,7 +758,7 @@ mod tests { let verify_result = engine.verify_block_family(&header, &parent_header); match verify_result { - Err(Error::Block(BlockError::InvalidDifficulty(_))) => {}, + Err(Error(ErrorKind::Block(BlockError::InvalidDifficulty(_)), _)) => {}, Err(_) => { panic!("should be invalid difficulty fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } diff --git a/ethcore/src/executed.rs b/ethcore/src/executed.rs index a787209326..9ffd673154 100644 --- a/ethcore/src/executed.rs +++ b/ethcore/src/executed.rs @@ -24,7 +24,7 @@ use trace::{VMTrace, FlatTrace}; use log_entry::LogEntry; use state_diff::StateDiff; -use std::fmt; +use std::{fmt, error}; /// Transaction execution receipt. #[derive(Debug, PartialEq, Clone)] @@ -148,6 +148,12 @@ impl fmt::Display for ExecutionError { } } +impl error::Error for ExecutionError { + fn description(&self) -> &str { + "Transaction execution error" + } +} + /// Result of executing the transaction. #[derive(PartialEq, Debug, Clone)] pub enum CallError { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 65be24dec0..9bb2e94c1c 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -54,6 +54,10 @@ //! cargo build --release //! ``` +// Recursion limit required because of +// error_chain foreign_links. +#![recursion_limit="128"] + extern crate bloomchain; extern crate bn; extern crate byteorder; @@ -112,6 +116,8 @@ extern crate ethabi_derive; #[macro_use] extern crate ethabi_contract; #[macro_use] +extern crate error_chain; +#[macro_use] extern crate log; #[macro_use] extern crate lazy_static; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index e344ee6b12..76a011343f 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use ansi_term::Colour; use bytes::Bytes; use engines::{EthEngine, Seal}; -use error::{Error, ExecutionError}; +use error::{Error, ErrorKind, ExecutionError}; use ethcore_miner::gas_pricer::GasPricer; use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy}; use ethcore_miner::work_notify::NotifyWork; @@ -393,7 +393,7 @@ impl Miner { // Re-verify transaction again vs current state. let result = client.verify_signed(&transaction) - .map_err(Error::Transaction) + .map_err(|e| e.into()) .and_then(|_| { open_block.push_transaction(transaction, None) }); @@ -411,7 +411,7 @@ impl Miner { debug!(target: "miner", "Adding tx {:?} took {} ms", hash, took_ms(&took)); match result { - Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) => { + Err(Error(ErrorKind::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas }), _)) => { debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?})", hash, gas_limit, gas_used, gas); // Penalize transaction if it's above current gas limit @@ -436,12 +436,12 @@ impl Miner { }, // Invalid nonce error can happen only if previous transaction is skipped because of gas limit. // If there is errornous state of transaction queue it will be fixed when next block is imported. - Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) => { + Err(Error(ErrorKind::Execution(ExecutionError::InvalidNonce { expected, got }), _)) => { debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got); }, // already have transaction - ignore - Err(Error::Transaction(transaction::Error::AlreadyImported)) => {}, - Err(Error::Transaction(transaction::Error::NotAllowed)) => { + Err(Error(ErrorKind::Transaction(transaction::Error::AlreadyImported), _)) => {}, + Err(Error(ErrorKind::Transaction(transaction::Error::NotAllowed), _)) => { not_allowed_transactions.insert(hash); debug!(target: "miner", "Skipping non-allowed transaction for sender {:?}", hash); }, @@ -981,11 +981,11 @@ impl miner::MinerService for Miner { trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal); b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { warn!(target: "miner", "Mined solution rejected: {}", e); - Err(Error::PowInvalid) + Err(ErrorKind::PowInvalid.into()) }) } else { warn!(target: "miner", "Submitted solution rejected: Block unknown or out of date."); - Err(Error::PowHashInvalid) + Err(ErrorKind::PowHashInvalid.into()) }; result.and_then(|sealed| { diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index e41b61e6e0..ae1805e85b 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use std::sync::atomic::AtomicBool; use tempdir::TempDir; -use error::Error; +use error::{Error, ErrorKind}; use blockchain::generator::{BlockGenerator, BlockBuilder}; use blockchain::BlockChain; @@ -141,7 +141,7 @@ fn checks_flag() { let mut rebuilder = SNAPSHOT_MODE.rebuilder(chain, db.clone(), &manifest).unwrap(); match rebuilder.feed(&chunk, engine.as_ref(), &AtomicBool::new(false)) { - Err(Error::Snapshot(SnapshotError::RestorationAborted)) => {} + Err(Error(ErrorKind::Snapshot(SnapshotError::RestorationAborted), _)) => {} _ => panic!("Wrong result on abort flag set") } } diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index f61c799933..f17fa7dde5 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -26,7 +26,7 @@ use snapshot::{chunk_state, Error as SnapshotError, Progress, StateRebuilder}; use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; use super::helpers::{compare_dbs, StateProducer}; -use error::Error; +use error::{Error, ErrorKind}; use rand::{XorShiftRng, SeedableRng}; use ethereum_types::H256; @@ -189,7 +189,7 @@ fn checks_flag() { let chunk = ::snappy::decompress(&raw).unwrap(); match rebuilder.feed(&chunk, &flag) { - Err(Error::Snapshot(SnapshotError::RestorationAborted)) => {}, + Err(Error(ErrorKind::Snapshot(SnapshotError::RestorationAborted), _)) => {}, _ => panic!("unexpected result when feeding with flag off"), } } diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index 223de30f75..7007da5be1 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -69,7 +69,7 @@ pub mod blocks { use super::{Kind, BlockLike}; use engines::EthEngine; - use error::{Error, BlockError}; + use error::{Error, ErrorKind, BlockError}; use header::Header; use verification::{PreverifiedBlock, verify_block_basic, verify_block_unordered}; @@ -88,7 +88,7 @@ pub mod blocks { fn create(input: Self::Input, engine: &EthEngine) -> Result { match verify_block_basic(&input.header, &input.bytes, engine) { Ok(()) => Ok(input), - Err(Error::Block(BlockError::TemporarilyInvalid(oob))) => { + Err(Error(ErrorKind::Block(BlockError::TemporarilyInvalid(oob)), _)) => { debug!(target: "client", "Block received too early {}: {:?}", input.hash(), oob); Err(BlockError::TemporarilyInvalid(oob).into()) }, diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index d50bd1cb34..ca633b0f3d 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -472,17 +472,17 @@ impl VerificationQueue { let h = input.hash(); { if self.processing.read().contains_key(&h) { - return Err(ImportError::AlreadyQueued.into()); + bail!(ErrorKind::Import(ImportErrorKind::AlreadyQueued)); } let mut bad = self.verification.bad.lock(); if bad.contains(&h) { - return Err(ImportError::KnownBad.into()); + bail!(ErrorKind::Import(ImportErrorKind::KnownBad)); } if bad.contains(&input.parent_hash()) { bad.insert(h.clone()); - return Err(ImportError::KnownBad.into()); + bail!(ErrorKind::Import(ImportErrorKind::KnownBad)); } } @@ -502,7 +502,7 @@ impl VerificationQueue { Err(err) => { match err { // Don't mark future blocks as bad. - Error::Block(BlockError::TemporarilyInvalid(_)) => {}, + Error(ErrorKind::Block(BlockError::TemporarilyInvalid(_)), _) => {}, _ => { self.verification.bad.lock().insert(h.clone()); } @@ -773,7 +773,7 @@ mod tests { match duplicate_import { Err(e) => { match e { - Error::Import(ImportError::AlreadyQueued) => {}, + Error(ErrorKind::Import(ImportErrorKind::AlreadyQueued), _) => {}, _ => { panic!("must return AlreadyQueued error"); } } } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index d0bfcc0c7c..814a12aadf 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -358,6 +358,7 @@ mod tests { use hash::keccak; use engines::EthEngine; use error::BlockError::*; + use error::ErrorKind; use ethkey::{Random, Generator}; use spec::{CommonParams, Spec}; use test_helpers::{create_test_block_with_data, create_test_block}; @@ -372,7 +373,7 @@ mod tests { fn check_fail(result: Result<(), Error>, e: BlockError) { match result { - Err(Error::Block(ref error)) if *error == e => (), + Err(Error(ErrorKind::Block(ref error), _)) if *error == e => (), Err(other) => panic!("Block verification failed.\nExpected: {:?}\nGot: {:?}", e, other), Ok(_) => panic!("Block verification failed.\nExpected: {:?}\nGot: Ok", e), } @@ -381,8 +382,8 @@ mod tests { fn check_fail_timestamp(result: Result<(), Error>, temp: bool) { let name = if temp { "TemporarilyInvalid" } else { "InvalidTimestamp" }; match result { - Err(Error::Block(BlockError::InvalidTimestamp(_))) if !temp => (), - Err(Error::Block(BlockError::TemporarilyInvalid(_))) if temp => (), + Err(Error(ErrorKind::Block(BlockError::InvalidTimestamp(_)), _)) if !temp => (), + Err(Error(ErrorKind::Block(BlockError::TemporarilyInvalid(_)), _)) if temp => (), Err(other) => panic!("Block verification failed.\nExpected: {}\nGot: {:?}", name, other), Ok(_) => panic!("Block verification failed.\nExpected: {}\nGot: Ok", name), } @@ -716,7 +717,7 @@ mod tests { header.set_gas_limit(0.into()); header.set_difficulty("0000000000000000000000000000000000000000000000000000000000020000".parse::().unwrap()); match family_test(&create_test_block(&header), engine, &bc) { - Err(Error::Block(InvalidGasLimit(_))) => {}, + Err(Error(ErrorKind::Block(InvalidGasLimit(_)), _)) => {}, Err(_) => { panic!("should be invalid difficulty fail"); }, _ => { panic!("Should be error, got Ok"); }, } diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index f7626b0efd..4a5acae526 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -25,9 +25,9 @@ use ethereum_types::H256; use rlp::Rlp; use ethcore::views::BlockView; use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockStatus, BlockId, BlockImportError}; +use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind}; use ethcore::block::Block; -use ethcore::error::{ImportError, BlockError}; +use ethcore::error::{ImportErrorKind, BlockError}; use sync_io::SyncIo; use blocks::BlockCollection; @@ -502,11 +502,11 @@ impl BlockDownloader { }; match result { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!(target: "sync", "Block already in chain {:?}", h); self.block_imported(&h, number, &parent); }, - Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { trace!(target: "sync", "Block already queued {:?}", h); self.block_imported(&h, number, &parent); }, @@ -515,14 +515,14 @@ impl BlockDownloader { imported.insert(h.clone()); self.block_imported(&h, number, &parent); }, - Err(BlockImportError::Block(BlockError::UnknownParent(_))) if allow_out_of_order => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(_)), _)) if allow_out_of_order => { break; }, - Err(BlockImportError::Block(BlockError::UnknownParent(_))) => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(_)), _)) => { trace!(target: "sync", "Unknown new block parent, restarting sync"); break; }, - Err(BlockImportError::Block(BlockError::TemporarilyInvalid(_))) => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::TemporarilyInvalid(_)), _)) => { debug!(target: "sync", "Block temporarily invalid, restarting sync"); break; }, diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index bc8e35ed49..eaab13b6f4 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -101,7 +101,7 @@ use bytes::Bytes; use rlp::{Rlp, RlpStream, DecoderError, Encodable}; use network::{self, PeerId, PacketId}; use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo}; +use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockImportErrorKind, BlockQueueInfo}; use ethcore::error::*; use ethcore::snapshot::{ManifestData, RestorationStatus}; use transaction::SignedTransaction; @@ -943,10 +943,10 @@ impl ChainSync { return Ok(()); } match io.chain().import_block(block_rlp.as_raw().to_vec()) { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!(target: "sync", "New block already in chain {:?}", h); }, - Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { @@ -955,7 +955,7 @@ impl ChainSync { self.new_blocks.mark_as_known(&header.hash(), header.number()); trace!(target: "sync", "New block queued {:?} ({})", h, header.number()); }, - Err(BlockImportError::Block(BlockError::UnknownParent(p))) => { + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => { unknown = true; trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); }, diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index 0f6660e179..9fa669817a 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -427,7 +427,7 @@ impl LightSync { // handles request dispatch, block import, state machine transitions, and timeouts. fn maintain_sync(&self, ctx: &BasicContext) { - use ethcore::error::{BlockImportError, ImportError}; + use ethcore::error::{BlockImportError, BlockImportErrorKind, ImportErrorKind}; const DRAIN_AMOUNT: usize = 128; @@ -457,10 +457,10 @@ impl LightSync { for header in sink.drain(..) { match client.queue_header(header) { Ok(_) => {} - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!(target: "sync", "Block already in chain. Continuing."); }, - Err(BlockImportError::Import(ImportError::AlreadyQueued)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { trace!(target: "sync", "Block already queued. Continuing."); }, Err(e) => { diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index 4578b88acd..e38dc3ac67 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; +use std::{fmt, error}; use ethereum_types::U256; use ethkey; @@ -112,3 +112,9 @@ impl fmt::Display for Error { } } +impl error::Error for Error { + fn description(&self) -> &str { + "Transaction error" + } +} + diff --git a/ethkey/src/error.rs b/ethkey/src/error.rs index 0ac2d221a9..c7faf67788 100644 --- a/ethkey/src/error.rs +++ b/ethkey/src/error.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; +use std::{fmt, error}; #[derive(Debug)] /// Crypto error @@ -51,6 +51,12 @@ impl fmt::Display for Error { } } +impl error::Error for Error { + fn description(&self) -> &str { + "Crypto error" + } +} + impl Into for Error { fn into(self) -> String { format!("{}", self) diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 439f13ba39..f9c2f8ba37 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -27,7 +27,7 @@ use bytes::ToPretty; use rlp::PayloadInfo; use ethcore::account_provider::AccountProvider; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock}; -use ethcore::error::ImportError; +use ethcore::error::{ImportErrorKind, BlockImportErrorKind}; use ethcore::miner::Miner; use ethcore::verification::queue::VerifierSettings; use ethcore_service::ClientService; @@ -257,7 +257,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { } match client.import_header(header) { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!("Skipping block already in chain."); } Err(e) => { @@ -428,7 +428,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { let do_import = |bytes| { while client.queue_info().is_full() { sleep(Duration::from_secs(1)); } match client.import_block(bytes) { - Err(BlockImportError::Import(ImportError::AlreadyInChain)) => { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { trace!("Skipping block already in chain."); } Err(e) => { diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index aa660efc9c..4e5fa2fb72 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -19,7 +19,7 @@ use std::fmt; use ethcore::account_provider::{SignError as AccountError}; -use ethcore::error::{Error as EthcoreError, CallError}; +use ethcore::error::{Error as EthcoreError, ErrorKind, CallError}; use jsonrpc_core::{futures, Error, ErrorCode, Value}; use rlp::DecoderError; use transaction::Error as TransactionError; @@ -306,10 +306,10 @@ pub fn private_message_block_id_not_supported() -> Error { } } -pub fn transaction_message(error: TransactionError) -> String { +pub fn transaction_message(error: &TransactionError) -> String { use self::TransactionError::*; - match error { + match *error { AlreadyImported => "Transaction with the same hash was already imported.".into(), Old => "Transaction nonce is too low. Try incrementing the nonce.".into(), TooCheapToReplace => { @@ -330,7 +330,7 @@ pub fn transaction_message(error: TransactionError) -> String { GasLimitExceeded { limit, got } => { format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) }, - InvalidSignature(sig) => format!("Invalid signature: {}", sig), + InvalidSignature(ref sig) => format!("Invalid signature: {}", sig), InvalidChainId => "Invalid chain id.".into(), InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), SenderBanned => "Sender is banned in local queue.".into(), @@ -342,7 +342,7 @@ pub fn transaction_message(error: TransactionError) -> String { pub fn transaction>(error: T) -> Error { let error = error.into(); - if let EthcoreError::Transaction(e) = error { + if let ErrorKind::Transaction(ref e) = *error.kind() { Error { code: ErrorCode::ServerError(codes::TRANSACTION_ERROR), message: transaction_message(e), -- GitLab From 8fb47b52f549505ef293985d3afbec216e3f008e Mon Sep 17 00:00:00 2001 From: lihuafeng <31607114+EighteenZi@users.noreply.github.com> Date: Thu, 19 Apr 2018 19:16:04 +0800 Subject: [PATCH 086/263] remove From::from. (#8390) * Some tiny modifications. 1. fix some typo in the comment. 2. sort the order of methods in 'impl state::Backend for StateDB` * Remove the clone of code_cache, as it has been done in clone_basic. * remove From::from. It seems not necessary. --- ethcore/src/executive.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) mode change 100644 => 100755 ethcore/src/executive.rs diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs old mode 100644 new mode 100755 index a97ee37081..142086beb9 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -237,27 +237,27 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let base_gas_required = U256::from(t.gas_required(&schedule)); if t.gas < base_gas_required { - return Err(From::from(ExecutionError::NotEnoughBaseGas { required: base_gas_required, got: t.gas })); + return Err(ExecutionError::NotEnoughBaseGas { required: base_gas_required, got: t.gas }); } if !t.is_unsigned() && check_nonce && schedule.kill_dust != CleanDustMode::Off && !self.state.exists(&sender)? { - return Err(From::from(ExecutionError::SenderMustExist)); + return Err(ExecutionError::SenderMustExist); } let init_gas = t.gas - base_gas_required; // validate transaction nonce if check_nonce && t.nonce != nonce { - return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); + return Err(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }); } // validate if transaction fits into given block if self.info.gas_used + t.gas > self.info.gas_limit { - return Err(From::from(ExecutionError::BlockGasLimitReached { + return Err(ExecutionError::BlockGasLimitReached { gas_limit: self.info.gas_limit, gas_used: self.info.gas_used, gas: t.gas - })); + }); } // TODO: we might need bigints here, or at least check overflows. @@ -268,7 +268,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { // avoid unaffordable transactions let balance512 = U512::from(balance); if balance512 < total_cost { - return Err(From::from(ExecutionError::NotEnoughCash { required: total_cost, got: balance512 })); + return Err(ExecutionError::NotEnoughCash { required: total_cost, got: balance512 }); } let mut substate = Substate::new(); -- GitLab From 92b5b5644f817f492ebff38c6b7e636cf11be67c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 20 Apr 2018 16:38:30 +0800 Subject: [PATCH 087/263] Use forked app_dirs crate for reverted Windows dir behavior (#8438) * Remove unused appdirs dependency in CLI * Use forked app_dirs crate for reverted Windows dir behavior --- Cargo.lock | 7 +++---- Cargo.toml | 1 - parity/main.rs | 1 - util/dir/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72c163e4d8..fd37230460 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,7 +19,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "app_dirs" version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/paritytech/app-dirs-rs#0b37f9481ce29e9d5174ad185bca695b206368eb" dependencies = [ "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -379,7 +379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "dir" version = "0.1.0" dependencies = [ - "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", ] @@ -1943,7 +1943,6 @@ name = "parity" version = "1.11.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)", @@ -3766,7 +3765,7 @@ dependencies = [ "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" -"checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" +"checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" diff --git a/Cargo.toml b/Cargo.toml index 9daf4fb558..4237bf545f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,6 @@ toml = "0.4" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" -app_dirs = "1.2.1" futures = "0.1" futures-cpupool = "0.1" fdlimit = "0.1" diff --git a/parity/main.rs b/parity/main.rs index 24b53ae2c9..705cf777e7 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -19,7 +19,6 @@ #![warn(missing_docs)] extern crate ansi_term; -extern crate app_dirs; extern crate ctrlc; extern crate docopt; #[macro_use] diff --git a/util/dir/Cargo.toml b/util/dir/Cargo.toml index 5963833a7e..e1a13401a2 100644 --- a/util/dir/Cargo.toml +++ b/util/dir/Cargo.toml @@ -6,4 +6,4 @@ authors = ["Parity Technologies "] [dependencies] ethereum-types = "0.3" journaldb = { path = "../journaldb" } -app_dirs = "1.2.1" +app_dirs = { git = "https://github.com/paritytech/app-dirs-rs" } -- GitLab From 9c5e35548de8e05c8533fa03e9d889456b71ad1c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 20 Apr 2018 18:22:19 +0800 Subject: [PATCH 088/263] Permission fix (#8441) --- ethcore/src/account_provider/mod.rs | 0 ethcore/src/executive.rs | 0 ethcore/src/state/account.rs | 0 ethcore/src/state/mod.rs | 0 ethcore/src/state_db.rs | 0 ethstore/Cargo.toml | 0 ethstore/src/account/crypto.rs | 0 ethstore/src/account/mod.rs | 0 ethstore/src/account/safe_account.rs | 0 ethstore/src/accounts_dir/disk.rs | 0 ethstore/src/accounts_dir/mod.rs | 0 ethstore/src/accounts_dir/vault.rs | 0 ethstore/src/error.rs | 0 ethstore/src/ethstore.rs | 0 ethstore/src/json/vault_file.rs | 0 ethstore/src/json/vault_key_file.rs | 0 ethstore/src/lib.rs | 0 ethstore/src/secret_store.rs | 0 ethstore/tests/api.rs | 0 ethstore/tests/util/transient_dir.rs | 0 20 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 ethcore/src/account_provider/mod.rs mode change 100755 => 100644 ethcore/src/executive.rs mode change 100755 => 100644 ethcore/src/state/account.rs mode change 100755 => 100644 ethcore/src/state/mod.rs mode change 100755 => 100644 ethcore/src/state_db.rs mode change 100755 => 100644 ethstore/Cargo.toml mode change 100755 => 100644 ethstore/src/account/crypto.rs mode change 100755 => 100644 ethstore/src/account/mod.rs mode change 100755 => 100644 ethstore/src/account/safe_account.rs mode change 100755 => 100644 ethstore/src/accounts_dir/disk.rs mode change 100755 => 100644 ethstore/src/accounts_dir/mod.rs mode change 100755 => 100644 ethstore/src/accounts_dir/vault.rs mode change 100755 => 100644 ethstore/src/error.rs mode change 100755 => 100644 ethstore/src/ethstore.rs mode change 100755 => 100644 ethstore/src/json/vault_file.rs mode change 100755 => 100644 ethstore/src/json/vault_key_file.rs mode change 100755 => 100644 ethstore/src/lib.rs mode change 100755 => 100644 ethstore/src/secret_store.rs mode change 100755 => 100644 ethstore/tests/api.rs mode change 100755 => 100644 ethstore/tests/util/transient_dir.rs diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs old mode 100755 new mode 100644 diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs old mode 100755 new mode 100644 diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml old mode 100755 new mode 100644 diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/account/mod.rs b/ethstore/src/account/mod.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/accounts_dir/disk.rs b/ethstore/src/accounts_dir/disk.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/accounts_dir/mod.rs b/ethstore/src/accounts_dir/mod.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/accounts_dir/vault.rs b/ethstore/src/accounts_dir/vault.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/error.rs b/ethstore/src/error.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/json/vault_file.rs b/ethstore/src/json/vault_file.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/json/vault_key_file.rs b/ethstore/src/json/vault_key_file.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs old mode 100755 new mode 100644 diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs old mode 100755 new mode 100644 diff --git a/ethstore/tests/api.rs b/ethstore/tests/api.rs old mode 100755 new mode 100644 diff --git a/ethstore/tests/util/transient_dir.rs b/ethstore/tests/util/transient_dir.rs old mode 100755 new mode 100644 -- GitLab From 24f6d8296b56e85d17ba246a96bc31732a97a309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 20 Apr 2018 11:32:00 +0100 Subject: [PATCH 089/263] Block reward contract (#8419) * engine: add block reward contract abi and helper client * aura: add support for block reward contract * engine: test block reward contract client * aura: test block reward contract * engine + aura: add missing docs * engine: share SystemCall type alias * aura: add transition for block reward contract * engine: fix example block reward contract source link and bytecode --- Cargo.lock | 18 +- ...authority_round_block_reward_contract.json | 61 ++++++ ethcore/res/contracts/block_reward.json | 29 +++ ethcore/src/engines/authority_round/mod.rs | 117 ++++++++++- ethcore/src/engines/block_reward.rs | 184 ++++++++++++++++++ ethcore/src/engines/mod.rs | 6 +- ethcore/src/engines/validator_set/mod.rs | 4 +- ethcore/src/spec/spec.rs | 7 + json/src/spec/authority_round.rs | 8 + 9 files changed, 412 insertions(+), 22 deletions(-) create mode 100644 ethcore/res/authority_round_block_reward_contract.json create mode 100644 ethcore/res/contracts/block_reward.json create mode 100644 ethcore/src/engines/block_reward.rs diff --git a/Cargo.lock b/Cargo.lock index fd37230460..547c3c88bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,7 +462,7 @@ dependencies = [ [[package]] name = "ethabi-contract" -version = "5.0.3" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -514,7 +514,7 @@ dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.11.0", "ethcore-bloom-journal 0.1.0", @@ -745,7 +745,7 @@ version = "1.0.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", @@ -780,7 +780,7 @@ version = "1.0.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", @@ -1786,7 +1786,7 @@ name = "node-filter" version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-io 1.11.0", @@ -2084,7 +2084,7 @@ name = "parity-hash-fetch" version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2305,7 +2305,7 @@ name = "parity-updater" version = "1.11.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.11.0", "ethcore-bytes 0.1.0", @@ -2708,7 +2708,7 @@ name = "registrar" version = "0.0.1" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -3815,7 +3815,7 @@ dependencies = [ "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "" "checksum ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05e33a914b94b763f0a92333e4e5c95c095563f06ef7d6b295b3d3c2cf31e21f" -"checksum ethabi-contract 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca2263c24359e827348ac99aa1f2e28ba5bab0d6c0b83941fa252de8a9e9c073" +"checksum ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "210c9e21d164c15b6ef64fe601e0e12a3c84a031d5ef558e38463e53edbd22ed" "checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" "checksum ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3ae691a36ce5d25b433e63128ce5579f4a18457b6a9c849832b2c9e0fec92a" diff --git a/ethcore/res/authority_round_block_reward_contract.json b/ethcore/res/authority_round_block_reward_contract.json new file mode 100644 index 0000000000..e008de117f --- /dev/null +++ b/ethcore/res/authority_round_block_reward_contract.json @@ -0,0 +1,61 @@ +{ + "name": "TestAuthorityRoundBlockRewardContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "list": [ + "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e", + "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1" + ] + }, + "immediateTransitions": true, + "emptyStepsTransition": "1", + "maximumEmptySteps": "2", + "blockRewardContractAddress": "0x0000000000000000000000000000000000000042" + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "eip140Transition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0" + }, + "genesis": { + "seal": { + "authorityRound": { + "step": "0x0", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, + "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }, + "0000000000000000000000000000000000000042": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029" + } + } +} diff --git a/ethcore/res/contracts/block_reward.json b/ethcore/res/contracts/block_reward.json new file mode 100644 index 0000000000..9209967f3a --- /dev/null +++ b/ethcore/res/contracts/block_reward.json @@ -0,0 +1,29 @@ +[ + { + "constant": false, + "inputs": [ + { + "name": "benefactors", + "type": "address[]" + }, + { + "name": "kind", + "type": "uint16[]" + } + ], + "name": "reward", + "outputs": [ + { + "name": "", + "type": "address[]" + }, + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 387dafd50a..4807d6c3fb 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -27,6 +27,8 @@ use account_provider::AccountProvider; use block::*; use client::EngineClient; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; +use engines::block_reward; +use engines::block_reward::{BlockRewardContract, RewardKind}; use error::{Error, BlockError}; use ethjson; use machine::{AuxiliaryData, Call, EthereumMachine}; @@ -68,6 +70,10 @@ pub struct AuthorityRoundParams { pub immediate_transitions: bool, /// Block reward in base units. pub block_reward: U256, + /// Block reward contract transition block. + pub block_reward_contract_transition: u64, + /// Block reward contract. + pub block_reward_contract: Option, /// Number of accepted uncles transition block. pub maximum_uncle_count_transition: u64, /// Number of accepted uncles. @@ -95,6 +101,8 @@ impl From for AuthorityRoundParams { validate_step_transition: p.validate_step_transition.map_or(0, Into::into), immediate_transitions: p.immediate_transitions.unwrap_or(false), block_reward: p.block_reward.map_or_else(Default::default, Into::into), + block_reward_contract_transition: p.block_reward_contract_transition.map_or(0, Into::into), + block_reward_contract: p.block_reward_contract_address.map(BlockRewardContract::new), maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into), maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into), empty_steps_transition: p.empty_steps_transition.map_or(u64::max_value(), |n| ::std::cmp::max(n.into(), 1)), @@ -388,6 +396,8 @@ pub struct AuthorityRound { epoch_manager: Mutex, immediate_transitions: bool, block_reward: U256, + block_reward_contract_transition: u64, + block_reward_contract: Option, maximum_uncle_count_transition: u64, maximum_uncle_count: usize, empty_steps_transition: u64, @@ -620,6 +630,8 @@ impl AuthorityRound { epoch_manager: Mutex::new(EpochManager::blank()), immediate_transitions: our_params.immediate_transitions, block_reward: our_params.block_reward, + block_reward_contract_transition: our_params.block_reward_contract_transition, + block_reward_contract: our_params.block_reward_contract, maximum_uncle_count_transition: our_params.maximum_uncle_count_transition, maximum_uncle_count: our_params.maximum_uncle_count, empty_steps_transition: our_params.empty_steps_transition, @@ -970,9 +982,7 @@ impl Engine for AuthorityRound { /// Apply the block reward on finalisation of the block. fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { - use parity_machine::WithBalances; - - let mut rewards = Vec::new(); + let mut benefactors = Vec::new(); if block.header().number() >= self.empty_steps_transition { let empty_steps = if block.header().seal().is_empty() { // this is a new block, calculate rewards based on the empty steps messages we have accumulated @@ -998,17 +1008,33 @@ impl Engine for AuthorityRound { for empty_step in empty_steps { let author = empty_step.author()?; - rewards.push((author, self.block_reward)); + benefactors.push((author, RewardKind::EmptyStep)); } } let author = *block.header().author(); - rewards.push((author, self.block_reward)); + benefactors.push((author, RewardKind::Author)); + + let rewards = match self.block_reward_contract { + Some(ref c) if block.header().number() >= self.block_reward_contract_transition => { + let mut call = |to, data| { + let result = self.machine.execute_as_system( + block, + to, + U256::max_value(), // unbounded gas? maybe make configurable. + Some(data), + ); + result.map_err(|e| format!("{}", e)) + }; - for &(ref author, ref block_reward) in rewards.iter() { - self.machine.add_balance(block, author, block_reward)?; - } - self.machine.note_rewards(block, &rewards, &[]) + c.reward(&benefactors, &mut call)? + }, + _ => { + benefactors.into_iter().map(|(author, _)| (author, self.block_reward)).collect() + }, + }; + + block_reward::apply_block_rewards(&rewards, block, &self.machine) } /// Check the number of seal fields. @@ -1521,6 +1547,8 @@ mod tests { empty_steps_transition: u64::max_value(), maximum_empty_steps: 0, block_reward: Default::default(), + block_reward_contract_transition: 0, + block_reward_contract: Default::default(), }; let aura = { @@ -1563,6 +1591,8 @@ mod tests { empty_steps_transition: u64::max_value(), maximum_empty_steps: 0, block_reward: Default::default(), + block_reward_contract_transition: 0, + block_reward_contract: Default::default(), }; let aura = { @@ -1617,6 +1647,8 @@ mod tests { empty_steps_transition: u64::max_value(), maximum_empty_steps: 0, block_reward: Default::default(), + block_reward_contract_transition: 0, + block_reward_contract: Default::default(), }; let mut c_params = ::spec::CommonParams::default(); @@ -1894,4 +1926,71 @@ mod tests { _ => false, }); } + + #[test] + fn block_reward_contract() { + let spec = Spec::new_test_round_block_reward_contract(); + let tap = Arc::new(AccountProvider::transient_provider()); + + let addr1 = tap.insert_account(keccak("1").into(), "1").unwrap(); + + let engine = &*spec.engine; + let genesis_header = spec.genesis_header(); + let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); + let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); + + let last_hashes = Arc::new(vec![genesis_header.hash()]); + + let client = generate_dummy_client_with_spec_and_accounts( + Spec::new_test_round_block_reward_contract, + None, + ); + engine.register_client(Arc::downgrade(&client) as _); + + // step 2 + let b1 = OpenBlock::new( + engine, + Default::default(), + false, + db1, + &genesis_header, + last_hashes.clone(), + addr1, + (3141562.into(), 31415620.into()), + vec![], + false, + ).unwrap(); + let b1 = b1.close_and_lock(); + + // since the block is empty it isn't sealed and we generate empty steps + engine.set_signer(tap.clone(), addr1, "1".into()); + assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None); + engine.step(); + + // step 3 + // the signer of the accumulated empty step message should be rewarded + let b2 = OpenBlock::new( + engine, + Default::default(), + false, + db2, + &genesis_header, + last_hashes.clone(), + addr1, + (3141562.into(), 31415620.into()), + vec![], + false, + ).unwrap(); + let addr1_balance = b2.block().state().balance(&addr1).unwrap(); + + // after closing the block `addr1` should be reward twice, one for the included empty step + // message and another for block creation + let b2 = b2.close_and_lock(); + + // the contract rewards (1000 + kind) for each benefactor/reward kind + assert_eq!( + b2.block().state().balance(&addr1).unwrap(), + addr1_balance + (1000 + 0).into() + (1000 + 2).into(), + ) + } } diff --git a/ethcore/src/engines/block_reward.rs b/ethcore/src/engines/block_reward.rs new file mode 100644 index 0000000000..510a5255f5 --- /dev/null +++ b/ethcore/src/engines/block_reward.rs @@ -0,0 +1,184 @@ +// Copyright 2015-2018 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 . + +use ethabi; +use ethabi::ParamType; +use ethereum_types::{H160, Address, U256}; + +use block::ExecutedBlock; +use error::Error; +use machine::EthereumMachine; +use super::SystemCall; + +use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json"); + +/// The kind of block reward. +/// Depending on the consensus engine the allocated block reward might have +/// different semantics which could lead e.g. to different reward values. +#[repr(u8)] +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum RewardKind { + /// Reward attributed to the block author. + Author = 0, + /// Reward attributed to the block uncle(s). + Uncle = 1, + /// Reward attributed to the author(s) of empty step(s) included in the block (AuthorityRound engine). + EmptyStep = 2, +} + +impl From for u16 { + fn from(reward_kind: RewardKind) -> Self { + reward_kind as u16 + } +} + +/// A client for the block reward contract. +pub struct BlockRewardContract { + /// Address of the contract. + address: Address, + block_reward_contract: block_reward_contract::BlockReward, +} + +impl BlockRewardContract { + /// Create a new block reward contract client targeting the given address. + pub fn new(address: Address) -> BlockRewardContract { + BlockRewardContract { + address, + block_reward_contract: block_reward_contract::BlockReward::default(), + } + } + + /// Calls the block reward contract with the given benefactors list (and associated reward kind) + /// and returns the reward allocation (address - value). The block reward contract *must* be + /// called by the system address so the `caller` must ensure that (e.g. using + /// `machine.execute_as_system`). + pub fn reward( + &self, + benefactors: &[(Address, RewardKind)], + caller: &mut SystemCall, + ) -> Result, Error> { + let reward = self.block_reward_contract.functions().reward(); + + let input = reward.input( + benefactors.iter().map(|&(address, _)| H160::from(address)), + benefactors.iter().map(|&(_, ref reward_kind)| u16::from(*reward_kind)), + ); + + let output = caller(self.address, input) + .map_err(Into::into) + .map_err(::engines::EngineError::FailedSystemCall)?; + + // since this is a non-constant call we can't use ethabi's function output + // deserialization, sadness ensues. + let types = &[ + ParamType::Array(Box::new(ParamType::Address)), + ParamType::Array(Box::new(ParamType::Uint(256))), + ]; + + let tokens = ethabi::decode(types, &output) + .map_err(|err| err.to_string()) + .map_err(::engines::EngineError::FailedSystemCall)?; + + assert!(tokens.len() == 2); + + let addresses = tokens[0].clone().to_array().expect("type checked by ethabi::decode; qed"); + let rewards = tokens[1].clone().to_array().expect("type checked by ethabi::decode; qed"); + + if addresses.len() != rewards.len() { + return Err(::engines::EngineError::FailedSystemCall( + "invalid data returned by reward contract: both arrays must have the same size".into() + ).into()); + } + + let addresses = addresses.into_iter().map(|t| t.to_address().expect("type checked by ethabi::decode; qed")); + let rewards = rewards.into_iter().map(|t| t.to_uint().expect("type checked by ethabi::decode; qed")); + + Ok(addresses.zip(rewards).collect()) + } +} + +/// Applies the given block rewards, i.e. adds the given balance to each benefactors' address. +/// If tracing is enabled the operations are recorded. +pub fn apply_block_rewards(rewards: &[(Address, U256)], block: &mut ExecutedBlock, machine: &EthereumMachine) -> Result<(), Error> { + use parity_machine::WithBalances; + + for &(ref author, ref block_reward) in rewards { + machine.add_balance(block, author, block_reward)?; + } + + machine.note_rewards(block, &rewards, &[]) +} + +#[cfg(test)] +mod test { + use client::PrepareOpenBlock; + use ethereum_types::U256; + use spec::Spec; + use test_helpers::generate_dummy_client_with_spec_and_accounts; + + use super::{BlockRewardContract, RewardKind}; + + #[test] + fn block_reward_contract() { + let client = generate_dummy_client_with_spec_and_accounts( + Spec::new_test_round_block_reward_contract, + None, + ); + + let machine = Spec::new_test_machine(); + + // the spec has a block reward contract defined at the given address + let block_reward_contract = BlockRewardContract::new( + "0000000000000000000000000000000000000042".into(), + ); + + let mut call = |to, data| { + let mut block = client.prepare_open_block( + "0000000000000000000000000000000000000001".into(), + (3141562.into(), 31415620.into()), + vec![], + ); + + let result = machine.execute_as_system( + block.block_mut(), + to, + U256::max_value(), + Some(data), + ); + + result.map_err(|e| format!("{}", e)) + }; + + // if no benefactors are given no rewards are attributed + assert!(block_reward_contract.reward(&vec![], &mut call).unwrap().is_empty()); + + // the contract rewards (1000 + kind) for each benefactor + let benefactors = vec![ + ("0000000000000000000000000000000000000033".into(), RewardKind::Author), + ("0000000000000000000000000000000000000034".into(), RewardKind::Uncle), + ("0000000000000000000000000000000000000035".into(), RewardKind::EmptyStep), + ]; + + let rewards = block_reward_contract.reward(&benefactors, &mut call).unwrap(); + let expected = vec![ + ("0000000000000000000000000000000000000033".into(), U256::from(1000)), + ("0000000000000000000000000000000000000034".into(), U256::from(1000 + 1)), + ("0000000000000000000000000000000000000035".into(), U256::from(1000 + 2)), + ]; + + assert_eq!(expected, rewards); + } +} diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 3412c48367..8556879f95 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -18,6 +18,7 @@ mod authority_round; mod basic_authority; +mod block_reward; mod instant_seal; mod null_engine; mod signer; @@ -56,7 +57,7 @@ use ethereum_types::{H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; use bytes::Bytes; -/// Default EIP-210 contrat code. +/// Default EIP-210 contract code. /// As defined in https://github.com/ethereum/EIPs/pull/210 pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b"; @@ -119,6 +120,9 @@ pub enum Seal { None, } +/// A system-calling closure. Enacts calls on a block's state from the system address. +pub type SystemCall<'a> = FnMut(Address, Vec) -> Result, String> + 'a; + /// Type alias for a function we can get headers by hash through. pub type Headers<'a, H> = Fn(H256) -> Option + 'a; diff --git a/ethcore/src/engines/validator_set/mod.rs b/ethcore/src/engines/validator_set/mod.rs index de2164f918..d439c69c2e 100644 --- a/ethcore/src/engines/validator_set/mod.rs +++ b/ethcore/src/engines/validator_set/mod.rs @@ -38,9 +38,7 @@ pub use self::simple_list::SimpleList; use self::contract::ValidatorContract; use self::safe_contract::ValidatorSafeContract; use self::multi::Multi; - -/// A system-calling closure. Enacts calls on a block's state from the system address. -pub type SystemCall<'a> = FnMut(Address, Bytes) -> Result + 'a; +use super::SystemCall; /// Creates a validator set from spec. pub fn new_validator_set(spec: ValidatorSpec) -> Box { diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index c1fda86672..7f6d650dd4 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -848,6 +848,13 @@ impl Spec { load_bundled!("authority_round_empty_steps") } + /// Create a new Spec with AuthorityRound consensus (with empty steps) using a block reward + /// contract. The contract source code can be found at: + /// https://github.com/parity-contracts/block-reward/blob/daf7d44383b6cdb11cb6b953b018648e2b027cfb/contracts/ExampleBlockReward.sol + pub fn new_test_round_block_reward_contract() -> Self { + load_bundled!("authority_round_block_reward_contract") + } + /// Create a new Spec with Tendermint consensus which does internal sealing (not requiring /// work). /// Account keccak("0") and keccak("1") are a authorities. diff --git a/json/src/spec/authority_round.rs b/json/src/spec/authority_round.rs index 4dea4f0989..4ef9368362 100644 --- a/json/src/spec/authority_round.rs +++ b/json/src/spec/authority_round.rs @@ -16,6 +16,7 @@ //! Authority params deserialization. +use ethereum_types::Address; use uint::Uint; use super::ValidatorSet; @@ -43,6 +44,13 @@ pub struct AuthorityRoundParams { /// Reward per block in wei. #[serde(rename="blockReward")] pub block_reward: Option, + /// Block at which the block reward contract should start being used. + #[serde(rename="blockRewardContractTransition")] + pub block_reward_contract_transition: Option, + /// Block reward contract address (setting the block reward contract + /// overrides the static block reward definition). + #[serde(rename="blockRewardContractAddress")] + pub block_reward_contract_address: Option
, /// Block at which maximum uncle count should be considered. #[serde(rename="maximumUncleCountTransition")] pub maximum_uncle_count_transition: Option, -- GitLab From 28b5906d9e785c7f9e8f8ab635708fa8e7e53f37 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 20 Apr 2018 18:32:25 +0800 Subject: [PATCH 090/263] Improve VM executor stack size estimation rules (#8439) * Improve VM executor stack size estimation rules * typo: docs add "(Debug build)" comment * Fix an off by one typo and set minimal stack size This avoids the case if `depth_threshold == max_depth`. Usually setting stack size to zero will just rebound it to platform minimal stack size, but we set it here just in case. * Use saturating_sub to avoid potential overflow --- ethcore/src/executive.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 142086beb9..cded6358e8 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -34,10 +34,21 @@ use transaction::{Action, SignedTransaction}; use crossbeam; pub use executed::{Executed, ExecutionResult}; -/// Roughly estimate what stack size each level of evm depth will use -/// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132) -/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp` -const STACK_SIZE_PER_DEPTH: usize = 24*1024; +#[cfg(debug_assertions)] +/// Roughly estimate what stack size each level of evm depth will use. (Debug build) +const STACK_SIZE_PER_DEPTH: usize = 128 * 1024; + +#[cfg(not(debug_assertions))] +/// Roughly estimate what stack size each level of evm depth will use. +const STACK_SIZE_PER_DEPTH: usize = 24 * 1024; + +#[cfg(debug_assertions)] +/// Entry stack overhead prior to execution. (Debug build) +const STACK_SIZE_ENTRY_OVERHEAD: usize = 100 * 1024; + +#[cfg(not(debug_assertions))] +/// Entry stack overhead prior to execution. +const STACK_SIZE_ENTRY_OVERHEAD: usize = 20 * 1024; /// Returns new address created from address, nonce, and code hash pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option) { @@ -332,12 +343,12 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { tracer: &mut T, vm_tracer: &mut V ) -> vm::Result where T: Tracer, V: VMTracer { - - let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH); + let local_stack_size = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get()); + let depth_threshold = local_stack_size.saturating_sub(STACK_SIZE_ENTRY_OVERHEAD) / STACK_SIZE_PER_DEPTH; let static_call = params.call_type == CallType::StaticCall; // Ordinary execution - keep VM in same thread - if (self.depth + 1) % depth_threshold != 0 { + if self.depth != depth_threshold { let vm_factory = self.state.vm_factory(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); @@ -345,17 +356,15 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { return vm.exec(params, &mut ext).finalize(ext); } - // Start in new thread to reset stack - // TODO [todr] No thread builder yet, so we need to reset once for a while - // https://github.com/aturon/crossbeam/issues/16 + // Start in new thread with stack size needed up to max depth crossbeam::scope(|scope| { let vm_factory = self.state.vm_factory(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); - scope.spawn(move || { + scope.builder().stack_size(::std::cmp::max(schedule.max_depth.saturating_sub(depth_threshold) * STACK_SIZE_PER_DEPTH, local_stack_size)).spawn(move || { let mut vm = vm_factory.create(¶ms, &schedule); vm.exec(params, &mut ext).finalize(ext) - }) + }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() } -- GitLab From d86333af6b51afa006b438de63e7acbd05f05985 Mon Sep 17 00:00:00 2001 From: Anton Gavrilov Date: Fri, 20 Apr 2018 15:45:53 +0200 Subject: [PATCH 091/263] Private transactions processing error handling (#8431) * Integration test for private transaction returned * Do not interrupt verification in case of errors * Helpers use specified * Review comments fixed --- Cargo.lock | 1 + ethcore/private-tx/src/lib.rs | 11 +- ethcore/sync/Cargo.toml | 1 + ethcore/sync/src/lib.rs | 1 + ethcore/sync/src/res/private_spec.json | 30 +++++ ethcore/sync/src/tests/consensus.rs | 4 +- ethcore/sync/src/tests/helpers.rs | 42 +------ ethcore/sync/src/tests/mod.rs | 1 + ethcore/sync/src/tests/private.rs | 150 +++++++++++++++++++++++++ 9 files changed, 193 insertions(+), 48 deletions(-) create mode 100644 ethcore/sync/src/res/private_spec.json create mode 100644 ethcore/sync/src/tests/private.rs diff --git a/Cargo.lock b/Cargo.lock index 547c3c88bd..ae38937ba8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -858,6 +858,7 @@ dependencies = [ "ethcore-light 1.11.0", "ethcore-network 1.11.0", "ethcore-network-devp2p 1.11.0", + "ethcore-private-tx 1.0.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 80510938cf..12028ddf12 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -306,11 +306,6 @@ impl Provider where { /// Retrieve and verify the first available private transaction for every sender /// /// TODO [ToDr] It seems that: - /// 1. This method will fail on any error without removing invalid transaction. - /// 2. It means that the transaction will be stuck there forever and we will never be able to make any progress. - /// - /// It might be more sensible to `drain()` transactions from the queue instead and process all of them, - /// possibly printing some errors in case of failures. /// The 3 methods `ready_transaction,get_descriptor,remove` are always used in conjuction so most likely /// can be replaced with a single `drain()` method instead. /// Thanks to this we also don't really need to lock the entire verification for the time of execution. @@ -339,13 +334,11 @@ impl Provider where { trace!("Sending signature for private transaction: {:?}", signed_private_transaction); self.broadcast_signed_private_transaction(signed_private_transaction.rlp_bytes().into_vec()); } else { - trace!("Incorrect type of action for the transaction"); - bail!(ErrorKind::BadTransactonType); + warn!("Incorrect type of action for the transaction"); } }, Err(e) => { - trace!("Cannot retrieve descriptor for transaction with error {:?}", e); - bail!(e); + warn!("Cannot retrieve descriptor for transaction with error {:?}", e); } } verification_queue.remove_private_transaction(&transaction_hash); diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index a09f161e2a..6930baa101 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -35,3 +35,4 @@ ipnetwork = "0.12.6" [dev-dependencies] ethkey = { path = "../../ethkey" } kvdb-memorydb = { path = "../../util/kvdb-memorydb" } +ethcore-private-tx = { path = "../private-tx" } diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index bf3b475fc6..a3e24bdb82 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -46,6 +46,7 @@ extern crate ethcore_light as light; #[cfg(test)] extern crate ethkey; #[cfg(test)] extern crate kvdb_memorydb; #[cfg(test)] extern crate rustc_hex; +#[cfg(test)] extern crate ethcore_private_tx; #[macro_use] extern crate macros; diff --git a/ethcore/sync/src/res/private_spec.json b/ethcore/sync/src/res/private_spec.json new file mode 100644 index 0000000000..f93d754a61 --- /dev/null +++ b/ethcore/sync/src/res/private_spec.json @@ -0,0 +1,30 @@ +{ + "name": "PrivateTransactions", + "engine": { + "instantSeal": null + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x11" + }, + "genesis": { + "seal": { + "generic": "0x0" + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x989680" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } + } +} \ No newline at end of file diff --git a/ethcore/sync/src/tests/consensus.rs b/ethcore/sync/src/tests/consensus.rs index 287a61916a..8825bad2c8 100644 --- a/ethcore/sync/src/tests/consensus.rs +++ b/ethcore/sync/src/tests/consensus.rs @@ -48,7 +48,7 @@ fn authority_round() { ap.insert_account(s1.secret().clone(), "").unwrap(); let chain_id = Spec::new_test_round().chain_id(); - let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap), false); + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap)); let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them gets lucky to produce a block. @@ -135,7 +135,7 @@ fn tendermint() { ap.insert_account(s1.secret().clone(), "").unwrap(); let chain_id = Spec::new_test_tendermint().chain_id(); - let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap), false); + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap)); let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); // Push transaction to both clients. Only one of them issues a proposal. diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 54b62c79a0..086dc503bb 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -33,7 +33,7 @@ use io::{IoChannel, IoContext, IoHandler}; use api::WARP_SYNC_PROTOCOL_ID; use chain::{ChainSync, ETH_PROTOCOL_VERSION_63, PAR_PROTOCOL_VERSION_3}; use SyncConfig; -use private_tx::{NoopPrivateTxHandler, PrivateTxHandler, SimplePrivateTxHandler}; +use private_tx::SimplePrivateTxHandler; pub trait FlushingBlockChainClient: BlockChainClient { fn flush(&self) {} @@ -210,7 +210,7 @@ pub struct EthPeer where C: FlushingBlockChainClient { pub snapshot_service: Arc, pub sync: RwLock, pub queue: RwLock>, - pub private_tx_handler: Arc, + pub private_tx_handler: Arc, pub io_queue: RwLock>, new_blocks_queue: RwLock>, } @@ -335,7 +335,7 @@ impl TestNet> { for _ in 0..n { let chain = TestBlockChainClient::new(); let ss = Arc::new(TestSnapshotService::new()); - let private_tx_handler = Arc::new(NoopPrivateTxHandler); + let private_tx_handler = Arc::new(SimplePrivateTxHandler::default()); let sync = ChainSync::new(config.clone(), &chain, private_tx_handler.clone()); net.peers.push(Arc::new(EthPeer { sync: RwLock::new(sync), @@ -362,8 +362,7 @@ impl TestNet> { n: usize, config: SyncConfig, spec_factory: F, - accounts: Option>, - private_tx_handler: bool, + accounts: Option> ) -> Self where F: Fn() -> Spec { @@ -373,11 +372,7 @@ impl TestNet> { disconnect_events: Vec::new(), }; for _ in 0..n { - if private_tx_handler { - net.add_peer_with_private_config(config.clone(), spec_factory(), accounts.clone()); - } else { - net.add_peer(config.clone(), spec_factory(), accounts.clone()); - } + net.add_peer_with_private_config(config.clone(), spec_factory(), accounts.clone()); } net } @@ -410,33 +405,6 @@ impl TestNet> { //private_provider.add_notify(peer.clone()); self.peers.push(peer); } - - pub fn add_peer(&mut self, config: SyncConfig, spec: Spec, accounts: Option>) { - let miner = Arc::new(Miner::new_for_tests(&spec, accounts)); - let client = EthcoreClient::new( - ClientConfig::default(), - &spec, - Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0))), - miner.clone(), - IoChannel::disconnected(), - ).unwrap(); - - let ss = Arc::new(TestSnapshotService::new()); - let private_tx_handler = Arc::new(NoopPrivateTxHandler); - let sync = ChainSync::new(config, &*client, private_tx_handler.clone()); - let peer = Arc::new(EthPeer { - sync: RwLock::new(sync), - snapshot_service: ss, - queue: RwLock::new(VecDeque::new()), - chain: client, - miner, - private_tx_handler, - io_queue: RwLock::new(VecDeque::new()), - new_blocks_queue: RwLock::new(VecDeque::new()), - }); - peer.chain.add_notify(peer.clone()); - self.peers.push(peer); - } } impl

TestNet

where P: Peer { diff --git a/ethcore/sync/src/tests/mod.rs b/ethcore/sync/src/tests/mod.rs index 8b9059fc13..eb01108286 100644 --- a/ethcore/sync/src/tests/mod.rs +++ b/ethcore/sync/src/tests/mod.rs @@ -18,6 +18,7 @@ pub mod helpers; pub mod snapshot; mod chain; mod consensus; +mod private; #[cfg(feature = "ipc")] mod rpc; diff --git a/ethcore/sync/src/tests/private.rs b/ethcore/sync/src/tests/private.rs new file mode 100644 index 0000000000..a9e8718e5e --- /dev/null +++ b/ethcore/sync/src/tests/private.rs @@ -0,0 +1,150 @@ +// 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 . + +use std::sync::Arc; +use hash::keccak; +use io::{IoHandler, IoChannel}; +use ethcore::client::{BlockChainClient, BlockId, ClientIoMessage}; +use ethcore::spec::Spec; +use ethcore::miner::MinerService; +use ethcore::CreateContractAddress; +use transaction::{Transaction, Action}; +use ethcore::executive::{contract_address}; +use ethcore::test_helpers::{push_block_with_transactions}; +use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor}; +use ethcore::account_provider::AccountProvider; +use ethkey::{KeyPair}; +use tests::helpers::{TestNet, TestIoHandler}; +use rustc_hex::FromHex; +use SyncConfig; + +fn seal_spec() -> Spec { + let spec_data = include_str!("../res/private_spec.json"); + Spec::load(&::std::env::temp_dir(), spec_data.as_bytes()).unwrap() +} + +#[test] +fn send_private_transaction() { + // Setup two clients + let s0 = KeyPair::from_secret_slice(&keccak("1")).unwrap(); + let s1 = KeyPair::from_secret_slice(&keccak("0")).unwrap(); + let ap = Arc::new(AccountProvider::transient_provider()); + ap.insert_account(s0.secret().clone(), "").unwrap(); + ap.insert_account(s1.secret().clone(), "").unwrap(); + + let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), seal_spec, Some(ap.clone())); + let client0 = net.peer(0).chain.clone(); + let client1 = net.peer(1).chain.clone(); + let io_handler0: Arc> = Arc::new(TestIoHandler::new(net.peer(0).chain.clone())); + let io_handler1: Arc> = Arc::new(TestIoHandler::new(net.peer(1).chain.clone())); + + net.peer(0).miner.set_author(s0.address(), Some("".into())).unwrap(); + net.peer(1).miner.set_author(s1.address(), Some("".to_owned())).unwrap(); + net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); + net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); + 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))); + + let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &s0.address(), &0.into(), &[]); + let chain_id = client0.signing_chain_id(); + + // Exhange statuses + net.sync(); + + // Setup private providers + let validator_config = ProviderConfig{ + validator_accounts: vec![s1.address()], + signer_account: None, + passwords: vec!["".into()], + }; + + let signer_config = ProviderConfig{ + validator_accounts: Vec::new(), + signer_account: Some(s0.address()), + passwords: vec!["".into()], + }; + + let pm0 = Arc::new(Provider::new( + client0.clone(), + net.peer(0).miner.clone(), + ap.clone(), + Box::new(NoopEncryptor::default()), + signer_config, + IoChannel::to_handler(Arc::downgrade(&io_handler0)), + ).unwrap()); + pm0.add_notify(net.peers[0].clone()); + + let pm1 = Arc::new(Provider::new( + client1.clone(), + net.peer(1).miner.clone(), + ap.clone(), + Box::new(NoopEncryptor::default()), + validator_config, + IoChannel::to_handler(Arc::downgrade(&io_handler1)), + ).unwrap()); + pm1.add_notify(net.peers[1].clone()); + + // Create and deploy contract + let private_contract_test = "6060604052341561000f57600080fd5b60d88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146046578063bc64b76d14607457600080fd5b3415605057600080fd5b60566098565b60405180826000191660001916815260200191505060405180910390f35b3415607e57600080fd5b6096600480803560001916906020019091905050609e565b005b60005481565b8060008160001916905550505600a165627a7a723058206acbdf4b15ca4c2d43e1b1879b830451a34f1e9d02ff1f2f394d8d857e79d2080029".from_hex().unwrap(); + let mut private_create_tx = Transaction::default(); + private_create_tx.action = Action::Create; + private_create_tx.data = private_contract_test; + private_create_tx.gas = 200000.into(); + let private_create_tx_signed = private_create_tx.sign(&s0.secret(), None); + let validators = vec![s1.address()]; + let (public_tx, _) = pm0.public_creation_transaction(BlockId::Latest, &private_create_tx_signed, &validators, 0.into()).unwrap(); + let public_tx = public_tx.sign(&s0.secret(), chain_id); + + let public_tx_copy = public_tx.clone(); + push_block_with_transactions(&client0, &[public_tx]); + push_block_with_transactions(&client1, &[public_tx_copy]); + + net.sync(); + + //Create private transaction for modifying state + let mut private_tx = Transaction::default(); + private_tx.action = Action::Call(address.clone()); + private_tx.data = "bc64b76d2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); //setX(42) + private_tx.gas = 120000.into(); + private_tx.nonce = 1.into(); + let private_tx = private_tx.sign(&s0.secret(), None); + assert!(pm0.create_private_transaction(private_tx).is_ok()); + + //send private transaction message to validator + net.sync(); + + let validator_handler = net.peer(1).private_tx_handler.clone(); + let received_private_transactions = validator_handler.txs.lock().clone(); + assert_eq!(received_private_transactions.len(), 1); + + //process received private transaction message + let private_transaction = received_private_transactions[0].clone(); + assert!(pm1.import_private_transaction(&private_transaction).is_ok()); + assert!(pm1.on_private_transaction_queued().is_ok()); + + //send signed response + net.sync(); + + let sender_handler = net.peer(0).private_tx_handler.clone(); + let received_signed_private_transactions = sender_handler.signed_txs.lock().clone(); + assert_eq!(received_signed_private_transactions.len(), 1); + + //process signed response + let signed_private_transaction = received_signed_private_transactions[0].clone(); + assert!(pm0.import_signed_private_transaction(&signed_private_transaction).is_ok()); + let local_transactions = net.peer(0).miner.local_transactions(); + assert_eq!(local_transactions.len(), 1); +} \ No newline at end of file -- GitLab From 9e9045ab94570490597df33a09f6de5465633b8f Mon Sep 17 00:00:00 2001 From: Nikita Chebykin Date: Fri, 20 Apr 2018 15:46:08 +0200 Subject: [PATCH 092/263] Update Cargo hidapi-rs dependency (#8447) --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ae38937ba8..408a1c2276 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1210,7 +1210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hidapi" version = "0.3.1" -source = "git+https://github.com/paritytech/hidapi-rs#e77ea09c98f29ea8855dd9cd9461125a28ca9125" +source = "git+https://github.com/paritytech/hidapi-rs#70ec4bd1b755ec5dd32ad2be0c8345864147c8bc" dependencies = [ "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", -- GitLab From 4e76cce0b7752b1e86e836476ccffbf89153a8d1 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Sat, 21 Apr 2018 11:24:51 +0200 Subject: [PATCH 093/263] Allow 32 bit pipelines to fail (#8454) * Disable 32bit tragets for gitlab * Rename linux pipelines --- .gitlab-ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f3a8a3f0c1..3a04125e57 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ cache: paths: - target/ untracked: true -linux-stable: +linux-ubuntu: stage: build image: parity/rust:gitlab-ci only: @@ -31,7 +31,7 @@ linux-stable: paths: - parity.zip name: "stable-x86_64-unknown-linux-gnu_parity" -linux-stable-debian: +linux-debian: stage: build image: parity/rust-debian:gitlab-ci only: @@ -80,6 +80,7 @@ linux-i686: paths: - parity.zip name: "i686-unknown-linux-gnu" + allow_failure: true linux-armv7: stage: build image: parity/rust-armv7:gitlab-ci @@ -96,6 +97,7 @@ linux-armv7: paths: - parity.zip name: "armv7_unknown_linux_gnueabihf_parity" + allow_failure: true linux-arm: stage: build image: parity/rust-arm:gitlab-ci @@ -112,6 +114,7 @@ linux-arm: paths: - parity.zip name: "arm-unknown-linux-gnueabihf_parity" + allow_failure: true linux-aarch64: stage: build image: parity/rust-arm64:gitlab-ci -- GitLab From 650948feed36d96b96f65494cf616e7ff40ad7cc Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Sat, 21 Apr 2018 12:27:39 +0300 Subject: [PATCH 094/263] Update wasmi (#8452) --- Cargo.lock | 6 +++--- ethcore/wasm/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 408a1c2276..2b5807fe50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3627,12 +3627,12 @@ dependencies = [ "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", "pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", - "wasmi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmi" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4033,7 +4033,7 @@ dependencies = [ "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasmi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26b20dbeb7caee04597a5d2c93e2b3e64872c6ea2af732d7ad49dbec44067c35" +"checksum wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb" "checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2" "checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index 2b8075f741..a39e6ee529 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -12,4 +12,4 @@ libc = "0.2" pwasm-utils = "0.1" vm = { path = "../vm" } ethcore-logger = { path = "../../logger" } -wasmi = { version = "0.1.2", features = ["opt-in-32bit"] } +wasmi = { version = "0.1.3", features = ["opt-in-32bit"] } -- GitLab From c983efe895c6ef3aee0e7f6fe035ea14073c5924 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 21 Apr 2018 17:41:09 +0800 Subject: [PATCH 095/263] Return error in case eth_call returns VM errors (#8448) * Add VMError generator * Return executed exceptions in eth_call --- rpc/src/v1/helpers/errors.rs | 16 ++++++++++++++++ rpc/src/v1/impls/eth.rs | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 4e5fa2fb72..acff796646 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -24,6 +24,7 @@ use jsonrpc_core::{futures, Error, ErrorCode, Value}; use rlp::DecoderError; use transaction::Error as TransactionError; use ethcore_private_tx::Error as PrivateTransactionError; +use vm::Error as VMError; mod codes { // NOTE [ToDr] Codes from [-32099, -32000] @@ -375,6 +376,21 @@ pub fn call(error: CallError) -> Error { } } +pub fn vm(error: &VMError, output: &[u8]) -> Error { + use rustc_hex::ToHex; + + let data = match error { + &VMError::Reverted => format!("{} 0x{}", VMError::Reverted, output.to_hex()), + error => format!("{}", error), + }; + + Error { + code: ErrorCode::ServerError(codes::EXECUTION_ERROR), + message: "VM execution error.".into(), + data: Some(Value::String(data)), + } +} + pub fn unknown_block() -> Error { Error { code: ErrorCode::InvalidParams, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index c894f16dfc..a7ff4916de 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -859,8 +859,14 @@ impl Eth for EthClient< let result = self.client.call(&signed, Default::default(), &mut state, &header); Box::new(future::done(result - .map(|b| b.output.into()) .map_err(errors::call) + .and_then(|executed| { + match executed.exception { + Some(ref exception) => Err(errors::vm(exception, &executed.output)), + None => Ok(executed) + } + }) + .map(|b| b.output.into()) )) } -- GitLab From b0cc44aabbdc09a31fd9cf20d438300d492975de Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Sat, 21 Apr 2018 12:54:48 +0200 Subject: [PATCH 096/263] ParityShell::open `Return result` (#8377) * start * add error handling for winapi * fix typo * fix warnings and windows errors * formatting * Address review comments --- parity/main.rs | 2 +- parity/run.rs | 5 ++--- parity/url.rs | 52 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 705cf777e7..6774a83864 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -231,7 +231,7 @@ fn take_spec_name_override() -> Option { #[cfg(windows)] fn global_cleanup() { // We need to cleanup all sockets before spawning another Parity process. This makes shure everything is cleaned up. - // The loop is required because of internal refernce counter for winsock dll. We don't know how many crates we use do + // The loop is required because of internal reference counter for winsock dll. We don't know how many crates we use do // initialize it. There's at least 2 now. for _ in 0.. 10 { unsafe { ::winapi::um::winsock2::WSACleanup(); } diff --git a/parity/run.rs b/parity/run.rs index 6ccd4caf56..f07f67caa8 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -145,7 +145,7 @@ pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, l let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; // Open a browser - url::open(&token.url); + url::open(&token.url).map_err(|e| format!("{}", e))?; // Print a message println!("{}", token.message); Ok(()) @@ -157,10 +157,9 @@ pub fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfigur } let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); - url::open(&url); + url::open(&url).map_err(|e| format!("{}", e))?; Ok(()) } - // node info fetcher for the local store. struct FullNodeInfo { miner: Option>, // TODO: only TXQ needed, just use that after decoupling. diff --git a/parity/url.rs b/parity/url.rs index 4189ae2418..41c4e54583 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -16,33 +16,67 @@ //! Cross-platform open url in default browser +use std; +use std::os::raw::c_int; + +#[allow(unused)] +pub enum Error { + ProcessError(std::io::Error), + WindowsShellExecute(c_int), +} + +impl From for Error { + fn from(err: std::io::Error) -> Self { + Error::ProcessError(err) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match *self { + Error::ProcessError(ref e) => write!(f, "{}", e), + Error::WindowsShellExecute(e) => write!(f, "WindowsShellExecute error: {}", e), + } + } +} + #[cfg(windows)] -pub fn open(url: &str) { +pub fn open(url: &str) -> Result<(), Error> { use std::ffi::CString; use std::ptr; use winapi::um::shellapi::ShellExecuteA; use winapi::um::winuser::SW_SHOWNORMAL as Normal; - unsafe { + const WINDOWS_SHELL_EXECUTE_SUCCESS: c_int = 32; + + let h_instance = unsafe { ShellExecuteA(ptr::null_mut(), CString::new("open").unwrap().as_ptr(), CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), ptr::null(), ptr::null(), - Normal); + Normal) as c_int + }; + + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx + // `ShellExecute` returns a value greater than 32 on success + if h_instance > WINDOWS_SHELL_EXECUTE_SUCCESS { + Ok(()) + } else { + Err(Error::WindowsShellExecute(h_instance)) } } #[cfg(any(target_os="macos", target_os="freebsd"))] -pub fn open(url: &str) { - use std; - let _ = std::process::Command::new("open").arg(url).spawn(); +pub fn open(url: &str) -> Result<(), Error> { + let _ = std::process::Command::new("open").arg(url).spawn()?; + Ok(()) } #[cfg(target_os="linux")] -pub fn open(url: &str) { - use std; - let _ = std::process::Command::new("xdg-open").arg(url).spawn(); +pub fn open(url: &str) -> Result<(), Error> { + let _ = std::process::Command::new("xdg-open").arg(url).spawn()?; + Ok(()) } #[cfg(target_os="android")] -- GitLab From 1ab06ce2d2e8c46ef090fcf342bcb327099492b4 Mon Sep 17 00:00:00 2001 From: "Denis S. Soldatov aka General-Beck" Date: Mon, 23 Apr 2018 16:36:08 +0300 Subject: [PATCH 097/263] fix docker build (#8462) --- docker/hub/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/hub/Dockerfile b/docker/hub/Dockerfile index 70d7277800..71655036e0 100644 --- a/docker/hub/Dockerfile +++ b/docker/hub/Dockerfile @@ -59,7 +59,7 @@ cd /build&&git clone https://github.com/paritytech/parity && \ binutils \ file \ pkg-config \ - dpkg-dev \ + dpkg-dev &&\ rm -rf /var/lib/apt/lists/* # setup ENTRYPOINT EXPOSE 8080 8545 8180 -- GitLab From 7a28f72abc5689527e8e21e9a1cd46ce8e71ed52 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Mon, 23 Apr 2018 15:36:20 +0200 Subject: [PATCH 098/263] Add changelog for 1.9.7 and 1.10.2 (#8460) * Add changelog for 1.9.7 * Add Changelog for 1.10.2 * Apply proper markdown * Run a spellchecker :) * Be pedantic about the 32-bit pipelines :) --- CHANGELOG.md | 25 +++++++++++++++++++++++++ docs/CHANGELOG-1.9.md | 26 ++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f42b78188..6272c32a7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24) + +Parity 1.10.2 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455)) + - Update Parity beta to 1.10.2 + - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) + - Disable 32-bit targets for Gitlab + - Rename Linux pipelines + - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) + - Fix Cargo.lock +- Backports ([#8450](https://github.com/paritytech/parity/pull/8450)) + - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) + - Remove unused app_dirs dependency in CLI + - Use forked app_dirs crate for reverted Windows dir behavior + - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) + - Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) + - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) + - Improve VM executor stack size estimation rules + - Typo: docs add "(Debug build)" comment + - Fix an off by one typo and set minimal stack size + - Use saturating_sub to avoid potential overflow + ## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. diff --git a/docs/CHANGELOG-1.9.md b/docs/CHANGELOG-1.9.md index 0351d61135..133c93c477 100644 --- a/docs/CHANGELOG-1.9.md +++ b/docs/CHANGELOG-1.9.md @@ -1,3 +1,29 @@ +## Parity [v1.9.7](https://github.com/paritytech/parity/releases/tag/v1.9.7) (2018-04-23) + +Parity 1.9.7 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Update Parity stable to 1.9.7 + Backports ([#8456](https://github.com/paritytech/parity/pull/8456)) + - Update Parity stable to 1.9.7 + - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) + - Disable 32-bit targets for Gitlab + - Rename Linux pipelines + - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) + - Revert Cargo lock update from master + - Fix Cargo.lock +- Backports ([#8449](https://github.com/paritytech/parity/pull/8449)) + - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) + - Remove unused app_dirs dependency in CLI + - Use forked app_dirs crate for reverted Windows dir behavior + - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) + - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) + - Improve VM executor stack size estimation rules + - Typo: docs add "(Debug build)" comment + - Fix an off by one typo and set minimal stack size + - Use saturating_sub to avoid potential overflow + - Upgrade crossbeam to 0.3 + ## Parity [v1.9.6](https://github.com/paritytech/parity/releases/tag/v1.9.6) (2018-04-16) Parity 1.9.6 is a bug-fix release to improve performance and stability. -- GitLab From baeda9347471760d52be9a6b08444196f01f9bea Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Tue, 24 Apr 2018 15:25:27 +0300 Subject: [PATCH 099/263] fix typos in vm description comment (#8446) --- json/src/vm/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/src/vm/vm.rs b/json/src/vm/vm.rs index c7e33b609a..8cc01e3bac 100644 --- a/json/src/vm/vm.rs +++ b/json/src/vm/vm.rs @@ -22,7 +22,7 @@ use hash::H256; use blockchain::State; use vm::{Transaction, Call, Env}; -/// Reporesents vm execution environment before and after exeuction of transaction. +/// Represents vm execution environment before and after execution of transaction. #[derive(Debug, PartialEq, Deserialize)] pub struct Vm { /// Contract calls made internaly by executed transaction. -- GitLab From 7fdb87ad38f8ea969a4e733c7bbf621b1668a82d Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 25 Apr 2018 16:00:58 +0800 Subject: [PATCH 100/263] Use rename_all for RichBlock and RichHeader serialization (#8471) * typo: fix a resolved TODO comment * Use rename_all instead of individual renames --- rpc/src/v1/types/block.rs | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 2b3a085ca5..486e3b9c14 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -44,11 +44,11 @@ impl Serialize for BlockTransactions { /// Block representation #[derive(Debug, Serialize)] +#[serde(rename_all="camelCase")] pub struct Block { /// Hash of the block pub hash: Option, /// Hash of the parent - #[serde(rename="parentHash")] pub parent_hash: H256, /// Hash of the uncles #[serde(rename="sha3Uncles")] @@ -58,37 +58,28 @@ pub struct Block { /// Alias of `author` pub miner: H160, /// State root hash - #[serde(rename="stateRoot")] pub state_root: H256, /// Transactions root hash - #[serde(rename="transactionsRoot")] pub transactions_root: H256, /// Transactions receipts root hash - #[serde(rename="receiptsRoot")] pub receipts_root: H256, /// Block number pub number: Option, /// Gas Used - #[serde(rename="gasUsed")] pub gas_used: U256, /// Gas Limit - #[serde(rename="gasLimit")] pub gas_limit: U256, /// Extra data - #[serde(rename="extraData")] pub extra_data: Bytes, /// Logs bloom - #[serde(rename="logsBloom")] pub logs_bloom: Option, /// Timestamp pub timestamp: U256, /// Difficulty pub difficulty: U256, /// Total difficulty - #[serde(rename="totalDifficulty")] pub total_difficulty: Option, /// Seal fields - #[serde(rename="sealFields")] pub seal_fields: Vec, /// Uncles' hashes pub uncles: Vec, @@ -100,49 +91,40 @@ pub struct Block { /// Block header representation. #[derive(Debug, Clone, Serialize, PartialEq, Eq)] +#[serde(rename_all="camelCase")] pub struct Header { /// Hash of the block pub hash: Option, /// Hash of the parent - #[serde(rename="parentHash")] pub parent_hash: H256, /// Hash of the uncles #[serde(rename="sha3Uncles")] pub uncles_hash: H256, /// Authors address pub author: H160, - // TODO: get rid of this one - /// ? + /// Alias of `author` pub miner: H160, /// State root hash - #[serde(rename="stateRoot")] pub state_root: H256, /// Transactions root hash - #[serde(rename="transactionsRoot")] pub transactions_root: H256, /// Transactions receipts root hash - #[serde(rename="receiptsRoot")] pub receipts_root: H256, /// Block number pub number: Option, /// Gas Used - #[serde(rename="gasUsed")] pub gas_used: U256, /// Gas Limit - #[serde(rename="gasLimit")] pub gas_limit: U256, /// Extra data - #[serde(rename="extraData")] pub extra_data: Bytes, /// Logs bloom - #[serde(rename="logsBloom")] pub logs_bloom: H2048, /// Timestamp pub timestamp: U256, /// Difficulty pub difficulty: U256, /// Seal fields - #[serde(rename="sealFields")] pub seal_fields: Vec, /// Size in bytes pub size: Option, -- GitLab From fa261ebd02906df6f25d79ce9c8fd597184cf680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 25 Apr 2018 15:39:46 +0200 Subject: [PATCH 101/263] Don't require write lock when fetching status. (#8481) --- ethcore/sync/src/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 6270bcfd59..c66a1c6a62 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -318,7 +318,7 @@ impl EthSync { impl SyncProvider for EthSync { /// Get sync status fn status(&self) -> EthSyncStatus { - self.eth_handler.sync.write().status() + self.eth_handler.sync.read().status() } /// Get sync peers -- GitLab From adc3457a893bac241c00e897df702e9bbc1468d9 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 25 Apr 2018 16:25:43 +0200 Subject: [PATCH 102/263] Bump master to 1.12 (#8477) * Bump master to 1.12 * Bump crates to 1.12 * Bump mac installer version to 1.12 * Update Gitlab scripts --- .gitlab-ci.yml | 2 +- Cargo.lock | 216 ++++++++++++++++----------------- Cargo.toml | 2 +- dapps/Cargo.toml | 2 +- dapps/ui/Cargo.toml | 2 +- devtools/Cargo.toml | 2 +- ethash/Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- ethcore/light/Cargo.toml | 2 +- ethcore/node_filter/Cargo.toml | 2 +- ethcore/stratum/Cargo.toml | 2 +- ethcore/sync/Cargo.toml | 2 +- hash-fetch/Cargo.toml | 2 +- hw/Cargo.toml | 2 +- ipfs/Cargo.toml | 2 +- logger/Cargo.toml | 2 +- mac/Parity.pkgproj | 2 +- mac/Parity/Info.plist | 2 +- miner/Cargo.toml | 2 +- nsis/installer.nsi | 2 +- price-info/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- scripts/gitlab-build.sh | 2 +- transaction-pool/Cargo.toml | 2 +- updater/Cargo.toml | 2 +- util/io/Cargo.toml | 2 +- util/network-devp2p/Cargo.toml | 2 +- util/network/Cargo.toml | 2 +- util/version/Cargo.toml | 4 +- 29 files changed, 137 insertions(+), 137 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3a04125e57..2c216496f6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -188,7 +188,7 @@ docker-build: before_script: - docker info script: - - if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi + - if [ "$CI_BUILD_REF_NAME" == "master" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi - echo "Tag:" $DOCKER_TAG - docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity - scripts/docker-build.sh $DOCKER_TAG diff --git a/Cargo.lock b/Cargo.lock index 2b5807fe50..bb7936297e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -478,7 +478,7 @@ dependencies = [ [[package]] name = "ethash" -version = "1.11.0" +version = "1.12.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -504,7 +504,7 @@ dependencies = [ [[package]] name = "ethcore" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "bloomchain 0.2.0", @@ -516,13 +516,13 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 1.11.0", + "ethash 1.12.0", "ethcore-bloom-journal 0.1.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", - "ethcore-stratum 1.11.0", + "ethcore-io 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", + "ethcore-stratum 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", @@ -530,7 +530,7 @@ dependencies = [ "ethstore 0.2.0", "evm 0.1.0", "fetch 0.1.0", - "hardware-wallet 1.11.0", + "hardware-wallet 1.12.0", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -596,11 +596,11 @@ dependencies = [ [[package]] name = "ethcore-devtools" -version = "1.11.0" +version = "1.12.0" [[package]] name = "ethcore-io" -version = "1.11.0" +version = "1.12.0" dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -611,14 +611,14 @@ dependencies = [ [[package]] name = "ethcore-light" -version = "1.11.0" +version = "1.12.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-network 1.11.0", + "ethcore-io 1.12.0", + "ethcore-network 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -648,7 +648,7 @@ dependencies = [ [[package]] name = "ethcore-logger" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -663,12 +663,12 @@ dependencies = [ [[package]] name = "ethcore-miner" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 1.11.0", + "ethash 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -682,21 +682,21 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "price-info 1.11.0", + "price-info 1.12.0", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", - "transaction-pool 1.11.0", + "transaction-pool 1.12.0", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ethcore-network" -version = "1.11.0" +version = "1.12.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", - "ethcore-io 1.11.0", + "ethcore-io 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -706,16 +706,16 @@ dependencies = [ [[package]] name = "ethcore-network-devp2p" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-io 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-network 1.11.0", + "ethcore-io 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-network 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -747,12 +747,12 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-io 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", + "ethcore-io 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", @@ -782,11 +782,11 @@ dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-logger 1.11.0", - "ethcore-sync 1.11.0", + "ethcore-logger 1.12.0", + "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -819,10 +819,10 @@ version = "0.1.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", - "ethcore-io 1.11.0", + "ethcore 1.12.0", + "ethcore-io 1.12.0", "ethcore-private-tx 1.0.0", - "ethcore-sync 1.11.0", + "ethcore-sync 1.12.0", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -832,10 +832,10 @@ dependencies = [ [[package]] name = "ethcore-stratum" -version = "1.11.0" +version = "1.12.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -849,15 +849,15 @@ dependencies = [ [[package]] name = "ethcore-sync" -version = "1.11.0" +version = "1.12.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-light 1.11.0", - "ethcore-network 1.11.0", - "ethcore-network-devp2p 1.11.0", + "ethcore-io 1.12.0", + "ethcore-light 1.12.0", + "ethcore-network 1.12.0", + "ethcore-network-devp2p 1.12.0", "ethcore-private-tx 1.0.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1024,7 +1024,7 @@ name = "evmbin" version = "0.1.0" dependencies = [ "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1165,7 +1165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hardware-wallet" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -1330,7 +1330,7 @@ name = "journaldb" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1784,14 +1784,14 @@ dependencies = [ [[package]] name = "node-filter" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", - "ethcore-io 1.11.0", - "ethcore-network-devp2p 1.11.0", + "ethcore 1.12.0", + "ethcore-io 1.12.0", + "ethcore-network-devp2p 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1941,7 +1941,7 @@ dependencies = [ [[package]] name = "parity" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1951,18 +1951,18 @@ dependencies = [ "dir 0.1.0", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-io 1.11.0", - "ethcore-light 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", - "ethcore-network 1.11.0", + "ethcore-io 1.12.0", + "ethcore-light 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", + "ethcore-network 1.12.0", "ethcore-private-tx 1.0.0", "ethcore-secretstore 1.0.0", "ethcore-service 0.1.0", - "ethcore-stratum 1.11.0", - "ethcore-sync 1.11.0", + "ethcore-stratum 1.12.0", + "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -1979,20 +1979,20 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", "migration-rocksdb 0.1.0", - "node-filter 1.11.0", + "node-filter 1.12.0", "node-health 0.1.0", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", - "parity-dapps 1.11.0", - "parity-hash-fetch 1.11.0", - "parity-ipfs-api 1.11.0", + "parity-dapps 1.12.0", + "parity-hash-fetch 1.12.0", + "parity-ipfs-api 1.12.0", "parity-local-store 0.1.0", "parity-reactor 0.1.0", - "parity-rpc 1.11.0", + "parity-rpc 1.12.0", "parity-rpc-client 1.4.0", - "parity-updater 1.11.0", - "parity-version 1.11.0", + "parity-updater 1.12.0", + "parity-version 1.12.0", "parity-whisper 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "path 0.1.0", @@ -2017,12 +2017,12 @@ dependencies = [ [[package]] name = "parity-dapps" -version = "1.11.0" +version = "1.12.0" dependencies = [ "base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethcore-devtools 1.11.0", + "ethcore-devtools 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2036,11 +2036,11 @@ dependencies = [ "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", "node-health 0.1.0", "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-hash-fetch 1.11.0", + "parity-hash-fetch 1.12.0", "parity-reactor 0.1.0", - "parity-ui 1.11.0", + "parity-ui 1.12.0", "parity-ui-deprecation 1.10.0", - "parity-version 1.11.0", + "parity-version 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "registrar 0.0.1", @@ -2082,7 +2082,7 @@ dependencies = [ [[package]] name = "parity-hash-fetch" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2107,10 +2107,10 @@ dependencies = [ [[package]] name = "parity-ipfs-api" -version = "1.11.0" +version = "1.12.0" dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2124,8 +2124,8 @@ dependencies = [ name = "parity-local-store" version = "0.1.0" dependencies = [ - "ethcore 1.11.0", - "ethcore-io 1.11.0", + "ethcore 1.12.0", + "ethcore-io 1.12.0", "ethcore-transaction 0.1.0", "ethkey 0.3.0", "kvdb 0.1.0", @@ -2154,22 +2154,22 @@ dependencies = [ [[package]] name = "parity-rpc" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 1.11.0", - "ethcore 1.11.0", + "ethash 1.12.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-crypto 0.1.0", - "ethcore-devtools 1.11.0", - "ethcore-io 1.11.0", - "ethcore-light 1.11.0", - "ethcore-logger 1.11.0", - "ethcore-miner 1.11.0", - "ethcore-network 1.11.0", + "ethcore-devtools 1.12.0", + "ethcore-io 1.12.0", + "ethcore-light 1.12.0", + "ethcore-logger 1.12.0", + "ethcore-miner 1.12.0", + "ethcore-network 1.12.0", "ethcore-private-tx 1.0.0", - "ethcore-sync 1.11.0", + "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", @@ -2179,7 +2179,7 @@ dependencies = [ "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "hardware-wallet 1.11.0", + "hardware-wallet 1.12.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2195,8 +2195,8 @@ dependencies = [ "node-health 0.1.0", "order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", - "parity-updater 1.11.0", - "parity-version 1.11.0", + "parity-updater 1.12.0", + "parity-version 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2212,7 +2212,7 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "transaction-pool 1.11.0", + "transaction-pool 1.12.0", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -2227,7 +2227,7 @@ dependencies = [ "keccak-hash 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-rpc 1.11.0", + "parity-rpc 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2253,7 +2253,7 @@ dependencies = [ [[package]] name = "parity-ui" -version = "1.11.0" +version = "1.12.0" dependencies = [ "parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)", "parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)", @@ -2303,21 +2303,21 @@ dependencies = [ [[package]] name = "parity-updater" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.11.0", + "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethcore-sync 1.11.0", + "ethcore-sync 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-hash-fetch 1.11.0", - "parity-version 1.11.0", + "parity-hash-fetch 1.12.0", + "parity-version 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "path 0.1.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2328,7 +2328,7 @@ dependencies = [ [[package]] name = "parity-version" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ethcore-bytes 0.1.0", "rlp 0.2.1", @@ -2355,7 +2355,7 @@ dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", - "ethcore-network 1.11.0", + "ethcore-network 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2418,7 +2418,7 @@ version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "keccak-hash 0.1.0", @@ -2493,7 +2493,7 @@ dependencies = [ [[package]] name = "price-info" -version = "1.11.0" +version = "1.12.0" dependencies = [ "fake-fetch 0.0.1", "fetch 0.1.0", @@ -2573,7 +2573,7 @@ name = "pwasm-run-test" version = "0.1.0" dependencies = [ "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2802,7 +2802,7 @@ version = "1.4.0" dependencies = [ "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-rpc 1.11.0", + "parity-rpc 1.12.0", "parity-rpc-client 1.4.0", "rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3415,7 +3415,7 @@ dependencies = [ [[package]] name = "transaction-pool" -version = "1.11.0" +version = "1.12.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3620,7 +3620,7 @@ name = "wasm" version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", + "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3663,9 +3663,9 @@ name = "whisper-cli" version = "0.1.0" dependencies = [ "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-logger 1.11.0", - "ethcore-network 1.11.0", - "ethcore-network-devp2p 1.11.0", + "ethcore-logger 1.12.0", + "ethcore-network 1.12.0", + "ethcore-network-devp2p 1.12.0", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", diff --git a/Cargo.toml b/Cargo.toml index 4237bf545f..a611458e65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ description = "Parity Ethereum client" name = "parity" # NOTE Make sure to update util/version/Cargo.toml as well -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 8e35b213e0..a7ce5a5489 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity Dapps crate" name = "parity-dapps" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/dapps/ui/Cargo.toml b/dapps/ui/Cargo.toml index e7f409b1c1..acb7a91735 100644 --- a/dapps/ui/Cargo.toml +++ b/dapps/ui/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore Parity UI" homepage = "http://parity.io" license = "GPL-3.0" name = "parity-ui" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [build-dependencies] diff --git a/devtools/Cargo.toml b/devtools/Cargo.toml index d5e275a3ad..71eeaa2ddd 100644 --- a/devtools/Cargo.toml +++ b/devtools/Cargo.toml @@ -3,5 +3,5 @@ description = "Ethcore development/test/build tools" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-devtools" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 91f1ce56f7..4bb1b50470 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ethash" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [lib] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index c9db7cf9f6..147d9484c7 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index ba76dc3b10..3853ad910f 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -3,7 +3,7 @@ description = "Parity Light Client Implementation" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-light" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index a726448bd1..25b5ec59f4 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -3,7 +3,7 @@ description = "Parity smart network connections" homepage = "http://parity.io" license = "GPL-3.0" name = "node-filter" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ethcore/stratum/Cargo.toml b/ethcore/stratum/Cargo.toml index de65a470c6..bf967df504 100644 --- a/ethcore/stratum/Cargo.toml +++ b/ethcore/stratum/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore stratum lib" name = "ethcore-stratum" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index 6930baa101..d2d060e686 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore blockchain sync" name = "ethcore-sync" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/hash-fetch/Cargo.toml b/hash-fetch/Cargo.toml index 6a735fe37e..d4f46a121e 100644 --- a/hash-fetch/Cargo.toml +++ b/hash-fetch/Cargo.toml @@ -3,7 +3,7 @@ description = "Fetching hash-addressed content." homepage = "http://parity.io" license = "GPL-3.0" name = "parity-hash-fetch" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/hw/Cargo.toml b/hw/Cargo.toml index 778fb26e06..9a717e4bd3 100644 --- a/hw/Cargo.toml +++ b/hw/Cargo.toml @@ -3,7 +3,7 @@ description = "Hardware wallet support." homepage = "http://parity.io" license = "GPL-3.0" name = "hardware-wallet" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ipfs/Cargo.toml b/ipfs/Cargo.toml index 15bd173c2f..9c7b5f3b00 100644 --- a/ipfs/Cargo.toml +++ b/ipfs/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity IPFS-compatible API" name = "parity-ipfs-api" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/logger/Cargo.toml b/logger/Cargo.toml index 368d860fd4..a1f793769c 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Log implementation for Parity" name = "ethcore-logger" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/mac/Parity.pkgproj b/mac/Parity.pkgproj index e5229f927a..36b8921ee2 100755 --- a/mac/Parity.pkgproj +++ b/mac/Parity.pkgproj @@ -462,7 +462,7 @@ OVERWRITE_PERMISSIONS VERSION - 1.11.0 + 1.12.0 UUID 2DCD5B81-7BAF-4DA1-9251-6274B089FD36 diff --git a/mac/Parity/Info.plist b/mac/Parity/Info.plist index 2cc7e67b83..e0bdc21e69 100644 --- a/mac/Parity/Info.plist +++ b/mac/Parity/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.11 + 1.12 CFBundleVersion 1 LSApplicationCategoryType diff --git a/miner/Cargo.toml b/miner/Cargo.toml index cf8eb0cdd8..95dd888dc9 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -3,7 +3,7 @@ description = "Parity Miner interface." name = "ethcore-miner" homepage = "http://parity.io" license = "GPL-3.0" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/nsis/installer.nsi b/nsis/installer.nsi index 0115572340..c1f4033312 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -9,7 +9,7 @@ !define COMPANYNAME "Parity Technologies" !define DESCRIPTION "Fast, light, robust Ethereum implementation" !define VERSIONMAJOR 1 -!define VERSIONMINOR 11 +!define VERSIONMINOR 12 !define VERSIONBUILD 0 !define ARGS "" !define FIRST_START_ARGS "--mode=passive ui" diff --git a/price-info/Cargo.toml b/price-info/Cargo.toml index 8dd497be9a..948f09983b 100644 --- a/price-info/Cargo.toml +++ b/price-info/Cargo.toml @@ -3,7 +3,7 @@ description = "Fetch current ETH price" homepage = "http://parity.io" license = "GPL-3.0" name = "price-info" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index d35a64af9d..b8eb525462 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity JSON-RPC servers." name = "parity-rpc" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/scripts/gitlab-build.sh b/scripts/gitlab-build.sh index a2a084adc9..5f353a63da 100755 --- a/scripts/gitlab-build.sh +++ b/scripts/gitlab-build.sh @@ -313,7 +313,7 @@ case $BUILD_PLATFORM in snapcraft clean echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image" sed -i 's/git/'"$VER"'/g' snap/snapcraft.yaml - if [[ "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.10* ]]; + if [[ "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.11* ]]; then sed -i -e 's/grade: devel/grade: stable/' snap/snapcraft.yaml; fi diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index fd19192993..b863078112 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Generic transaction pool." name = "transaction-pool" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/updater/Cargo.toml b/updater/Cargo.toml index 9e7733bc46..d76db6ec0e 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity Updater Service." name = "parity-updater" -version = "1.11.0" +version = "1.12.0" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/util/io/Cargo.toml b/util/io/Cargo.toml index dca0426d50..8538863d03 100644 --- a/util/io/Cargo.toml +++ b/util/io/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore IO library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-io" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 74edf83ad5..a8207ca615 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -3,7 +3,7 @@ description = "DevP2P implementation of the ethcore network library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-network-devp2p" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/util/network/Cargo.toml b/util/network/Cargo.toml index f98cd9e93c..f7131da038 100644 --- a/util/network/Cargo.toml +++ b/util/network/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore network library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-network" -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] [dependencies] diff --git a/util/version/Cargo.toml b/util/version/Cargo.toml index 1cc0dc6d2c..297211b2bd 100644 --- a/util/version/Cargo.toml +++ b/util/version/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "parity-version" # NOTE: this value is used for Parity version string (via env CARGO_PKG_VERSION) -version = "1.11.0" +version = "1.12.0" authors = ["Parity Technologies "] build = "build.rs" @@ -13,7 +13,7 @@ build = "build.rs" track = "nightly" # Indicates a critical release in this track (i.e. consensus issue) -critical = true +critical = false # Latest supported fork blocks for various networks. Used ONLY by auto-updater. [package.metadata.forks] -- GitLab From f56c065f57d6a27332c7afabf27c53c9524caf16 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 25 Apr 2018 16:25:57 +0200 Subject: [PATCH 103/263] Fix snap builds (#8483) --- scripts/gitlab-build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/gitlab-build.sh b/scripts/gitlab-build.sh index 5f353a63da..89fa2a0854 100755 --- a/scripts/gitlab-build.sh +++ b/scripts/gitlab-build.sh @@ -309,6 +309,7 @@ case $BUILD_PLATFORM in x86_64-unknown-snap-gnu) ARC="amd64" EXT="snap" + apt update apt install -y expect zip rhash snapcraft clean echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image" -- GitLab From 4e85015836a0e0c6ad89d3124fd4532078df7f43 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 25 Apr 2018 16:27:22 +0200 Subject: [PATCH 104/263] Update hardcodedSync for Ethereum, Kovan, and Ropsten (#8489) --- ethcore/res/ethereum/foundation.json | 111 +- ethcore/res/ethereum/kovan.json | 3422 ++++++++++++++++++++++++++ ethcore/res/ethereum/ropsten.json | 1522 ++++++++++++ 3 files changed, 5052 insertions(+), 3 deletions(-) diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 53322e6ffe..4438718711 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -174,8 +174,8 @@ "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544" }, "hardcodedSync": { - "header": "f90219a061d694007fbaca6e23e73e29c8c6a60099abc740ab7e27ae3cd1b9c6a47efef7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347945a0b54d5dc17e0aadc383d2db43b0a0d3e029c4ca0a2f1bdabc1a72737de1c22a76cacc8fc162366904f759a99db7d6d19efee3090a0ac5f5b236e8977928a2ce43c7569ea5a74919643cb0b06d7540407b1ea1298f0a04356ddc5d77c83923a6541260308be167386e0969a608a017770c9e38091cfcab90100a00010002001009080011010141088000004000080081100000a002023000002204204801204084000c000010008000000000880080020c0000440200460000290005010c01c80800080004800100406003380000400402040000028084002a80087000008090a00200100544020019580022000000306100a0080100084020006809000e80000010000254810002000000a240050014200002002c10809202030006422022000203012000241089300080400000009001021020200012410348500028290230408100302000000058c0000020c08c20480081040020260004008481000080000800010010060020000e00020002140100a8988000004400201870b9af4a66df8038350a8018379d54483799eba845ab0426d984554482e45544846414e532e4f52472d3231323134313232a05eeccc80302d8fecca48a47be03654b5a41b5e5f296f271f910ebae631124f518890074810024c6c2b", - "totalDifficulty": "3144406426008470895785", + "header": "f90216a03b798fd7d7c51f61fdbe7a08d6d2257eea4501c12dfc5442146b85837c0da51fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea674fdde714fd979de3edf0f56aa9716b898ec8a0a2df7c321f2a532f63cdaf4e234227dd067f3782787db2ac892e875a8cb6842fa0c3a3f2c96c938633c7a99531a3876d544dbb8d5fac06879bea8e3cc5b6ece09da0221863f4a4fa6ca8dc7b6eed0eaefea36a5069f06ba9a61e78b87b634b5e4409b9010000a02080204012000000004100800000c0a08040041160000000740200200148000000000104011040800081808000102001180000000a80000011401020002c14008402000000100014400e20082080400000aa004100000000d10e8a0026180020882008200400a548000000201010088080000c0020800000001004046200600000052004020001800400800400420001800084002c1200040088028840004604020820400000264000005808500400410451c0808020140380c02014000440000002010422080800000240000000048a80072140000400409020020220810010020018008021800280a05008020000400000000044178000008000044410870b075e7ebe9d268353f001837a11f88379cd17845adfefa59565746865726d696e652d6177732d61736961312d32a0c92755fe5da24ea52d89783e387d88e1c2e24ac202641dd9906fc704a88979d28818d4dcc0009d0541", + "totalDifficulty": "3828700463149109414955", "CHTs": [ "0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc", "0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11", @@ -2757,7 +2757,112 @@ "0x568f44291c13efc908db42d2473bc91ebb16e062e9b4368bcb770a3033d67741", "0xe5ecad510448855ff0aafb92a8c7aa54aca0fb390bec3c14ad5d2ba200380aec", "0xa40aa7655c1458b76c04ea5934ae171fb01c72c8c375bb61a0c27b0ebd70f21f", - "0x770ad5107ac47fd983979b016553ca8f340a13e2647b9140e65c980dcf349cff" + "0x770ad5107ac47fd983979b016553ca8f340a13e2647b9140e65c980dcf349cff", + "0xfd074cacab08d2d5f113669672632ab0e94e03bfbbe17fc3de27a30e9f0e8327", + "0x2063bf5ce8eed483242157113534b314296deb123cb33083cb0cce04db610c9a", + "0x9dfb8274e842fd3cb7d73506e64adacc39eb12ebd8a972b7101385ac4eb5b12c", + "0x8294c3d4892cb0bcba9acdd31d53af5bfc97daf124f08d903297da8bbb28cdfe", + "0x9dc2d04fe197009f24ebd4a0c95a0b91d4ff0093387b61569af993fa91edb3fa", + "0xe88e256abdc6447b1f141c2fcf2c46721d9717a9fcb302513c93ed6e31b7c11c", + "0xd2ad4ca6091f6ae6c323b6565522c208a839e36958a1675e5e9b48b13068e7c8", + "0xb168169f2643b8cdbec58f3f94d7889af37117a35389726563ac770f5205faab", + "0x09f32b423ca728b8fd04f9872325c0e2a4c9b1eb36fab49b31ae51254c69ebab", + "0x0b47f8f28a3242c9ca705fd11949e648f190053de023366f98e6c736eb2f0de1", + "0x870a8067623b35b5f0146ec95047869357617fe3773a8285a622c18d44963f9f", + "0xd14e05d8f3238294ffd8885c1f1710f64f2d8eb3d3b4e8a921f7f5c94a0a6288", + "0xf9cdef6ffacbea7692e9fef3de1b778bd11399492486dca0209b27bd474eb04a", + "0x5dc41201eaa00957d070c68bb289fc00eb31b7e5fff52f0603d52d27a40abf81", + "0xae3a53054ff4e3e5562795b45777e1e3e82abeed84e2fab748af50aace8bc8e2", + "0x93fd6f9af3b1efd27487477edccd690b19902300a4eebd34cb0d9b2e60b3cccf", + "0xbe475a9dc045e70ac8218e5a65450edf026d70f3f814162251f83a88098245c2", + "0x20566435d247cc1e7d0d81e143c01b6649fa1fd3cd5a9f97738e6045b29460c5", + "0xb37273228fe8b0c1679bb2dab7176ee1282400daddaaeb0db415c716f5dd1f71", + "0x494bb2cea59fc43629b0f8be3fba9ee5b52948c72fd1f1c94d31600756bfb675", + "0xc690eb3d8e65d5efc211def8fe8f198e42c0321000b8998a6ab218d897d593a5", + "0x26821d73690b9d1bdd9594c92b086291474cd365bd41f7de5edc49dfc29c26df", + "0x026a57937338c9e168d254f99dc9dbe3fb41508049ac1a5b6d7df868e2935e6c", + "0x50dc451812556bd69244f3728c6a17e958b2fa125248103942ac94142610bcc7", + "0x0ffe7ea32c3ef43049d8041a16bd3381ba89b1439dc5329e839546aa01a64726", + "0xab1e06f13dbaed341fc9e33ef387ebbe187787ccd8961a47560f7e02617a06db", + "0x8b72166b0d16ebfd9c3156f5972e3778e16b3d7edf3decd4b6efbc779990ca3c", + "0x149de0dcdbe03bf6d0ae9ccc989a074a4cf2e78311ce8cb6dee3856c2a374caa", + "0x42147f5960814dc31cc38b692089e6d1d53b85cc85a69e4cc01954dc61c268a6", + "0x1460ceccff1ac00f3e126383c3102c424b75c2abeb973d0baa8bec8e7bdda692", + "0xdbbbf28a5d25c832c5f625868dea79a481dce880d5145f4119d3e9eb32356a6b", + "0xd8e5b32a88bdb502fbd62888b9906a0c7955ccaaad1ead31636572a07fe7419b", + "0xdbc42abbec7d223666da11767d9862cd1458f91b5bf2f6499da4ae5bff281888", + "0xc3138499753f545de139238bdc8cd4cbad254c6b87bf0eb37dc1fe7a85168e79", + "0x42be700f627bb081543ab289fcd01235bedea5e33a9779d6d14744685f5a652a", + "0x8660e4130c98f6a8024c1b587dd24ebe402126d4d9a2adf610c62bf033b749c5", + "0xdab926bab8c4ff9e492f992b5696e8f7e3ba3ce77e49fe0e2ca36d3efc8791b6", + "0x0e3911bcf379fd57014bee6a1f796b884c62f2392cf6e8ac5a145126e4622b88", + "0xbd52346714664eeb7b4034bc6a54804824bdd40d9e5bdbae9375a302926babe6", + "0x641e58eaeb404f7a40b9c4be686c26721563b310f7624a654185a60374c1512e", + "0xfa07b0f7b970413ae5085f042224861bb1bc5f2f6ad72a44c3681d47a817c0a9", + "0x70cf3fffa7e27f03d5cbb1664bbd0e1315dfc43df76f1b0e3dce494255e54752", + "0x1d5b0118939994aa8be89dc365f909309df84e7c92530aef25d62118b09e0572", + "0x8b34c5a5cd5a42a58bbc60166f3f2a4be7d79057691c708e7a9639c21b6f57c7", + "0x7b149005e7f8378189c70c33c073d897cb07f62ba5ae319088b3be204beea8e4", + "0xf2a41e8feb5d294faca47dd1f7a90f66b7b616addcd179ae60c5f173cd44a85d", + "0xa2875c8e5a226f2cf69f07e19b13a628ef6a8662f3a5de4c9d666ca5ebddb001", + "0x4231ca8bdccd59526900a487608912a4fc0918a6c693250bd67787bc61a9d09b", + "0x2b06301a6372e0fca0da8a15d4e31a08522ecb91efbda58c3e495e2ab7f4fceb", + "0xd0e19f62b07275097b56e7f409cd52826a1dbc0be26eeaae20562420559153dc", + "0xa4ecf1ef04bcc95ba0ed9214e9118129ae5497c37db94dda284dd536b4dd75c9", + "0x3dc87ba482aaac6b59678c899bfb1da9b768e1385e0f8e8574852efeee2db8c0", + "0x07f8df3f6ec63d926c3a76b17ad1750a9ac6c62a8cdffa549440e651f6087178", + "0x96952f8ba7c83d640119868a030cb7397624ef322b2d153aa3843259da5f468c", + "0x08eca2fb4295f069f3fa62849b354a9e10b8a8e9b771cb8d2790b28b7b09d70c", + "0xfd5832f531c8819c0ce9d031434c33eb442578e81cf711e8ba23e9b21d096e13", + "0xfee9a8bae124565c963b65fa47dcf7f0c9b5ef7e778c2d99539b8a04efd04522", + "0xead692739a0723a73dd38b3aa02f93d72b3b6922c2520ea0b74981eaafe7f6a1", + "0x890dd8befeee6c7c7b4942b02a3bf1a9d1b9e1140ecd1c07de570f38b6c323b6", + "0x690343489ed214b9195db6181c42237b7a62fc935a18ca1a5dc883a2045ceae7", + "0x4bdfdc1bef8c19b89344230c0f48841abfeea788a4973c34afff4d2039ce4417", + "0x6ef6a94338d794400f95f8c0b6d5a40df8b56c31e9bd0037bdd7e41234bb32a1", + "0x00b7568bfdf2d4780b8650a49f707752a12fe9a88302622e68f264622877acdc", + "0x83e96e0b864df30b53ae08075acc83f785e9b8b2bc80e8976b1a954f995df012", + "0x664305b610d0b3167dd25210acba7eea291a37a224546a6f6d59aa7b71d16e5f", + "0x3d3a6401ab83eabc2af15a23b9c0e6d123f661b3599c6131d5923a106f562ac8", + "0x7a11833fbc8ce3d9883088649b930238625e6f6136dfa06a00daf8e646cd020c", + "0x112c33932097c4ec4e18f6308b2a6502cbf746605f1e404555dd07703d60ba2d", + "0x9e77cd028749d69caf352a95f75dee842c0d9323e3618afa2927b2aaaf7fc4a8", + "0x7fe0a62bfd04e263b4c67c5808f6231ad6faca7ff0f5bc0c02177034608d6991", + "0xea820d62b423b68da2f8ce345dbb56e2205fdfae1fce261d64acc959fb30cccd", + "0xd8f6367448dec55e8e2e26b5d304d92969abde131d402de313b1705c0bfd528f", + "0x4b97f3b4e0bff7cfe322e4f50176f6bfb379a706d42308ae75b2a46735762a95", + "0x7425ff9cea5e4869332ce12ef727fbcb004add827eb567424fd4c17717def390", + "0xc7dcd4fd005ae8d4d9e125727b54a64e900b3fee9cdc82fb5057c012178c8483", + "0x8ba88bfba201db1db716f762b5517369d3ae232ca045d2932fc27f6c47b15806", + "0xad2f63fa4fddd0cfc7f6cb01116d285e8aad4b0c51fa9445d39a4cb4949ed020", + "0x366874aec4ea26ece424f5402604ec7df9f40fc4cb9087cd3f45e764b1e36ebf", + "0x7f27eb75010b0d5da72794c129042511e24794b6c8491c1ff2e257dadcc7052d", + "0x27eadc596f6eaeb9247704c3339f7fe4e649f683fd815f9d71270caf5d9e38cd", + "0xba3f72ce8f45b1575554bd0c64feda3959c2a68f0300f021b67880b56f7152e2", + "0x50833c82dc63533f7ec918cd6d58ffbef4e2d597f354589b8eb66c9de0fc9697", + "0x30fc354a8893f683ef03bb024254574b550710f3c05496976cd39166a29e1c98", + "0x1b6b8d13fca6583d358b173c1a255c3db9efed8ad72084eadf10e29868a26fdc", + "0xb1b2a80122d1210160d8649d31422a1edc26b23e8499aa3a88b047dc52b42222", + "0x4e6c85a13cc0c739fbdf844a4f52c78979a84a86db728e4a5d2043ee3b2fcb3e", + "0xe98c28b49aa690aecfa43527acd3e5a010c8f90faf79ef5b4b479a715fe66a99", + "0x5b56e2b50ec96f7bda3f529ed71321650d688e2ee5c16723f6199256532ee660", + "0x1c9b8f5106a23096f2f57dfdb2a7a82876f4374be97b6a818fdc3c742b216b09", + "0xcb6973f775356ec7596ed6f9a036258e98677c7c5b2358da75af28f553327506", + "0x26b42a54252893f59e8eca923a0d2f2c0fe507a680e8907e2904702791c42aea", + "0x25fec26921bb5b6cd9657588b09813270cad72947abc6cb2726764db44181ff2", + "0xdfbd186df632b63f4cf74db660c59e658e0b4b725fe244a563c6698dd94adaf4", + "0xd1e00635e2399f6fa625f5c204e4c1643a7b619271394141433d26d902479bbe", + "0x3d3323fea45851eb0bc0b6c80a79cc0d0582abd8032aba957e719c31bb7901e6", + "0xe7d7b4c68d4f55ea8b71b43ad20bdd86402d36b6360ed0ca18082942736a7e41", + "0x1436749eca0a72b74bf8d596e3499414d412fbea0b936ee3564c4f83de907092", + "0xa828c16af52bd4adcb64928fada82a02d0a49fd3f53c5083ca9acfd998f8af1d", + "0x0fe559ad45cde755dd41876c5a65a690d32fc3d294fafeaa43e3fe133ae48da8", + "0x8f91d2082e5a1e6c1c905936515ab5f03889ac67261ef1d892fd909a9379a8ba", + "0x3881a9fe4ba6a24dcfa86351be2ca741dc9b2078409b2e7e0140569f19733505", + "0x4a3295525bfdda29bb9a552d8dc5c992649699f5694f96ff5bb0647910386db2", + "0x337389b3e800bae87fdbe5271f2167f169ffeb4710ecdcea30f08b2cefba57b1", + "0x2978e1e3c2b5dfe0b41ceb5c9c4029f42d346a2123a199c52ba6efdbf1d5fb68", + "0x8abbdb4f1f88fe8900afdfe15f3d03244435d4fb871606a689c11f6420145b45" ] }, "nodes": [ diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 0d00478c59..1cd74d973c 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -55,6 +55,3428 @@ "difficulty": "0x20000", "gasLimit": "0x5B8D80" }, + "hardcodedSync": { + "header": "f9023ea032ac0e3f2dcc2042b6b47cbe502d5c7dc39d27d147e3273e17fbdf7966518a69a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400e4a10650e5a6d6001c38ff8e64f97016a1645ca0c97490dcc8dc3a85050fb7df999bd772c3ab40cababcf5df4ea7141a9a183353a002bc045bf48b7208ffc5764f48c35162f488bd1213c5e96b3b06c0dd3a32f24ea07041b8f6d8db9964497fcb512b3de8e71cb87d89ab7ef592caff47b444f30637b901000008000000004000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000200000000000020080000004000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000080000040020800000000000000000000800000000000000000000000000000000000000000000000000000008000002000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000200000001000400000000000000000000000000000010000000000000000000000010090fffffffffffffffffffffffffffffffe836ac001837a1200830a4245845ae02fd896d583010a008650617269747986312e32342e31826c698416b80bf6b841cfbb3c579ee8e631a9b2916de71778e0c4f477d1424ed65cc9ca7958899c4cab09721b8eada42b49c146c870291efe475bb8d88652810819dc03ebda2659f3f100", + "totalDifficulty": "2330161772435517944412054200548742154048251186", + "CHTs": [ + "0xdb9557458495268ddd69409fc1f66631ed5ff9bf6c479be6eabe5d83a460acac", + "0xd413800c22172be6e0b7a36348c90098955991f119ddad32c5b928e8db4deb02", + "0x7f2f84afc6caad6efe59a0fb9ff523bdd96efbb5bd22a0f67b3be8bfb8bb036a", + "0x7b7d86ae379af1c88f75a4b44d3097213b3461b9b7fd7333eac581537982dbb8", + "0x8525f5fb8149a1a64a83ec1915a78f3ce03a4a9afa4683544076f40f0ddbeb59", + "0xcc4a4b3e1bad427ad0d8b8ffd1c1c0789a08a67a09fdb0d1ffa4b1e71eb43aea", + "0xbaeb6b0b2fded26cf7f731603df0838397489bc12fdf8713a7cff865f009c5ec", + "0x3dbef76befeb39249e5c65d068fd97b8aea736714001a6dc2353b46d44f4bf35", + "0x306d007ef62b7cfed18e711d1cf449c009fbd5a8af7c9af66f3cda47678b478e", + "0x6b6038335d65726218d1d0301e12e792488a7ea879367c95263a20870ac91aa6", + "0x85ab7fde05c7cf468c4a65c5f7817e902f16038b3ce5e359490acae9c7a4f6b8", + "0x6784db2e15b6dffe0db864b2738804cf7b9804ae8932a2bb93a6bd2f2d4a8c2b", + "0x634119343bbd64c312a540e290b227adf6a84872ca9ea0fb7b3a7f5c2a4ba293", + "0x5836715c071dcaed0a79c77c12a02d54e6af55baed2c9325e10debc6fb07726b", + "0x7508b06556911cddfe4fc80e8a24603fd93cc79081759d4b7f19b2a6550757be", + "0x85de35d1995609af96aab65b1509dae77281a72932cda1e52e6af1d2c81cd46b", + "0x6575f31d4a44a479af6e4f53b7f0a5a1156c6965767b6e06cc3da8b46fbf0355", + "0x1d2ca9c1629b0e0775756536de5afef7dba628856e87dc84e5e6d16b08e12bf1", + "0x776edcae4d9a2e2a461fdf99eaeb1e717e3599f77934e058094b769c0a51f0b6", + "0x7fdbd14ca3a7408577c4e5b3b982edec1e7a95db784a34f9828ef5a30878f85b", + "0x64bdaef77b520a11c7ba92f494caade113a7682a565126cc4231d825412cee6d", + "0xc413f58e336df38771b3616ff1c9a1cbc881e4729dfa0a4bcd18dfca8e22f2d3", + "0x8da02b95474762995773eea74254861bf3eb62c099488aea97d0d271677a513a", + "0xf8d0c469352bd199cf28c997530afc31eb6b47662e1de2a1af05bcf31e6d5d00", + "0x88d9d2f7c1c44d4d0498c1f5ec21ea5d2ed2987e62f8dc6b17359b40200dfff0", + "0xe389fde4b8b06ababced10fb3756ce80b01a36751defff9ee0528accbf979b0b", + "0xb1f3785c2d15132fe17cfd455d015a01628ccf0116006d57de6425ef32bcc63e", + "0x9b2b9e6c015d85d3ba14bdf6ba6889db43cb8dd02dd020d1a01a4e7831604f03", + "0x8b22134cbd6b94ed1d17c89dc73771a3d3df57bc5c4b3d1540631c18dada7e4f", + "0x0a08bcb5fc682d91f0f95f934b4a38a71afe763b4924c8d049e407dea2bbc467", + "0x1d67c81b3c9316621088b42599abaf7e7cce42d60da44d2eafc8b904413b2c77", + "0x7bbbc5f13015a3ddfed8d3abc1d85ddd4646af588b534656256d894677c08c0c", + "0x2a442700726b19f5c82f756b08d07e9bc2777fe1557c079cce7a391684fdb59f", + "0x94a08a1519a9261f664c972e0c56b4628c3a0ab25a245abb4957cddc8a8f4754", + "0x5982827a354ee3703427518938a9b5b281249c04265db359bc47a7061f994a3c", + "0x3dd33939d000789b3ae1221b47d80ab4b8b248f79c97ea69c10148a4f8e946b6", + "0x37e5bf322012483f8e702f8a2a511b5f1225293b7c1be743cc83c637ec83c5f5", + "0xe671341e7a0275c306d55183e36b06665d2380bec4865c4c7cba51612446cef7", + "0x57ace89c46a589ca5150fc99028f9d586c4a8b1b6cf7af8b17ec1a16ebbdf8df", + "0x633ea492c2391b957bdac23f5a9428a5ce69882dc90db968e2882304bdf2b560", + "0x16aaa8ad98f3d2c127ca4dee2c9e1a36a0d4009447240e3297484d7cb2d5ce73", + "0x21abe93df9c382e5897599f54a31d3f46ce8e5e969c655c61da1125e6abe45a4", + "0xb01895100c1b028bfaeb1a126c4b4208075ec2a15fbc29a6499edbf939e7866a", + "0xd635cec21335fe1a644ec8913ea79ea987b815964ff883f00fc01c3a18c9d7a6", + "0xe5c761d35900479ea482e7804a056ca810043389f96ad208f55282e2e7617000", + "0xfa73e547f6a32b8154abe367a0138219514bd0d3fc304c742cb8b3d1eb8f70c3", + "0xf9de607cdd47e7337c815f4fbd44d983da6e38d653c3d3fbf2c6ac8d33707a63", + "0xa0d2cde0aec685c1d6cc05b21bf59817f123700e778cfe5eb80eb11add7e3dbf", + "0xaaaa3bd9f11785b477762ea0a3fcbc983c8a11b34d64475d16bc8c7d43904b9b", + "0x0031a12ba8c6e7408c7ce7987179b7534f1aea95a10aacbba0dade542ef4e1b9", + "0x101544e606fc49a7555855b72be050aa8a7a77e1e8985c3f54dec8ff3bb49a83", + "0x62202e7ed22ddc5d0cb3ccdf81770d4ed935e771be3d689c4dfd24afdb9c20e0", + "0x312cfe1c896a2624e9b2096ef5f3579b543d76ae166cb468e76a3b3b7fccaec7", + "0xcf1820f096d4b80808c50fbbf8de1b57da7b399a6f40312a293c4b5c7eb6d73f", + "0x1dde45a5e8ee62605753259a78e2c34a74cd5cf053a4c045ec5467f9e1311161", + "0x6b6ee017250b468ef3ded726892be7e8dae77c9e9e998b7e9889a34ff5da0cfd", + "0xb82bad6b19786930dd7159f35a4a24336d3f3b5b905b43f2a58165e0845b881c", + "0x77d20bc08ac7a25e115a1d23157c35c6ec22afd89948daba7ebd4809c3b95a2d", + "0xbe24e34aeb20602c184302bb10ac1f424226a985741f34faba4f346d8937e737", + "0x505e5b92245ecfde4a870197f7ece1ad181b6e8be4efce08763a37947122f4ce", + "0x6aeb3807dfe7a6db67278b5b6b6ee9ebb8996034c5ec82b3446a8c2efd3588fb", + "0x495f38afce7862a6614ed3d35531994e8d1e81dede4a4c9702922a3c06084e20", + "0x4acef831186426af96b90e1007561bffe2e8074bb33955dc36cdffb85e61174b", + "0xb2d7638804d6ee3e0747a4de335a26506898cdfd9221fe7e7e464feb268136b1", + "0x1aaa327ed400e0f6780fbaf818fc1f69c6cf407ecf80aa4f769ce42bffed7cdc", + "0xb955281446f41ea2330d07603803e148d5f1a2519f6233cad87dfd1ce4985259", + "0xec5f0c5f001e7897464a5570543060957fe20f88a905d3769615355c240e4859", + "0x18f872e3796787ef015a99bb3bc5ee4d31eeeec260213da70bd452f64de14c6b", + "0x9df2268daa9354a8264b5e7428d390a8d813266188df966fd58549dbb66898bf", + "0x6fdf62c4c161997e854846ed44e2096ea948c40efcdba2479896ba87fe484138", + "0x206bf3386af35a010906ea7a5263a71fa47fd317d23b57e448e49a36082916ff", + "0x4f627219247a8a93fbaa32b7f95e84b45146752d245e54299e7f74ca7070b2a8", + "0x3235819426f3a8b7affa6b38c0627c8efe0c2abd1eac7f8d6545e4332ebbf4f7", + "0xb5e514ee180f781ffadbfacc1831926f24cb305c352bb76ed7ae0a8247e792cf", + "0x6f287758e18c7967a5d52c05f8458e2d3ab2ec86fe0ef1d3146b99d7c3e3f5b7", + "0xc17dee632a1da285bc78d6c83715810e0e003c65c61c4105899b440487bfd126", + "0x173bab1413b65b801e136fe2dbf335b7d1f8689a127eb549bcd24f55b0bfd979", + "0x7e85be26cca16f2f34468f1aadd30a4766e4fe9d3746455f301f7f6e1baedc6e", + "0x85a0a9be1ab79a754c8875688b19a12719087e09d4cbe03f29965bbffee8437c", + "0x9c1c826a39e48b1b8d9d88ed29ca2d1864425d28e273695e35168eb01179ee62", + "0xf88831327094e7ec631fb9cf42719f89c4bceefbf25130784f09f4fa0a3b0a05", + "0x813e01a9713693c11c2781ac98604e51d7c7f610effdac795f74d538f7e5ec89", + "0x35ad80a70b0086c0a762ec29c577b031ea85132f777a324410c3870128aa91b3", + "0x6db9c2349d95bd51dfcb499ff26e90bf73e999f25b693ffa232c573f67164104", + "0xcff82a9fddf588d3d40e642f1eba1b9d24ece27131104e2e3995d6643e8afbf7", + "0xc6bffabb187ad144e33e7e3867f94f754e7e479c503d03de4fa891d294b175e6", + "0xd360ab92cf13a519f5bb41ea825e9baac0bfdf2298220c5ea60304ee9ac15617", + "0x8920024d447d0635cbe88f642966da52c1ef74d3ddc6c1c2df1df80c0a0014a0", + "0xc64a9294f5ca5fd1e1e05403e625222568c32bfd2f2f95bed2ad532b4c3a33f7", + "0x258ec76b8532f1f5169b44d8f5e0c1ddfc19fafab4cfce7c6afddc8aa4978cab", + "0x47f2aac68456bc931a0a8c458b802651173b1ebda2e032fb9541139352148156", + "0xa87a36800ed7e27bbee7ad937c1ace3ae08e2ae50a6673af70a2ec6e44ef1ec5", + "0x9182c6debf58629bd0d37043cc70b3c5e4af18b8aaa23cc5b455f009d1686371", + "0x0fe5abb9ff345ca06fa55cdfaa0804a6523c3ae162638e95edee4ba092eec443", + "0x24d7d4eb0c17869860d83e8be8f7579212cab60655aea5fcf070cd1461191357", + "0xf0971d8a37bc9b6a54d37ac7cd90aa4766cfe78cf8a6f376dac2304cea05683d", + "0xdb3e2e62d2da694788d2a0aecb2226c01de2b9d655421a079e2bb34092e7fd8b", + "0x57100a2ff274daa465da031c86f9b282fa03724c93823399c08d6b014054d207", + "0xc81fd4efe86a9ad97415928ae213959f2a716361da4a2937ceaab7358f105382", + "0x5836a5c844e45ae687b388603d62d28d81cc98ee1eeea6a34dad79d7ea6a599c", + "0xc98ad6c12f3f371a69eccb37407b43d3185b68380dcefae448b2e43db41afeaa", + "0x33ea1db64fad9787532d20f7739dd53a35fa810db902f2c33dfec4d652921073", + "0x3219209ffb0a9c5ae33779564dbf8a9618fabd1c0830d32a06dfd5a3990f7dad", + "0xeb6a367ee7f10c5d2882d86850f4a2680f78ce9374b7218d7cff11f0b01ff336", + "0x026bb678fb224a4e62c0d31450cf5394f4f71b9519106a5e92d58464edfaf63f", + "0x040ae0a25cc2c70fa710d394be7212b81128d7593a5c210549a96bf391a2f58d", + "0xa32caa1d1b36281e2c917f1951b3b0a0acde7c78f775681dd09c7cb81a2f14be", + "0xfe532be3ae441c5e9ec98fa0e006fe8529dad0ae6ba384300eb2198841014391", + "0x49d3b4aa6742d68b59eea7b44aaeb0693670c7b3b43788e93cd99f10d7ddbb7c", + "0xb205da5396369be6b68fa19264df3326c2bc825d88814843ac4f654cc7f921a7", + "0x57521341b29c1ed0cb02e8a64c43155e6020c4d8cda103ff56b2d2bb0cacc749", + "0xbbfc055f310e3930447bd33092081917d7661056ded31d3828b9a4eaff3649ce", + "0x52fefff36b4a0a9c2ce8cda94cb792a8260507df759ae2348ce79a6df3a2aa17", + "0xc4a7420741c5e8e041b8c7765b5c48ab0ee01fdf780efc95f820fbf549e5331e", + "0xbf90dab5cfd58fe4899475a911afd460ed0bed6e79487d9739399f7749520642", + "0x1f27056f98106e007efed121b017e82fd5c9b2c05de65cfb28fa9f67edaa6eee", + "0x6ebc2d4f7bc27d116b499dcbbaef72f8dd053559dce743706ecae5ce5338b508", + "0xdc6eb02678ccd7b2db8a9a9272ee53fc8110415ae5e84fbb8bf981eb25ccda51", + "0x3e261edddd8d34ba379cf163dab618aabfc198ce81bcdb1484b71a5bc4b50fc5", + "0x128bdd0f27a6d741399010b26f4056f0a919e7c1bdebb1bb69f22d32c80a2b88", + "0x68a749488b6e5bbeef10c98b678f67d1a7e53fb62bf502dc3743bf3c9138247a", + "0x52dc462248ddfead4b4aa85f4b2179280799b902519e83f721a849cc2f2b6037", + "0x7d70e4fab02e6a462e4688e96f7fc56a4fb9a945da942925ae039c6f13907c29", + "0xc746bf3861b3b63bd15b3cf0f0b6c0c331da578c35705176b90dee8a5b1e0d6c", + "0x4e251d7c4b2ae114b2f11a532fa060f6f7b1c4f0bc760034fe4e69c053a43746", + "0xe67185a040a731762897ac2e07ec2b955644d0784d18c6351c805d28e83f776b", + "0xa8ed7fd02d1dca89683183877cdc2a4c9985b48141d7967b10b38b59b831cc6f", + "0xc1020b2e8587f3c967ea138ea755437d2660e69abe8caa0d9bf9da9201b50750", + "0xd789a8a4a025f5725759e359859f2e15f7901a077d7683e3572d9ddba15ae94c", + "0x54f4372c804a66eb887614df08364d0e6b1f10c090584619c89c43962f513eda", + "0x3aa00d2431ba1c4c03452536047bdad3a5af547d2e16baad0bfeea0e7a8c3722", + "0xb341d41f92def7f5bf2d7c9a39b9fcdb2892b95a63ffd7b643bffaa523783dbf", + "0x9796b217efb64cc5f829a668989bb1915206e016c9714325f068b8cb2cd303c7", + "0x5deef3457cc95fae69c47f35422ca8731c80da50fd7f664583d13bb44d2f9ac4", + "0xa381a97eb8cf01a9b162666aaf9dd3142c6b2a2247830faf693e894ce99809de", + "0x7418829d2890fc2514b6e4da7b5643af269016ce2dd31d1aa7333c66c1273a6b", + "0x65466713071b4b5abe6a9c9b0e9fab247d56d72fea481e96b65999e2a085de95", + "0x0f97a6523532b4b80a7b54c1850ac2b062ff99d0c7848457fc3465d0d60623dd", + "0xdd1826c79f92c089522f853f87b551104b8b173f1c1797a752f2e8da2fd506f0", + "0x86a635a38b956903ce95ed3af65257383e2d7d86e6b63a61deec3ea5c8acc081", + "0x4afbdcdbe4a647f1137d417ac3580a116022c87cd6e7511330c4f2494cd90a0e", + "0x1d179aa8b0cb3b27844da4f06734f199fca43b66319cd2f16a60722eda994121", + "0xb1f1e42972a0b99268f42f6149452019259565cfeecc3459a58c17ba69ec4ad1", + "0xb80f8b8bee43d9e98eba909691ed6c9e900e8757326f7d20b6e7ba741d404a4a", + "0xadfea6390b526ec42aec881cf8226b9ad94f28ca1e682237914b30564d887208", + "0x50619f2ddec37c184798dfe50b067ae4bc0401bcfc1ab4d42cc19627b7b183a6", + "0xa53a92d3d223652e6572a48ad7624aeb2bb24c10872d17ebefd41ead1579edb7", + "0xeef7725747b978d578e5b576bc18d5c6e7148b68c2389478e0102b7656e7f3e6", + "0xbda668b4961ca5f6951f6ac55ca3c03a66e475e21905dfa8e797cd4a5ef1381e", + "0xba8c3be48f94186114afaab72a27a21db0316856619b400645469511b2bcc165", + "0x44d80fc17e0d131e6e98a4567885cdfa5224aeba8616d8f369cc84f3b85566e1", + "0xdce65f6c57bb81f01fe80daa1c6869c890a4bdfaf0f016456098bbd13c376f72", + "0x0b63a4585671669622a3c751d5ff5433f07cb0e9f4dc0acd9dff493c6ed01495", + "0xa287abbc612e2d318488a370e792845ff01ba5f7d387a2f0d82c21fc3d236992", + "0xae83dd70c6cc9cbd2a418397401461687bfeb8fa6d606fb7105153e50b5dfce0", + "0x02e31ae89b0dd8f66b6590a1f65711145bb9154825b7c68ae5d76228d92f016b", + "0x1e38ed1613141cd046a2449540f1450ffdca2c1a8d9ec2f1ce8d9c74ee189d89", + "0xc8f4747dc7b311c1a234f7d7eff3e9000e11c38624c23519b889543d8d33dfb3", + "0xbb7aa989e7d116e3c288ed8fdc0c7884fb3c6183ced8a0ea63a9de037ebf49ee", + "0x88d5a00fda80c28fa6e6d0bf6a6891b492cd6c85526955cfdfbba2428c9353c0", + "0xab03bd8ecad4f1afd0ee84a2caee745d4b7ade0f32bfbd61db50be15688e4493", + "0xb9ee61e8ab9ad32da0728394b5ec53452014f6fd99a5409923cf75c8d739da5d", + "0xa4c357be81081b833b5d4fd3cf4644b2ef1a28fdf67a8e0b0b2af3e8cd6ade4e", + "0xfb56d0c3b65882317ba962e2953a75d9d9b43c9f40ea0894629dc09bb29f6712", + "0x0f354b29bf19612285957523fc7d487922795d8fe5fb0aa4019b94a1f13d89d7", + "0x61c6ec536ebec0a740ad39900a2a71cfae8e8ff81ce3a37c5a4354ae48d39ada", + "0x769d94d0b3fcdcf22eb6c36a7c5b18711c79f69c27e9a396476d03e92ab0d058", + "0x5009c84cc24149c0134790682e0a9bc88fa5a8d2bd650207309002c25bc345a4", + "0x32b697d3cf2ab3bfb9ef79d27f3e61eb423ec9d802f2256b1d8875df78ca5887", + "0x3b8ba94c607acdcaaa7f0f7ad30028ecaf4d505d0675df95c358607210a23eae", + "0x433ea023715de94c5885d16762c0caf40079f5377f3cf3f5ee871c6812182ebe", + "0x4758426d43b67ad4d6e7a36272a3d772b94dc497d45292b061ac655111c41240", + "0x12542964fe7e8c837cd8e20a0f80de473127bab6aecfcc5be266bc7bcee87ccf", + "0xbe7362114d69220ba08ce42396e92d87027a63c3287be0fcf633c8a2853b8c71", + "0x722e26ddb7fbcff7dec266ac0ca388353c3a34d8ee23bbaef579b7acda48241a", + "0x04ede2fbedd140490e0b215e89850b8bccb059cfd7a72bd2fc3118495aa4e811", + "0xf47ea26f501cc95c62c4da4c57e743bb20c4caf6e81b394ceea58bc64b1a77a6", + "0x6f208393c290c02f4a505a6e7b2420da859e7ee83583e9a41d709333e67dcf9f", + "0xbedadad9293e12d706c963f31fc06535dd23432f7b27d157e529cf73e4f5603a", + "0xbc3572c828c9c1d1f0c90f56bcee1fe414a413fdbb7362a416bf4033405276ee", + "0x084bdee3faf8a9e45990094d668f6ae0050c1427e3aa918223849357f7865633", + "0xec5a32f5ff6f3887e5aa33d6dd61d2d63e36520ff0647a9eff2355a7311a0fe5", + "0x13fd23c260c0298286e193f23295b67497fb00c60047017bc62f94f6a25d4574", + "0xda66b3d4773530c3a3b563a8721523dd10f4b598b3976aa2f3becbc15fdda495", + "0xfa981ea461800e9eedd73c1423291c69bb43555321e1c5710a052a12bdc68707", + "0x232b0ab7709616262fb48d32ff36284ceb5dafc823ff4f6d5b79e8ed12c7040a", + "0xd90bc0dc26f812e0f05433c30fd8e19e81a81ac589c49a528e86027e8a352e78", + "0x3666c6eaef02990c263e0611e90d793c82815bc0032c2ae16813e957659c6412", + "0x5b46e134edbbc9466540878a637ce22194f040f519efd98a52da8e9bff05595b", + "0x4bff68f29ddbf33950af965ccc3fad46c81b6e2371922abf27b88fb2d669b83e", + "0x67dbb166d4afd3d1c32b9ce9ed5da75a25eaa160f90baf0d46a74fb7ddb09dd2", + "0xdba720e169d3c1dfde88d08bdf445eb428908560a520ccaa1da84d2dc07369b7", + "0xeee7477387db069e7de5d10a8e77d7f3ac7d692b4d582b5256bac44ba3d8381e", + "0x968ffed5244efe79aa4dbe1bcc7a05e24b5e50d1fd4d92117e1b654707bd3c43", + "0xcff2abc22b0cb5865f9767b5f6fa4b1420e3b774ff4de6f593516db3511d9fe6", + "0xd710ff4e765bd0d5e2284c8a11726c4924b6ba159702214a6016555110c2a251", + "0x31523dcadfbc24f1d3011cc1cff03a4df5f2c10fc4bef7cf0bb807edd1c97520", + "0x079cf6974e4e64675de7ce75b1262e2fed194440c2789f6fd72110f105503754", + "0xb121c3ac31a421442faf07a4b553de22be8e1726a67b0feaa4d426e5b48930c5", + "0xc39a8aa81b5c0a95d0037e20f3043e16832cd4b4cfa78e59a424493cd8322754", + "0xcb30c5710457eb0d9ece9274fcf01a96758e6e48db64093b1a08f773f5bdd594", + "0x916203fb9c6cb117f46f66a6693501711481691c0bef0ba0563369841762c657", + "0xf6711b05e901583fe0b51177597d44354ce57364282e042e143f37185af0b13e", + "0x3f22f516c9fb33c327d2184b842edc2535dd6cf4969178c56ab98ac11996ea46", + "0xd51b6361e37ceb481bc6e37eb61432fdfe23d52f2b64aea70c0a12a3c79d2784", + "0x9a1e99c578e7f7a69b7d914c0f748b3f94b6b30bae1be056849bfecc74e31751", + "0x5539c971cb882506860bf724b3f3d05cc399af4640775ed805288468dd83cfd7", + "0xc54c50d46acb1fbe017364ebcb66b4563bc0ab60753b055a19b126a55c476bc7", + "0x3adb55f5b09858cb849ec9edc3adf5e3ffb8eac43434c1ccb817038610b57c08", + "0x5fa06980ab83374613079b9d61c53d6ba93d41af996f5d9fb5e5ef05d36d8aae", + "0x1b66a155b1ebb780d501ac9f6d14f8ce6c644af88b7f86f87b5815379258c494", + "0xb75860039c1886823bd489d9f3b92c4f6bc46629d3fedc9f7d6fde59a318518d", + "0xaffab6d2682c1641658270a5b63e9e46b0bb90c05eeded11079b8f7d33899983", + "0xb5aede6209f50349dcbdaf85ff444e2252bd3e8e2faac12b517552b493ce4cde", + "0xa7c3e97ca8efbde3c829f2e363c5aabde3afe2fde9a1d106f868e87c0fc0682f", + "0x84f7405932b9aabbda33ac93170ffb73ccd5c584f0f55c17af4cd66fc938f739", + "0x7eb2a3d7ef2dd3fc0fc337070f1429e9b472a5912f9217ce4777bbdd07911034", + "0xb208f1088e65776f684d8b097b847c98cee4e274d49b07918e4ebae9585c443e", + "0xe0cec73204567174e0594f4082d01d7b8e8d382a6602e40b35b3197ba2eead6b", + "0x06642dd13587031239255686a40625c53358c4ced6eab78c696413f3cad9c6d8", + "0xb91a9a676da327548f5ed89ca74608c9403b994ed8f0cefeb53a1b5b09e76da5", + "0xe7dec1d92e8d551a54e7e310ca217933375c3a3944371ad5975d1601d5c6d0ac", + "0xee0d0b46a607e2b7df37f24ee652dde4ff65c95eb94b93092452a56f6ef9c754", + "0x8ef8f5852fd8e1f96f82cd3f4bdc716824070b3eaccbc2cca5da345298b752e4", + "0xe801666d13de5a51eba7c9e1d149339023b1b56c513bcba2e37dcf22bdb261a2", + "0x37a53559f626a819de48d74f7e6b484ec90c1fac766adfe08bf9234a139b0fec", + "0xeb8d703867e169bb31f5390ec877a7c6c82aab53f144593b75fc1599604d6c80", + "0xfed3012f3f281de26b447003799eca69e9845c6b5be85bc42670a64487c92a3f", + "0xf70358dc2c4e9d449727affd9cf45ddefa0f3480d964f85aaeb1543427e062a5", + "0x6491b2c05e217b7f21094e96c3381164f9db86c480b0970a27d8e25c875f5b7a", + "0xb4561f6329dd718c03d7ef6be0224612d776b72511294d29b293eb2e0a7b5cad", + "0x89f4a1b613ee34e1728899eeb294c48a21c28da7035d5d036cc46439fa42c965", + "0xe78f95f15c015a18e4598e33f06f6517c4455cbd2efd0dec1bead6080f050b35", + "0x7c64eb0c96598f099d0e9383eeabdc303002819b35223f744bf8a2bb80cbe394", + "0x98e5b4eaf42e390156a730d9e80606d80e2c0c9203e5511af1cea5361af63165", + "0xa481b0af82146b7aeb690456acab564fe356b2b8a560c4b5ab46817167bbed33", + "0xddac876def8620f40cc43a04c8d939fa12bb6d985223caf955e8174c46578bab", + "0x10a97a5a30805c28828d6e4eb4205905845d121149b7146e7373cdad4850ac88", + "0xe14ce88a794100c126707edb5a99922d394e004ce5fe178fbd02c8a34202d4b4", + "0xc3f18b1d11de7706063e2aeee7159589f64539fee39db233ce6983b24ffff076", + "0x6ae533d2bf3f35c6f1f256b9d1fdd863d5394956ded7a80b56ab1e12da78c93c", + "0x79ec4573d7df2f3b48ea706582d48d29a8d1483ae29577fd85b11c346a22e3a9", + "0x263652485fc477fc5407ca079eb494d4618943d01ffbc27ba3824fbc34e6bd63", + "0xcd414c2dfd20a303c9fd623d847e0387cb93cff53d006f335358894be35ac0b3", + "0x75d23d879b23aca1f2152147212506b0cc789c3e15fa8644a6c89a10ac926336", + "0xe166233fed0bfa647b84b95b4a04553087b4f42784334f5017dfd2a8e246f0d5", + "0xc48f212eef40b227aa429405e6c63d25fb35e9889a33007fd1afcc2bbb57a8df", + "0xfe6e67fe4057baa0701a7bc7f98f1b59e8c0ef03401e564d51b9fbbb49a5d11c", + "0xc31d73c0443dad07f6eaffa3171c77c8da87c54780d4f374128adb79fee4ed54", + "0xa0ea13b2425ec84fea7bb9f121f0aa72cfb00e36019e63fee991606246569281", + "0xce7e8e4515b0ebfcdd0afdb002f9017076de88e278b914c902bafca65a8b12fb", + "0xd14a72a5605124a8545dfc4d7419f00e85083d558fc662dc17b3bb289107da83", + "0x3e89c3740c294a0f54068cf769091b1a976fe4e60ab4fa48b9c38c034c08e9a8", + "0x2ee8355965ba13e91d71bde2a72347709c97cc33bcaf1ecc6952c860b07c60c4", + "0x63a87a93a0e410e53146a60a46ca870604f8301e221fb5b470402aa2dd5b9c54", + "0x0bbdfc34316855dfa828a58923acd7ebc556c88a43b655d32bd46ec6008d8351", + "0x4721db737d99128133928670bd229a0a7fd2889e00e222378fe5f663e35587f5", + "0x4f52db42c0f03f342883d78d387ec913a65f92961276b0e718d4b5fa268aaadf", + "0xf7d28588843f736c341b8572322d1ab397e0c5863ac9a30facec3eae0126f3b8", + "0x48940fceeebf3fca0496483b58228516b9c54404fddd31e573c951b12d017d2e", + "0x87542780e6dad24843883c420ef6fbcb2ebea31b073fe54cbdbd5ffb2c4b30e2", + "0x35bb6ee5defc7d7489b24e9e8659b7131ab9f7673960f3ab9bc9324d6034f3da", + "0x11719cf1a1d10bc3c4a48ab177ad65039ff09d1dbb34b1b7c15fa78b5506b5ce", + "0xd086c0fa8b0a1f7cabd9bcc5a1e36137f59b7ed6d91057defc6f62fbbce73956", + "0xeb461e410c324c9ef9a0d240fc5f153e1af9e88810f1563767022723bbac62bf", + "0x10a384a0f6c927bc9efc21ae1b2988e79268de24065b91065b582aff4e0cbcb2", + "0x7020503d8d86fe9bce39301207283c9f9bea9d7789d0f1488506a4073d482d6d", + "0x93657d3b8bd95e33b9b13c3a4130a623d4ed6d8eca8cfde3e6fc9e16b3f1f898", + "0x40727606bcdee8714dc15b349561d8b7d293ca4231227384c56f1a8fab986041", + "0x5ba216663e223675ed7da19a7bbcb08483f6871cf11d911c3ba992829e40ce2d", + "0xe9eabb151a2d735f0ca36ac9ed65c612276a21e28b1a63b5fe632dba27207969", + "0xed88ead1835a70d30368a33955de7c4736bbdc22ba95f04aff7097589887b2bc", + "0xca47f392632e4684e54fd50f5cb8e6983c8c2085d4df8550e3398c4e2bfb9bb7", + "0xeb8699fcad43fac0bb54ab553c4f29c7d1a3ea6079e9d5218a14b675477576d8", + "0x912ab118b513c06e618f29f9a7273e8035b4723b3a21521a91a43100486759d1", + "0xc89d31d9d5bf2fcdcfbf8ba8c61307656bb5673474ea605d1e5d70ab1d7ba43a", + "0x8fbcad4bb94b91cec5d9ac2534666f019c807f8889d37e3107fba28002c7dd1c", + "0x3f606a227cd3a38e2d5da4c611b9069c109e9c291d390e5c1bb3b427be68c5d7", + "0xa69c47f146ba22a6f53562f4ec3d13e1cc5499db587095dadb4a89f6456be664", + "0x36a9e5d14b3fbc061dc83eccc0e6dc3f2a56f0a56e88a987f09d89257c2d2ccd", + "0x9d77184cdeaec05bdde7df7005467af592a625bb0a470e5b071d6cc6537a24b8", + "0x3f9634b50a524ff350dbd4e764d3c01d848b44400485f792d4ce4e17a3afed80", + "0x142e648622d2f13dbfa4c0e58f91ec0073455a6b327a2a2273fef05ca9fa7553", + "0xa4348c80308a3e0b0b4d290152bd09b24d2420281ff3240d2b54c406ba2ac003", + "0x95e86927eca33fadf4d35feb4514ecb90babbcf2ab5c801533a4d36ea8ccc87a", + "0xbefc0239b823cfca21afc0f57c144226a8a72f6acf86a1152d8a80ccb27475e1", + "0x1bdc16bd7d21c2cf818f4d3f5f1cab4a7d256ebb8b32a8464c6b6ca111c9ab87", + "0x04aa15ecdc0277166a77953b4596e2558af4295a342330ecf9d21b6221f21a40", + "0xb432d2660f59648ef7929901a0ce38ff577b4162a69ec92609c8ca1cbea5f8e1", + "0x985a13bc2bafb56e5ffd1b0e582790eff30786bbacc6e28ca57017d398f1552a", + "0x57c5399f6606f02bd06c9470246948e3d482ff9dec5de270f6c06dcc49c8c8dd", + "0xee471268956c3947f22dc8a6077c850f10c1227f50cd24ab7a059b94f3496274", + "0x97cc4534898ab427418bad275c9c21c18d6f51cead840bd5b800e27e1bb1f76f", + "0x1370774538f3c6aff104060091a573c94269421e5347d9ee26c9c5ec90956174", + "0x7b29a2dc9f4e8c3d43d3ec93d01484205583cfc6c8fac71ed0dd6eeab3c7e987", + "0x2127f737690dac5f24595b5d0b96e869f750b732fd8f004860b5510376b154a7", + "0x196f4545946a3a4b9d5a1c2ce3813e55245cefcbbe424eb50dc7126a6f7ce294", + "0x89a6c2dd239f741797b47166d4a97d8a6147b26c7f61471a272035fa6a19ca04", + "0xd4cec04b0a1a8a2240cd2745e53e55dd560c3da0bef625e3472a03c60e5e1346", + "0x482aa6954d7bfb528abdd0d2a44ca7256adc9d2b5c885f67af0424add0f85039", + "0x16d73722fc18c4c5fe53ec609695dab204ea3a0ac8d52356acc56377495dc715", + "0xa2fc87f2deaf252bc56f50d67e5ea24cdd23fc3a0931c69e5c7f832c57e6cf5c", + "0x95702d0ce28a00a2c52cac13db300b535e6be5aab6f1acd8f7f8f3664d8f1942", + "0xd7423e6ac1d49688437234bfcaff2f8075a6237b35b719084c6f9257d6b095ea", + "0xc1efed370db76aa0e6e31680e91ae03788ffb343c13700ed30012102a727ab05", + "0xad108c165dfc00e6db95fe8fb28a51a21f471d16093f761af92dc3c1a76cde18", + "0x579ff43e25ed4183ab6638a5b3b8ca5ee06343b410a47abecb154fa98fa701db", + "0x58446a3cb729e43ef984f52bd3a1c0c5bc2986b355993dc04826987c9a4c2b0d", + "0x916b6e17ed534b2ed79c4139250ced98cf81a39ce19092ca7593b8046b010fe9", + "0x5a85afb15b437acc1958c1a35beb35ea25a4e4bb2856fe82f4d2c257ad92e4ec", + "0x74f15f12f6acbbc1ebe68f82e5832c2581660451eecec1d2369ca842c0384927", + "0xe3724b93bfba09e69c4d3991f5bb7560dfa58f264a2ecefc1fae2a933fd81c75", + "0x4651a72f64ecfaa2b51804f6c02f0e341d43163b408786df50569668d6b1afc5", + "0xd67008562a459791d2de81c71369507475fc3727fb46f68ded3bdf313ae3dbaf", + "0xcfd841df8cc01abfdb09b47afd98caaaba19b900c7d4249eac819f24ef7ae98b", + "0xedb8f1bb736b4b16985f41b97209730b6f99d981fe3ca0c614d138cc9f3651e6", + "0xf03d65be04a3b5011007b48aa3eeae54b39166013f8f0977fe185036a2302360", + "0xdbc7e5449a0af2b69668ef3f860dbaf2b0e0053eb5f96bd5879f59d1535aac78", + "0x44e3d860cf489a017a5a0c99b7fe2facf87c7bbe8c641bc2ac020bd45ae278f3", + "0x8f2d4fb90e6fb5d1465e5e5368b36d44d2081842b2c3b1ac3c2789cc8e2061e7", + "0xb47a9bfac379a6414b66c2b79ced91d87f130b0c2f86c67ca5295fa656547b24", + "0x8975e42bd19f5ff5a6336f835a53e0e7d8ec1288b9f59c266e1da463fff8f24e", + "0x52a573f0165af4f0a8bbd90c8ec2539ff430ae8bb9818c2cbc2c91f82ec056df", + "0xba647605f77311d053ff9c76ac71e88b6d1dd6b4dd5296eb0b7fe3e07eb43880", + "0x1c6d4757e48f80ac0a247bc7b2649239d0284b2580248a8b6706f04ff47c1f1c", + "0xfe42314e663a9196f7bc6b795bdf2763f49467c9b2183eb02c25b5c79e20fc44", + "0x15b6054f899df7793f03ab925c1d8df2f94d6221552b890af6de5d8a5b7948f5", + "0x694798b4238b93838948377161ef5165af4dfbda5f0f9d8d2d37c083c3718393", + "0x58724b920890120f1f90ce8bc3e9c6639042b3cfa78123bc9917b8854315e31e", + "0x21f057c8e538eee76a95659618bccefab9a7a5ffc955781141a3eef71f3b3423", + "0xa5fec657cc7ab1b633023791470bb2c5a7f1dbfb3ccc4e6442565a791754f319", + "0x67a17493b80cf75ab905ccee157746c7ed048a8406fdd94af1c6916cfcb29220", + "0x9d5132754a73e0ba316da2f824f5264e851526c6a75bccd153cd41f232e1ba42", + "0xe9f6b8e973183e7b89ab72479003bcf07cd0d141521c23e4e4269f58f51692ad", + "0xe52cf37c47ddd837146288364ba448980c24dda74c6a2560a99ece3174c94a57", + "0xefb69d2b602cd8b073314ae5af7d6200d23335f1e46980c205ba0bdd979d0ec1", + "0x3e2f6e13459a82666bfc366941b39506d84b1b6a1c94e4361d51d30cc1bf4218", + "0xac8562bd8210325b1dcc8cc3c4214a97d04ce795c3fd9049c7296f0d855045a8", + "0x22b62db26899a50ef8630a9aac5cef645512355901ba14e8f1a3468610473756", + "0x24f7a40ba3243eed13a4c2ad7fb273a1fd822a3d2b8ec729b0e5184c3f791e76", + "0x1ea72f2b13fbc945e3ca51bd681b2e12e4ead38f42622ac3be54a1b89c826baf", + "0x95b26a476c67aa211235b0b177964422d037768a1c162526a53e73b2777b85ed", + "0x1ed2cbd748843651a8ab0a31b256d4d3c6bdf3cbd3db7e73090a679756880a6f", + "0x20e857d94a0038a51313c8a67d30f7aed8b335e7cebdffe8795ee03e62e5443f", + "0x9b807ff518a22a7a40521537b137cc25904b8d2607d7d9ce1f0e50f2327801b3", + "0x35e573f1dc47520f16eb43240dcddb95d167eb8e59430c608f17303a9c86b639", + "0xa06a21571951ec87f6cba9dec2cc9f1e55b4b4d5d3e2e9415d30fbe50370af12", + "0x7961da55526e7a67feeac00e625a1ca93607b7bc4d4d68142ba791e46d333e78", + "0x5accacce3901feda7004414e0d514129bcbb14ea727f34f58fddf4b928774589", + "0x0d66a4004a235178a69941894ccadc2e91a843c849284db82e90a088c3d3c6bc", + "0x8255a1650988cee8c57e30a5a8fa159f71fc2f3e23f799e11f5bb31b09c54667", + "0x7d6936163556f21f56185718a6b7de5bec0375a01f4c88467820d8c66dd983db", + "0x3e3c08ff6cd5f69aa8f85e9a5d8c91462cc228a41e392b7a544e2efb6af87cd8", + "0x4f401bca18b8cfab219430fd6807aff86867ea52f12b45ec224fa9dc318dd789", + "0xe14e32f37af0204cc56fb10ae891cb09b0c27a116ad42b5946dd1815f445cfe2", + "0xae46c70ae8bd612e760b614689d48b34358bf504a2414b660224312622917e4a", + "0xe8870fb901d8234646d87be0eb0b15d46f55c8d3765beb631dbd06da88d50038", + "0x997b7b18cccdd31b611bc01767a3be138f5ffb2c92de11aa1fa486a578c94799", + "0xecc5dea6b6e3d233f7caaf17e07a5f58febf9fa6d0736228da43b28cb5538dc0", + "0xb56b9b982a7915d85fef49df531e0a1e8e8d000b30da66104265eaa7317ee2cd", + "0x09601975476271e885e83f96799f15cfa6c0a67037b9d31eebf01cf510fdd752", + "0xab2e7c3c19f0d7aad30ff986e9b2c8a56f09906b851c53455af4d35d61b20a32", + "0xe5590d245bcc42d8efe40d677c42d840da1b32c49369bf352f46690bed9a4dfc", + "0xb46810ae0d11af6412e219bb99be0ac22c033433b1567a36a69cd962c9456d41", + "0xc296086ad6481ed8954c5542e4083388a4048132a952f500b2c362a19e8333c8", + "0xc39bf0d7e42ecfe35ab387932eb54ce0c1e502168ba5aa74b838aa17ec294d27", + "0x1ea48989819dcdf6aa0e9b0cc41d52a4d348fa80c8aaadb24091c517e3fd203b", + "0x58974a726103f506b2d8c904a8b942e247ca648678b7b98e484c203e4bf03ae8", + "0x0ccee08094a04e4db707f8d570c6098cb87b271a2aeeed08e0f589d2c162afa2", + "0x5a8620a1f85f856a8cfc105a05d4a935cfe626de46eac68e2c78c7b8fbb08c31", + "0x070101ef142836edb475e9e5bddfc821fbac8b2f8605ad9f52a1ae00bd0d1f6a", + "0x822efecd485d634912a4fdad41d72479c31b7cfaf664f3a0f78dc9ebb624cede", + "0xc6c7f14ff1b5618cfa096080c6fa59d301b3c2f516ed9f4eb0c3acdcac3e1ee2", + "0xbe85e53c24900f6d22564f33f05f1250c9f80b1b4616c0dcbb6f500f22d376b5", + "0xa84385d0d3f54995864695c96c5fdd30affe8dd9548b754edd12d80802706ef4", + "0xe12c3324e68b4efbb14fa5522ef6d2418ef7c397f390c2b91e30352ffb538c48", + "0x06cafdf319f45ac908dccc5e510b67be82635a488234d9b3fd016dd2f09667d3", + "0x236822c1c20ce528a5d9a985c2a2eaf8349a3ff1dc13cb7f9a8c7bb5bc39e9de", + "0xc438b7d70a69768bb81ab867d6772133a592f7cf770931eb51e893c106461143", + "0xa49a416419f910f762ea095d4e8eddaaa7b01b406e730d3bc1846d24b6952302", + "0x08c83875d8ad54befb643c8d8dc684358aa22c144b9448820c0a62e5ceb9e9a0", + "0xd81a30c959e06eeeab28bc3b95a1c8a3466f2552d51ec0bde69a1d1f107f5405", + "0x76803ab074a7170033dbcc33a68d2b497998dfde8b9ff86101fd54539d1bd393", + "0xf7b9503ce1753623091cd263ff23af68851445bdf97c166358b890ff9dc78f17", + "0xbef1f09e8233542c73ea380abf0115279469e2bbe3abd557b89d12b514bc7a7f", + "0x8ef2348cff8d0d40e6f1b0973636915adb3ca63fec663383b8afac1a46dd0e8b", + "0x9724f0ce677572033e30756e4fd356680bc64d171acf7483d5dfc936267d3d8d", + "0xe5fe7147af6d1d1d52d34714de41a7cf7bedf38bff1a29a25263beab0f59fe61", + "0x3782ed2e5a049f3d877c8480b590a5d2055918c17804fad7ee7a6c2a4358bdc6", + "0x9bb40bd9cbb5d20c8987aa4e75b0a8036d0d10d87c46abee889d5fc23d10c98a", + "0x75d9d23fb96bde45550b2cb8ae4759ad36fbcbed51f00cf1bd1d04d0f5d0400f", + "0x5a5f79793464475b35bd7fc427a745b76541ab65d62e500d93e5357e588948ac", + "0x903e3a38194c6eb3cc98c857b98ef68bb1fc988220b12138ab40141335b2b9af", + "0x9c5c6d1fc8f1242a0f3f41e6dd9cb7c1ce6dc644b1ce552b3dc0ff7db83251f6", + "0x77b89a725a743a7b31b01022e4ffd1f35f733461828f204cc75f4f00290a01ba", + "0xabc38d580c92f199cc0aece60899fb6967ca48a096b98991dd757ed1fba6c36f", + "0x61742ed64d417b66d67e4638d0bb60d95f88cca17cb7630b1254ac3c47739df5", + "0x47f7bdedee6e8eec229eb0f66fad208a8a05450c8b649e2dc400e1b5759f4b1e", + "0xdeea16c07180d8a4eb104e309343225a354a3adfbf1b8af733456a185f3ca669", + "0x6df5b47f5b11511f42b4e981d92d55cd9aa3373fd90735cfc4c594c516159027", + "0x5a5af9e8656afd3b52f4e27002f1be9b09c5e7a3746fac7e64f5973ed423c14f", + "0x1ccb86d370ee32261f76a3e9d5948c40489c26f2f4216535484d7bd586f2851b", + "0x313dda0f2ce1542eb1236a1d555959516abe06951460d77664650b6cb7613d5f", + "0xfcf5408ed6675b5d1c15629e02635d726777e63817c3ccac36d4726bf95fc4db", + "0xbf5f15c67971a4b624a8ee8f81086fe24f1940a084bbfa031d0b69b865d553c6", + "0x9fbc4b0ebc2a128d391b68be84f6ef7833d5413bd95f751b503799a54c55c3c5", + "0x7ba3b1dec981980a957680b3c125328bf3683578828412c3de197ad07d06565c", + "0x4d2ea255cff42df73c96d18fc2c372e5ea9fe80eab5c98a6c6579725bf4c6fa1", + "0x9793db50b81ac75df1846e8b8898dccfa822d69bc4f99f6bcdc95ace2e3317fe", + "0x21c1959416e88792275d6eba88e8fa503c40a1f4a4b78cbab5b94e6c1ef714ea", + "0x3161a8a5b42bcf792b44bc3f7fef3606978b6bf716effb5ca1b0fa6b85518ae1", + "0x59ca1b7fd1f09941c911a4a6d0365e7a852a420a43af73ee0bd76f6413c6f3f6", + "0x86db4d45c982f195667fefc3de1af4a17b083b6f3700e47568ea43829e686e06", + "0xe5a713d52d696cbe65220fb30a4183ff9121ae1868967eee002cc032fa41b07b", + "0x446668d8777d9666222a04bc9963f89873387535f485490adbbd15094e6cb9db", + "0xda139e22348743ae9d600e9e2f651a717b8864f7bc8a4881a875945daa2645fe", + "0xae22c6f51fa8c11daf898addd39665d7bdf6d266d42ddabd790accd6538a6778", + "0x1059bd6151a5a3de93e45f7b3c498225b759a46444717cef5e66879b6e0a43ab", + "0x893e490bd7a3cef98d878f4f55d22aa0456f934e16a5ed635bab5d993909b006", + "0xefff7bff0a97e0e51718eff0d61540e164cb131ebaf466f01516ebe956b6e0f5", + "0xe6eef674ead50579daf941c526fdb904419a37f009fd432ce0521835b7ea09d1", + "0x7cb9c0e3aed016176058c80a03eea8f70e6f0467cc744ee752d937422ddf455e", + "0x995c33746119fe51b3a3c71311fbd4d91810a2ad95a558101bd11ff1a9913da5", + "0x926048c8fa6053aaf47f8986f195d19f1a86a4e01d5b34c45c91a09f57be0cfc", + "0x18ff8ac452c3f84463c8d8d92fa6f5550149f0d9cc0bf9b9a6ff6f05a8e3dac4", + "0xb495eef7e11375f1fdd6fa2fe3f97e1b834c39abe60ef1eb75333f36474a57c8", + "0x8dd386ddc871b764849a057f98a838f0f66883cdaea5ce4a9728910d3e1d124b", + "0x344c77e81e60bb40be5a20fa14b7fdc8c4c696d523cfcabc408e04df7fb79259", + "0x6b55d08a7eeb8f800866f031cf194c0ac2292923fe0df0460fedddcc77ba59ae", + "0xa007e70a725287607f23c03a782cb36ebecd692b45c1273b62769ddd1d0caf1d", + "0xb196d7291e437b6a26d006634de1edd3096367faacaa2b64b6c52a5d2228fd43", + "0x7f4f82aaff92c6e348d8b52e3bffddc7d06780b3750630d40022d54e668ec761", + "0x942e657c2125a5f57351b6e5fc76cf6ff6690529034f65d1bfa18ec8827bb241", + "0xce436799308200b480aa234ee2a4ad407bed1142999a360ce8a3d2230bfd4285", + "0x9f3fe03371f56c4afa64fbf2379c7dda3752eb19077a4de4b412fb7b5a4721be", + "0x53f63ddffee8a93759f68730026c3a8c9026a1a61a17ecd8b98d29e3d24dd019", + "0x08c2112cf1abe207076a67b43f67402df0d9d99990cec96e10ca46f4799134c0", + "0x41c4a5929a07431a1a0918caa5294b9b0f706960afe8e75b0e4555e40e182d7e", + "0x188b2fbd1b54709384dbc8b62e21cb1cde0b5c743aa3c25d8ce5ba4557728a54", + "0x92cc75e85ad9a09407bd0c09d68436fc419eda5c29614e125ff99964e304c0e8", + "0xfad03371877721fb4477f73575cee54356114f0842222f6a343357a15d409568", + "0x6072b8482ccdfe974790727775e8c0c43228a724068a39e351a5c702e7086fe3", + "0xdea9c30a8f46fe7e34b191d90b14fe09aa61275a32063ccca2d138886419c60a", + "0x3c24861389a3d1a8ed5d2c71e052914d4dabca490be956b7ed63a2195d65bf60", + "0xa2dd585af11cc6d60b55ab7b5295db6f5fd49e34c58948ece2ba6a4417f53fed", + "0xd0cd3dfcdee7cf3b00e718b6086ffbad37e61b80df49c373371b6ea449e5dfe9", + "0x018a9cccbbee610c3d978afce046e1e729013fc7ae71a0d80b2c22054acc32bf", + "0x6cd7707d257de792f35bc5d5080ae5bcfc50188ec61b406743f0390e8f5e4ee0", + "0xf036437c80029ef8595f65cede2446255b436ab2b47cacebcbc513ee09bbc6dc", + "0x438c8373efeb9d010e459097f7eef12dfd469a5d447f5494742321fcad2f5fbd", + "0x97174ad7515662e1cde2300a93986316ce4b7ae00b7f35a0908cde607ef6070e", + "0x8527198f8104df2b8559ff578ef5e2a84a9f0ffd63d8faedf26a50b44a19932c", + "0x7e4b79ce0fa7dfb5b4cfb92a98a0f4de105ac1a931a34efe94c16e29d5b03fa0", + "0xc240072b872710ac52ef170ca53ab03b3f76f1e2c1cc40dd48ebec3d0636d6cf", + "0xf957c0f8495186575f4a1bd2fc19350c9fed57fd60a884999d943e5fdca35038", + "0x814f0dfbdf3cddeaa502feb0f13f879223d9f0a14d01d756c3b3e773b44ce581", + "0x999f07e2f640408c58cb9cc0d15b4ff6c90db7b85e98e6888f74beefce295c1d", + "0x71e4362451b4d259a942b2a0425a070a9f0053aebface053d9c02f9ca4a5ff3f", + "0x28a29356d506b43e9dc9fc05bf6c7533e6670f5ab1122f49ac572bc2c9b94b49", + "0xa6dc1aeb3352b65845baa0329491789262c71b444171e36a55f3e20ab5edc026", + "0x6a0d71aee995e2857459513c124ccf8f81212ef0f14ea8a99b24b395e763e2b5", + "0xebd35e5b9134079efbdb4759e0c2af7728b73caeabc2c2bfdc3f590d5eaabc68", + "0xf1a7367e7b712b141602d204924a0c8808c68b013006b344e30d207a3b8c179a", + "0xb142818bb0edf0b1cc120389d0bef91b1a7b3e1fe0058810bbf73d04cd573147", + "0x8aef2ed196ca7cea305211c656084a46438ccdb7d2549f24fe4bd3fabf11af57", + "0x934cdfed19bc7321061d3ad217879cd14def18b18f6d8d2baa625626214d39a0", + "0x16f1b202a884faa4dcccf5d408b3acb639a78aa1104d1bcae40182f71d94a1f6", + "0x5cdb53c18168fa65c252659ba594552ed95150a4f0f2b9391ea3fb56badfe814", + "0x304558b9ab585c1201af4e88848d81f5fbc380341bfe8df9e9ebd279a94a1c4b", + "0x7c13cf0890b8fea28d01b7446750a5f1429d343ba69525e3909f054495d30f41", + "0x38ff978ee475767c435e5cbf5c0ba9c10c48426a9839735b67e2d32028a1582e", + "0x7fc90ebe34bd2cea4744c1ca0f3968a304f7cbb133353cd0aa76b45d0e88a23b", + "0xb0da2f67974a7cd5a291665ee3d216d5f57df1b66e7a2f36dabbd97cc68bcd0b", + "0xc220942a0821ea338d4307365bd1be586dc8b3a89f2b0f60065c92375b1bfcf5", + "0xda1019e4bac45eae0717a35e7aad0c63e0063ba18a8e970cd631112a9baa3d3f", + "0x7efc5e52c0a590ceabce9eb4eab90c50a1bdf595b7a59b0ffb3e3091317377c0", + "0x2347c7c6cc6f741e484eac237688427292a65d01f037ab25419d3c17d538db6f", + "0x207e2f3f0e856faab65882a7d3cf09daa37f08406cb96e5bb4252c8d0fa7f27d", + "0xc425eaba8494a111289148c65db0c8d6a6dc27d16986b0b70ee4995723c878f1", + "0xf7778a3d1b7fd83b3d4926d2022cf823801a2749283c9ab4f86f87126b9c7e80", + "0x1316c7953bb3170efc234d13e9632e017ec4f58a30e4e062ead373b206461f1d", + "0x9b4cd6a0e47f2c64c0ba4d9a7565f74e956cf881bdc33b1176617bf9f25af5de", + "0xa972bf247d8428e97218ec0e9a36e3b7fad10ce9a3126bdeb2cac7e9b4e48e46", + "0xc6a4e22ff93e8c9483dfd8eb8f2c384c72fe69cc4f5644e8d68d419b92509c61", + "0x601a9a84099f3205c6aecd034b53f586382379dc39be605facbc2da5f793b990", + "0xb7ed45da8acd237dc9c265afbaa15300cc7cf72c740bbcc00eabaf4dd90cf9b1", + "0x37bcee935e0ef47df22a7f9833b3b3a3830efb1656059c450a7e6a144798552d", + "0x06e7ecbc0f4d4b16a24d4260d77d0161c5a627083589747c72f765281ca8d3c4", + "0xc45d35b6c6a81240767ee9d994c8e2f5823d8a4e0f51abb7187e234d6dd5076c", + "0xd3c726980fdf096fa314533ca3e882cb1c1a2a5eba4b9ccef7193e9ab7ce34b6", + "0xa6c23887788743ac8bdc123c7b21873889d538f7acc389c28d6ac9dd26da06ec", + "0xb8b8e38541b9143da71d68cb705ad5076b089b6174d99bab4b87428d8828ac9c", + "0xa70ec737a97e306a66b7ab8a7866d03d496bdac04a08a0ccede2b84583ee5d21", + "0x6d43013f53b03cbaa4c82a2d42f5336306301bc7a624542387cb0a822ce89a50", + "0xc24661eb76bee7b5db00df129db5c2038dff544a90de77809a447530e8200d02", + "0xfd291a2a58d472bb262b3e9b4b2c08f8ca40536082e05c081ccd502c77a78fde", + "0xa34be368c12bd1c05ada73b647d72da9595b0d618679905c2df760ff1a2b6dfa", + "0x4e68946f1b2d9f9a1c10f90b0d354084561bf5440a823945c2d95f76fe23a765", + "0x44e04796d2516db3ec1d1b47b47776999614e81f6d300e2dacbd4d15746982ea", + "0xaac3047a84d57dac9b3f3c8ba907bec354f99ec2d35b915f115f4af6a658cb41", + "0x58489c0ccf49e147ec986ffeca33e037dedabc57690bdefeee7af8a70b781fbf", + "0x3707fd39b11fa9b79749a84848deba1c70534a493769788de1610798b30eb70a", + "0x891483f79855a712f99bf6bbad19a3291c4d417a4f27d66868951c454ad1bbbf", + "0xbac1fbd157279efe1b895138c55e8da4be5dac3b78c179c4cf25a0c8b5e7c5a2", + "0xed050c00def0f6b5936324a13f426cda7229ffc68c7f0eb0ff6dadda957c737f", + "0xb0e759e352ea7ccca080e4ed51a6a4aa4573c7c0d703183da7a98918fa9bed81", + "0x914fb73a4233f0368088073688994cbb0bf5f973a5afadc11076cd64f92ec5d3", + "0x153136092380ba6be166df58738c72d5be76acafcab31474a72b7f7e70e9296b", + "0x7d4d6f2fef46e1b87a73acc8c6eac29195286af79ed7e07998aa966c536f8f80", + "0xa0d10b259aa47815403230b836be272c3dde8cea738868ded0d55d89f2692dae", + "0x13ba7e74aeb0ad66c77cd5112e1ae1b6d3eea84a7c306d161408ef592f2f3399", + "0x491fe1f14cc862fa156f04901a7a93ef26ad272cf98e4f29d28a6250f8b4738a", + "0x92a8a01853ee89642fcf51e42e6a39616f8374937a98ea579d9fe35557d37bdc", + "0xc140bc3ebebc1509940644318dab91a6b8722a54bc32ac7500d94d1aa24ae1ed", + "0x55a5a8541d36a244b1d73b32fbe99263cd6a7b3d9b88312747de6d66302e2a63", + "0x510caebe6714728c47beb114e95177c3a0fc2438369842278a17da9c4327caa5", + "0x8ec8d3e19017cdd4bb4b789ad29bca53d8635596e6771e09becb9e261df64be9", + "0x2e832a7e47a73b47ae881794122f86e1a06e1d84c5bd0a946bb61175dbb5c0bc", + "0xbdb48c7ec1f278b646faca580983ddf4088835803fc0dc2e505be6b092442d04", + "0xcee8eee843b37076f11f69b77094872966f88b4629240e04cea69d4eb16d642c", + "0xede0d0302e40a6e71dd63a52fc1bea3828c4dd56c754b576af9c441ffe2945aa", + "0x07c84f827310d73cc44181f612f5f5ee0ac1207b3f72ae857f9f1fc0180e8454", + "0x40c4dddc5fff7a7a5372de4d64945900e1d6908f378d87b4bb75e425d1fd3daf", + "0x61d9dec3abd29d998af2cadfdc7d22344b651efc717797a486712dd10a726c01", + "0x9de133af95e03c3bacdc17ee428c0ee05b70ef2b1b515edd6fe488db3d091e88", + "0x109aa9704907a39615ccbd296974e428bf5fbac0bce5af02d9c3a8e45e47e160", + "0x8a1f2230da7f048dda7d17e7347cb1cdd2bbcc2ed0908980f22ec070d158689f", + "0x9e8215bd095daa6870eca13dd025edfc700bb5f5ae4f0ef9d44a85b04f15596d", + "0xf93f90b45c5e3358a73392f21fe640c6aff9cbf352eb7a1725088313630d6226", + "0x4e4c1ceb1177bd15944b238624f6e41aa0713564eccbd7f0976f22cfb03c90b9", + "0x2b7d1e8792dc0271b3802e79e4531e42d93475471d880de288dd4cfdd85155df", + "0xbffb3529844e19c7e24a3bad1fd0b90d8319c6982badd3716ec897ae01b0ff57", + "0x497725904d682be0024f5327c62907f1507530231fe6437341e85373aa941d03", + "0x20c7929ae689311a8edc8672b1ff85d79b2187c46da7d0f1e0decdda16eec6b9", + "0x87fec4a78f73a200c7798a07e9f7d956aafc83ab4a90309591bb76152b8e11e3", + "0xabe053b8ae209ab83d827b63e43e08b9b4228b04d51026bcbf044531a2e8f86f", + "0x4220e78d59f01c20f45273e5183a2a36d6d89c2f406df441e76fa8b3f540c8e4", + "0xbbf658cff95c4f1cff08b95069d5eecd60ce5960818014edd66b4f0761708827", + "0x885d316eed1f99685d4dfb1d50701b7a0c9892131a99bf1c676d53c15ba1f7d7", + "0x0fd86d1ee76af5eacc36255f29606e4574b93b1501762118173cfb9997996c78", + "0x400114dc52b491898bd47923cd5d91384ad6a728f725ffe87c916ba858e58a95", + "0xd489355bf13693c3c70b031421c885aa09772cb9d10381d6a5dad584f2055790", + "0xbbe033546ee5909557cb5b96d466ca32973b455f34bba60ddcdee782d8b6cadb", + "0x207bdb63fcf0b403bdbeef4f714da0393b1760adcd1f1f5b21a178bc404c9617", + "0xa30b9d2cffd283cba9de68eed716761ea78170a8d7e6444068d64563c141dd2f", + "0x995015315151329c91ad8ad28aac545c50196dabf0ae393c72d9f369524c9fc8", + "0x3928c0b178546ff50c5668677d2605b701b06f4d28af0c189e746b73b9d5c53d", + "0x46bc7b35d38eb9efecb3082436f28e3d0e36465e41222dd8b8b47fd9857de499", + "0x93d83ff35c0e00277205f12b3ccc89ae35c28177023f2c37b562df491dfd0e1a", + "0x11442d3d7778f2e463da87bfe957768e36087cd2b777e8b0d78fedc624b9a9e7", + "0x2c4ca247e8c280db854ac3ff7d270ca3100b30377b6ff807b853da46c7321113", + "0x0f72e138a21dd3ddd2913dd1eeae525cd78aa578b909672b4450158bcae26aa4", + "0x6a02b4d5e27880290806d410461c10558f33ea04ab655d291e45a7baae5d48d6", + "0x5698a8526618fe20a06bbaa970590e97ca9677ad95b0b532cc816b2577ec1bc7", + "0x7fb913cf94da8bfd05526a954c1f2e1382ae275a060b646d2ba78f004d67d30b", + "0x1aab7d83cd25cceeadc8352a9de9600b0b69acf33a3e157e5e54044a4b1baa60", + "0x03df372e7293b449518d07c4d672c76157c97c6bdc8d7ea75b5d37daca19dbb7", + "0xa928453adde66a9ea45a6b19560fef2619fde93a0a0ee463d64ce538fed0f8a2", + "0xf9cb142d5728bc1dfd59812afcaff8877e6357a46ac9da8beb54c1cdb53bf4f2", + "0x3c67d2318e1867ee0bf234129e7f9ff7aced4d6a94bc2493df3d49d3ef7a1f1b", + "0xe7995735d058d5f1281298652cfec16318f36d90aabb73bec620db045a4127db", + "0x796b4fc8ff8d962425ad653c20cd5e3cf5802edf8fc363824cbb4a117e5dd9c6", + "0x3e1f5f3519dcd5649bed8a4fce463bce7b8a28ce4853b2a34c219c76d8e64238", + "0x0b56a06fcc04ecab448189e170470bcee6415c859a59a2d18b5e9a838bcf2ff3", + "0xa8ceb396b19d4c72d6379f27d0a8283a06c7920811c045dd2521b20d719c9f60", + "0x42c02012a9f184d3bf976ecdb7f65e7abd70b4a32493d75cbf0c3403f5ca358e", + "0x79aa61d2303214ca5099ce8d8c8b59d7d3f64d4af9a009683ca4fe2ecd1ba4a2", + "0xbf626f7b1e4be0c3fbd962e021d50f40e580f133b6127a71ee06c621fe6508f1", + "0x3a8e93479758ef89aca8a3311a16fb82fef78b19ed11c058625e6bc6d4a4dab0", + "0xb44da67d7c6114b0578183dd1287bf06f0f8185a41c77ea75728e48954b4959b", + "0xf49609ba698b8085cccdd8f95a51996d9df32cfb8d0293c01182482dd03b56f2", + "0x94226b7a92c9aea67f94df39675af2f27cdc9a95c847eeedf85ffa17238b3b58", + "0xcb27475102016a2ac05f8c8718e110b74fffcd6c2a97ad0b344ff07a6a806e2b", + "0x84b0c9983378884ad2ecd01c7851efa8c0906b4741d42581c3f1c52c47a88151", + "0xa9071e8c2f56b564873a782630fbe3bd292337b2b620eaead27a397ee3b3aafd", + "0x8c057d25493e712878bd8b628b3cff7bb1249ae41dd34c25ff57a3bd12b9a96d", + "0x7c2b71dbda144cfea3c1e492f0a1e30f2699f3f1968da76a97fe39f3867d37bf", + "0x63b9d33e4d168389637e6fff44d525b67b5e0c52bfab9fbeb53df0ecdd601984", + "0x2a74b62ae8feff55542905a34d6f45c1441891130351bc9959c62f53864385b5", + "0x725a488e62ba0c296ee78267ce714a8ac84ecc3fb8dc4b5147024ee500821dd7", + "0x6c54d3f508c1421a60a707000e1236dd6b45becf483b1f21a53723188c1629b6", + "0xea9072804289a3b9fabd8652a56c2da6e661f14ba764f72949f7fce38e517e7d", + "0x65118fa4f148eb7b0feabd60c0ab9d42802a5ad7685b70bee9ef8eab668c046b", + "0xb07416ee467668d8c7f92a260a6fc430bf636e29b9d5ded3dfac9751e006eb4a", + "0x55385976c32b170335a70a213780cada5fb0c6dd5402cd3056a60a40a6f13afd", + "0x7d9f44575cfa89ae8f4e160a1f432e3e05d02c40b9d25ca0c06df6d35226985c", + "0x12774d382f48d5be794157e2a601c3814135f8cb961d534e685368c3d605f430", + "0x2be48bbedbb5d66af410fa612328524aba00374c152a0b533fb2f15e98bcce10", + "0xcceb249b515238c46a805cbd452395633f28864f16959cef39ca13b69acdcc2c", + "0x90b5204c90b256708cc946daad4a70e3cbbcae36356b377ea6cb251568d8e87b", + "0x468a2c9bd83eabbd10a5e301201e54b9530b9a376452096bbed509240c6d7b08", + "0x322456bcf4495d9787fb66d0d8f21242210167a1dc622706c647e1495c19d064", + "0x1708f1ba83981d7d6d21b8a7d55a4bd9c6355195bf42eb96e870a36480f90cd1", + "0x904c7c58505bb73503c5baefa79936d96df91a15a6ce8121c7f38c632dc7172a", + "0xb2592d5491583e30e4b0e89820f6cd518d4b082436ccbb3a7685c365fb6e9aa4", + "0xf2b08ac926804a68d4c1dce8fda9cc1eaf14e963499f29527caf4797fc47933f", + "0xf9274e64683f5717fc4bce6bb2590921be5a67c1c3f9275bc390a438bdee8295", + "0x7d6c4c1ddfd161753d2782c80532479eac3ae593ca4decbe0b4308123759a218", + "0x3215152f21280b1baf712191a11b3bb80d48f936221a02d199f52437d878c402", + "0x748ac2bba96f92574ff048d2e3100b8e8543c181c8e817f3770e405f24b4e3be", + "0x056d9dd029b79d40d3599b6f6bf240603931a247979db979dd9e6dacdcc53d94", + "0x56c57e769cb7f53c4ca489db4de4eec62071cbed1bd33759c27662e411de0221", + "0xfc7a497be0b417bc1557eb04ec43f9ba4432cb029b6684c295b84e500527d5da", + "0xb505ce1021402ccac337fd5c5346fa162c6843b2d945b44ed45afee0139df1c3", + "0x267595787775e5a0d97e1cdf0a4deaaa785c03b8456a6e5b433767bbadb00ab8", + "0xdfd8e51ed2325e8f2d2bbcefcd24bf9242fbfd75dac246ac8186cf3a72b35de9", + "0x11004185cc8175d91364e878229f5aa5a5366130152e1dd8132cd22cb0333086", + "0xf5ec1ef381b33decb885d21749cc32ad02cfc66392281967758c3fb30158f9b2", + "0xef7fce98b3054d4fc282b38aeb4bddab1c35b085ad4ce803856157d7fc9025ce", + "0x7acbcfac776f80cf46614121866a2621df9302b7be20c079e224cc1377637586", + "0xef8433ec6eca61afc8bf7e8ccef7e1284aaacbb4972938fe061086307a6417a4", + "0x1f76cba9e66ca16339c3effb745c71443bcae09a22f1b07e39155a1805402890", + "0xd720f64f8ae3da220074c029256cb459b1ee8be67ed4dcaec10933cad35fc58b", + "0xf841bac34a5db54625473826eab74d3a53f7b3448e5835cdf4df370624d24aa7", + "0x7b784f45b8f2b0ec9229924fcbe26f66c306297cacec42af1c474566e1f83f6f", + "0xeb333d1de57ffe52d60603c66bbe9f2941fdb01f81832d418307596c156cf54a", + "0x06abb43d2b3733811dcf3059f48be59587425b5d24c086689191e5bc69fa03a3", + "0x76ffcb35a00362f10fb36d68eb7676093c3e36a3fe7ad65acd0f58a064865f2d", + "0xbfa99b31b08807772e417d9ed67daebed645ccfa0d94607dc0cce754bfdce0a5", + "0xa91db056c961f435693a047611028c7fb784ca015f450e146bc8e2b85ac8d592", + "0xf2489993da543373e00b5b42b8db157eae15026a65635e5784d06702d6574de4", + "0x1629e6d410d12987f412c01d14a21ae700e4939f45ec4ef0e1820905649b7899", + "0xf127b506db1c5b3a1aa6bcbb2c530e822bea1ab3deb497c54430fec6a60824f5", + "0x4860301daa24a54ae1902388dd072e7eae2ad449f4a86c123caf783284cbb7a4", + "0xa54be84ce7432042663e40822685cd4c3c1a33bdddb295dc32f9170ba7c95a14", + "0x576136e6b6f941a6861e863989da38d7234f524886f278f8a57e88bf925088a4", + "0x08e84b8d1e15a7aa660666a346a0b90db8cbbee7cc086378d4020d86b1385511", + "0x9229a29e091b9184dda6d66e244af33b0c536eb7e61b7777a5bb0d02f0a283dc", + "0x58e34e5a073bacffd29a05f85320aa52625a9cd27675954f739f3f9229e3a163", + "0x25d2f9f20d7cedf8582931d6dd9ef68233f3af9caf6c9c6d5a10f2b9372358ab", + "0xad43fec2e1ea1ff81772fadf5e38a4f280305cb225567becda2cd518ce2f1dd9", + "0x05195e944c209b1eefbe1925827e976c19d065d18b3e23d883ae2086471c73ac", + "0x62232485944c27ed398d4928cd9ad1680765a4efa652a925b97ae26220229fed", + "0x735c916d78f40581506a4cf286e044a6d61afe6d70daf97d80f8c584ce41d940", + "0x8b50f9bc93ce7c7582ebbd77bddcbc3a123e90d43434d63aa4b5c397a18bd1e1", + "0xa270240950e22fd66879927f8c51322f0feaffaf09e7bba8829ce5dd841b9e56", + "0x6791446d6f864992e3b50fb590719af98aadd7f8af54e4c71ec474cf0db56cb0", + "0xa22feb28061c72ce02f7d6bf27c7d04049900ec24394a73ea678b90c100de62e", + "0x0fbb9f4ef4d048767b036f40babd8769e185c549cd71e2e46cde94b2fc1916e6", + "0xb32bf314ae6b3994bf2caaa716691eb2116289a796f968ace5c49482965d2037", + "0xf68f7edc391befc772458ce2dc9e5a1c3eb9d3c709c4e177535a14a863eb686f", + "0xee3c3122cf1f7890fcbf409897c6ca4a634b6a90df2d33cafd8dbe1fd2895ea5", + "0x44c407d967d458d6cdbec3e4fd90e0f5fce309f702f08df5f7fa7d4d66ab8d90", + "0x1e4c7644e30228dd70194e600a57f98c3501a598835ba35a3b0c99f53101b108", + "0xb619a4deb408b73810fd4c5a827c0cdc3f7f9885470f63c468794c7a0796c184", + "0x69ad24f8814b17603ff6ffc1f585346e243a296f74bc3781453a512bfb746a9b", + "0xd311dacba946134de52ed8f98e5a643c0b4f8d5c6d2c928ebc5087b33b309422", + "0x59ac40ae911e0a13aafdb4961c459a9cc8168e444f9288cec782911aea1e5548", + "0xfbf447c35dabf67ad4e88a41e30c40133f166adbebaa154f0c571028f86bb183", + "0x64792ffea472b80e6241942b1191a4e4228e79c4e0a436873ed3eb714338aff7", + "0x618ea5b82192c2e43742b8d74e78234efbcd6332d74c18c97ca087be66baa8e9", + "0x8e659da466b2150870fd5ccd6b4c7e879f3d5e248bb386869bcef965fef02837", + "0x4ef68ce8190a3430e4aa1497ccfc26e31d17ce522f1f16bb7280fa9ca2d377b4", + "0x79a10cac12b7e9b922d9c8d1cac99ff5616826a5f176a81536402cb968377e9e", + "0xa4fe7b019557ab1cd8d212da8704a0a84e8078eb9ab53952c2ebc0c3914835b7", + "0x59916f12d4cdc91b9a0e135d84630d10c48a803dd9b84ae35fe00c29d1acaf58", + "0x802690bc2c2f03e08e2d2dc7216a033be7eadcce3180f220fa5baf411cfce958", + "0x40fce55d2c349a7f97a252f6ae7d10013c396710905abdac17ca794ee1e247e1", + "0x73dc6101cee72bcc15f9ef398f90f2c5e3f616c97b0c6714b65e9a6a83edc190", + "0x7a179bc76526a5752b82b1556692acb502a72e364ba1295aee91abc726c23de6", + "0x313f3a435058fe29e7e9c490553bd9791dad94ceea2ba672a2a2a3e7f69039c8", + "0xb528f654e6456ae46ca764295454d78f4d5a4334d49340a754b5d8ac24b0d21f", + "0xc06aefcbe61ee635fefaf4e2e933c22c73c48b55f8672cc6a3c8ee09836af286", + "0x6626a0134d8ead3f18aa09af7b1c05c01be0cd88c286535115edf3ff19e8f06c", + "0x90051f7019b8d99acbeb816ee256899d8f0a5504f156475cacc631f427273c40", + "0xaa93485a22e1fc2da4c5b5483ad81208bbac2595e758e23677e93521106c1665", + "0xb334853c4ed01341742733a9b1d7ba7430f3353fc1a52d0751808c98f621ab51", + "0x67d2672662726fb24d884ea92668fea97d9e0d908a11f70bd29126fdcaed009d", + "0x09cc08cd5c0da5caaf74d0e8e417fe151129ee7ee9b5082f415f2ede57351dca", + "0xf87ef937db4618c977d871e06bcd6e2eabc7a20faa0ec0f08deff573200b0aef", + "0xaab334b96f82ec056e3c8e1e95b9326f35d57408ce24e63071e182dc38d552b9", + "0xa0d5f838bf15f771f9adf19f82e01308ec34111bda56e2edadf5806dbe80aa88", + "0xf288f085a08d5edafdd58a3a0637a48f0f6cbc730b0d3a0530a6780cea152281", + "0x8a9e915a3e1ac769bc5e3b308fb05cd49d6cc40e97f6cf8cf789f1cbebf7bd6a", + "0xfabd2bf75fef724ead94c7b6e24026264ec2728bf792bd0595aad04900c69640", + "0x3b4a6d3a6e62b3fdc14173ff99419ef02b18134050f8433080e65322bb0934a2", + "0x8d72cbb4e088da0a6725163af3aa47a69b63120f3bd02b93e12788b144e1a26f", + "0x0a112bde7c1434c444519ab9371a553ac25250067c72171fa6779efee4bdb7d6", + "0x8b89d89dfa4a2cd35757629c84edf71815311ade9742e48b6f28d1886f1741b5", + "0x538bd079c14a70a3f6db4b45b528e405a210fd6e2343fbdccec4235a09f016d3", + "0x95ea30334671da97054445f307f3b991ccf1fc965ef148000253bca44f6f4209", + "0xce98031baee0108eb9695be729938f22ee71abd8f368c7284fa7c102c2c03672", + "0x916fa5e6d29e5b17d29e6393f96f2707b2e245ef49a671ca30987c9d31223ef8", + "0x1caceadd646069b69b86699e555e0695c756108dce2c74ebedaa00b8f4c1d4cd", + "0x46a5419c22b3bca18ad94d7b0f34af90c62bb3cf660a4b0b6d28bdc11b079390", + "0xa83044af490b0706b350357979a9e648e041ea747ffec7a50f952b71b9c42a66", + "0x677dff9b0b4ca0f39d526ef4a8fac9bb49d83b5618f73d7ef78c3ace311fd071", + "0xc85d8672b034eaca3715eb6db5408d00d8157c991fbfb55b8fe29ce168aaec9d", + "0x89869cff97616604b696706b28474ae54d88387c2d5a30e690c0e5b31bffffd2", + "0x168585a4f4a9a745a588d609d3eced8e550f1d69a7399547a60456df218bf4d5", + "0xcb4d9270dd367735a6844dcc314782b708ea9b2de82e5f1fc11bc83b0970938a", + "0xb3b2ba42395b4c15d6de64f7ce010486ce1dae4e6b14f01901cf1f4b6a538d30", + "0x11601920286560aeb98fe1436a1f66e2c9ee69ed2ce11ef1eaa6b4b3be447787", + "0x45cdc9aea631ac46062e1d848c3a737da5f7f1d396177196e52b4ae1019a73b7", + "0x113956d33be8473ea7b52f062945a1fafe98a424d50b8b418eb1b4f8403f7036", + "0x2d5a740fe5eabb6fd783b9c47ee75166e2ef7916e75bd5fbc40fa0a6680d97e1", + "0x3bd16b4f04c059d78b8a28627039d6e47954d6a87543c611d6fc8e2e941a04de", + "0x86b1f14be4ac193baaac8092ca3d377f47dfc4e41b6b81e02dd51655fb590c67", + "0x1cc63d91541476745e3732b4220403bc3c994be2e62c6fb2e788c5a47af7445b", + "0x5d09f5a6d1570b09f03b79e869b7f55b344a2c5087bd4c2c06c8d4a85f49095e", + "0x6b48201724527b22e31898ab54616f0008afdf463b9afb6f0c516e7347bf0519", + "0xe79894ec014f7835965959a9914ec4620c6dedaeeabe7aaa791965b30d503908", + "0xe549b3679ff2dd8cca080bbf27826ebdcc14a6ef6ff6f06a2f2ec93a4fb1baf6", + "0x5bbb4f98a26c9c9fa8ecb2b71bbe032c0c4d349bfeaa81790eeb066412de248f", + "0x614dbf21c81332c690c934bd9d9f4c640f3df9c9510e9aecd105f5d2563a6071", + "0x44231b331eabb55fc08363ce5da10d7df42626b94fc9dc4d08f99ac220ee145c", + "0x3e22a80bfbb6e99438d4394700bd26964ca97de1214b20c8a69fd1788c50a4c0", + "0x280ee234189ec732bec0b7a25b9bff60b04e7be32c54fcb95121b14725bf62a4", + "0xd94627e7ecf1abc160c432aed8c677eeb4a0502b3100737567bb2d19b1c81478", + "0x6b2de1031473d511a197f131e579522f8bb2bf9abfe7ee561d8e7ef9b1912b6b", + "0x80b1447503f606ec08175cdf5cadf774f3d0d2a1f447ba41ee66941811690b68", + "0xd0b95ce90aa06affd35cfe7d1f3b45fc121bdf2565ee5d3a1998a932c2fb6db9", + "0x4575abb623e43a73f1be5ee52988e2820cf35170b68c6ba8caeaff086783a1eb", + "0xa03708f13596c11a3b76c49b44102350c06aee7ba92b3f2bf3829952f6fd6c86", + "0x4916a6e3dbbcbc8a13c91f4db3f0695f94cca48b81cfd56b9836e7ea44af8daf", + "0xb73b5c9471a175c8eba25a4df896302b65af142819e047928b8847a5261e13ce", + "0xc5e4bf50a5d4825fcc44eadc3877bbbae0589fb5a2e9ce1b16bf9fd60056af5c", + "0x43abc2f7f189448316cec758251cc7b63526e95b16ad919e74fb50a9831b76fa", + "0x072a4368d93c89d6bf3beee22c6df5acac53b9c8225e53bf3e368739890c2bf3", + "0x395bc2072a773c314c9cfa3c9983f7d8d23fd77276a6cacc93f580405ffd03e3", + "0x50528bae45e8dff5a7d4533bd413b103edd5097c78f35f49d0674c6f4378f7d0", + "0x02c2b72bb7fcdc07939d7fcd641dc148ce0699e5b9c76e7af3984c36a7da08ad", + "0x0b6ce8ccf42bce819e02e2b0f725830fbf136095e361806a2b5eee5ec975af90", + "0x59da0fc5802651044d72946d162d95412e98e3a3bbc170139a5a54a9d0330a70", + "0x2d2f3bf4346e6f38045e925bcb90656bbac77f7edf2182a3c6835b2f6e61f9f8", + "0x213ddcd0341b130de4699b81b7eeaf93126907e52ee92213ecac458bd957eb5f", + "0x0ffbbec5a21fa439c09f975abc684ad9884d396433aaa4f4890e5e377d7cb4c6", + "0xf52462396c136854067622763c21ee796e880115bdf0fa08a07a130ced1031b4", + "0xfc9bd5b2de2b2ca5b16a7f7c608ed4218f3ab60499a691843548e530123ffdae", + "0x8eb92cab2abcc01f735011f27566324816450dfc5ae2d0af14137028b046bc29", + "0x0795e1456a6894c0ddfc3ff3cfa979855e39179b03c15285ce084bd483067a63", + "0xb8b428f8ff1ceea1e694133996663d000a9bf0304abceb7cdaeb6db5be74983d", + "0xe682c8aefc32e0ea3899f6708057ee708ce46125462e8dc2b2d4605f456e3539", + "0x100f58fdafde5a4e2070784f54088d7522f2537ab249095966cfc9b8250f6bc7", + "0x8efb5cf8633396437ab174527ced3ede99be7e20790ef382b5e25e49b7f49c23", + "0x196ee4cee920a9faa42cd5f3262af5b35dd212169550664a3c9c15bb3a3fd86a", + "0xd6781eebac997c5b8eed3b0058a058b3f6da487d143fee14711398a017d16333", + "0x096aaef445abfcd0de2a662b16cba39ce371d053fae63c27f3599df3d169ed0a", + "0x3eee47ffe2e9d5b29c5e1139911d57d3a3d8d87b4ef290dd95e88a8d9a56d890", + "0xacb1b75fdbc4c4850565ab27978e7d10f7c29d6528e7bf198958238a4be4846c", + "0xd0cd5035132f5f8b303aaaf10d6873482b4870a74965d8055c48e8449935b76b", + "0xe65aa97a1cd3aa5b9cc906157f7d9352cf6592abbeb66647623632a9f3a93b07", + "0x76d08e7ef145ee5f393fad5faca53efb07b9fb493157a6e0b290525127b5cabd", + "0x533af4ec13c168f2e7c7368cba5ab0a138a5633656b8c19f284c98c42018d849", + "0x0d61ae94270aa651231f1933cb968bfe0cd2f4e097ae2f0ad8d41b8e2a785327", + "0xc22f8e6418938369b4e505425a28488c54571c4a803df35a233f70ebb933c635", + "0x743c0c8d16b790edf5e51a8453601ada99965007cb4dda51c82cd68e7d77a224", + "0xe5a62da310591a98f6b3138ee367ad2a334cd48d430399c425b71a57ba44a46b", + "0x5a7dad70619d620e5991b7476d125af8db51b67935a49c786b57f09d3fbc4035", + "0x1459d52e06d83b9ef94f035d08af0d63f66ce87bdfc3fa25984292aa2680ec68", + "0x2139af4823664ad7b8f2d6222f86a5feb7a5df0f1a934e8af139d73a6d008d84", + "0x31a7000f3b576d91c543c5ffc4dff45205aee1120d9732c3a342318bbc4d72a7", + "0xe046d4e9ea0c367a2b47a0a23181e144d95f9a3b8d77244fd70384f031fba4b1", + "0x294de2ab05861fb25db6e1392e8eca830217680610165a2dc3f6131eea1d9918", + "0x1f2dc7721a6ec2f13b9c9dcfe3d166b323c53dac5ed49c883fb6104caa841184", + "0x3b2797e3eb732182ff4928045800ce8837b7b4796d9af977b118c080ebc1099c", + "0x4f076d935900c3cdcce4ca42e206caa7e63dbc926dbe230f640807bbb7965c60", + "0xcf8dd9699ad2fb397f19b16b851d85a565b4d197735f8e3c279de61fc4e45bdc", + "0x3d3544db3dc8e8fe1b672ec5ae8c341524bc7e1eb3c96bec3867ae910d7b85a7", + "0xb7d7bfdba9ead1c68bcd54c46c7ac2a34f5292333f62e7b91b193baee6c09037", + "0xa8fc4eea921532a7fe31196f68a915f6f935b8ab480b9943dfddb7279cc069f6", + "0x6c749c6ae083721c5f5613a581435fb837166bcb3f07325873ba321de17f4526", + "0xed17ee542d4953c8bd4a7035bd34be4e6e80b73ed19f86d3198c7efb661ea78d", + "0x24e11ece5e106eb20534043c2c9452d5faf327e0555bc3b8f923c108781dc1d9", + "0x094a0636d62e402344d2bc9c01fa145ba0f32e03383e5eeaf85b257eeac3acc1", + "0x0e02c54a2ddff2892841d6e450d8deb610057e559ade4b8c3c943bca63b31384", + "0xcf147eda0c90b66e59c407ae4b2edb236270672ffc4bb68ac7da7a23b0274c84", + "0xae8054abfb1b72499642a11f80348857e49aa315b8debd3d61cad8662ef56b08", + "0x8f9429544ab9309d5a18a2af44ae6bcaf2e04de344d9d55cf22d8c503caab64b", + "0x8c6288b1027063bde39e399be8e7c82a7f8f9b853fbc04a32f73404945002e4e", + "0x189a06ad980a6e9710acb970572b8c04c2fc041fdd169ccde19b5a939b69cd81", + "0x0ae24fe54c7724a8c075eed2813b90e1c520119e2eaab0a0578e8759868e3ae4", + "0x5d22a1a2f551aa1bef7b552ac797f5b2a22441f7c3fbdbd017f4c5dea89b7842", + "0xc1827d89c778f3fb6c35842aaf940bf8a829079e008421db792cf04018bc2b03", + "0xcd9547011c12cef89331daa486d5a89bf36c8dab81d5d0e4abdd9c2e35d2bd8f", + "0xf115534a66431250450d68d8c1ef80ab9a3c68e63a203094ccee81fcce0213dc", + "0xbe9a16558434d1f940ac08ce7bb0ed0b1e400583b7bcbd06dbd9fa933d1de6c6", + "0x692dc4f061262a3f2a50765773294909d03477b0663f47f4aa0f675f2c0cf0d4", + "0x6127590ebcd139f736331080139c1b3bc6aed2f3c961732395ace62edec7ca5f", + "0xdc75a2ea1a80516dda32d61a2d671fcd421ab9ecd81473230ff9d3be8aab444c", + "0x369e3a3621551d67f48e544d76a815cfcd9a72b188972b02c12ec433e54c5f7d", + "0x195110af607c6bf30e268ae88dc0245c6d3a34d392f0d7698e51eceb1e10ef4e", + "0x950743ee4492e360e7a594dbc4b786ef4ca1b061210fe967bb5acad5622f43fe", + "0x926f538cfba0853b453169710a7acd6c2a002b87d2826374bb55790ddeff417e", + "0xb93a4ff2a88a8ef3ac4c77b55e828172f20b9b9ed655ba7a37b00ffb524b5138", + "0x08947d220add3e64d2db582c988faa58556b11257b9b4d8ee817122085145340", + "0x28ce559274d5455f0f9db83b263ceb6f1a2bfc00a2512931b04cfa23e7887612", + "0xdeea519fbf4ff441c8e61ec1f0ade9258a50a10a4702d0be90b408f30b27aed8", + "0x3aa93241858d4d882409dacdb7e716e6fc8bbd19587c15e349ddd5a7d90e287b", + "0x87a42a8eb92cd20a8dea17bb9a241354559443dbb1b4f549e2f9764321a1549d", + "0x365f92d4e3e88e73a155edf264ff3adad231b6a8eb9de11a1fdd473d9f2fd27f", + "0x85056e53a4b8368bf1ac1327db65d01d35e72da358274dc7c0d47a924615dc87", + "0x0fa77604f4d0a3bfbcbe9019207fd21dfdb118d94b391c8f3467b7ede0085494", + "0xc58d6bcd06d9a666bd5217cc75ec70c65d90f45d3266d78262d44dd1c48853bc", + "0xce225ea3d493c85c9ff2719af2d7316577c7c87e43598210446575fa10263038", + "0x010a27979371a2f4c5790ec5d61aa1ea443347d1e8622b4869fa33816306afda", + "0x34cffe4d5ce1449e6c1efc3c6ef2dfa24b3502370dd847b536a41976cc1e7e55", + "0x423da7e80d01cdb061b17cce2dca3f31fb62c25ce0b25c7ee5a45df3ca02e72b", + "0xff680f2c9fe4896d1e117bdf7e655d7d86baeb0753ed21b373a621d954be262b", + "0x9527f4e412a189e2e1bdccf0217cb6159b912c0c3765d5ea7f9e54e2cb393b48", + "0xa14f94bab1a626a844886e0338510b09edc8eaf9f3b416787b72bb2729d22c3c", + "0xde5afc9aba2c6db5ab784212bc940193db7f03b695049dc969f1d5ddadbd722d", + "0xdb39c68d462695c642bb704f1fd8de951d4752bd15e25115032a5b36fbc6d2c4", + "0x64987238a6b0d048f5747a81ed04806e89108ac247e5ffb3fba66fd875797690", + "0x0eabaca3229eed1341b2e330bdfa87432bbb685a116d02f943dda9ac66b4e877", + "0x2247273340e0c7954df9a5db6700911a4f786eea68c98106a29ba0c3abe96baf", + "0xaa035892630e9168378963dc34c427fe2146d6bffc6c8d1c5026ef8c3ccf395d", + "0x26a8e42afb55511f170429010e07fcefdce8bff03e3acbb3f8571be05960bb6a", + "0xa95bd3416ceb31df25f3b5e262109680341f742c11580e2e83da5f36d8b84ea2", + "0x09929d531b919f43ccf5b6ab7e87265ede17ee5b4103fb3fe2bf608fe9075c25", + "0xe6ec4893fa4840d90006defa51d5599b5a164f0e19c54a624430b5e7be1f6280", + "0xc21953eb5683f71adf5e5229286e6167c48dd68f2599d7cc35817b4b9ea0dc35", + "0xf30d268431af3d017f42363da727dc3f4fb42c6c1397a2417f8a6d862131610e", + "0x8a686f06e784dedc2b9e015d7ca5232deda4df832428050361c4c24639898c40", + "0xac5ced4388aa2f66869f6c3f72de0e531787bd415c8472e1a491cf750b4d2d41", + "0x5f4bd5ed18dbc2dbfa1662c45363fbb662337f8253cb1260dfa54ef496b51ce5", + "0x67b8eb13416e83606e2b1544a02e0172a1a9c1b9cba1d56613d2c1ac4c243966", + "0x3f450fd3a47b94ad683939f8af79603cc390bfe4747c6c013321e39f6f1807ed", + "0xf7f5ddfaf17bdbf632bab24d9aa0bb6a960e0e7bf1ea3efb3b60bd558aa357fa", + "0xe00cad28e524f273884ed368866865d466c0afed78390d8586c2660944e0d007", + "0x370dc3ee72f58da1a1cfc6d5311c688f171251c46b322d07f61548c41948ee36", + "0xd5b426cb386ed0f0017206e0c551cb2ef9f3cf02a3d94f68cb499f8f900f740b", + "0x837bbfb8d1db4e394c5917798b251d7281e4e1d024d95a0f8e8963ffa0a3fd95", + "0x2e7b8bd8121d24134418f88bbf49f8888357fedb1ffe1f928ab0ed4d3ef96a1a", + "0xa695fa51c83d2eadfc3b3775c200a8b39a239aeec091b281a022c9a3aed96b7a", + "0xff4ce70579c4ebed37684fc8f2d774cc358ca29a54d2520989cfb66444a4449d", + "0x7a34a4cf28f43b160218d77f742251b92f8ce3b627c23f632fed544e9234b2d9", + "0x67a36d6b2f04573dce9a2f0adc37bb9922ab038d2e706330ab6bf72b60afd88e", + "0x5c81c0bf60c07bd82794389b682be408a09b34dfbf016453a174229152e0b763", + "0xbc48cdfd853ef43a5982252eabd16b0ce575690195fa2cfe12a66fe10b3555dd", + "0x2125afff5e4a9e2451df3955e3bd17c8f6b10e628f8c3060a30ebf6bc4c616da", + "0xcf447b12f03d41da20fce5d8046559be590173f902e96ebf3c9b037398fae548", + "0x58b29b2b214e0c58bd8e71fdceca3ba0825bf7614a504e7bceb87c7f13ae41d0", + "0x1683843f47ac40ad0ebee6ba68a87894fc94e37a11433882a8d9363bf7bf4b44", + "0x17d702c3071014ef41b20d93cf42084dc31db7c97121f2f41e1b0a8ba2c7d557", + "0xc3f57d154b1047b3cfcf25b393aea31e0c87dc20cd601a62fae58bd56158e30f", + "0x1034d9216d4db99620ed2a256c454cdfd9e803e1c066eda49bd2ba1288d59d2c", + "0xb4f23a426c5458e52a667cb01c734d6d7473cf0900139da17d355cb679d0406a", + "0x16b7beff5ba9edc9442bda4b46e34afb8fc1ed917d226a4beeb6d9d2410d8fdf", + "0x3b2cf0a7782ef7e1a1b4590df0930c44ec2053ec2f519612b0f20f6e48f47107", + "0xbde784b24ded1a05e6d650b238021e904c72cb35d02dfb6fce107925ac947873", + "0x7a42213f3c331c3d183703dcf4e7704b696728c6de4296161b1fe73c78277a01", + "0xaaa0c71970eee0f71ee064dc6c908dfa1d2c0637983a18a78ad6284a72a5e010", + "0x72f2af281d44553d2cc0645c0b1a01a9a089c282344a4d2d2e5271594c58ec3b", + "0x46c6cddfaaf1d204e735c4804be955fbd0c3aa2720a6d40640641b4e777b18e1", + "0x7e52fbfa76e745f3cfd6e0e0620e7597afb4cac20374e8a54c56dec4fb1d040b", + "0x69ac36b338093a55343f7b1e3b2288965e7113f255d34add5d08211932c35b1d", + "0x9cb03dc2371657f840b5da9fd420c4202176168b1411fbce0eb93eec3c342229", + "0x14eaee01119803c9c427f990418126a03d1ee9b829b23d78b11ad94e29f92c1a", + "0xfee4f3621e875f9b69254865849a58538cc742e79843ba229df2a179bceb5b82", + "0xdfbc9322655f9f2ab5e918c2dcf819f0b4d6de07905dd2f94607e3b564275f57", + "0x07c42d1a39c3fa351ae4aa0adf903c39f3f7ba020776293b0ea5250b09c4cfcd", + "0xad6101974f08962920d9edfcfe8bfa4181d9465c1a571b128a5767406c7c890a", + "0x9f29341ba8b368f9c4dacb12094979a0e9bf2f6969c5262a880e974ce98c2aee", + "0xbcb3768fca1e380de80628bc55e911aac7a3e9810794ab9b86fd2ccbf3a727cf", + "0x18d8a90af389f112f1229b591f3898ea5a0f2a6ea46eab7aec3c99d82ea40760", + "0xfcb7860baa54275ba72b34069fd8874ef29a22331b65586671ca2ce88410cc14", + "0xe8323d318b6d03ddedf163b07961e747830f51a8b7ba90ef4b568305d5a8589d", + "0xd7d9d5853392e3cf51e6a4b9b8d60e5e1eb0e00962bf70270ae7f3a64e2efcab", + "0x2f6cae0f3f4facc6d5b1e87f4dfb2698211cbb6429c00af32af1b8963aab2750", + "0x4fe11c9667cecc0cb8ffa78a2ae76cda09adb8c993746149bc322dd4dbb389f3", + "0x1d7c6bd7731617983089a3a450e3cabb5c9e48873a516d08646c9b90ec152615", + "0xf3cb5662cd5414b486fe8d664a799550957422ce0b990f36bdbd9403ceb9afbd", + "0xe0da2757036de2ef8539c522ecaea947e47b351f68a1426c86ec621ed4bf54cd", + "0xa865a7275662e1f977b260ba85d5ecf1236fba2ac01a69aed047b2d261ed2610", + "0x780cfe59c907e3db653c573888464c41c4b8883875fceb57501f60ea34fb1322", + "0x754f80993771441ad0836d84a0233bfde1a4fc0fd20e199c1a0b6a755932b83f", + "0x9253cdd043387ddae4da68098b995268b3983a17a200c8990b4de3c3102042fb", + "0x4aa535ff3fcf8ca9ba6ceabee3d59fedfa3c7632cf68fbbd3743ea9c86686fb8", + "0x4f5110933431db2c0880d9d4699e33e8f4bacc31e4971801ad968cc25f064d44", + "0xe4443aff0965d78b747dbe5b7e92b03b4c1898e7fd9911177f3afc3f8e765fc9", + "0xc7113de3a6ed094a63f9d1cc5f68d29801ec550d8dd48fcf1296f10b73f97988", + "0xd707b5f7b09c7b264e323df29236aadbc03389a9fd75da07c73b9eb76ef928ec", + "0xc671f6c1003e8a2fa46a0f6100b1ebe5fb4657b8a3bcc8c4190de8a5770e2bd7", + "0xa1f8030d4bb2d37062ecd95a87dce8b3ce7bc7be55de7aa1028adcdab436cb96", + "0xef9a06d2dc5c209a7f7747128c22b17c2724d62b655f07b57fbde1ec5926a168", + "0x82b15ac8a4341283ca4177e0e7b89378367e205ff8fd59e3e43439dae8d6101e", + "0xcf641779c36577bf02101d739b7b1bc19f1788b22d72f473bb4129a44869c26f", + "0xee111a9312dde0a65002434b38bac07e127167463068d047fc95eb53469dfa5a", + "0xc21dce0be4bf464ff63c59b104f3a9e8ac9a5900cdd77b7fc6676e4e2a17f260", + "0x546772808ee95a5453a95e581b86ccada861e2f37840de932c70ddf65450779c", + "0x748dd0b051d0dc1e5cf18584c1111b1fd7648b62d0f340539eaaf2ca155e292b", + "0x668719274b07db2b66d0f2bd7e5efb6e18455f25e49b07bad9d6c046ae8543bf", + "0x305c577aaa37c8f67c631de5a2ff8833841daa6a1f52e8f860e7b6cfaba5e921", + "0xa7a197c39bcfb74d5f3c523de12af1651b76106f422c1f52fed35e6628749804", + "0x6b46e5b4a447ab9f64a529756a689db73706c626a94b5fee28415c33c0175e94", + "0xedd9664015849f4dba53c83f75e8f86e44f8b79d3fb9bd48e526cabc85b8501d", + "0x218bf5e9a2db20afdbeb167f75574adacbf64463f11665f2b8be2b76d741fb95", + "0x9f1c7175bb294b7e24a5eb61de4da073a5af547e7dc911c9b05d98ef64358d58", + "0xd6d859b88c49be0bbc83b1d34d7c87331bf281136146651d3320ad49db320f30", + "0x3b4ecdff0b3eb94c8d7acc0e101b7fbee9aff87992fb2431fe2c4d9f44a394af", + "0xd33de0cf69370a33f13d9d7db35e3490c88dec0ee23b71ed040338049616e274", + "0x84d004e9a8ba6b1bac42e8d6bc1253ff21b47a1fb494e5d19caa1bcf34b6c22f", + "0x71057ea68aacfbaa3655aa22c75a22fae502a9afce8aa206a220d96654b9d4e0", + "0x8a47b01548946acdd553570ad9b9bf3c78bda4f96fba851ee9b0a94b355d1c55", + "0x53b7a7ae02459b17760ad47f69dec212ed628d3fe856af16a0568468e7a0b752", + "0x66ee4b75bd15f446fbbb3f1a9f0f3a159b8f6c66f708917156d7fee5fe64e6b6", + "0x706b81fb39b3e09eba9e83250f2b3e2b567f9fb1c397125fc0157e346d5ea352", + "0xcca91f2ce2b51595cfb86e0a7458d45654f61d35a66e49d25e6dab01ebb350c6", + "0x4397d4d33ec5ad07b3a583e9f39df02f5756dbca92fbfdfed59a11cbcf9e08b5", + "0x88ad8498c15ebfbdec6b1f68deb7515746e5c110910150eabadaafcf715a50ad", + "0x715d175a3badf17771c686793223fbd837f2579ed674539eebb0ce1244fd45c6", + "0x96acfa1d0cc7475359b4f1ee596aa2975a87f314e80d4baa0a6af7c7c77bb92b", + "0x26b4c14547c255841bac2852456f386e8addf8cd8c45cc9f4be0377e05411bbc", + "0x124524955310b1a35fdd19104b6c0bfef503541fa55d0b7c24efdb8d0cb33a4c", + "0x9806202158a5a5421e94f69a904670c161bf61ab1c41bd5d104ad9ba63866067", + "0xf156a5c71bbe49c45f91ec3185654ef8cc446e9d18d2ae6d51ea0f0409fc89b1", + "0x7003d7fb1b01fb6e036fa33ca535bcfb836415e7661277634c47c628d81bc140", + "0x6f23e519c11871c12185c1af12b8840ede513e28877f7e860603703b3853b14b", + "0x3aafd215a348dc20c5ee5444cc007cfa0e90157bd33c8a4c4de4fb5b7a231ea6", + "0xe8f6cdda4ae600ab617fb40d96d0b2c13ead6ed5e36eaac9f8cff9df918b35f1", + "0x75e63daa0a330a4b52efe0e0e447b345622fe35586037ae88e6e48a8b544a087", + "0x6c4c8865b2673508e4c62dcc711e9886e57043d758a60787c6241578670550bf", + "0x21ed5b252ba5e9607045ec6ec85455db4615a1fc43e22138ab3a087c5e6236ba", + "0x2e2ccc6f66368ae083905358a182b0cf3e85330dd2a3875a846baba61c9be3ca", + "0x4a8987c10833a298ff22cc199be4816aa05f25e39a10bf007e72790081ccc26c", + "0x7a4b05fa47d37c86aabe456bda0ae7bfea3b28a375697d4d19ea2b1676425016", + "0xe203aec00f8bed45f3cb0911860093a5fe228c22476f189f2dfe4621145f49ba", + "0x7b2ba1b4da99ad50a33de156eb412d0020efc63c85d0840af6d9ff9199ff7dd0", + "0x0b84a8362a67c9cd715fbb09e0a48e046afafe8814ea7e1c0bc99da9ca670bce", + "0xb9457e83e503f6b65bd357b0c1cfb655b4c157e213c1aa2e4ebe6b88524c20fe", + "0x401fa17417f9c8f21156a3e660fa2b0a27eea8fb287bda37ca309a3c918d1c91", + "0x8bd1e0e83f35107a65777a1889afef35f2d89e70e9ef3fd56a0fe77b5a5a07f7", + "0xafba338c738de0a748fff79650392894482f094f79bf0c88b871324a6db0b1a2", + "0x40e66643c2f93c60de74a976f7f05d753ab09d33601cc1421da1e987378be84b", + "0x4a5d0c268a86af032703b688745b91bde7090b4e3b245f235056b5d675760685", + "0xa8d7233658eb85c4a309293e35aa9768768e78b9635ff989b4a5a1b64f6f26b1", + "0x7b30cf0f31a942afa35ee2b30bd3e67cf0fc3c366eb35b1e331ad8805e9e0d40", + "0x5730206b218be1da571ff8022b975412746f88606ee3014626a03eac8893deb0", + "0x4dc767b54a2e685d7588f6fcc1468cfa7c7e47474297b29b15957b2f21fb90d2", + "0x528933096ece3ea9bd4b3e0fa78ecc95915eac29b8b608af3b18eb7fd4adaf50", + "0xbbbe02a2b2949c73839afa56e959b23d3dff141776137e5e804d5d37a69ecba7", + "0xd8c4081e5c0ffe7797f07db6e5696e04ff097410b1e45a649bca43362366bd87", + "0x46402c1f08238694bc32bcc396093230cd2e522c54dbf7d00d042986d22f00b3", + "0xfcfff397df45c333b4fdf271b63a4510c45310a3c9cc78b97b867372203228d6", + "0x6d2350213ec1c6a79fb7dfcb5a66f065fbc41d4250075d81b7647e4db991543c", + "0x393995f9a4a358d13b5fd9684510068f9fb86c71f2382230999bb36b41586a56", + "0xb3b65d3c835ed1aeed86f34117431fc46d62ee2209db054a5e04cc81c1f795fc", + "0xd1ed46b6e64544acd6f9fffb126fea4b74de84664c2b22c760eb89878cd44ad7", + "0xf21c944b3e41a4f630ad5452a28633c885427b386ca81ec9814ca14bc94bb2ed", + "0x54c5c6c093bd6cf2cc72e058fbeb26012d71fc8e2bc6987fbdadaaa48ccffec4", + "0xa2e79a266c6044703233fea5d0c31bcc22ae247eeb55a982bc2e1c0c64af1468", + "0xafd38477bf1cbad227b489818e335a79d38bd052f7957efb2d07b9adaff6c68c", + "0x4872bf318a2066d5338e31929da36fca3e2390d1dc8dfe88eae5ef854b81bf97", + "0x896b1e0fb7a6daa96f00f7ef633ad67bc4462c962ec288d7f924c64c978f21f9", + "0x0c3617575c8a625e7fe35c30312b147be400b2777ac4b1c0fd84ee233175faf1", + "0x6f47126daaecfa7b84568c26b02ee779763c9f63b4b7f5cb0cf0ccd4a2c0a499", + "0xedf2e0e03c0d321911693c1554254d82c764f2987dcb5c76a4204b1184906abf", + "0x5af810bb6ef491ccccf2dd00c658bddd02a1124ca26be59c97a69199605a2d8c", + "0xf8a597f22125a6f3fd76e28db6ca04fde9f5eff62b78e162855b9a48c51a0cf9", + "0x9b50cf0abbc883c6af57fb52c48defb2ae67f77de2f2ef5aa4fd42f6236f3f43", + "0x6eca9c995386aa4f161e6f4c6ff999cf6bf1bb4184d9beab567abaccfce9fc1d", + "0x7d7dd300658f784ec68cc3021a54680ac5767085657bf87ab6f76f05e505e6eb", + "0x1eab27e441a43a3534507ba0b5390a13c7df373813131b09b2eaabab179b5cdb", + "0x45efe5848f21e2b4f670bf06f0067fe453eb29ef45df102588c7b8f902005066", + "0x086f17e6047e9476d828eab4ba0016e3a4a0f51f25eace2c27445b5fc28926be", + "0x63547a7274cbc857d547291923cc9e507e3f4b6fe85b1ea88a527674f15403ce", + "0xdb0d2c2f050c4235e9fd03de4c491e09061ddfb4e55fda8ea25a8c8f013193c4", + "0x5f5bf14f72834ddb7ef96affc52b3461d0512fd9bb0337313cb7cedbfd858228", + "0x92c4250a5ba9ec5890c39a608770d500ac31ae5da1cc26c05aca55a453e15a25", + "0x4fb2c385632f512303dd76f4c9a3888837227bbb5e5b949a7b9d74906ea6d015", + "0x4814397680a72cd024c3df1faf854d03c0d308b74c93fb846e620de95de7bcbf", + "0x068512253a6b5ccc302e494d1b17ab082f2ff4ee710c58d345d6de4a436fc3ed", + "0xbcba2fe1b54c6fbe1438fcc26e955ecce58c5f30f4f19219195a413fbf1c6eba", + "0x29ad9a11da3f646ae4ef3a5202abab2ed8a7058f336a6039a5c41d3619752d6d", + "0x5fc2a5edf9264de88df58c3bbc705b8e73bba19179d097f414598bd4b5fd63bb", + "0x9592c969a049ac723d756bd2ffd95cf599087a1da14ee9f472ca07e7e54f8ed4", + "0x735ace051a5e3896a9dcc788654f95cf0dd9cc98eea1b5d8d7340f9e51eba698", + "0xed5ec9f70d613be406c237ab7e8e2480c7a81cc666316d984bb3f9c67e10d6da", + "0x3b8248b4de2768d9a4ed2ce07c8735103b480e23bd17ef1910d75d29c2791886", + "0x2a9ce5a8366862e7b790d865b0406d9d5d4013999f42caa9235d4c2b2813449a", + "0x6c67c00db439fbc9d548cbdb57377064419ac47211be90747c74c13b29d4e562", + "0x1695a7ad7e64d438a9b749b07180910a7af207bb46063a92d41be315cecfda67", + "0x6fcb36c8b8ae4d6e4bc21fd14e80dcb402561a011fb4e71408f05807b1141f49", + "0xf6ff3dd9e40b6bdf881654e12fc9959a928bb7d83a81189db1520bec70386ec8", + "0xf17f8b88f04772598eb87c8bd1b3a03f5d96ac68de7d36be6c1fbe5fd4a2ef4c", + "0xf5d9c9e25075f8ab6c34e9231d36becfe90df0ae6bece4ad1847dc4ea938ede3", + "0x5d409a230ffc6a7e149e94b0184bcd00eb8705fe173c67ccf4f81e2f0d3cb0a2", + "0x80647dea82a0c218462836c14cab2550f558391a901a708d7e4e6c28b4b71869", + "0x4ab906af7910a57f1f4bc338d5e952a899ed256e2a28e1947890a372aa29814d", + "0x6e6e180aac3ebd616af90069674ce54459f169d33d30d95d98351259d90a38ee", + "0x5d30699b02a45d5cafc14c945bbd208943ea83ac6a10229c199a92b87dc0c76f", + "0x19c26fe48c497a4b64a4d537eea9646cab7704dc28c46fc3510a14b226b9a690", + "0x5ddc881ec8fd1bd34601f06a5ae0cd23680e2e8bf12b78df48a5f86ed6e96ab1", + "0x39b933493defd81502420663a0c85df3a6cf727e4270816bb3cdec3dc58bc7ef", + "0x62a9e911426f267561f84210d7356069f6168c4e7afb9aca4a4a70d18fb34ba1", + "0xae792d0011eeabbae89f6de39ad44f0620e50e5ffe7392f9bb792a966d1f83f7", + "0x737b257fc55f1da44584687b3cca4bffda13ae014f089e75f0c75b0b2d08c426", + "0xe923546185355abaade908d18f3223bb9c404c4a399ff94419c3a5798c90d9ef", + "0xfbbd3e2dfe2e9e6f985d139dbcfa5b95da918acbf49de992d01875bd44b61e28", + "0x781d9962f2cbe94e355b93e4c0eb3a3de44d9779eabdc3c6d18e7120b3c0c01d", + "0x2722229fd2cef3564c38d8e4120a6ae89728ab4063c8199ec098f139b83ee0f2", + "0xe29866bef5051041d25449f334e4ca246df606c5d7c0bce7067c6c98cafd0534", + "0xe0320de1a972b563113eddbecfc90fe902f2ca80befe15378c94bd073b44eb92", + "0x9227e1d6c68bdd60cd0deb8ed760eee67af6623c44d05136251d89654f3f2e7d", + "0xfc3c7dd2d36ca954545f3a978cbd7e4c413ae38a0fb5cb59b84329b5f5ff2347", + "0x934c332cb52521de4216c29e40601d3250078fe9314a364064692daeb38f71a6", + "0x77aa1b31191caaf80acdf5d411c4b6b834a6e50f2f0ceb17e1f06a807e3eef01", + "0x43eb0928a0ab9a29ed084cbf9ae75d1e5593595d55fc8a32151bf56b9977a1dd", + "0xc6f4fe473048728c5031a465c9157e38c72367c7f937aa9633768b32839e765b", + "0x21dd6e252382965adf71b94fc0b9b2e6e5b0b9dc9732987e1fe8d8610b1125f9", + "0x9808b8c9e07babfb30c120a4a7d3582cf4259f8309e586ad42bdb9e9cdd3dbb4", + "0x72ec40a055dd6c5f21333f9540bbe7e38f28f39f90204f6f87f3c94faebabeb2", + "0x3a04743cd849a1a48e0b012f39fa4eb690c314eae7b0500ff1ea487a6d399734", + "0x484892e8d3585d871f7105a49cdda18af036d787b6519f9d32f8dac5a3eb9546", + "0x3a73f64acae91b70d39cb20c1ace35547e733b253b47339a1c47ad0841c7a27f", + "0xf33014797bb0e339f2f0dbcda6706dc6b33c8491cb9ef777ee2cb88b8fd1e35a", + "0xf94ec9b178e1e287fc2aa53d397960e89485ad22f306bdf0226212415900648f", + "0x8aac6aad1127202909e112df54be070e353fb9079dc5cbeac146ed09faabd4dc", + "0xb8fdae091491634efcb9b2f78f1258d401a9439d806fac04de4a0f9503d9259f", + "0x4e872ddaeda3ae79efbdfd3ad8e5ac3597003a933aa793c50fe74fb59ef43637", + "0x15293110604e842775b59198cb8dafbdf07b4069fa0c3e2d61ce6665ec8f6742", + "0x7423d6d010ca3aef37831e003164b583c2cde4e859705ea191e6ec687f08cc49", + "0x73828a90a0f97e5bd83c4a6484f84ef8af04d325b739a2cfb96b8cad36717b09", + "0xc9af1d054e4ba3af1002ff0ed63fc361be99f8c7bbe90fc951357ba28fafb8c2", + "0xff2849e97d79e7c25a58266dfeab64f512ebc57620d45d6f5106a71fa43063ec", + "0x98da87856c0aae3af6dece2efbe0a2f7bae295ece2b90b633ff894e5c83fd407", + "0xa17f5aec76c8f4aac84741baae18e179ce5c1ce0d23d3e2e5b4fc7f79ee91171", + "0x79c9a766323f5381dce7241fa53da4c7fa018a43556352c54b52fca209f3ee37", + "0xeccb07e66f967613c13a1e867f8a96bb2c96b7c0347e4262ebdb583eca48e71b", + "0x36c357f0249aff34dc519f420b77fe14357a009022262cca7f1467c2dff7d0cc", + "0xd52a496e2c176cd98b94e8dd4c18a9651f46ce47d70c51b21e5970bc7d81c96e", + "0xd3fbff9d80c163f6b9d4ad4660f4504101e167ba866266ff905f8564ca7ffb68", + "0x321b832e81f461e871bd05e6847f8548825464425036a1a92bc44fc30961fab1", + "0xb58be0aa640c7047e2b27c6044dfc44c216b4b69f48751686cf29e66a8dc985f", + "0x2c9153f20a845b8ec8e70cb1dba8436c7af618367c3344130defb1e7c39afe1d", + "0x6d129dba3e7c6e5ba8412d9290d7dcbd29b36f3e93eee6b6d203740de06802ca", + "0x5f8573d1de1c9b4725fb639b565a2ab6dc79d138c3d6495325e6ee609073965c", + "0x5f78ebcd3f73da424734bb2ba0c711fc54be4f21f29afb1c33af44c598d31dd1", + "0x6b48dbe0e509dfed74f60e16782d268076e53863b9f86e4078c90f4c6619b644", + "0xec30ba6ff376fc1ce9f4b87693e586b5fef2cc5a5ef26726d8e756b3c8e28920", + "0x8ac0cfa126e35c8dd715bb0ce13bc70c8d55c34be0abcb85576393a460762659", + "0x8825a63c211a92ba8f8f5aca7a27d1921df071072467c88ec9932a41d43ab5bf", + "0x39cf82416d543f45afcc6aa0cf68522d0d5ed4f76b07b9f742594a88309b393f", + "0x105449b542eb5ab0b1ec7ce69c5e8bed9a72b6470b644e0815f15c6d9122663f", + "0x10fd8c442d6d44b533675b937e5defb004271a87d4ca3b238a395002da42adf9", + "0x390a40177f4155c30bc10539a54991f4759ecea69c31e9b2904743834bbbc618", + "0x0f11e934cc159af39a4b22bcd6817b1abc21bc6fe81c442dece1c178d695787d", + "0xcfeb9c70d8e2d4e40bca485200c0b5db1152d9440237f76a58d4cebaf43cb1b9", + "0xc45c5247fcea2312642437f90870b6fb4b9927eb2af3adda30b5c738eefaa952", + "0xb6886cd5b6329ca5f5e36d1c49b7426b1a20d3e3455f660e662128193b6e1a32", + "0xb708efc6f2f6ab093482d8b53483a3d8216043a437da09433ad0eccd4c9d607b", + "0x12b76069143a66c55fa3ba54a27e2cf51a94d8300a6a6a317a65df345a9d77f8", + "0x0d9b6dacca16c1be986db368dc92d652984da9aad149ba7c22831ac94719139b", + "0xbe298f54460f273d2106a102dfda3e86d7eed783bac4ab88d8caadc0f3116ab0", + "0x82fbddaa5cf8847d2166d40f9fef5fad4933bf338422bc5457e5d5c29774e5b3", + "0x2a75f2442f4ed494666f48168ebe8620819d97f9749b279eafa550f20b1b622c", + "0xc874be785abc89e0fa92d089889ce06e1b2297f647c31cddd24d29017ba74b0c", + "0xa6984ff3e4f7ab1da131668f77342bb0182cd23593dded5e487c134b1b13a9cb", + "0x4293f4fb5bbd41aca9fb12f58e2427e20b791ea523fa125c40b72699ed89ce02", + "0xc316b1b066bf437d3933d7fbc8a8546a10f7c274d2ea84781d8a99633bdc0c3f", + "0xb40cf7adca885ffa6148d8008c5df235e938659d6249fd883960b847a409747c", + "0x3285b34b3e90a83293292221a89bb244a91ddf4647cf2d297c2116826c605640", + "0x465af97dbd1276496387568d41ec69961f70b382c6e0686c103a73bccf0f7830", + "0xda2cd161e715ffd3ca0eab361e66e55450230f9acddf8ee635b412807a9067d5", + "0x3136630cc6b24f59ba9c0347c6c612feb043f9fb58d1d26598331aa623fcee68", + "0x24014d00bd6ed71da4044cbbf256ef99927950736f084cba2a61046ed7c8d471", + "0xcf1824f9a407009243ade6df4e3f241dcb60bd7257d843792d12fcd42e659076", + "0xcfafe5abf154f2ca9b6f9d70a91149b01cc8fb6b8bd083e24559b860e439f04b", + "0xa4de7f7024d405f6738301df2132107b135ecf824777f1b844685bfaee6b30e7", + "0x507abab909bf25bd3907ff757a69acca54af0c21ed6faa975d20106908e8540f", + "0xd6e584b876926c3989b84151eb574d737bfd229151dbb0f653b693b2bac7c45b", + "0xed4eedd2952e96c9298f68a1f8ffc4772652517356ed4a02762a3355e7dc89f7", + "0x36d0a7f0f5ebf3c35a576ff56c8aaa1caa04dda95edda5d496381c9601949451", + "0x9beca310b79181f7695a0b6b49e923e7b67462904457df0af82c88b92fe4ac3b", + "0xcf792a534a0b5126116e9f7c9b92aa4d32083fbdb539c91dcb8de347000b49f5", + "0xd4024c9ca180adef5a9311c8a2fb0fe75e64728af00ca4ea1484548f182b5488", + "0x5517e825a0d6e1bd9ab4435278b8691ad2772b9edb581b58725483c4393187f4", + "0x9e4ae4c36d00217af787ee52862f87bd37cf391adb23a8b51fc05ed1ec3f6631", + "0xe428dd2523abc537b868bb6f5588597175a622767b600b1ed9486d09624c8ab1", + "0x2fb95198976ddfea942f737322470f9de6635f7116839e5148d3f64766f6fa2a", + "0x211ff8c237bba495c03bd6e8eea2a64f05c8a0eb15951751cfcc4c337f1cbd02", + "0x44c49c62604c39e38561c7d9285b9a2e168fa164a47c7b17f1fe83faaa3c581a", + "0xfe663bd908aa64290ccddcc300aa5f616455d8f10032af9317ddf717c94d0bd8", + "0xb04add424a6780e81e2cdafbd81699fc5ad621c666e1ab5583f3953ce8b3abdf", + "0x5f2f6958e89ad99e28e96059aa8b6e2d9518009f824874e327dbce226918e0a5", + "0x491c9e17210c2770c0cbe566aced7dcfcb6781e70a288f91d4eaac8dc4fa07a0", + "0x73651853f625c534d5848d1bf7f93433b09d9297b13d46aed9b022ddc37c4b85", + "0xb1333ff43af73637e2235f97a1a7a5f42c590cb15f93a733cbe16d1a9c187e0e", + "0xddca0492f5c36c8eba140575b4521227ad1216d04a7e60da7c9727cb2a756df3", + "0x6da48a25ef31b1e25e33b1df1c539b14e6d3837f8061c6a4faeccc861b7c908d", + "0x7d250fc602fefae7409a7edb1260f4c520d4717b881c8afb6551a89cc781efc9", + "0x043db87fb979042ae7ea709cebe4ad58028916f035e99382be9826f1236e5753", + "0x01b125ca25e2a254e0ce54e4f3da04c647ff6fe982f1df158c3caa90b1e2a2b6", + "0xec617f330285f2d4c6ad161250688cbe57bb81a5e45fb11354ac033e2fd724cf", + "0xf7cc72b3307f0ed731b990d2c10f71cf195b02f7e1d2767873c3ffc192cc43ae", + "0xf19619c5e62c5f244ef4156cc2c8f6edb6c230664e4c19ab32e1fa137c9ae173", + "0x91c313a770e9eeb92fa74c335f9cdb735bd14582b385d2a380bca534cf7a6dbe", + "0x14c1ecb6b06c18c240932c705154f009d9032dfe576ddb545a3a4cfab9968fc4", + "0x7d2cf6029c764b4c676c3a30567efa13f0fdd3cd6587631bd79cc08f26d75505", + "0x8c889efbf596d20043d654a6cda1a58d480ed2e3c3db65f51aabfd25f85784fc", + "0xe0bcdec3debf12856f3b4fc781d407a52b6b3d544b56cddf847105760a99775e", + "0x32c229b6b99b2173338bd7615a1a0c2c4fb5acafd41e332c9be7dba91b8e89dd", + "0xb24b187ffb16385b85e6782fcb4563309afefa8a7900cfdb81d024c2257913fc", + "0x81bc38df942c4c9c309f19e4fe5119f3d7fc2347fceb83f7d31e990a042581c0", + "0x1e6ec7caf14747f470d65bea046f7cc03e081271775be615905632ec9a18a637", + "0x4eea8052ac23fae83fd1fa63b328bb4c2c66277480b78ecc00132c1afa53d37c", + "0x8810dfc2084515339a0c6f1b3fa771aa0819b47498e57b3733aed0d40b9a55e5", + "0x3cefd28b10c2ada59c1bb66a832f1ce79c6d96dc0eae3b2759515839cad25ce0", + "0x8fb0cd31102c06d1e33f782fd9dd7f6f9af8e975e10fbe560183ca366d088039", + "0xbd7842672dba588021f7b395a55b949d41090039b14741ac667aa75977e00d62", + "0x7c4ceca9b53e12dcf2bd5a625274f30e2a825d5075d640c7bf78abe4bdab907a", + "0x945f8fd6e3171159a57fe5ad95e46cf93c494613247051b941bf4ee7fd6d4e29", + "0x01e9b5d3ec0f6f100907603f591e5007d086086476dcdca849996b98089b924a", + "0xec9545ab618538789965fd828fa8830ac17ee52489dcbbd71b296abcf12c11ba", + "0xdb1466a3705b6a035fc7794fafb497fd2e7606b003e73c6cae16b8d9b2aed314", + "0xdc36ec38da93a79b5a1e70d1cb3453f3ff324793d2fe64fc1c4e8fb1b22e7f29", + "0xc1f2a76b96cc31541362b5d6ae9271740bd540631b4f3f0274ecc5928e17e10b", + "0x4a5108aa8e22f9555d94caa9c29b9793b4a97e2c7270b8e24b2b3717d9efd8f1", + "0xc8938a2890c4f884837acb06c4a3854d1c03286d58d5d62c85c06e00d8597fe9", + "0x61e1708488fca9b334a1682d4f11bb046b5088151a7333655c733766ba0e5e5d", + "0x75705cfc2a41a44eada0a51ad75eb93972d84122658c487803287235c0a5a405", + "0xd818c5f5dcb79e84b2b41341261bf3e4e97f1bcbe572c1eb5be5f7e3eaa52db6", + "0xee9b8a62f9bb12306b38c129ddca08e1481db588b6e07b45a7defc3750cec078", + "0x1bf73759029c056f0e59b27a8d05714c916daf36517080e724662bffebf9e380", + "0x4ad981191be35ab37c559020fd42db86f57c56f51a902017aad1deb2d71debb8", + "0xea76176e1ae162188a798fc6ba2426c5e39b98a2832ef5f730c06d51f0b6d71f", + "0x1e425a410f888435fe7c1d6912efddf8ddc3a763a136ec730c31ca3ed0a3c162", + "0x5f6ba29d31dcbaa0220a7c2f901b987e968233bf19f398528e91973b421aacf6", + "0x935266f8976c34566a762204de924295a5203630aac2d2bc9c9cd0cc8286819e", + "0x323fa129d881b6406662cf69f01c720060a13cb7c93ea7fca3f089cf47d1b9c5", + "0xe17499346fcb6ac5f95e10c794f05ad12ba85d201c4d9a2571837b287dd90fb1", + "0x8bd288a3aa8be55687979fa9d94ef1d1ef8a0036bfc5615419920c6df3c31bc3", + "0xf05028fd3368402e82d4f6c6a4b12e622b048a612f80567d6e874541998b87b7", + "0x7e35b77cce743749b57b7614bf4f3724226ea82cc1f76e6f6232ef25b42eb6e3", + "0x58cb381e320b2ee7ebf17aba08316d86c6e8f2dc038f8fc6839e94f16b411a3c", + "0x24c1e91b745127f12bd8603ca59bacde6fe1b990a1d4de58c5e91c29da27e371", + "0xffb99ea8a8fc58a1c7e33ffcc199519165a452ed9b87196cbfb48ca23198e571", + "0xce37cc2df44d4308d1e5b846d46c9d7f2bd78f6b771b1eebcda1142858cbd4e9", + "0x0babd6dfc4f5a3da90ffd6f74297db7ecc7964f23bfdd3404f49c47cf7019856", + "0x97ba6463ece697d1b340dbea1e4e51e2f59e1f1283fef71d2aef12060b188b6c", + "0x3cb4d7dd238435f316ef70fee4bda79bce6b9a333bc10a36c2e58f7fa4bc24de", + "0xe44502680a574938a0f483c72cf5843ffc506bd2d9eae270bd108a4b7dd55422", + "0x3c9ef69fbc9a23ff7646a9d99f27584f3969b20bc56249dddc7f83fef68742b9", + "0x555a8316eb846760d2996998291e81d5f80bb0d8db71e5c02c42791ce83e456d", + "0xd4d68b9b231fa41e4571e258fb5d4770e843b3e50832aee6c7e327a568c062b7", + "0xe0a8bef3a6755a4d50f379f9f324f0404fe677372f307fc67ef2b938eedf986b", + "0x57f32b8c263c9fa6e3b5df8603307216469dff93a400290cc54f3a76b54a2a75", + "0x3749d954f6fd6dd710a0a9b4abcb0da071b3c50d125206c0caf4f4786d590d4d", + "0x58efd182fb42171c896accf391b30f1916503f616102251b9dccf2a45a823c5f", + "0xe44810336515f4f45693cbc57ad0eff2105d70faca32097f7ad6aa505c4d3b67", + "0x0d720fe2f29af2607ee5582016bd0f122f63d0f82a84c4931446a184843594dd", + "0xb3106d35e5a904b6d460ffa8cb494f6a95045d717b3f532847105bad0dc5ecc6", + "0xd1bcc88ff9f5ed1b7625e7242ecddb2b615401dd8fcd01c9b9f03a6d22d144cd", + "0xd4d4702668cc3673bd4266be291aa0f25e8ff835df3c43d556df01342986a279", + "0x9fb62301f00d441319f81de73fd49fa1126a29b3a11b022b3a92401dcea15772", + "0xdac3eda26ad4eda3d83c0e83d65c74ca4c4c3ae47eb4e5e82c6b315f80266125", + "0x7b24a259081a547d55e9af822fc54d5dc6f69ee3e961ebd0a0248ac36f6e25dc", + "0x64e96157f5e4be77c9f50df8ea9c518026ce1d7db6adc52189c9354922504635", + "0x35ee981b1a7d307671605b25399cad71503fc9ffc00d2f9ca80e868901e9c269", + "0x6965520591a7697f7c62ce4aaa6bd90691ae1a89a5f8e29237ce5241d8003636", + "0x30c305cc886b538fb8808be71bddeaec3a1276986906b7f028347511bbb653e0", + "0x5f63caf0aba563f62811903619a10786761011d2fa6fb58e835b8dcd5cbcb3ff", + "0x6d7219f08e8288e4dad53a7fe227951e81d9ff2633bbfa636a3d0b147b98342d", + "0xef315cb919bc5537bdc9bc47d2dda7442e4a372c74163fc2134173773ebfd7a6", + "0x83016cc642eb5b55b5a667d36acccc35eb9c33cec2caa28ec263f00800bca2c1", + "0x0c855426475046350b58fb7e179202cd794f482598d73ad05bb0072774561493", + "0xcc8dcd45a49fa55fdd2871245cbc611613f203203ae4ffdb1e647e7143b8513b", + "0xefdb25f8a05ae4c869bbfbcac9c302f3dcd8a917eca4d5807deb09833e876820", + "0x055646d6adfd108be923b275e21c07162227694df780512d0dbd7a0b58cdda91", + "0x4abdf1b201aaaf4724e81ff29e8d48a223f7b98ed6d9c9696375047b7643280b", + "0x929ef44a9c004029274bc1dbe13b49bd6452ea3a3ee6d378dc296c9baf0b1e9b", + "0x909a57470dee2764e5ca646d6711de3908b3b35d98e73f67adc23a3a8aa3c48b", + "0x42e5bfa041faf65f224d7985ad464a526a18fe591a156c0b70df9d397beb9aa3", + "0x241d0b24f3c0e08a17f10d579e49e72af7d2e4d0f0d621ea8975d50a3901950c", + "0xb1f3ce2968fed1bfcf363a031d79cae0174d642e931862adff7ee97f947522ed", + "0x7e4db35d3aaf0bdba5cf1d5465f77e6c927f42b775e8ec2bbfb43be36270b5b7", + "0x7995fbf9d69f7222ddb9d28bacc6d97c61780755e933d3dd47998f1f3747aa32", + "0x31317d422307751b59eeb45270518af357bcbf7ef413f81c8e7c6bd48d79d696", + "0x5c58fe54e2781cf91a9d09e080a9ae5b6a8124cc06275aea65ffe422567aca2d", + "0xa4da628ada51d57b378717218e6753fda428e2b8ce88859f37837b4c2fcc5076", + "0x9c9f744e7e3275808f9913767657af8a33a7717e45adfd84305cfbcce328a065", + "0x1381182d1b1ecd75969148742706a27a044cdeeb5cd984886945e5de5f3311d5", + "0x71a4759a9096d67a4061ad639ea4ff7df35c811eb1c7b10638aac889584567f2", + "0x1bf9536eb1692291213d4f7f340647025c10793c2c84e8e775db5cb5afb5022f", + "0xf2af02ebd1cf78bf30a215d80133c7d5f7361a58b827efa23e940e7c91430af0", + "0xa90ab1a925b660baff138369712be90a6cf8ebb658ccccaa9e8b0305adcb4ab0", + "0xbcaff27b022e0873b10da43c78b1395f1878e2ab1c8cf33368988a6060c6132f", + "0x6154955bb4a81d1b96e618ab29a53c393ec78153a733f90227c9f83683131eeb", + "0x451b4a606ef40653e1ccd38b07fd4e8efd9fe796e01b5a5772ff903b45042187", + "0x011e748c7fbb39346bba2b3235c185fde946d28627e2f6ed39c68076d5e6fcec", + "0xa849d075319c4f0cb13f3115ab99e0cdf0341d719f5c65a36b100ac1bec98826", + "0x1e61220e9a615b1ec127001aaa19f307c268bfbf14bca900ba1005539a7ced1d", + "0xebc6254608585c487baf6e312130a06468551cf4ea171335480881f42ec626a7", + "0xce073708172f6fd1e6d792f4b9fe088dc06e164422c5e85e4098c0c8672bdecd", + "0x8102653797d93a7d372b1ddbd92c8c8cebf79fdc8213392668d62181c2639a48", + "0x2062a79855e50c96f3eceae62ab0f873eb3f051f66931efdb00649f07b82061f", + "0x28302f6a2106296e587b03f2f0963ae9c8f8eca56198f7d5e0fb52d4485e1da0", + "0xdb69e062fd4f03ad8327c3b33fce7efdd2a1455cb9c1c90a7e2e9127b12ca041", + "0x984232b5675edfe8312be559135281ff49be1219e3ab17e84560221368166aae", + "0x303557f3d60ebeaa591cf88e583c366a7db4adf1031b3de9c8d3381466e15b7a", + "0x2179d8b03104be3b8d2e6f4ab4c6b9851bf85ed4545aee93fc40d3320d3b5d2c", + "0x708174830261838f9d87279a51c4d65814f7da2495c1a7ba1eb867ae7217bdce", + "0x5c5b77681b0d9d6789aea3494c60571311f2b6690de38c2e4c2a8caa738afe5b", + "0x68782d0db788b3e7441e94e4300a93c50d641c060677c6ac98ac50c69ee972ec", + "0x3c3acde8f5a99d8e131d33c7d55ed4415f0c230ed6fb711627b11e464faa3264", + "0x0289fabcc6d32e03cf75d7958e22ae050c8fa6b31c03221d78ddab3469d9b95f", + "0xf10cc55e619ba8b9aa5ab92c272ed1459020ae6f43e45fd9d427075d86230c36", + "0x20ae1b4f3c79618339a0f0627919ab94809328164ec1dfa6b9e1f556e68ce770", + "0x071e6f74436830ace1c6bca63d915218d8f561e184d15cd83ddb199319907dad", + "0x7334a6ac9991ef0876f0b4bbe18dfc407e748c65ee79bcf114c1a2a71b46f41a", + "0x4f44e709a1e59bfc7315843f399add75d5c1e8c3cbd0f485afee94e1c4cb0d33", + "0xec0514297634ea605be68932d68de290e15306061e20a16b2e3bf675fe573bc8", + "0x9c72bdae94b6f57b594c11872ee21af41c704ba1addfaf8ec4d828d6ac6101a7", + "0x1d1a60f27879b14930bb0351e39d3d31233e7d55f3ecae5c9cad4affdd2edb67", + "0xff4fe06f62b19f1e6079955baafbcf5b74627785b5edf90cc49ac75490a07f8b", + "0xcfc332e8af474ce72548c5f0fd50d4e6c10858376b0ddfb706e99703177b31e5", + "0xd7d5eb515bad41cf09df99d5fe0400ecab66ebcc9f7af53ff8cad256d9ad2bea", + "0xe6f7024457d9e945da6737c34090f689bbaacd479849a7c64afb6aee85b6950f", + "0x15fff05c7ff12fb455b77b5430532011748a52abce46919f69ee0a4c30b59fd0", + "0xaccd46e8d8482209373407310b988ba3e1f39d6eb17f07861d33bfaefeab3347", + "0xd97650055032b7bdbabc7b49b7343d0362d6241aa45fb17ce9ca1815e7d58983", + "0x0a4b45c31d3a1dab81b47da37e896360fe5a1e45903f59d6ad0f0b8ceb2a7747", + "0x8b2a42405ceba8740c02c526023247a262088e35588fa4253eb6e229c273463f", + "0xf43516578e7fd03970d57b08384b0bb3441ee7f50213c2ac0d1830d43c857abb", + "0xe2aa1bc333310c27fd699455b06398679a100f6a942c0eb37f70da89d7f025f7", + "0x1f13aa876a2a348d7de6adaf51e8af65ad7bfe0332c4c9cbb4dd709dbde8e1a2", + "0xd766018ae514f5b7daddf6e716bf4570456cdd46e7a3be68c1c515f2df441bf3", + "0xa2ce855ff00054aea57559662ac95b2445c1fa2491d9f4448183a474396daa53", + "0x8583ceb1254f6546539fdd57d1fa1e3580d81f1aa44dbc875de8b0f56e5e7ea5", + "0x7e09579f21572f2ee72399c3ef67c01a5f3f27ee4a3c43e8b6f692e231fdcf1d", + "0x6153e318c7eb123db88f9afbe8ff1c8f66e1cc0e8704db45730912a8281b3366", + "0xd31dc325333526bfcfd29e50e5fe13cd696e5948910abf46e66dc73f7d271942", + "0x9089fab0aa038217485edcae76bab74735a1fd2897c30a610f5e43f1d2da5425", + "0xe193e06c904f53031be5910209b7aab785bca6b65e917351764e2f231800bc4c", + "0xf732414a066d5a8fd13241f5aaa9570e5c6285119a1f7c69063a8b4cb62729ff", + "0xe149ce7e516f9d54df933717a11040e4a9bbf8ce13c5a3612288009a99724295", + "0xf29212544b867ec2505e35cc5ce79ede41fcafd676f41df15af7f178d6dc5cd7", + "0xcdbad6c9eab35d13dc6461ffaa793b180e28085b8047cc56a5328f4066ca944e", + "0x13f5597439e924b31cc8ab8b9cce0776a8d89bdf7e6a0a306763ae259bb92787", + "0x791e0daad106b9ba1ad684994744d2ce89c6e413c51954321d9eb3d87e0ad14e", + "0x892436f41d7a6d8385d66f6ff19fc7235dc6241477d2745792bf3a38085c8d5b", + "0x68b0efdb41ac9e0c2cf0df78ff6f9f790c3c1ba63ecec6bdf9426d860952f81f", + "0xcb4cca4320ab1a4ff11f868d769ce9fbae1e98d154207acc85acf2f8dab8c4f4", + "0x3dd2dc9e0d99e9ff820f22283ccae495545ff37b6e7e89b3d721bdb5ee169eb8", + "0xad216b8e962ca5b8f388c89bdca543059065c7b6573c5c0868be031b74c2e184", + "0x36953abc02bfd8d72b7667b068f63f6c441e78938b15591440a9550ef796b8c8", + "0xbf85fd9301cb248c0e616e4297e2d4ec43783bde218ab67a7e2049059236f633", + "0xd6764c6e1f3e8d671f1cfc1e55c4d65b274fccdf783ab1b27eab1099b9f46299", + "0xe1f4b5fc4fa5e50ea8a7129f2786d7b13531d608ad6e413d3acd0637ddbfc5ae", + "0x225f99906c6ffebd2c77eda9c7b2e318740a36f84b8d6424b2f479f3e98b1fed", + "0x7850e352fda7e9b524fb1b1c04ee4695ba3613441ce0c5321b26b9cdb3317625", + "0x4913a582ff57cb276667a4eef0e85d31c79ff5f048b8b017dc89653fece5e88e", + "0x1cf357321372b71199a20da7e7490bafa5d9f837fdd3e433a68e8f84d03fa550", + "0x978cd04d02821dc54a1ae97385ca618a91ab42e9c227b5da2be433369825aff4", + "0xef0098b9b604b3bf4b7898d887b5f36ba8c196606b5688476547e89981e84a21", + "0x1c9cf750c7a5188cd346781612291b20ab07039831a77e55ed890987a876a412", + "0x6bd6e5e5f57b23bab83994c68760951a0a5126976fa9c46a99bef5b329ec7cc6", + "0x14db2e7acd6fccb3b019382385a1f988dc368d5da69cb96956901bc4ce06ec1d", + "0x48c20e5365cd6febb128db3fb93ca7a88b7f2cd3dfc5b7a6fda331e62d8f6875", + "0xec6ae4cd53c6c40f3b77e82cbf386d478120145c0c18f26220eeeefccc54b883", + "0xb27738db32dcb1fb5637ee6b86c528aa9ad75a47777931d45285f0745d6d9618", + "0xfe9671bdffedf2170714da275ff0dfdd533ba1be2ce2590bc1ebdea9208bc951", + "0x25cbe60b7936b87c09e92b9982cfd1bf80ee1d6ce65133434ac330065c9a60c1", + "0xc777ee866895e41d8e7320601a8341fcd99c98ba9d600888397f1788ed79fce9", + "0x63425e84adaa76af6e58807d3fc3dc294e9bd9c32a170a60d8571c667ee804bd", + "0x086c8a54c5d1c2f4160d7f0f5f6c1a333ca91875ba23727025d77225e2f4db95", + "0xd8da17ce51dc8419c40723d1c3a88f74fe336f9a4f98eca61bf1349b0d4a89da", + "0x0d2169c32328187125474e97c7a917253b90dfecec0682f3ca7982e064fffdf7", + "0xc83f335b6903eb3ad4b0f94fd6bb3a8b5b463d0137547a4252043d58ac00df75", + "0x175f57c174875ebc474879251e4bca53bb7efa9f27f456f10266864719e073e2", + "0xb0ea4c419abf7a74ed69807b3d14e0de6def5f55e645fbf0a625c7e9e3765201", + "0x4a246d6ec272afa613f9b6aa288477795bceb920d6b3ed1a78286314cccc2e35", + "0xd3af9fcf65dce23d27b46704753c0b4b24dc752db5389876d31181313cf91ec2", + "0x7301d3627cd3bc2ab317c377e4f81ef6b07ba64939813b20050b53c8f63a533c", + "0xcf785d9ca7c95247ae005537d0db37ae9c54494b0a2c1e655e9c5ee1292e8338", + "0x3de4a30d38f8ef549ae45b777149a547c8cc785c6e6f48e5dba40b7bc7fb4c82", + "0x27fbff002680b942c31cc8f04211be03c8646f024857ae52121dec778163452f", + "0x2a37be7d47abffbfd08f1aff379a27e1d9dd79833f67b466a59b8ebad854e3ea", + "0xedf73b72736afb79d07c6e726c74b88039da0c21285ae55b5e2c8191d3f802f0", + "0x99a6e045680aaa9aa3c175140a9337aee7967d78e97b41a0cb37c03f60c24b63", + "0x5baf77fcc6542689195c10fedca877c6d59ec418867f25c79d4c3ffd36493b84", + "0x85d64816bc21349e07c5dc852a8790c6169d26274dc4a7fc35c53c199c8f6dff", + "0xb59cca680fc9baee6d3d80e11e374bfe8c111b0f47be83157e54e6d18ca93e02", + "0xae13047af776510ee9d13cd6af0e669495704651d5894f30e5e49c6c9d33bd0c", + "0xb2cc9c6705f969f07f700e3d9fc62fbd9de299ca3510985ae5e6fe339e187c75", + "0xb198d0787de7b8e5e9beae4821f587608770fab12845a901edb33da4c50dd217", + "0x7fec95f60944c1796bf42a978a3a771613b889fbb14e6cfcaad143819bafff9b", + "0xda81d0a99cb64b0c8828a05f11bbe38719cd6ddd6cdbdc814a317cee492b1503", + "0x554823c8958d8631a06ea110de162710e66da426210c4c89bb210684c7dd9394", + "0x0914908175ce4d9fb7415d5fdb52367c616a1b95198c9421459cc1c769911cc2", + "0xfbb629523797ff98da78d0f41e2acc45acbb20e4a1e0e1dacbce45c69216a964", + "0xd88684c269bdced43c0bccbf8c041aa6fa2fa9354a6aa67d7053aaa0f2074962", + "0x3920c4c386860756180fb1f7fe605801f7696d5b9e4e1576e1aae0e8525df880", + "0x5deb5c080a346877454cd98ee36312bc3e4a79b3cd9f3c39971d892ed955e927", + "0xe099ae7dfa63b764ef3952ef921cd229acead0b0e047af94030ae09a34b0be2a", + "0x7e754b454ded479b4bf36835b0d52074183c9eb6c42398d3e7338948992d08bc", + "0x1b22378457b71df9263473eceba4f57933f11d33d31be11ec5edcb36df0dfd95", + "0x6605794adab619d57a2ad55913afe54cd5ec219f3d6740185409ac61d32a2567", + "0xa1039d1a4bb3e763dae6dca5b8c00deac9bf0b76c178eff53527a95852c587c0", + "0x9d43d1daf7c4295431136143ae7ad2192b71c16e8da4cd1ae9a282d113122c6f", + "0x38d5c14dc112d21963208fb735e8f76d9842c2ad13e2cdf32b0f6e70006f911c", + "0x09396c809912d9403208968d6f13d8845398b26e93f444acf7538e5c357df7b3", + "0x1ed6f3b995bfbabb0d55b107b2b3ec11c4be5cd68f207d9d059a8eb7671ccb8a", + "0x69db9592c01441747056fc5c646057d4bb992e4affd23654af7f24c47a002900", + "0xef015d193b0137175d8de710c2141d23cae1130c368a20f19bd59f9289d1a17b", + "0xeb63f8ea306392d336b2a8e0568e1a067d8f40c4e2b28f7911ebe48a67638942", + "0xfb12bbb145b5dc7ead7ad984045e62b922649a70ec00da06ebd9eba65fc83c23", + "0x10bdd7c613ce8584ac10f75891afefacc98cb0c711504e0f0284f634d19c3714", + "0xab851b2b35fcf427bd0407865a5989c533b855e65a9891e39b2a5e161a345af1", + "0x6bce48ac8c3553878ff831b672de737cfc7d7c3293e86fe322d229ea3f5d2c78", + "0x0c7313d927f845de9f7c03c09775e2c8fb8e9f2fe63413fff066e9f38d799ed0", + "0x347135f2e53f4002b5687d287b5134de9134eeef4cfa4d4494b086d957157870", + "0xedde43ae708664ffeb9d92cbeb03daa5fc0c7d1d03ac3e9d6541dabe9ac50c65", + "0xd14aabe2a11d404dcbabfbbd8d7c73ec05af5a0f9fcb79bc8f198f00420a2179", + "0x2c9d2e1c881d46c0fd68fffbd5ac45e3dbde2a4d1ddbb77d0ddc4f520ab83c94", + "0x42ea8109042da88b6ed9c71dca34907f54c356b46db55955e3a6cc1541904a0c", + "0xf81c890a5e8660bee4d5a0f18cc0f3a709ce48a5a49a36f0138ab6431783263c", + "0x492144091be2113571cf9cc84c53390fd00db10eafa2f5533f78b8a5d6bdc7b8", + "0xb42ff2a6b3d1e736c56a37a0a46f927caa4ba9fa6bd3f2d1a98459c7c30eb262", + "0x464c4d7daf1acf7786041d3c797f15354cc03cc5620454abdd88679659df1292", + "0xd5dca22e9c436660ee18a941129578021359c0bf2f22008b161c91494ed80594", + "0xb54d6f7ab969f0f95ca94d0a2070b5f2aca9f991e3b64a60c903a03d3d48e938", + "0x1261a3e911769c5c55151982e994aefd4d773fd96e8583f41a44cda306b4e1ab", + "0x669a364ae954397361f4c703c102513315552af241e306406fafb3dc70db8ec9", + "0x54d5a3162659886b7a0aad65839ef2cb72233dab58bb91961d6b6ccb1476da8d", + "0x449242a1b0ecd0bcfe9acdfb2b6779c9f291c98c09add8e13981617486423bbb", + "0x4dda9dcd34dbf574f62d475b7e3052b2e393be6331ab4b0ddb3f1a6270041e8d", + "0xd23f7682f463c5f58940bd199136afba80496fab562aaf665710ff1d5cddee66", + "0x70503762d711f0ed6eac70a12b728f3d84152094b1e4f9495870433592cfa268", + "0xcba23bd9ebcf36500a69fb8be017f0ebfe9872abba5070c6702047e3814dfd0e", + "0x0e2fd927efdd930e1843103c837526ea8f846230ef6ec9f0e8af61f9d3b19aff", + "0x518a527d8d9af923c12692405837e35d58a4625ca36c2041e539d9e369589192", + "0x0a697ad4d29f33cf10f6e08024a18d36a09f459f8ca427cc8b36def0fbdabc1f", + "0x5d96d5562fd252ca3b5f2bc6e6439572ec842764594463b349fc50cc8681d8d0", + "0xa093f86f7e70f80c308ce12554c6c23cdfc02dfda87579335ff1983d549619a5", + "0xef0d1f6787ea178b22a66632a6e44ff464b7de08afd8dfc780f39720b4746a08", + "0xd3a6e3eeaf50eb34d9af9ea4fc461fd4784ecbc6a2b7a8eadc37796d7f00218c", + "0x4c1dac930f116474ffb251df529847732dc575ab404342e651d6fcd67708be96", + "0xd5ef4aa7047c1ba5f18e81417886490624b5520743a1cfacbb04df4dc7724af7", + "0x2c0b01e814e880c5d9b9e01c08671e9a5bce1aa1190e58e0fcee1acf14b36cf8", + "0x464c6952f2738c8b28819299565a7ad027ffff4bd74d06ffe210ac5a44760975", + "0x5bb7a03847d5d77fa84567f913b2da4b87e4d2d453bd5194dcb15a2d07fb284a", + "0x7dd9b9c68e2df4a415c1c4898e979229a764cbda85c215bdf9b8eb2fc0af21e0", + "0x75048e56ab8cdf0cc6031e3a57fce809e540664872bfef2aa32fcedffc32e597", + "0x6c570e74626bdc74454167d24b0e755469e57930c0c5514847db10dd224beede", + "0x511151b41b26e5137b1e564295744e6b9115a277fe569a355a63cd483e2af7c3", + "0x885899509c8d7dcbbe3f9b6fc3ab2b1ec3df00909c92450dee7b329ba7abbe7d", + "0x40bc202e2040897eb3e06346d5d5c71276985470ed2e582b6f32ab8e4107984a", + "0xb442612b838cbc33bd65416baca317ae931bb2b6724bd565ca181a4aae95b590", + "0x23be2219b6842dfbe704c7fdb2bd4723cc4c12fff81ef96e0368f0feed5486ba", + "0x8ce2344dc7c2f11924f54185e191f22b536ec7a9ed82930e223e0dcac3ea6649", + "0x68b8de1cd88ae7fd5be9d8eaa51af21efe55359e5dba2aac1125232d01ddaf1a", + "0xc771dc187da76a5c761c9f00dbd9f50bbc0f149ef98f897c519457104c9f1a0c", + "0x697ef9d13cb317e94d4a40b9c6f45cba2680d6a2247e50ceff250be0f0934fa0", + "0xeae45a6899bdc251611165055e02b3fe3fe65dd938fbef43b01da4282d7fbe8d", + "0x3a352faefaf059235c46420d95a5d26618933e993ec97dee1a87cf55be10d4d8", + "0x59a105b2a42cbdec8ac080fbd09c98bd671ba47ac654c69fcffa0089ab9f4d95", + "0xb2e2c32ca966983c1951db62ef157be6824228d14468d1cb9856d53f9be6a9f7", + "0x67371fdd266043a11d59d4f05f0c5d920eb2f60b434928d7b558099623050c9c", + "0x0d0b97a7b38358d661718b2b77f50d1ab580632f030985d9e44ef3116cafa38c", + "0x2d19591fcdb7bbfe41412891fa43201363d0a5b18a48994674dfeb211701507c", + "0x7b42ac2c855a619963157ad7f3d36bcd1de0ea5689dd3e454aa2afc7b28dd071", + "0x16298885164e7c509b99d5a05549f95f57f3401f723cab1719b76a2bbce8b0d5", + "0x91b028e3ebca0b60cbc4080fb0f816d834f0898fd00ff42080b3e8dceb28d66d", + "0xe3802595c56c2981e3a4b35c149e29c421107c47ee6df2b27e979f59bb06cd3e", + "0xd285c7cdd2fa2eefce09e902c86a1856ab4cfe33e6695e94dca8fa74695a5424", + "0x2b78d2e0c0770ffc67b92d56c4b26a675e7f3639ea394842edf9019ad6920b2c", + "0x495f1461f887371cd29e86bebfedbd429f7eecbc7c759ccfa56500d7845db4df", + "0xeec765f7d794010adaf8dd7f07674eefed3f6d5b9dc43e39a3b3537288b9c9ac", + "0x1a4f6372274bdce3bc6ea83f768561d6c9ed996e72145d524211df0130f3b7b7", + "0x3955a47abdd98eebd3d38244e408aab387096dfa74443b9f607fb6fa59456e64", + "0x7930f2d3fb73869045d7b144061eb1445ea74202b8f090f4f017c27e1c4350ed", + "0xfe0e4fed81793226f51942fec125072e439e701bebbb049337a5f7b24576d29e", + "0x87a4cad6943d444f9da79e4fcbffc198c96752ae72ee3fc2487a82e724a045cf", + "0xde75d28f56b1fc3e411dbfd9a56fd748de3f7490b931328f3a5131c143832218", + "0xffed1a9fe59006557ecf383d162f0f6011b59f63bfc693d61b77232329f8d956", + "0x1cf303aae3e5d342a33d369736563133519e1434f981bbe6067f444e16d89230", + "0xf3be3a8b280dde0fd0aa8322cb7836136b8801420602e45c8ceb84ebed7c7e02", + "0x2813d9eec11134a3987955f4389d4bf07fb4b986b700d982f89d2c81caa2ac1d", + "0x28f236d43bab078d0e9662be120609f8de33bb4661596317905815e7771b42d4", + "0xd72f262c68e657dac4247a7db98fd115b1865942071d0eb06f68ddbb64b392d9", + "0x4215eb42c3bb1333a0acfc8240f1b5d9938b68acdcf0c048fa037d90cd6c59aa", + "0x5a70ad627a347a1884a9e7fdd6c87cb7c0d5922ad69054a3b9d56e96aee436c0", + "0x8ad7e96941d03426434d6b7e0eac92a04e94108d2b1fe71178b582f6d861e2c3", + "0x9902aa9f7e7f1e9e1da269bb387739c103b3ff7c67032097e309df96768b21ed", + "0x0af467ddad68dce1180ecaf84a397e5c8fc98281ac52c10d064e5972fcf87d52", + "0x4f945046721c0071c9b53a8324b391126d26c8bef20435d60a6aaa69e2d156f1", + "0x78bacb8175c8dd89e4c12b74aa687211114b47906d763e0f26cba8410e5e3300", + "0xdf20aab8a9e472d877262d3985813365acdab5dffd05139f0fb87eeae10a4627", + "0xda39d3fa1f48b617d3586f3700119f60a294c1e3d2546393e3a4bf09ba5e3030", + "0xb6ee6e1a15c36710e6d37d2cee67f4646ac94de616c3ad65b08cf6b7aa3b32c7", + "0x17fdf37e749a06f9b8768d73993bb7fcff8b6da75ff4545c1facd812c5c89031", + "0x17c88f6d416ac2e913cf054b9116f8639a566dca223243fa9dba0e0dbe047597", + "0xa04fa8fb398b38a48e134c62d9e31fabce109651e25fab8d32318bc6409edbcc", + "0xfcc5dd8bb39b3782154608c5e3c2a6b050382ded90f0b8352c645ca2b80a88eb", + "0x6b3f1cc76318f33d63b204bdd72a009a7e2acc1a81ff6530739c41990de6552d", + "0x5f4e8c17b0f337f546abdc595f953cfd056015e3add1aacc4e058b318277a3cd", + "0xd9917cc1fe0d4b12b85b2713c9942cdb07178e4c6f594baa4fc2617491d0ff07", + "0x2f6df9e5f1b821365dae46222c7f252a13693fc34a9ff96c1038f154496b49a1", + "0x5807dc551b31c69db61bd1619ad0f9631483957bafc20d4ab1a3e6902332fca5", + "0x04b97d025d8a5b1ac619c36ba6dc8185c05b4f1244993f684299f7368ebeae3f", + "0x16c71e2b84a27105527ae46ad63c9e2eb8d2145168c285ae2f7065e5354d768e", + "0xa562d2718f87e2086106f87bbb574bcb1e767cbf9471999018eb3cc21515b004", + "0xc2ff97b7e8736ef6de59a226cf0ce16353eab76b4a8b8ee147995238dff57d73", + "0xa9abdc4a8f70bc74134eed2e64045b24a1e9290ddbdc6d833179fdb4122c2293", + "0xbf0473bfd49593b516300cae47d7e603f9a2ac0767db39e2ee6e028083099490", + "0x8479dc0704190c2e34795dcb6dd447a4aa25672b9e45dd2e39f3864fc9521203", + "0xe03fe87b29737c7e663196fb33c69f02a35caed2e791f2a15a562bd2989d8cd5", + "0xf50fecb879d837e8556ebf2a5ae833649ff8f97118caa2e3b617b59153b65b4b", + "0x0eddf32c7032a26f6a0e0cce24ad9cb266d11500db33b863dc5d3470e3ee0a60", + "0x85161c9ae941dac62edc22409804ff1ae3111d9f903843a7f86b7a138e702da8", + "0xaba0acb42e5acf464de70e965b47872964d7241a57e21fe753535540b8e04a53", + "0x70de7226fe37eec9dfd4c7902761d0ee25a24748d47dd73202f9c10269bcfd18", + "0xe5f9e07e4757f99c0b3042102abbcc59b1472f45b53313626fa49fffb13a318b", + "0xe4e4be40e0d945d84851d54c2a317f0c56cb1a2a78b9efe1c58d996f9f7be4d8", + "0x5f45e651327d2fed7f559b97e56f2c954e82b843c59cd2e550628639f7f36d26", + "0xdb33bd941740ca4d547b52f857ab2fb06a5d144eef147b5dca309b6edfa730cb", + "0xdbedd24c3f6fb0f3d1fb2eefeb658076338a5274f01bf988dc65c7062f211d73", + "0xbe54c3757785c7346e4e94e2f975e97c6a9c542b2a621281b95529b58d3ba7cb", + "0xff9a08a7d3bad55b530fc2ce5b8437ad524b176f151b10366376e8752630a1fc", + "0xb8e1cc41b404d9b605c67ca266bb338f4b94db9d04f71c33b6205a7aad5e581f", + "0xbc06897480daec866c9faf1723f19873448feedff8237f8163ccd796dcc2a4c2", + "0x1681fa8a577b819397aef568125a2f81aeb94d313c5f37c8041a6fc8cd4619ae", + "0x91b95548f18cd07f37ae2b7d53c56a37dba797361f986d1dbf290e169a8f9bcd", + "0x2e0daea275060cf0d7759fea5f50a5d22bc13c2ad85b1776154409f4d4eb30c4", + "0x1999fb0544b4155419e2e84fed331c401f6a2e3314117acc21da81a135bdbb47", + "0xa35676895a52c8b1de46ee4059d57d1fb5efd480828fdb120048294347c3c18f", + "0x8892717f9562e3f1e5dd2f88b45c299ad91e8ab05dcf6be1c0de7a95d0ee7a3b", + "0x91ac521bd8ddbc2efc821a82c6336d01cca79b55c36fc05932ba588d68bb62ef", + "0x76850eae9c3e3984a06d664df14c1e3ab86532b16624e93603fa098df1136ec9", + "0x4379c37011e615085ad33e48b21781b943437e073964033d6bf2dc9fe85fad21", + "0x15cf24d1b72cf5c797531314204207e899820c07f2c611377fa4a8d2b23e9e64", + "0x964b36d4050d4eacf96a2e71bdde62d6908efc0291795432b45b3032f78c5fca", + "0x5e8abbf414ebf24bca3f1db28a81e34ab73491ef8535fd661661ff7064b989c9", + "0xc1499796680c37d46d0844a902f0ef966efc8117c2460e73f89b1d81a3b35f76", + "0x16be9d9569bc82d5245e0d2f5f2efe4a52ef09277d84efdfecf219ce5c7368e4", + "0x05c7f5f0b28e1fca9441830a38e54813e4ea3a73c7c4f7a873781040e4718c95", + "0x0902c45ce41d4e6cbddd66046e9baac2ff2b6fe4b4b5fce0ee91932d57f74edc", + "0x523cb2017561cba6cabdbcbb54ba2f97d6a52a5ada114c533912c457a4fcd02e", + "0x9df4d35c4f05636670123ee3d9a6255c9adddfd7d17cac6ea2b6e8dd33becc09", + "0x05638d9e998b4eff7249981556c9493fbcdc39f78d34f6c120cf87a0b4153316", + "0x451c25c490adda5cecad4a7569450e4be71b08e6541f0e122683ea3544b74375", + "0xa82e2fc3c1d30e7bc9f5a4a83ac3efdd57a7d05617889001c075086dfdb0d206", + "0xb2e0beed5b15c9db6e0d4f31a2111c4dcc193c0dae3ad9fd320d0e2bd4410ca1", + "0x40183f421d938e028836b39156862b8af8f88b207ac17b9f7535df0f6e7c8bcf", + "0x311e6dfe62efa8e3b5ee21ed0abb73d1ec69b357e689f22d04d7010b3e6c9ed0", + "0x7abd56b8ecedeb87fc6ae95d2a108829f8ccb109e05d75ae19ea67bfa73a13e1", + "0x46771d8f8adaea3d100fa756a801c22d277e1ada2256fb7e613730484a856de3", + "0x3463faf96b0c752199950ccdc1ba7b16c07df750fb76c10c8ecb1b155e3ce021", + "0xddd0b47ff5d1fd28ea7bef1247f683c3c2ae6356b8260376b390b0e4770c2c70", + "0xe50cc4bf0b3278ec508e7d9d0f233e942721dc9116c56d65182c5afc04219574", + "0xa567e9287f6e919a716ca159f6f59e0ebc6e27bada9e0312e4e7a248f3a1a195", + "0xfdec56f24cd59d833907cb21a4311c47d4baaea891efdfd4cc1fe48f875ba73d", + "0xda2ecee4f7f28fd5893d7db76b248fd5a5c8ad18002230177438f1209e92449b", + "0x267e150fd803d5dfa94dbd099f8960c52278fe338d1786b1678ba7de6c101625", + "0xf70ae6d7f25e486d08489d70481e7e537eedd8303b71c656e80ec04359dba398", + "0xa02efe6e14630c760bd69af9a6fb3f8391b5e7ba3cfb8bad4958421b3cd067f5", + "0xa5c4ac4a8cf93b8695d2f1b080ea00745b52a656b6f55e4debfed402226f3605", + "0x434c8b7d449c62e779aca1daba7e2c5b7f264dca8879768dc0b9c02c02ff77c1", + "0x67268d79875e46e0abd507e67b75e5cbbf9aa3de463284e96c057ce2f3be893d", + "0xc3d6c58cd4418eea6fa0e0be7de002279c761588135be2dd2dc152c6f580d75d", + "0x52f6b52e67e84c9cf8d56fd1dfa7d8e45e4e4129d33f9a942307929d28ff2859", + "0x8833fecfb8236f00abb49621694b0fd2a59a41f41035d2704a81d05a196fc4ae", + "0xca068fd3b005b08c2f3daef99d7447332a7720880ad94aaec632d54c591063f9", + "0xa3de1f4bb4c142ad685773b15e9a4e97c35267eac119e3c29e0aa36f2b814487", + "0xe8433c0f128f18299bda56175b279a5e271a8af30e3176aa48f6a734352e5b1f", + "0x9727cfeb52499b591e360f88de264235661a21fbe7242ace5d849d90bc506c74", + "0xa0c2265b8ab7baccbf56801e5d06baf4ce6af5879bd7e193f5fbc67a717cf2b4", + "0xb6303d8b21a2d08fb82154142bbd014329841a5564adbd217468597302d4cbb2", + "0xc6571041af75a5bbb7552811ded08fd4d93b8e33e974451771a629593df7d656", + "0xcdbd84961c2639aa0159de12abaef96152026ba3710385ca44e2080b5ef6008b", + "0xec8fab8e1adf154822c799dd35e2627420663b4d1f9439c79d89f360467fc216", + "0x8aaafbfb4414ab5c8ea23ccc43b5abd2349194cdf98792bbff46b7734a886d00", + "0x1e2462355a74d1a705e3c3f28d826a6b229a134c472f8d2541e9d03ac37d8d2f", + "0xd4e33157363845de8fa0564d1145e4a46eb22fc909c6b182e6bd7aba4b380613", + "0x7949178782807772e6f9160a14b54fb0ed503d5c1630932cf17cd9e385b00ee7", + "0x089d7d1b5a0f3ec62db8d1c11a95365688a47bdb14954b72770d5cdb7af3a365", + "0x69fe40a2c3b725eb25be1310ba0b97e8974b17ce9eb233eafc1306a6ccd7a463", + "0xfb4cf8727985a7d97917d3b020ee11dcdb08cded73085363f625a37ed0d8b04f", + "0x5ffa2a923b9a50832644a8bd39f0ee569f9e4ad8f50c4e1d57c9ec96a1c03477", + "0x8360233860f889d96a7e077d221b4ab6d9e3f7f1c5fcb20287ce486e9c244979", + "0xeef9332e4fdb2022128df42a2f311dc5ac080c7273e1a24b50774058b1d9adf7", + "0x89d790c825dd9b3de1635ba3162fc0a3a99467747869b409db97d95f7ff6cf59", + "0x04a088709bb769fcb5b670fa79cd97ec2dee21e62992cb2df693e1f18b3a2d11", + "0x86519becccecba9b91d0af72c176a414589b056dab914f877fe8032ca1b8ef9b", + "0xe61b3d8ddc856aa2ab755d4097ab9040ddf3554a1d8493fc5b93b5fd58aa0fa4", + "0xd8efd5557426e233870b8bcb53e0fc89fe79545d4c2d1aaf13409a7fba84acef", + "0x0b74a2eefcd26ca8322495468afa0c2ed24db0e4cb8ddf30bb84f9d2bd9dc4a4", + "0xa9fbda8887f5ab139d567d9a14c507e574352003b6fed49d3cc3ea49ccb544c0", + "0x078261958231fa17c1b904ec7b80ec7c2a0e49925a2309abc701521b90306b6b", + "0xc4d9c5af76a0b6c55ed8243985779bc77d4ef86adfa63a8ceac44efe908ed012", + "0xb02867e224a85e4a929894919fdd1f3460f909ac276278129d7fbc859f56915d", + "0x7a66267c51322887433994e3a01fdff4600e596a06e1c627c5a50c42e2bf203e", + "0xa66849c9503997ed600daabeb23c1e316d938d7c36561013f41d9a994d819735", + "0x572641c0124606eab803d11c3548ea828cf67b3d238eda5efde6098a210ba6fd", + "0x0a920057716b8b6b968bd5a28478ff99224b687bc6c97e26669fa1dbaf99850e", + "0xe198e1c691d14b3ad0a6b1888f7ae40ca60042ac91ffca0d6df3b4bd12090898", + "0xcf8cceabc0ccdcb4951cc37f625c1e8c120620e42ff3f1ff4a72e4f6dd6139cd", + "0xfb06a9c8215be6da3ade6c298f565f7c3116d12c87da1fc9fa48d17240e3b545", + "0xc967f1f8b116fb2faac0ae0760622a488cecc6498c074ee0f013d985475c914d", + "0x7351f762b23b48612b1369c3a7754ac2414e4d337f94cbee4fc1adc29759eba4", + "0xc3410fbbcda7e7bb868ed399d8950db593b7e79d5fd482a5fdb6e6bf342fe6e8", + "0x68c7626ebe19b8d30af71d3cf3635dd7c7912aed7a47bec3c369b72eedcffd05", + "0x3de93c3bb133dcfdf07ede31fb2933d8acda317e7680e7bd18cc1485f30b9225", + "0x4f2c0cc1f9f2f2c1b84448cd9b033d95f74940f6dde28dff0cffeb2840b6eb67", + "0x4e2934f4981c6a3591ba4048b0f3794a6b92bbad76e94d68ec4a99ff95601d06", + "0x8ae0d36b4e3212e9055cef96398fa706d9df90c2ced2c89c4828758b62154840", + "0xde41a196177d404534cc4b46f6b877ca4dc22a443f6a4680915e43046396e8ef", + "0xcd273ae452ad455f430d5f57d6411454fd2fef1698f9b8c23a4fec298936e47f", + "0x95c9ab467c02ae75c80cf924e81ff6c9f9f9176b828bc3dead827d4707fc5cdb", + "0xf9ad1ac9623d7b8b55dc1b363ac5e6b81fee9cb0bba042ee9802b74f3d6d12ef", + "0xb77f49f9fe7da05e6233e1aafd35cfa8042f8ac8220bb04fba898bf75b485237", + "0x6c7dd1ae1b2c378203b2be05abaff1e6f24d9a16d2fc4fc76bf237e61f5b0951", + "0x50c1046183493f9a0b860effdce20c193a7c7e89cbb509cdbfc839c522c99677", + "0x38a84d66ab731cdc96ae16a7f0dfb8c61c586bd0755cd409f4a785d426ab2e74", + "0xedf3c6c8ea853068d511c74639236e1daafb2caf96964e5b0daa22d354e39658", + "0x3445d411938c39b0168b96f8a4b0e32206a531910bbf52743faf37b3581f3236", + "0x4c418ec9d20b934a3f237b4c13682cc1638ba8e517e86d168e8c990971098f97", + "0xa610b6a8777a0467100a3581087f5bbcc1e7d4b697d9f53d00d9fa6f0d77247c", + "0xdc9e46a16000ec340bbaf70284f6a1528dbec79e4e8c371d4b04847f8c844089", + "0x34e76ef7897de33eb66e4ae37b5534c6240540048c525f858dc832b166593181", + "0x36dda3dbe43f18880aad5a4f25ec29bfa2da4a6c7f964e6418c0cd421bdbea36", + "0x64221de18086e9361ec07e4cede9e0103109d315d97684f26f05e831ee2878fa", + "0xd0fdddc2384a132f50ae0670cac8e62e918aff264277d350faa66a0e95430a2c", + "0x4da406b43c8247743de53b0a395e47204ca3f0d15f2a29d8715e11a71001257d", + "0xd0e67a0d70cd2140f55941d6ca90cd15ca6886ae013ccca40c0afc0bb8bbe016", + "0x70e6b1561209e95921f3800b1c48ee3bf3e532f5571bb2e4a5d82e9b288eaa33", + "0xbbe85ae238d623b1434dc75fb5e5d09a75578d2b85c59b8e69d635befc784248", + "0xc617186c1cc1c807b9626ae1a68d8d4fcd6b42aa153dc586d5ee2192cf9918ef", + "0x018329ceb98202471fcd740a34c7c987c2daa081b0d105b86b5b948c8248ab63", + "0xa1bd431642f0e1dd5f0bf01e610c29e5d695b8f578faeb0f511a7a9a2fa3116e", + "0xc8df41c2aae79331b86e7b007a28e2731f27f50609e9b4924678b8ff24d509e4", + "0x377c56c1c8b9686225cfed2710e4934c17ce890222c7482e7fe7fc77ebccc52e", + "0x0262617467f33b9eb0f3b28f368f5d08483a38dc9423510442eb88537c6d49f6", + "0xcdfd57a4737a718352b19c48aa72c41b2be0a7267ec7abbc3b539c81fb5a4b7a", + "0xace32a66c3c9540cbbd81c26a429487e3ee135677b8a43ee7468c0fc0c584c05", + "0xd4a50046105d5d01c4c928a0ade2d1a82db88ec52dc1f02b7c2daecbe9985841", + "0x350c5fd3734cd35dc6e02080e087858bef8d8dfdee44bd8e2bf75aef795a961f", + "0x5e597461c6e1468b3056a2cd4483e85a8b38dc27195ba60d50ef9952aa640a49", + "0x4f9d19414803bee7dc37e16413e033bb710543d86b38d6133adb1ab4ce90cd0e", + "0x3470068fedcdb6183c16ab34a1743e2414151eeb7a46d71961c1359adff1e214", + "0x66054a35bf4b53cec8302e2c94b8be80f3692fcbee87da4f894769799453771e", + "0x752d55b28bc47a388b098fc5b6b5f60ffe153459ddc1c0da007cafb3be151be8", + "0x3b969e58d42a927a7b214ed99c34ca6a77234703908bbf4ffa17e17e21fb8cc1", + "0x6f0157bcb211940600bb88d08f026fe4af881dd11d8dd1351ca014c88c3db72c", + "0x8592dac47e72c7bc32099c102a582c00543a0d35f2dfbdb9b57068c79d077815", + "0x8c95e048954d689645df63ae447101dceed5e75d154502c61f37990e5a97ddca", + "0x9f4a5e8e60a88088c391040bc01c46538f0cfc032344a882bf5f00cfe1b10d3d", + "0x04817ac392930b9b4d81cd529703b6688717da8101fa8a327fe49c503c0694ea", + "0x446d3e1470d3f965fce24932f5f1824f998c9cbcd9eac1c9ed7fc7a323658bdd", + "0x8603a9e9b6b852768b751175cdd2b23e354777e38408903b42d67a108c1b0999", + "0xd04177d8e00ab233b6336da228ac1b9d683128c66a85f1eaf2d462e7d52c9ac9", + "0xb01c3a41c7864d5f14f7b2f18bd5e4576c2d4d296d78927f75dcc50f488b54ee", + "0x6c7f1c0024685c819230e8accfc6a0e5f967b440d069bfff8c79185f152f940f", + "0xa2106a57c2faaea7c6ed8c7edd48e64ffadca5c03674672da9a972b4d32ffc7c", + "0x2c245fd6206db27c4f95be2fc01b04d24febc0e7781efb69623bc5214e7ddb69", + "0xf4aadfddb0d2d00668dbb5a7aa1cbd4302d0778d3697af4cb2ceed68e5dd1639", + "0xca6ff39151d73d4ff9aafb89ec0843e5d93eceacdd69b1c95cfc745857397c15", + "0xa18081aa619e1ee71c310a810c8b3198d515a0954edd34994fedc974f24bd0a3", + "0xc05f8f372ddc52ad91874e45aa48683c969331a3c472708714c19af1d8e3dc07", + "0x57a2027a86cf6e524d7a4e7b0b920a98ddbcce80f018bf402f7fbe73cb366614", + "0x3fcbb5d3f51987fb786b0ff83f39526e2aaf1791abc5aabf2f11a6ec8ea4bad4", + "0x61dbfda0b2940f034dd239375ecb5c8fa7385547a6ffd4bc5951bca8f5c8bf0e", + "0x662820a806693485407041ced34740b6ed57649bdb2d346aba5cb77108f697bf", + "0xe368491b3e2fd70d2c6f06c6e05a41f2bce9fca28df109882fd1bf3e47c82287", + "0x6cedbe3468d4903c73316b43534912e1b69cba4623791121b309fe37b6ad9b64", + "0x6517d421dbdf6e9041df293e6112572b8229208430277c85a7e52acad8a760fb", + "0x8a1602ba31438ed89e0f922aa165e0740e9cd9caccd82ca7ac79c176fdd0a2e3", + "0x09a07f8791bc59a20a326a727803822d1dd8de5e9281870818469145ee90f114", + "0xf6c3a82062633e2072f5b2c59b78b3f6613663afb2b35546c1240c696aaff8a5", + "0x1b4ce49dc9f835afcb3c34e92caa9a30db92c0fc2cec32c1746cc5eda1caeff0", + "0x2bea42fdae58791ac76d7bc2fbfc08712cb8ecb70b011a271572f047a678293b", + "0x01964b0ad4072d281dd451f41ce9e2d61f990bb104fecf29baf012779652f8e3", + "0x773cf0d41e03244bc688be7660101ba39fbdfa2cc94e6bfb02a1dd291c5c7265", + "0x651f0346eac119d14bba1a1078536dd986024c4dc5cc5953b4d9cad09735f97f", + "0xa4389eb16c42465582dbcbb6af80198f8412091c6ef2ecc7ec84c093f8925306", + "0xed75036dbba0069f415af01cdc723c0901676182960e2e2b51994f0e0c6ce0e2", + "0xac433ea4fa502fe9d126115a386eabeb86df2c895e3908bcd02a9d7d125dcb00", + "0xa65d04561f73a2f6e1f107c3759143c136b12619ab498ff7ad31994e7db5438b", + "0x6d9815c2f081d54013ad118b2c0ff456aa1396eacae1dffef461c2f2ba066527", + "0xab192c650d80aeba5b885a67d07512a6f532fae12ea69a3eb39af7da95c64b8f", + "0xa1d329666928263f1980f72c9a21414c7302fb5e77cd1dd7a91c4dc5d6d748ef", + "0x9e84e47ddab8900337e35ae9287dbd041d0b1d059582f95d375f3231eefd428f", + "0x89c11687a6c5e5a5b45255b4a8ffbe337d8706470c3a39063a960d103ade6af6", + "0x3547ba85cf24a64983968f8587f28bace1a797a93ecc16ce6787263f0de18185", + "0xa98634b1d1c39ec41c7cfa6a4f353c4c276f0618fbb3bd257008b43bb33b262b", + "0xec39ca2cdf7a3798a1530c8bd1424622822f6824415b2964d0467ba313faa940", + "0x8e66c39bc71e16085bba945ac0aed19f3f169d9d2dc7c0ec090583bb896e1a51", + "0xfd7f6e227a8c9025a57c73ff8c82265bc69c9aaa185eebfa924ef608234f1937", + "0xf55d1247afbfc35128a41465800daf2f90c1d57866e4bd37f92bc8278baa95a7", + "0xe82faf145ba98fb5af7e32f5aa90e7b2aafe9e2074c86bcb2aabe17ff35a025b", + "0x62abf9c26e0e5a7c2ca3047c8ae9f27c5215846595b4f41aff72c8a05ce42549", + "0xfc5cd59f7ff8b54d787cc77e29af8f9f78102be33ab4fd561481dbae04426b3d", + "0x69af5e5777a5ee39cc76a049e268845af3e1ecfd0b8de8644197469460880a31", + "0x8c1ea859c343697564a88b170973903e588967d89b63d511f63218bafa4c4aa5", + "0x8f9c38834fee0d5653d4df327232737d342f9b389df61f5cd377164e38a91e6a", + "0xbdaff64768fcdb9210cf8e33fe94a6cb38ba068c2d21d970efe6cf5cfb919eb1", + "0xf64aac8df844e56afa1413e9765a955b6879af44202a43e3f9aa15db421f6643", + "0x06762bddba350befcfddef5148ea1f05729760cafe5f018eb71285b92e30ad96", + "0x536ff0949c7f34762613747c2b7d14f605d6bf0ac328346e34b4fae516771af3", + "0xc30d536522242b0b805546882d5a283d517efc518abbdd674156b6f67dbaecab", + "0x818fcbac4a40b856bed993b9021286fa5f59f0b76b25af731f4123a83b5eb90b", + "0x2e6c3d4de85428210eda505421b253bf3964f5b2403084a1202d940de2d6dfdf", + "0xb31f7199cc69689b24ee2f52c8b50746ba3ecba904c49e2b352f8d6a64f514f5", + "0xf910446802e79809cb62cf6d958d570186ec7a477a16ebf6c0eb45c245c514ae", + "0x36e60616ab618daa724963f56bec00da5cbfac517a41f291da6e6cda890d68ff", + "0x4ae4e0c39ed59901fc74ef1fe52643f1f4341457aab052be71382d9945115b47", + "0xf5038c706b2cdcb2337a88ff34ed3e8e3093fe95d48e0342fb3bc3c0adc2ce51", + "0x021c48a8ce17f06cf41f89033a70b201b73d2fdc5c314bc313e8cff57cda9fd5", + "0x363c94da2187a9e497c77688f70baec16e64c4454db1f0dab37925fbfb9139c8", + "0x2d7c8407dd4ac5ea3212b18e103f10626d8bbc0cd18fe261409043399f026b99", + "0x05c3dea4c6599a259c3297c51c38c13f618ee5372c6b43e1945396bdd7a91229", + "0x7eb49d1da78b683659a33b9346c65bddcf6154043c97438274394e3ba868d0ea", + "0x17c008f4a8fdde5d0dce03adc57310580912599fca0535a42144526b4a630503", + "0x0011edd3b9175a765f1ab25a3123b91ec9ff9f233e8f782a2001ced391da2f05", + "0xcb62dd00e7a67019c782abd7e4bf7e3eef12614b03f90219434bba24e3070097", + "0xee086e5721066d4d8886e61e228facef0f518f8140926067be9f0f55b261558a", + "0x683c738a40a8fb871f3f7ef575a422d9fc60511ef4c84cf0fa9161605c10ef2f", + "0x43a4ef42030692e416d28c72f899fa83b4e3d3066fedc72d8c1ce0c3f7f60dcd", + "0x964a579e0415c2875382d1dc5953a54850494ace6077f7ed247f00eeada0bf1d", + "0x286bca4d5a0ce6fe9c9ecab2110fef1c13f71f8e11c37ab5667e164d2f4cb3e5", + "0xf2faf12c85d82d434a5db7d43d51bc99508bb11db731d7a22136d08f57901639", + "0x645944ae04d68cf3c993f75d75f217c8a78531ea3f17718aea08c849bb705382", + "0x7e4c87b6078ae798210fc39cb080772ad2034dcd9ec0f7a28b2de7d7e15377b0", + "0x4760f5e4af303ec759aea4fc2add0759caa3ae96bff4f727c0654f81d02a763f", + "0xe2f15372e72f6e8852c7289b192e959fb797fed0fb9581afd755e4352ec288e2", + "0x760975db833255fb7f325477153462be406b63ce08e6ed0da0dc48f9dac5375b", + "0x2ea20f22253680c49663ee8df8c74aa2f0703223c5d0dcb3db37b8c3ae7475a7", + "0xe7622392c52ce0d6cd698806142e6e26c9d86c81f1877bfbe9022ef150cae57b", + "0xe973760c42ebed38e37252019fd73f4ef14f2503bd3ffb2d859124b7e25ee557", + "0x7d0c3cb847b2cb7c1a5341e0214e830ef886073983e08498f89617b5833c22e0", + "0x5f5939c73fb684dd39227cdc88af51936e59a9881f8fb63e071366b9df4a6b36", + "0x081d5b53b84e2fe7f8cb04a6a6a045e4c11dc726710b6e9994f426fa9d32ed9b", + "0x436e895e16cc13777cd0b740538a64bb3a1360a7038e6fe8efa3ed3f590d05a3", + "0x55a611a3cc6106a86768053e268658cb541c8ca17a66a4a90a375772f0b5e016", + "0x583da6ef703398a2b781acd935f9916932050fa0cbbe1548b86d40b3b1941fd4", + "0x055531e88f18a0d79546a3bf00cce987c33ee0f97ecb7550b3c301530b279bec", + "0x4408c0007dd2dabe7814546fdc336f3ebc5a1dcc7daa1d8a38a9db819eb86374", + "0xcf6e7dab9c72babdc051fcf35ea89e793aa6fe380830d61870cfb4ebc3e7d919", + "0xdb02f15887419e3f89e1930d620748ca53e7f0c026ea8b60cd6e9ebc62f9da1a", + "0x4d1bb9da4321c7f2962a275272c6c1b1c3da6ca9549c19134dfbd43cccd76359", + "0x6ea8fc2a9138c404993edc83b3f54b0d5d94c85367c8e6884ef5d889ccf1bfa3", + "0x4ff5c77a56a90c20872cc7ab5b868557f7fd5d0103503d4217ea2d0079690ef9", + "0x5edd2bd35b9d24b9d5a3c68025061137c82e04261291c4d958d9e0e9a2763329", + "0xefc287bb7ef397298052013ab79d5a46a3a80a55f60e42c66746c9a25ef2dd15", + "0x986fbdb20fba887f3e4441a5b4b98824e1ab4df9aa43cc1d151eeacc55bbf4b3", + "0xbc70117b2b1204e3868a610bf3d2819095185245be082c96ffd3e0c2e406be51", + "0xaaacb52b835b235c76b02960517159cd1f2fb08681f13c8352a04820a990fbce", + "0x43e8b0fb11a657e4afc022573de30184947153497936d6cd47dfb2ccb61bb110", + "0x63fc1cbad428e16b1e2063db10c85ceb6684680c044adc2aed184054492cb19e", + "0x776674ec78cddc642e69ee9b16f2ee876655ca3efaf6a24a72c99a998d55348d", + "0x09dfc550074184d46ec04de265047ce529bdf2c02f7b44e428742f674c31a0de", + "0x897263eb076edb3071a306922207d17cceba6ad179d0f7fead2912ee42c69774", + "0xbbd230729752cb6d078eb853681e85823d2946095ba318d44b28eca479bf217f", + "0xe731c6c7938b7f2dafa8b5935cff095289b993d5fa4dcbaa715e6817d83fc823", + "0x04fe3b2d9727b05033eb4955f0c6693b0e63de665db904bc62b4dad5ce59a487", + "0x881aec4ca776991226a24f1ba9c736f9e86a051cffd1ed42d563c01a602fd126", + "0x9dd5adf0aba333d3cf13bbd8636dcec128911b675f159d11fadbf75137e1b766", + "0x26fb6742fa3be87da75218a1a138a3ed64cfa939791cbc718c181e226b5ecebb", + "0xad0c9794ce6109aa72c3b0ea6110fe96191ce3efc89bef5a99696ae84380ef3c", + "0xd710b6759276fc3149afc75ede514256c092a9e044555ece9fe27e27364181e8", + "0xeaf3b11fee973c4aae9fd19de92a7b14ecd347275c64b2343a2e4f97d1204785", + "0xcfc68b631ffa430c95ea583a1a1cef0a43e3ca182deb646c399a451ce55aa921", + "0x52057b9108fdf67ce8b7a28596e933ff57369b9ec9f1183b79cb0d0c9f32d651", + "0x1b99aa1987d512c71cfecbe56d6bdb4828ff254d055dfe1b23c472ffa4a6c3ba", + "0x64968b18cf678d322a84d54b2a91e77f44c108e2d722cb1f52708cfb824d227e", + "0x51be4bb756c2a3b74d4552310d49c7edf084014ea2787e349bc32143295380c3", + "0xf98742fa2e646e8add000e8ff892eae0fbee6f61a2a200eb129758285938a881", + "0x0f963737d026fc353f0576ae146a0dc7a8a27f31138b3753101a07f0e833f1f3", + "0xc3af9d91a1e44a3e865f44e75cffd5e9b135b04fe6d423895fb1911ec08573b3", + "0x366072ca53e1b7c312088a2c3504894c2bbbe1f1fc3204e22a22b5b619e09a9b", + "0x46ca1ff3099150438131eb934083404728921e498773b5d91ea59814e8078588", + "0xe2b18d6bba927615a8f9252188c141864cd61cfe570ba65f7290e4ac0739b403", + "0x6844fe922e79f335ff103ec551476f4433d4617bf9f3e25efe5340cff0c9406e", + "0xd433ef7f7b8d1d517815e5f77f95a2f3e5100a08a1ba9e5de78fa57076d1d307", + "0x6a2a72db31e9cad268f13dd07c3c91d2c2c23e0c92c6f1047a6f3d59f447b821", + "0x9f0ceb8da593cf1c70f4eeb08a3f7dfb6f682ac4bc1c175efac43b10e100ac46", + "0x5ac594092618aeb04d6ab2c5b2612f1d4ad57162e62aff2d04decb0ace6658ae", + "0x003792b77b6c078c98e3ebdc29014a2c24c238a79e71ed5e36e27c1e273583af", + "0x15e869175252c89249a7728c33bb8e4c67f90f3c802d80356d25344ea05e9249", + "0xfa67b16cab4a3f1f8c4e8f6b3fe98f5be59e0f13ebc50d32f9d1dcf55fa4c984", + "0x3259027d8095d69e4bdaa0ed9c7d80681f4e40222b1d03347a141a634de40344", + "0x8aa2f2b46d0f85d66ebe39c00fd999b67d576e2fa119fad6783d6af4939fb25b", + "0x0f6073a427daebb861b9e1c45ab46ca9b8410e8f094137b979f6d17662fe4ed1", + "0xc9a4e1be21bb3dbde859c1bbd9ef9b63f8312f95c3d961414338ee8f9c8611d4", + "0x1c24d8de991c7daffe35d65f90c9eaeda59163f481140928c737d1066a95c01a", + "0x94f41fc0f4257b24ed6ee005e62486dff71f6ce8176b9fddede2eaff25d9fe55", + "0x9fda793acc69eb63981e28716bd20e8fa3ac091595929d943c651f73f6559593", + "0xf7eb671c5e563de2698cf69b2976e25a91c2c462eb7583d754211b252b4f8479", + "0xaac71c1761b78cb396167f177572144e68e1051ca3c332e94514041b9c7833e9", + "0xaec9323ccb0314b0407a591c05a0eb83e48052eda78fb5e9116cf32c902a79da", + "0x73a2019eee50ec26354b6f7d47416bc10982ac44ef47ce4720b6e73aed28f869", + "0xa45d192de4836829a913a20b14a9d8c95dadc04edaa07edd2599f2a75f85f5f4", + "0xcd8f6adf06fc2f226bcb713fcde720e205e4bae7a188d5135e3728d752835dea", + "0x59614e66b31bcaee5066f04bffdf318879126e7bbebdefe39b921fdfa5c1ba67", + "0xb27c406a25b24d78aa543a26b8321e43aea21523c7805215ded3d72c9043e0c0", + "0x1485ccd46c327cdae534d95c4b61611213377dbde0728f2ab309a65b69012deb", + "0xfd69566c9456b5af6a515aa031b326011cae67e88708557cefc5f1e67d76cd49", + "0xc7e49938469e6a6d27fdde544dcb48ef3f761d60ba4671163f505de1ca644228", + "0x96cdf2b037a658f75433883813f9edae930769dde761fde991e141fe383d82e0", + "0xc0ba35adef71f25b99450a0bb0a46b450dddc56ecea4c831a53dbea55463c594", + "0x97de7293e71b1779b23c3b51fd85e46d7ac86c55c18385d9c54d3da1c458a387", + "0xa72bf43cb3dc7ae59052542fa2bb2d5b921f49ac14485c1e9bfd1286af59abc3", + "0xbe7d7862602bb9911073bd4a8ec5421901a3a66698ed478102f02df87727fc12", + "0x7d17171e3edbeeb85326d785c2a68d6666526d8912c6aac44bf16fd0c0ef9834", + "0x3f3a36b17fbcc5ad93d99e71ac0bb2acb10b24fbb914773a0991c52287c201ce", + "0x0ddcef7f14d933eb8b28e5877e71595116a98e408b416f01de80be49a8e52957", + "0xccd5bc27319844f5b389b3b15e564ceecb55a91d748f145709025913fbfdaf91", + "0xaf27df2c5e88c00e482e78e44de581fd17edc2ae91e3b7d1017badf00aa8bc51", + "0xa850950e04076c8653eda7cd11761d6a8e9b46a070ece44dcbf5b8e99d9fb0c3", + "0x6c934e50d34130b0ea5d5776ab74fbf4ecf48f8a178115f7e93670599b406653", + "0xc6d3df6d3c0ea6c8573b314e7e0a8065d76d27333c0d6032b97637fc7013aa5e", + "0x4f7cfed4bad1d65ddbb1e28c8d9814450af8d573c0f1880d5647eb008a13a44f", + "0x0a3162cbd7a81248f449393fbd62f65ca948e9134cfc722554f28b2ef7ba4f89", + "0x6cb294c5c312be01110ff0566dd76d4b36e86c76587084faf6ff7f28b717873a", + "0x799574f8dee1769273651e19b56c17d3aa27d3422feee1d18080608b4882e2de", + "0xec0537da4c25bb664270f90fa72c0ede19127f7bfce5724762700715986f5b2e", + "0xb955c2ff50d42cce782c991be3eef70de85a1a382aaa6f7775c456d87a987592", + "0x79f931169917ff38a71b45d85a5f8e068bf45e8ece7a8e5530a0b4eb01efef9a", + "0x8d20869224be1328197ed93a88fd53d0b31ebeff49870bf7851d6e8dab77f730", + "0xe6323bef31280b55572d866f315b97f5be96148a3d640284110a23115a59ae27", + "0x47c847e3a20412135b22a2bed001bd32dcae67a70e5681a5e14a210553eff25d", + "0xb71b250754e11a7c9fe804a33e15a662321d9449fc63b1038a17d58273fab04a", + "0x89128e0b4180512ba5c75216b3030192d9b1574df87f1b926c5c7aecec92a7d3", + "0xbad078b9e9b0328b48dea551a962e437b51902c056c5b0776482712f9db786bf", + "0x4d5aed467fd88e4e026bf006aca0a78717d6b52f311d32449b1104f415bb5515", + "0xe72015b43036bfb62431d15335e719c549c61162f4879c0eaa81421017922d15", + "0xf70009d15065bd1570ef3fe2273da35e894206361590d38a4bd414ede7d69d06", + "0x2a4a2d96e00f06616d77b29a72d7c494cb6c29f50811ea616452ac769910005b", + "0x21f9218ff5737a4e6e6a167f83691dd6445a23732cdf4491ba7e24747fa0391b", + "0x26461e3689a21987bb38091f0fdc4f371002f4a84eb3b618e8c7ffdd6b3f1a31", + "0xd683d8a1f060a5e9cd282d641dd852ae20b7b1c0f9ba785d5ea15b234ace728e", + "0x6b4c803a6643293b9160d82212e5b3405b69a4115dde4de0258a24832ac658bc", + "0xe9a00afe1af35d7811d82e2312d02c5daace99f050e42388e76e5c1b745d8779", + "0xe756e9edf9bb83f450ba9791a245adcb89ee4fe56770d1894086ed6be3d089aa", + "0x729d6bfa3c1d41089d53e08164418779c9abf94d8276a8a8e7f1e4ff492183bd", + "0xd582a6b03425d0ab29d1405232e088822467053d470a99c3127c46ecc02dc93f", + "0x69ac67b95b725e5102ac7ccb59b46e4a4457e368b90f80624d84a37104ab166e", + "0x8de7f79cb5eb8dc096e9307968dd1b46acf940994dc1fc27156c5168e1ae5364", + "0xaf5fa4455d5b4ce635f9394f1ad4840e4686d80dd52696fc392c3eb89b7a536d", + "0xcfd7922b5650cab0a29e0468cf1e816f741b8b7af1768308f78ec0ac800870fd", + "0x5e14d14657d534de1846182929bcbe7c086d0bb9c418019193406ddaf34a7e5f", + "0xd727f88dbb4a62310cbdbdcbbe40023937a1f681b7d8f6186665129b9cbd32d1", + "0x5739e5a0f02a3239eb0f2b1242c7e8e0042bf7bede814cfdc6775e172d34bcde", + "0xd426e8bf6dc9171c6850a492b883bd4c92468b861f0c539ca890e444f854f44f", + "0x8f9b7d20a62ec75492dba773b54ed3416ff18adf070be3b3a35a803da5aba931", + "0x8af025719c903aa861de42fe4d082321f600c17e4b3a5f342ca408787957922d", + "0x43133e4fac22d85951ef650fada9a746b464a0659f370ee40ac6286d5ac3968d", + "0xd95ef78d2685255b58a7a0a581d953837b1d891f8764d2842c76137bb8f92628", + "0x5fc07f1fe21167cb65405edef11d30206ed7907d396252ed460365c9d6ea89fd", + "0x3b86a46c42d2ce31c39ac0bd352ac1feac8705e825c17b06d0f9db4f15f0b793", + "0x3672191b6d718f4ffe5e17039c25be00b258336cdf959abcb1615d7e77fbf415", + "0x017faf0c950fd86809e7a0acf0d7dea5b13d41b21c60d4844ce57459af471963", + "0x5236905646defeaf3666262c1781392fbafc496693b0f26167e14622ffd5e224", + "0xac45332d1c62566039b653fe67725544d531d0d0d385cb31d18d461e36ff3c4b", + "0x2ddde66714e4fefcf8d1130e2847d92bc758b39fe7a2b87dcecf9b3d0d1bc5f6", + "0xe8c6c341b96f9771c5897a0423dec64b2d3f57aa5923b0f694988302c99c1864", + "0xd31b332e66e44f8804ab8d224d179b3dc20f718dcc6b254273f2539311ae9038", + "0x2776a9d5ded89c9a8bb243b41bda3760dc173c41f16bc477a0c6e2de420f7aea", + "0x19c9b95e82cd6277e16bdbb383593459eae5584e8b746de7262b447f313f1052", + "0x6d602a973ee15804f76848823844da1ded9e2fe49b689e4e4c62948bbfb699ed", + "0xf8feaafdb855524369a0d0f011cee5f545b7e2dfc210148b13f84e0cfc5a7a49", + "0xe242c86f0d4421c505b4722b38c13e73c760d0d82bfb77fe6677a738e3f19679", + "0xe1d5352fdf59b76318738f0932c4960a590e46a0073694d9518a6e8a779206e6", + "0x7db333e369dc65cd5f8718ef0cbf38def00cd60bcc47c1ce2034203c6b2f8b38", + "0x1a57adefa64ef6f07306db76e9425624d106e73bc554822cb99b4697bb317f02", + "0x4a6acaff19b541b0b2fd43d9165f179fbefd353f8fda107d53926e71ecf68a8b", + "0xe5e886e9b31a3378ba585b16dc81f0d5cad83f4fc5aae85945e9a8898dd038c7", + "0x4d59ae8cb31c36c39c2aec16ff682862c097aadc499da6de1ffa72a6ed87b4d2", + "0xb92d833f46038c267f09c500c2ae557810709d7db9bd210ad4df55c65bc0826d", + "0xf1b971e2530edc4703ceb21b58a750a37399c05bec8a02409895af98df7e5e6d", + "0xbf1508b24e5d01809d39c110816f3ad5d703ebaeca4f218b24925dd9577fad40", + "0x2e25a66f7a580845ecf04e66fdb0ddc0e17237f6812f5f2a1640c3511c9f9db4", + "0x5e4f36c5ec099fbc35ca767f548304f8631700326b3a4497f8977d72c3727f13", + "0xaba60fa3aa0661858a1143d01d9408834c2be440cf06d72a93e4df1df6617853", + "0x42d149eec229a03ad942d1745ec4742f9f39a03534df077977f3f4691c939eb3", + "0x6b276de3cd30f0d7659292ba6e8bea190cc24badf88c10bf269fb4d6927b16e0", + "0xd978546ce32bc1123773b6562ae0a7a55b7d82c72f2aef2a56394c9940e7cd12", + "0x297a80b1aad7e95f57ba4f31c4835728a48f7af0e9adfa10d40fae8bd18cce12", + "0xef0d03d9db22500fae80ddba96bed81bf4769e645b25dd717c5ab0748e3da691", + "0x1a094a2ca17fad3f0e2703cd172bcdf4a0ce28e01840655a0bd19cd398153601", + "0x78f08815cffd7e21af3392d2ba9ce33335d8f25758631f9eb6352b826723d093", + "0x827646562aaa1ff4a12d97e59da6aa7c9166418dd2ba204e448bb12b321b7be7", + "0x5c0e92edb551cc6d182b35b9408d2538aa982b105003606575b5514c8e40729f", + "0x416dc98309f2e650eaf9a122508c163cc9e3c9d719812e0a6388b84fd48016ce", + "0x4f8382c1eee160e6877d95ce97b3a53cf7607c59483176cf55b40b47d198efcc", + "0x8acbe66fee2f75c73255b39489f15e6eaee75585426406d96ce786bf53076b6e", + "0x74ab3f7057275e0769c3356bb7515f108c69b42f4501a9d3873433e22639a240", + "0xe0bb35e880ee793203ad5ea844081b6fa99eeed85f570b6bfbbc0efbdd7f79ce", + "0x5761b5e7f8872c8cc13278f3c2ff836c325f4179b89897d0c5b6846752c312dd", + "0xeda698bc3ec12d8004406a7c7c9e3a16fa085a8448901352ce3713efdac58930", + "0x22138b1713dd83a25b1434813492910fa8e54d8feb9eebe1aa5d2bcb6ec2c69f", + "0x4ce3cfc5b1fe6f87e9830840e85b81ff6117ab62300953524c39bfdbf7868980", + "0x6a6c7372b5c90808a6a966c0b90419b5efc739e5ad5ca1fd0d6c9583ac37f240", + "0x257fb60e826d4a92c030a645375fb46b3790c5b318b56b1a299e09e0e7ee3911", + "0x5f577cc4d21c818bd18e427e6d9ebd8f207fc71ad5f883d0e24eb9f856e3e10a", + "0x0f387595af36d3d5df451ff3de879016c6cf575fc1f02d40d547ee91f6aa36c5", + "0xd8ae5a19d1327025446b5e16d0585740839bf32d9c5798bd39e3e0697113efac", + "0x10e80ae2881a780061bac8bae4514f0df0077152639aa0da1b9d8b3ae234e184", + "0x377f9a9fc5a6fdc69cc76f6f36282cedbe9c83bc43dc345fb49db28ef6b37cf9", + "0x2d52e3af5f7ca108b3ac7cfc495b96e05e2d7f82f7f83ee3234c84b77a1874ab", + "0xaad9190dc0748ae3f78e9e5a3b4ae10eb6bb0b2617cc2d16ad3806bdd994688c", + "0x83b863f21344a6a576f805ed480eb72d3ae3dd06a2979b539a43f2c955429a24", + "0xd4d0622b957b87f71610bf3af65ab018360d320ebf328222df10899830ca33a0", + "0x7ca92b8bf0337d0bc56aab4c1a57e29addf6f0a4b9070482f06a7ee89ccbde84", + "0xcb9c71abfdb931e30a67e7b77d247be70b005076b64fb138be12f260f9c73334", + "0xfe44663a9c2067fe4bb8b43d241438cc63af9638cc1859b5d4c7c7f89318e558", + "0xc962b737dd9438cff5272e16038ef0ca55c4e1b5497d75ef5a0aa53ac6c09448", + "0x2b3a80ef8b20644facd31b5d1618814507c8f603dd8079ba40da09b550f3a2ad", + "0x4664f49d6f114ae491a0364d007724cffe144f4085d91f24f8d3fe87f5b8e393", + "0x1e2456e2e055decfa092a838d2052b12527c6e56b43a787518b121b61f7e316b", + "0x2f45b1ef6d6ae7196818f81278f226f3e0fd535d3a27b63497a6fd208f195c0b", + "0xaf265121e6406f84f7711447d3118c02b446c0d6db9c4ef266208adaa1acc0ec", + "0xbdf275c92443f0755251473e89ff46d741681c7eb2e7811eae25a0f1853c0bc3", + "0x5adf59b0a9cc02fb5bb5c469a52582efec5c317ee1896d8df49d15c18db944d5", + "0xd9aec0aa26bdd240b709a688a0b0565f3543a9b3686b78efeaf070140f2eaef2", + "0x1f4890ecb2250b7ca57a092a0a40b0e4b0abeceaac015189e0f6e9486ce4bc7b", + "0xb0be545c813daf899627b982dae9edd9de72ae54094dd8eb25570423e5c5dbf6", + "0x0f98f4ac26d2966ff4b129950dfcb287098fef2e60c3bfeb1156425fab8db92b", + "0x5622210376d1016d0b7615552cf3d66cbbc2d39d3eeaa2bb100cc2328a81cd95", + "0xe3523e80affdd0ccc3090ce202e7aa408ebaea9fcaa1e705242b948eb15f3cca", + "0x98154cd06a09aa5f9d3e4b4c824f1efdf6eb5ad4b5c0deb1a16a8372bd073a94", + "0x6680dde58fd0b4ee4626a8564f827c8c2cb9c7d0ceb4437412f30a15ad486689", + "0x61f7582008e42c3bedf33342c9c47003a6ce9264c977204ab5ef778f6e6d234b", + "0xa8ffa5ea4717d9f8d55db7d5626799aa102f1e340d80c68896a14204ac38c8f2", + "0xb83aed2db0ce9eb79c45259f66d72cd00546caf8e39e5efe91bd03ec64cf96ee", + "0xae616f4c1416b46a21390e0bd5336935490b9894eaa7c653fd9909086a1df5be", + "0x18f84c5cbad9477e0571574a0bed0714d3fa587ca21e39839a95752e6e3f0299", + "0xdd5d5c64b54437f649d7004d54863160da8db8518ccc99ddaf6942fb551dd798", + "0x72b7fd1a0758b72010c216bc7394a19c1a0cb6620386a8a91c21d3db69004b49", + "0x2dafd23aeae504b4ebd17ed518648939cd63f5e0e7448bd8c0fcc78dceec4059", + "0x787827158ba2f53c21c6d05eeca56fd0fc2fc08026bf09c76cb17583340944e4", + "0xb1a4b60e4d00c8189d940ed2fc070c1238d03d58d572ddd029ae794e47352df5", + "0x33e1420671ccba2d938f5b75d45bd31d90c5b424d9a02e7e7eb4ca60ae402443", + "0x094b7129d1087747705a683bbbe61b13c546decbed3953c7867aef485865c7df", + "0xde05a46ee5e26ff79801bf32d1f4bb4dab2127ea60f7bb037dfafbc16678e1d0", + "0xc81b90e47d6aae3641ddbfade2f8146324456ef372da470b319528114131743b", + "0x2b835f2a36503a9ef3591f1913924ab134d3fba8c95153f1cc80d503c74a1af1", + "0xfe99568c1fc3808ad05d99fe2261b27308c97bb39a965f96119e012ca8ae63e1", + "0x2bc9ac9d5a461286cbfbdc7d6181c795321ea0779835322b5e09381db7169be6", + "0x6cf2449053f134a8ae48a4f0007ac1f8f39d30d9c3269155b8922581a64b5d43", + "0x7ff755adbbfee435992589e1eb09e92532624a9888375497ab3f46d921aa3aad", + "0xe708615d47cd53d7856688d2ce264311f7f94631f318588726b88ef29dafd93b", + "0x96e1a15735e93923060b3954925e8d52b0a4b5cf6516190efb907bdfe6bc34ec", + "0xd33e1c73fa37307c1199ee2dcdf3a0e92152f3f6f9f667ebafa190837a77cc66", + "0x57fa01905f12ba8decb5f5beda857a607e32e9781d39a46001679f537d57391b", + "0x2e5f2df2fb0d327f4b574c0a37c243b7fb4210af7a0796cc2c880252ad8438cc", + "0x26714de3dfeb00f0d8c27bc6729b89d3b55b82cc1eed2999f742c89fab424fb5", + "0x7bd11bfbafe1e87b58428db1f819f4ff2455a4f90db5e60e3d84b28d818a1173", + "0xfcf5fc7965f836dd04e54a9ce577aad76d10464b678259ef1c8bc2a0a0c67723", + "0xdb2e6587cea3bcc6f109e350d6c138cf919229e884a2597e4d6e599c26625736", + "0xd23ff7e12ed5f3177dfdbb51edba35d879fda9fc4ecb2c6f89bbd6addb772697", + "0x0a64a15947b2f5a87070fc3b8171485aac3e131619fb8c88b6bb2cdc1969a5f2", + "0x17d617aa1c6ccbd70ead8237a312152f42926333e8d9165266c497ee9a18da61", + "0x74082588643fb771a733c66b4ddbefcb50daf6742323e05ef4a2604c5d56eb83", + "0xa2cbc98dde5cc72ef8b0d222037f01d308a550ede1f3097c4bf7fa3e36914258", + "0xb7e7d0fc915050bcb17f685f798292ce93d3776096c2b3a252f0fafb4c799230", + "0x6f4f736ebd9941ebb79da6456d8ad423a3711f26d3cb643b81c8e02fc5689af1", + "0x21a21b15bf03238f62f610971eaa96dc5dd41ad45a6be2867afe6206f7ddaa20", + "0x459ef1b2c13a6bf1ad48e62b2020851a4505bcb88923bf0d5ec2408c309b973a", + "0xccb6429f43f6447cb714d4bed7e003239ff6926804185c6c51aabab4b355939f", + "0x5e580a7635cbfb695c97fd68a118ea37680c7408f1504b723189470826016f8d", + "0xc523d6c489334472d1af61a7ba1732195edc25bbf68eb821d1acb14ed5c98663", + "0x31a01c69fa6a86680831350cb67fd5fa06fe8accbd5cb6e2ce0ec689dbb23114", + "0x4fd4d85570c94d03c49e9aa60cd6bd6e684bc77d3b04eb5fc6b2b7f206ba9bc1", + "0x29b8a2ddb612c8c135eeb9f3d8791b603e7bf4d860c0d0b6bab53deb22b2070c", + "0xb156a9272bc83b3b85b93ae2c43f7accaceec85e1d77ddb1343b18356e00d572", + "0xcb08ef4355bb9e2ecc478bb4e80425acb497650f20509e10e134f3f60b216866", + "0xe2f0614ef7265b21deeda6d174341d59b7d13655ee7d473e5c4636dcf788d674", + "0x0727823720192b8a7a66ff04cf1913a31f0dd5b71dc145840533c30e0b7eed06", + "0x4b321b6181092414a3816b076bc86551fb8763ddb401a6923daa9c54c788ec5b", + "0x3831bf3c54c1aad7f557b8c914dc6e3d4c106169175d1e988eb028d160d49473", + "0x95d94729d493223bbd8649cb5117f14c279fac44fe40d1de1e82b7bd1d9261ea", + "0xe2632a472234dc31a473885d7a72e84c24f7883069afed9dbcb643cc5c32af55", + "0xc9bfa80366e9c466df9cda1b1c97de5f627a0142552e97f0554e597b8bc6563f", + "0x345a832166ef2f750ff143a57fadcb439233cb8292124d20bdcc294fafc5cb92", + "0xf8e032c077431b49212307adb00743b054e996e6d3dd101a40959cf19b9ec796", + "0x2243b4956a00a8d2d09275010330f4268d2f536cfa14741313231e6a7b33f445", + "0x12e0f3ff844f21b058d0e311e266cae6d0ab5dce8952d6133a95fb8659e337a7", + "0xf6d80062e8efaef3021b7a747220e713003c37ec733ff8cd15ace6b58ce60fa7", + "0x58c2f923852b77377eb36cb9c26f1b73be98a55c9b0dc65982098e5580ac8e26", + "0xb517d1be70a5d39a4da4ce46821d678257836e6f70621f529c4019d974eaaedd", + "0xa25aa7b0b4c5a3a0f063d4d2493d8b9ab46afc091161df9b1840f47d42334433", + "0xe1795c2a1fc25ea19e6599b070aa9209f2e89a10f0524d8aa78e921c12251514", + "0xdbec5c0577039e79efcad6ba30e0693127b50dd3b108281cfbb4adee3f212ca1", + "0x2c4835b03837ea2310484879212f94fdac6bd2dafbee292ed67f55851053f969", + "0xe0d9e5d1f86eb15c09f41181c96d64fa1ce3a9c69b3ceadad476353e0de1423c", + "0x2a0cff721302a055d3aefdfce14020b3f2418110084c0b1ac1c30a07e3ce988c", + "0xc8ab63d730c578afbb7611167850159fed6d1e73fc3c0b406db19934073ac0ca", + "0x3855c134a5a94513c46470411794ed81d83b29a8da353709035f6e224a9da80e", + "0x6b54eb434f5cb21a1e01b9f067647b857d9b236044220dcfadca3617ef2b568a", + "0x710ae824655688ac255d8046d8fd8438b110d768bdf9bcf4debc9381e02e873c", + "0xde3196ef84179c193b82b1175a417820a9403bdc06c4bfbb5010c8d83172edbd", + "0x5f4e1710e4896439b22f34cf4485b27edf1c35a2b49328eb8f018cb690d4ab04", + "0x37aaadc6f1e57a61a8fd925a6b583105eac77105e167735fc117b347ca58ef47", + "0xc02093ebafb3fc424cef40f5d8699681a4ef9fcad5c8b52002bd911f23812a58", + "0x34d274e1699647b5883100c125da1fce744238bdfe4e1ca2a694a5efb03a44eb", + "0xc14618c6491fe32dcc5848c2ae2a1aa26832343a1ca21bf327ae2a0ad182c85d", + "0x434b07e53641dd82eec95f4b472c1d1d9855ef8492ccd53137ecc82b2bfa5845", + "0xef6763df32b5ab25d8371067949efbdb7f2b9924685918ce3d8068766d6e729d", + "0xe534aacf1e9b44d4464b82ee17ed9cde79ca3a574c5869ff5b6f44d292d1a926", + "0x45ee62bf59e4bfcc76208dce86cc8234727de291de27a69a72bf15ce78488a1d", + "0xb170601af6545cbbab9d707a4623a07b9cb69471f994b769bb534338d3b556d4", + "0x73c8e569840ff39b4dbb24a7adc678e1e7b63621aa77a5533ca968e260d8b638", + "0xad8002631bf3e364dd09f094028a9f4faa5c67ad311838cf65215d6a17d58a04", + "0xee81a28db1d369d17ae97346196672e6f00fd622865cd618ad8447acab9bea7c", + "0xa8caab152258db32f3f03f44ce090e3759538b33d5e557f4a9a4169a0d436754", + "0xfc037393a2fc3a24a567923bca89a7714c72c742c1c466dc0d47296eb6d81b2c", + "0x1ff9e9455c7aa193842f453554c89ab25dd9033b0f7dce5c795e19b1c84b44f8", + "0x894d063e6911b107a6a42a542d99bca6f77192a0852029c0b5cd31a47c8bd2fa", + "0x6df6ca69e3a40334a4c081d74474e00c98ad6793f5cc58b5520be41eff4b17cb", + "0x688504ac6a0ae42368f496f0651e4c1f8ce13fa707a6b98eb52c1f264eac14b3", + "0x6f200669f73cfce5f2f0d9318673ed75c38371476e94ec96dbfcc683aa583816", + "0xff4a6e25786931e08a89007848dba7f62f84a776f7d926bd6983c2d9dd3a14a6", + "0x496c57858748bccddfeee4c5e496119f29a627a659349a4f8f65d1016e92d841", + "0xa5fefc6e3ea89e87875efe37fa9d796f678c6abfdd651897184b52d966fbdbc1", + "0x08e6f4c847dd3aff0e6e45c63939869cf7b007f712ffd79a16313eebf77eb4b1", + "0x00351e602b0508184ea47bad9e47b77071640422296e6574e1ab52cc02552a59", + "0xe1980e52f5fd5b81c96c6c9f1e6baf14bac191388d7e29e1191110fe68d6c88f", + "0x2ba58560d35e709c358a6caa9347c51961642756f4cd28d09b8aeaa532f7c382", + "0x3b8c4425cf002597f470d30c40ca0e40f019d72e33ca6ac54a5c80509bb4e45e", + "0x25da4aab586d49e195e1f9e0d8371d3368e88e3801ab9db750a40df31b2556ac", + "0x9b2693658ec603d976ec25a76c8ffb492d0647581da186a5b7b49bc6c18eafb8", + "0xd27630e4ef91c7144b5db0de4fd83fa53aafc8a463991819a919916fccb66aa5", + "0xd296657df9243ccfa00571774c0bfc0b85a64ceba954b876cb40713aca41d24f", + "0x9cd59fb8b4582d88a9af204976da07e57e066d48bc15b7c707c17dd11536f735", + "0xd6789d7ca6f21a983e7ff5baddd5c7743bf9a76419136384662a685060f16eb0", + "0x38e752a76cf82b63556556042e8cd6e4304d08338aea8746c55ee5864eae341c", + "0x56efa0c6d7d82b0d6b9ef82ea4b8d792d2786ac54b001d77e8493129accec545", + "0x9bb4717f3ab9f8d8a8fa059ef6d09716dea547ad0a1d99eb41d5ef3d21a46d78", + "0x2a616d50d6c4199351074e4bfb6701c3a8a6a65a235a7de581fcf40c6b50eff5", + "0x5a7f0e8b42847b84813d9129819636a60d7f50271f4c1dfac09b7bac0e00be54", + "0xd046e59d18b22e4ad6b9c83a41599afcd2d89d6bfa59f95dae874e8491b1469f", + "0x851c439d105b3622e675f986d249065d7936a7013a05d920bef87e44bc2bb08e", + "0x8e8c4e96b687a26e22a340465a8334fb8594544e7cd652f0e667ae5849cc082b", + "0x355ef21e4e57693374780b2a871b20f361f472074e938e9f33e7b4ebbfd9f447", + "0xbc97e95990cd4a23b97759f2a5ccc45359118ba88dd99895b2e5a3736753b756", + "0xf01b5e69d8d5871473833acaca6d2a1adaea66b76aec97e258bf72f50bcdec41", + "0x3eef80b3124ee89c5fda3a87aeb870dc5fbc781df98e7b0fc1a868acc3b01259", + "0x218a98c02e2b81ccef1bfc460703e57eb8ee5696553cab7b8ce9c95da70ea058", + "0xed6a555d0a858e362e15791f49cca517b74f0f764d8b032c0278becacb694739", + "0x23d9e9207f88148f7648c0955bcccae4138b029ed5b4bf2d574987a568d8283a", + "0x28af6fc0dcb7f57f8541a8b2bb3e781a0ff4d9020cdf26a8119a93401d45eab7", + "0x01989d5a75479a5a6eeb10430746b76a639a9716b8557b7864a1b7b778d265bf", + "0x475611d8792a80560752a9573f864f9ef3153a4c30bb16f7bf1bccb69241a8a4", + "0x0e52e291214aa6300ab1d875db31fbe6274d9769cf7dabef852b5d847e3c6a2b", + "0x04ea3fdf2d26c297c4276344bfc70b4a7645bb22382127f8ce9a621967a54ae4", + "0x64694ef5067706b01581730944a112fedcca32ce9e9103119d9ea4b4b75efd23", + "0xf37ab55394c6233443e1341d03ff07009f1b0771d12b202a78e2789a97e83c7f", + "0x4d723e3c6d46625adfaeccdd1d8bc3811539a7b658050ea0bc9dec625f180df3", + "0xf44e4c0d2e30b8bf0aad255325dba7e2093bb518b56e9c89625f67d5c139a65d", + "0xcd9bdda98c027168fcba6eed7c551291b59613aac11e6e02a00989c93a13225c", + "0x5fae33477d301fda6e6e0e29bb6ddf39c1720aacdf33a4b854806f8a09cf5e6b", + "0x464ae4d9549ea34f25c28ce8daae16fc129adc7ecf71527cfe6df6e1fed72234", + "0x01079ed69a40bd07152e241433be91d61bc1338d83a686d619fa1a21e8c57727", + "0x1f36d242a382eadc149704d8d525e4ac25e0fd2741876022e8bb474d3c726ce2", + "0xe54d3b597d9e37ff213472332bf31a0b16ffc809540c593b1478666019205dd9", + "0x24fd9f8ef011c060d698711a163444b20dde695a1b0db81dc3dc171ad227619a", + "0x01fe14f246bcec9826c6b5dd668b256baba5939749ed90932a603b1cab47fdc8", + "0x6e4f521a4824ae2306c046f5545c2f7ce911104d9ac1204095b8951ef5d63cb5", + "0xd8f0f8bfa160374ebfc90fa7966df4391c1aecea802e3b04a03c087080f01fb0", + "0xb4720294d8b145f29af00f220e076b271b587e9af98653efa47e2d47bbe6d95e", + "0x93223951fd8a31a3e6c98fa17cd33086e8155779930440a7c2fd25eca31f682e", + "0x752fb11e15acc591e78509137beb18cbf177877e4a9846bd33acb1a6426d1999", + "0x3304e2f07aafd6b10cdce727c41ed85ce0fb80e59fee6b96b9a2e98f73280979", + "0xa756425b9dedd5e6c2197ab4a76c14e76b250d7ce4e2b8ada00fc61e9f62dae7", + "0xdcc034de60f855c63dd2c5a9cd4930a45a54e416558c6945cf8e058d55886d32", + "0x77ab21e42cd147f95466d22f5e95e965e38ff22938eaa6b5bca2810d6a9e2e4a", + "0x65e59fd9132b911d65da3c1094a6b8523ed5d9b7eb8822b8d2273b55ce4aac61", + "0xff6aba7d3fd54e3948829cb59ae47084eb809481665c5c09300b834567ee4b66", + "0x0a2b95075de7b0579ccc23f174b3fdf6a4ce6aa9a42f1ace679953fba0956d41", + "0xcc6f0e601cfdbb0631c13df4decb454d5cbd554363694faeaccd4edf16a9ec26", + "0xf2937d3b0c62b8f47cbac34a29d0a7fe92ddda227f984ab360521d5168274583", + "0x9f0e54b594397e29868adafea8686c5e3536fe8ea767274e277d77a5ef2917c5", + "0xfb8ec9c26eae16db5dcd2f05476d89416d2c56a841157685dbd1653274ded2e7", + "0x07d71ac9ba4b3f0a616205d182155d7a34b2463c2db95a47b8d03a45382b8e18", + "0x6e5d854c2848a36b6feef20c80a87a88a40af50888e787652ca54601a7d37d90", + "0xf9bb21fa1e3d6af9962a9946d7fa4430708193335cf32766ed56aca50fc368b9", + "0x7750970996ed6e687ca27f08481be0fd426318aad87cdba015ce129dc896b41b", + "0x4ff8c843185d1b5b4291788c869ba3723969d2dde2d74a9b8fe27ba71da67ae5", + "0xd5730d698ac2ab71bc360f24bcd7a71b8001ddc86205d7274e636bda83d8e3a3", + "0xde41dece62466d3ca8700150723f0782fd624162030086be716485e12d5a93bc", + "0x7a709bc4ed84e8bf45818e0e918115d686504fa0dce6a3bf8513d0bd488dd39e", + "0x620fe2d0affe0c46bbd0b74ab6d7c3bc6b4950915cb83742c832c6117ea42347", + "0x542ee63637f2115e11a3e132bb4246d809232772e08b23401eb8a8f0067a4ed9", + "0xa284a3dfebff214c436ad67d8a36162a1810bd7a51387ab68188267a1e166d2b", + "0x0ea68982e12031ad38aff543ca7d623ca8945e649527eef2afca28993de42ebc", + "0x1249a7d56112d4146105a1f257bfd399f18aaaa94ed5198df8634c89c807d4c3", + "0xa691469bf6b8f7caa8559865c0c99f77350f41e0de9851dc887d850be5809cf6", + "0x34ee8cca77c5b32a79cc0a6811cc73910cd0353fb860171443f08d17e3f18174", + "0x73a7b7f8bb18df6038c0df35ee55b0fcb4735c7e0977efc98008c710530216ba", + "0x0a8d0b414621d022fbaf4a1c0a07169e879a857fb105637cd8193633ce755f11", + "0x36f21a7a7d142d026e9222b884b583387f10ba692b1cc9232a32ab401affd684", + "0xb5b69e29e0558368a8abc4ff3ca022d158fb11ac6f2138cbe0be84b387e1ab7c", + "0xa57d1845ab38ef86763a374b0323b7ff84722941b06dde3c5cec61de40c9afca", + "0xe8063bccc4fec0a51a6d57ff999a7169e15d93c0d7cc3ed57c065cf8afa912f9", + "0xe9b89463cfd719b357f878a927bbc72ca3d06f8b88f9a5c8568ef2afd3118ed0", + "0x4f2ae01579376ef5a2ac6e849cb2d3befdc4e5e814a5b8de31941183697e51dc", + "0x6356b87dcc8f1c6c83a2601be987b44f77180da8b8d8186e6c61eec301ffab06", + "0x4f2918a79394961e5802b8aed07d89b3b5b459a3d9706f0749ec65f3b3d9ebc9", + "0x145016d42f0052f68aae089538ffa956cfb2c5a0f26763fdaa940e427bea7ff8", + "0x897e9dd36d2c12e8941763ac6090321db8cf73de4319c99f5e4343d5eacc856f", + "0x7c1cafd66922a53506f93d8aeb80dfacc9da69e6b73cd3e4a9779cfee5e4f64b", + "0xbd76e3eb8ceeb1f47ed865351b54cf491173ef562a51f068966b71cd294766ee", + "0x600135fd75adae0801296f92e1a7219287ec588fb4627d18095887da1c71ee2d", + "0x1bbd55de061070b1060b4184583e9b5b2e307197235c986dc1a3b942f64cb107", + "0x07e182e958faeacdecdc43de50c8d4226c6f697d7dd4e2ca9754687605719068", + "0x3591aa6b10db91679824f182cb58ecbce7210444314eb4b4e657cbe6518a55a6", + "0x8948a1a48823911e4e16b54b3cf789c8b04a3c26008f97f3c71577a22c23cb02", + "0xd37594cbc0353af27e1e70e249db20f3f16bbdcdbfee1ded9bbbb178c3454d3d", + "0x639159845a1397fe73d7ab041d7d9a74b99ad8009e3d63d37f329df35afcec0d", + "0xe41e444d9f8b0daec348208914d665db316136f42614013a35e3c7e97e219dc7", + "0x2ed6880fd4b6631ee593d3161dddf19021a1365650009d01e264243e032f4f6e", + "0xa6e5eb641f39345184365aad2c9258d21ef4b7c65ee5dba93825aba5e8e481c4", + "0xe2880fe0d6e512ae4e0e78a9249f6319407ec2def2c5745292b750d16cc41786", + "0x54729b299e086a2ce795d339e5e20cf87afdfeaab0dc6fbbd0ce5f55194c319d", + "0xd3d3dc4b51e0d0487c9a09281e1115f593bd24cd09a113c0f1a89468ca1ea2b5", + "0xc86f8dc093f2adaf17fbeda345eb2f4ace3df6d5bde0c99e85200eae84cb892c", + "0x84ba70a7754f31ae366693375c5daf4fa38f7f086791c1aded55198adfb91392", + "0xc7ccc21a8a1b96591c32e98d2c7ad358279c2c1bf6bf51dadb18cb9504a1d751", + "0xdce9df5d5bc2852e8fa61e254a9aff0f03628659df28f51dca37a5a6816bc479", + "0x6d0a555491a6fb3f592fad8b97754d02bc6166257e5a83131fe9d859e05d1531", + "0xdf805b41cf7c7b9346ed152953e6334cca6725a6428e81b9fa4227329d231ce1", + "0xf94a98ffcfd4e28d863e790d1d6f507445f9e64165b3937b0c40af11789d5296", + "0x56723b13f5112f637e1e84c18bc3dafcdbc40508bb6a88c68f3a46e56f5783d6", + "0xd550a9d0bbb3745e7f5b7e290f6755b030cab20ecb6f5daf701dd3850737692f", + "0x7d88f7a5af354de5678a270b8083ce441be4c1bd6875a337b244d93bd3cf0d2b", + "0x52b48af317cb248300cebad6fa682a741f3dde7da4bf0e7c4162f9f1607e7d68", + "0x04a7147b282fead783019f3453ad8d95618f416eb7ac0d80cbe3be8f68a13c31", + "0x4be24f18efeb4c1f8b12f124bd1f48d3edd1777629094292616bd89ad580682e", + "0x146f8719d2e7f74deb3619ce6dbb782850431bd5a5fdf5f5d2dd33a54874f536", + "0x6497f392deeeb3359e35622360f6416da4d0986ef0770ba22876cf1990e5903d", + "0x858d7fc84e4504c9e5f54cca2c9facdacd309d742aa7657c6f90e25e4d7b6f84", + "0x6fc455af373dfa77825bbaa65b1539e9eda251850479b83db15b9be2b5e144c4", + "0x3893304198a242335c96423344d68ffeda11c17c9b6c5785bc59482c385f60d4", + "0x3b2a22d6d87679b173a1e82db970e6cec44179be8218489a8aa863b7603adc3d", + "0x52534879ad0d442147ca743ea21fb5dde78510c11da353fc21636f9725f9609a", + "0x194e094c77eaf3973447de9faa29007b7b895e3c855cd01c0d5609e478df10ae", + "0x64ca084e56ecda7e9f2a10b0b2262f29d5bb8bd361019367dc41bc8f97963961", + "0x05754bcc136f5b541e59f1c40c99572fe188f6f2eec3d91989072ff3f3c1ceee", + "0xaad0bc1df434492344bf9351345d3288340aff851f687f952e84d968e1a29afa", + "0x90c5f0e124e125b2fae5d2ae5c8a1f5fe065ac2cdaf62829733599c69f66d674", + "0xc20d9e82fda10425082d631b6705815ac17aea924aa2ca534066d76734ed1bdf", + "0x68fc07e734ecb1c3951262cf804b831ff32e285246ebeffda3949e62d31d937d", + "0x7e472ad7b556415586fb5950e8d0b85e895b8c9c7fa31952936247c8117fa0b6", + "0xf5c3457576bf1b624f0f558bdba237ec349349c60926eff5c3ba8c55b32fd6be", + "0xf9c3dd5d7fcadfe33b2dabfcc4f732661985a72166afb8d16486028b89f35bc2", + "0xa493336b47637629c4bbbb89e8c8e1272722db0f7f781f4f78185d6125f0e5a9", + "0xc8cab7f153c08cdc9607263c5129fa8278a7228188c950806d5732db541cc59e", + "0x85c0c18f11c32eac54537d2c492eb9cabea9a39d2e1ac56d8087c02f68f64bd0", + "0x26a001beca07a641ad1e3ea64c63e395c436836d098818f937b4354b7a925122", + "0x75cdeed9ee0eacc02eef853a54a6f0201693cd1a60d26e504d5ef16110ede59a", + "0x8e4a5fd1a18f9513cf70dcfedeea862dfa2b61cbee80fc204bb0315a2c051424", + "0xa42896ce30565041da64ffff0a80ee6a6e280d0459e5c29c0fa3a79587d4a330", + "0xe65f4193189ca1da6d6fefef1c2f14bb340e56271b2bae3024dce98dea451cca", + "0x48c844ef658f2270efa4be7b85879cdaa2d7cb27f5fe9cdce0ec4389a5801707", + "0xedf37c427ac85a7c317bce25f06acf626cbe86e79f99f148667a95c03ccd34c9", + "0xbeca93d3b7e0f9d2f2a6b9b9ff7fcfff658c0d417830e46a3aa233f31908782c", + "0x61dac332da33e3533b9eecc1a287e732cfb9a666ef32de6bf2d2706792264927", + "0x622624f3810a1e24d48f54082f0df3ab3227c9cf9d39b007875a3428e2d70208", + "0xc1276025a1c848b7dbdd6f4dc1b7b2f4b19dcc7b0e312897758ca538ea334bff", + "0xefa6b7d35c2aeebf0d472745aaf6d4118279a88273b7513d5a21c3f619af8f76", + "0x2250fd4931ae5059e99572a7bfcee0117090c362075c0d90eda1ba2be2c864bb", + "0xe9b7860868856d1ba5d17cfcc78020485a36814482e1e8812555094dd4e85ff0", + "0x4df6b40297b258ae69a8858e54ea4f45d58b0ab1b0f1b35c3bcc4f96c928c58a", + "0xd17bcb3447f309b3ce0a48b651de3d979810cd9cb7edecb9b44366644e25c729", + "0x7292155c0cf9a6466c80ac2930f8305cf9458f64f40523a6b5e08d2ddc180080", + "0x536bc35368df05c3d3773b27110217c2df04d2f86e6e8a8dbf9dcd13cbbcb984", + "0x0f4dd55ebf1e1ea736108e62612972036dc533bc4e52a8480e3c875a7961ef69", + "0x902334a20d083b4634a79aae1a2b4158df3832d4c7f9105e8aeb8e38ac0be589", + "0xbbce2d76e50b1150179456ec4ce4faabcddc8700435675ebe94204325ee6f710", + "0x6cc4afc371970811c0cbeed73acc72641066edf1d81a585f28987ca1c11e8ed8", + "0x7cf1f9f26bdc8c7ca419400a03d683564bd5947068e4a01670200358d339b12b", + "0xf1e37f56a2eefc9688ebd8a95772f98b9f995e3fa9ba6601095f973cd34a13aa", + "0xfd7ee922a80adc2f6719e6e1e90add658033c7165441e399a3f61e93ed56af2b", + "0xd8ee732eedd804de6063af6b828fd6c4d9496115a367cfdd424a035646cc9e02", + "0xbf6658fb5940aabd9cf82fd9e808c9a23d04d171a62d0601d2c9dd67009f0b36", + "0xaaf7099280336cb78b87d9cc3c06694c4a66aea2a095ed614a4578fa8d61cbf9", + "0x46e23a8b56b9061bb89a42253998e7fda17289a12c63fd239a0c2866df529f3f", + "0x19b3323694c1dc611fe3722987d1a927dbf1a1ccd211b3c148798cce7b814fea", + "0xc16ac7ee79c7ac2223f79bd97a193c3bb68f609affa1596b061e9ba32a4978b2", + "0x5b929b2451c9c284c40c745bd441e1db499e336ea8a0b616e925ae780a6553bd", + "0x954a69859410a4a8309ddedda3f1af305c0baf02b1c0cffb27c0f89e629e4dac", + "0xff44052a4c53837e32b9bf4bc6080e78d3a78108a69100bcb05a85d4cf9e65e7", + "0x6199a3fdaf20c64b9587cf303682571f0de0bfcbf6ae34b4cc20485228a39043", + "0x0472d6b6c1efa88008d9931b3a1348a8892a61897e8634f2416758667da516f7", + "0x566bfd31096a3829990cc587e64e2a4477349e91b1b37ad6100be6b3de6250b9", + "0x5f51ac85ca1ebfbd382b4d60281d3746d98950aec6cd6bc1ca5ab22eff929a20", + "0xd45228a818a9f5d8325d2fe4873ddf5b0cccf4bc6ca907a08887adc19223936e", + "0x71d00ba260caf196d91b48601bb92052272067d1eddc4492f8709c3494ca253e", + "0xea6234921dde61659d45b0c36da969b7d3ed641c53cb54392e5a56da9f8df1d3", + "0x5a0dd2c3c892862da0f65bb4be26de9984c65aa2ff90526e6deaa1a3c079e7ac", + "0x18fde3435086b1d71fd5d24888c99bfcc2d4e7146ef4715192f4213ee9af70fa", + "0xbdf9a94e2cc27a784153c66df5d7f25316300d43f5a802cb7c5d6979a502c23b", + "0xb111d486bad8fddd2cd7d22e49d3ea3f4a0177af6fbebcdcff7f7f6585dc97ac", + "0x56921a22df9c98a49aa2602e551ac3e3d07f857faa228b56dd55ff3962f2646d", + "0xf8c7cc4743849e6cae415696d543445b22150afd4f4badbe9365f169a8aae3fb", + "0x8b9945119a385c746b1eae86d57e2a53453ab4183d49aea9412003a5e815ae8b", + "0x0dd84a3fbdb5a44b934a223503e9dcc73f893d35c77c3110c005398c640d011c", + "0x0960711a40b3c268874fa251c6c642c9e43ab14adf98daff1bc44949ca4a472d", + "0x4097f47259eea82fa8a531ec8c32b20b0064a0c47ecbeb1c426514498e5cb703", + "0xb17fab14bf8cc4aa51a1209711533b566b907d83f17b5ba62187681951307e74", + "0xcf522b0a5f9c427dcd8a7c6e358b7bea8d683bcb1fcee19fb3ecc05b85afe281", + "0x61eba4f90383706a2220ed3ba48020c14b3b6f1b76bedfdd3dd84cf66e7b93dc", + "0x112dffaef31440102f9660a5d73880a7df7b4cbf3c5189b9cc86c7641ac87f21", + "0x908edf9e1920e01592cc0478bc15011699771fba5a3624296521b1997e409d06", + "0x44636c1768f04f94d933c5d93679572d01e9d69f88251e67e8ccca7a50d63bb3", + "0x146add71dd815d75bd46324c8820e2c3d485567ad276f0ce1e2b63c294c989cc", + "0xc3cd14435b5cbd2657f38726908aefd18b21d9fcc82e80b7e1ab0be96a13a2a2", + "0x7d9cee568a4ecbf2d1f980d8946595bc599bf56ad6b07ffb2a83e3b479b1dd07", + "0xfafb0df45cb663db42cdbfb09f7381a49fabaf9266f1ff788dd31ce22c30bd55", + "0xd16d87925d29d26760244c938cefeb1366bf9551545342fdb7583325e08850f6", + "0xc6186d21f0f3391a8456d1b1753da24806d02cb9c3391a40c9fe84143d5ce31d", + "0x14b9cc8f7d3e37d7af07f80c72ae6528b326b146c6380ad0bbdd8fda89d225a4", + "0x5580ba4d7233e13cce87ba2e2607db7a4e87e571d5b1b1a75887f261e03d393a", + "0x07b144469f1d123ef7249ef2c445760a995c2c70f6e48e6e166d5f3508f4333b", + "0x0d883f633ceb91e413494b00e9dd563cdf121d2a2dd397baf4d29f7664633475", + "0xc619796115f48419208b0122a9b18a0bbefc05f8d96c39248973d66583ffd8dc", + "0x994e6fe6c27ba71693d04b2e02ba9c0d8679d1b10fbe733240ee5c323ac5f936", + "0x88b987ef2d0f823fcd17ed43ab28bdcdc23d23127e462ddafe56163e4be4a980", + "0x67e115f2ec5c6f6f7983b4bc2c2ecd21f639a8da639da2a594b018be2a3bfe64", + "0x8e4b8ff44b5028560b047780ce05353c94fba885e186b1b198cac5e90a6cb990", + "0x0a0fcd91048ef7e0833552ca444ed59d74fe7151190d57e5b7fddeb02f119300", + "0x9a5203fa1af89bb99c8d2228d396731ede004ae03afab9566195b89ddfa51a8e", + "0xd540a1122c44c8e728a78048884f79fbe5367873fcc73cc46a9d4b5b4848e3c9", + "0xbf8a42d56b46f6036c6382bd1e970b1d6b5f72ba54d1d5b8d0a3edaa165b7165", + "0xe0262a446e33431abd61bf3e199fca97a575c7ccb97710c2a1847188157909f6", + "0xe7f717feae9bdcd172fa4b6b701f0ca5b58671f9608b5b5a01d51a048241418d", + "0xc0ee34d09069301fa5ac3378ff176efb2b526665925eaf67965699c8fa002c8b", + "0x241837a9dea17bf12b78b30255177b3f14f1871a7b9eaf5c964d30eeb2038212", + "0x2e5204320b7ff83e16ba9727b5df0eab080dd2ea374db22a664f0045540ad936", + "0xaf4e24e4430a008265a6f113c097729ba1802e23d119ae0efef2f2a8bfe4ca0a", + "0x462b2de54860e6d8efcbfde08b381d74eb8e61cd2b311cf14300853aa2f9e88f", + "0xfba00f6c3e6262fa9f282d179b976894376e7e644c1d745302cfdd21cbc3e311", + "0xfbd6361624060852c33c3199ecf0fcbd8e56549d64786d320850ef3911dc9fdf", + "0x7be237a921be1921f90265288026ab1ff7d951e1412bc93470e09bd40a17ce97", + "0x64f51dd23a43c312e57bb2c0da1fde00b48b36eb1c9142589bb66407acde869a", + "0x721c44f4450bc4d92330caf7faf277faa1f10ee8f4614f9f903b27e8b82d8e9e", + "0x71a65acf3a07914cfa45698674a9fb1a35618e6f849aac0be337e44afa7b814c", + "0x620969bddd7756c5d3990528b1ac4dbc81becbac02843b3c4c75ee991ebbf4f5", + "0xef0f2a4fca1191d5615ac096dbae87ecd3aa1a83c46c43a3cd48395a47b2b65e", + "0x5f9bdefe969c0554757a1bf17d990451a58cd2ac60cdb521679081699ba4c2df", + "0x8ffa4537562335a6e21036f6c3af75614887e1c0e54bdd719f53c4675e4e8948", + "0x700d67449ab43081029dd61cec4b31cad71335d822df7ae4053e5040e47090ed", + "0x22a9ede76ca8f831125f7e6d1600aa373934f0cefa888e84a0481247b2c98d2c", + "0xb5b7c6c9ca26d8981191b27dee2aad72dfcd7e6d135d09c3b0b5bbc6e9d64849", + "0xa24232b8ea1e1ef8a07cce001d37d148a07ecbf0792690470c106804476e61fc", + "0x254935114b97e601fc5653001b01faa3f0fac11653926e749cb114cdb8239874", + "0xdec3d44fc5130107d8270358b91d7e0d933e74c4bec6d97cdc9b6f77a1fbe1db", + "0xe947a36694956d7d65315377c81225aee6128c7f075c2a37db61b7b917599008", + "0x4451d920ca782f22a3dba977235c49a4e3b97d8de1fdf9cc9d819dbe7237ddc7", + "0x234caa79670cfa3aa39b37887e2cce3f88ab5472bf2c2e7063b9c9b9424b20d2", + "0x79d8c448a7c637fd4f4e545968bfb5fa59a62948bc7b9031eb4c17493efb41d2", + "0x0b8cc0552966a5ffa6567c51ca7e36f5ad1bbfb5dbf5a52759314721d4e5f463", + "0x774983d323706ba773f8058519a450ae096be9001790cb5e51d00ce1ff206b46", + "0x0dab876db72ff5b208e61e18360e37b2fa6425a3eadc178fdcf654ca273374b0", + "0x20339939f9a89a1c38d6a2dc5ac9a505f2f899a158966cb18775831b045baee4", + "0xa42e2405b8a4a4da00dbe1d2e2a7244e2270f9ce16f054128b93b076af58cb08", + "0x149f8b8bcc176aed12a041b55d040b306ea7d34cc84d5eae4dee06d7a1f204a9", + "0x9b8a117cd1948845b4b98086d80c3ba055a138e471fd3ce38173e3b06b55499f", + "0x22db704c6cd8a8efb8ba974ec4d0ddcf64b1396aabd57cfc271e47ddc5c66363", + "0x25366f36babf4dcd6a41a218cfc8007521c9934f3b70a6835eb5490ce5c32937", + "0x5d21555e54954b075214c3eea858256b109667ebba80b117eaf08a11d4c9a9e7", + "0xcd876855021bdd0ccfc05ae507c711b9ef1ddd7aeebb7e2d330d1205528fc2f3", + "0x09355ca9b36a3aeac9c496af56af3719df2e1e052a878731061720e1b77ff35d", + "0x488d20b385f25d7c6519042136ed3c959a7b341d0118220407034b9527bfa040", + "0x0c516cb443e22322e176465b7c2e0359823374cd4aba574d4104a70e002c1f37", + "0x586593c505b94eba3ea1f7dd3eaa1ffab88548e150997d05b336dea37cd9a971", + "0xa1ebea5af17b8c85755ca5693fafdb4fce32c5e1f6b87127b3306138612d3ca3", + "0x7cb91701609765f3df12a2c051219622cb4a662507c6a14384553364de076dd3", + "0x3d5540773e424e0a92c40204f7c531efcba2467d27d204e0f3c6e655b44e5c87", + "0xc59531ab703c789a20fdbbdd08179893bf671c0d2041631c75d4221bb865b3c4", + "0x7df727560b0f89ef9af22de693230ea551e315918b0cf268cdc07f10690ef2e1", + "0x6d95bde1d89676d0efde7c58d71f91cecf8777e701f7f02a59b9679058e67ac8", + "0x225dae1c7d795471bb2498f380f2a144bdf457734cd3090925027375303e840e", + "0xf14008b13b4db1498bb9a902f1468367e0040cf4d21922ba288adb2a4fee0a93", + "0x36f293cff22d6d738d3cee9e22772f9e3a344a5eee2caefbba321054226c4762", + "0xca2c1e34994d1c454d4abd4b2bf939534a2ceadd6c6a3103d40de4725f77e403", + "0x4c1c6a5ec4bae84cdb0f3252b9f721da9ad348ad1ca6986ffa5e5735603cb005", + "0x0d35e0d8950362606c804221ef0b5feb04b0ad62d5d90134bf1fe119bc5a9eb9", + "0xa8bdf0d3fc34cb80cd14429fbadd0a2d73273e454d96aae4448f60c42f0150ab", + "0x11cc9d0d3064d5c7468a8c0a4146df476f254b7bd8f748fb42d899ce9964ffff", + "0x6d8752e6f51856b90d4723a34d94db4aec1f8da55f2b0d94f263ef0393dc57d9", + "0x038a4fb7f9cea5e3779a026873da89b85d03ba8c9038124eeadf88fa85696f1d", + "0x9d55a956aa38c72d7fb45f856c440b012ce8969c2990c7e1fd48357daf8ecfa2", + "0x163ded59e9ba07e781e07a5329c2921babb49be1a36bc7a54e22b3bc325840f5", + "0x0afd0e16f53b05aab3a77749fd114b353fc848d5e17dd8d701c37baf5c976298", + "0x5ca8f5796743e66d24f7dd342da174ee646c60dd8bf1e7564a814ff28b0922f7", + "0x5e856feff23db5b9892430e9e493b10e2fa2db28bf6833523f158ec1946eba82", + "0x59dec8e839a2d9ba33a5a687fcb92d8b450585864660c202d7e79bbccfe49f57", + "0x8b0a8363e98ac24707164bc767c0f6df7ba6b4ed5584f14693a06b08c3a23c4b", + "0x9214f12639d8f39488579e8265d33850dffe16aee099318da700475551da4ba4", + "0xc98baaa91e6f46d6c218fdc79aeab7d46063fc22107e457eca0559d500489d8d", + "0xeed3ee9c8c71a9035585dbc7a69f91966ff45ca33d81ff0ac69dd9ecbc05df05", + "0xa4b2f4ff38e28613f5ddbccf9f8b4cd17cf50704e398ac3b9b7be043d631ac36", + "0x7de22d2449411bc1e342ad3ee83af0aab2461dfdd7dd51b915a17fbf4350a660", + "0xb644191de416e8385167f5ce348cc3fd3020b69aa7f8e4ce4b58d796b401e3aa", + "0xfa137d84153b3ddcbbea95c810592ca1d219a825a3a9144a1f60a2f15890d959", + "0xb297211d2aa65b91fdedbdc6445e56c012e7d4e99250727f0f18471a204097d9", + "0x87c07e37c34bf4fbaaa2cabcd7c72842828fe0bd4e0af3dbda59a8b7dd8f5832", + "0x60a8ed3981341120c3e6c821f09332c6b83770357dbb1bbcb535fa771ab9ce56", + "0xe79330fb9dab7ff5ebd8511290b629e0feb97ed3907199f47b422e2b62192cbe", + "0x699c36af1b18f84f1443cb7dda84e24eeba099c59b2a3d45a9757b528a459ecf", + "0x0cf4295cec116acd9b74e3ab126b020e82dc216259a40003f493f15d1c89a9d0", + "0xf89bc33459d999b54f77f66ec80613d2b4a7d7e5ca5d58d5d2d9f9f65d9947d7", + "0x2d3a04ea977f6aecbfb671f1ece353c899c6597660a945c78be66a9c3868ede2", + "0x064e090bcd4bfe32f0b9a2756a01f2764d82b7fbc71ecd6eeab2f018ca1a0237", + "0xa3d1be5a6aea2bd18f5ce206e0f8c2ca898e4d4581d2d9ef3bc1b62b86b4d6b8", + "0x3be703b1204cb9800e53bf8b1521eae921f7f6567080f9fe385e712390d92161", + "0xee5c0b22d83a67a2a9ac8661c79d8212252dcf7d4062420cb57878ab8b9dbc66", + "0xbb9813100f3153ff7472f61f97fbaf603f228eb6cd715031018b913c70070d52", + "0xe416f16bb22dba18d653ef75e374b73722723a9f426696ee7477598e1aad6458", + "0xe2d51294dba9887f33cb3009ce096a4e9d086b3bdb114fff71f3438bbd784a0a", + "0xfb6aabfa3219f4401ac3ee4bf697052aec4cba80f755208b42fffbb1b0b3b1e4", + "0xf4d28c88355ed07f3c2007b9e8b7f4e6b1ccd988ba2b32fec0733d57a178d123", + "0x824ff2ab95f74ef02726a483f38342338c16d895a1da8cee5177ee1e4719e465", + "0x8aeec0b4a40bee3ae28552df14d4b6855ffacfc3d01ccde285e66228abc0771a", + "0x5573c773bb5bb5c5236109ef3eda585d2da1c5c38eac46b908fe283c4d519145", + "0xb82014148f595f5e440b729035cbdc2490db0523b7d00f9f0fbd4c383090fd4c", + "0x3bd847f5f5514f396e663821c8865296e3d3f7e817da4e93ba1c9b98b1758812", + "0xe5bd2846840a2049c0f78fddcb4892639156ece271097b56a74fd338f3862066", + "0x916ea84d9ed21144b3f9d73b03d02fbec444449c3a1f982c30bb20c0f75e64f5", + "0x2c7c705d9ec24d6cfbfb7f2bbbc46aee8e3c81a41becf39a23ac19df32dc19a5", + "0xfb9693cb2fab44966e6a0ec4c118a68354de660ae0bbbbe4da349df91e231fdb", + "0x64503206586c60381d9cb74e5f548e417ae80767d48e15c61d2f08f50548b7dd", + "0xc7bcdb552852328cc3d511538e3a0c94dfe1b77d489f3a44cbfab30b3b781036", + "0x4d68f37bbe1a45eaa3e72e3543d23063a4eaa1d38ae56909fe11b309230c8632", + "0xc21a5df0d75ec8d06498535c40ee76a330eb90add0cb99b9f0f4671f504ab1a0", + "0x5558d71b23fd39caf7021402520090f13b50cba5edd669ecf7eac05196e03531", + "0x2164e1ba3b7d927af0ba644481273ccebc5646e2c49825d456a1e75fc7c80db8", + "0xf10702b40b03ef7ae672004cd1747705636f7432a7493021aa8c900397b0123c", + "0xdef29e2febf8fd4a3313106832f3f723469f352f614f20e7d0e6c2e298240060", + "0xe62566d6d85c3ca3d33b8daf61b518abe76b28ec26b91a0b747ec3affab41285", + "0x1c286207dfee4b99fc86818c7614804782c8921d8d8f8815cd2f190f42b992a8", + "0x3670362acbc89076aa41149033484fa2cdaae47c8c10461f6e886040cbabd1df", + "0x8a74d7452f3a76bd20e2d1686243b90243d3d0b40b5b98fd313ff33c8d932e70", + "0x13f1f59beccce0f8d8066742249156a5dc0f21918588b6b145ab40d3eb4bb822", + "0xacdff4a0adff4cfd4756dac55df04e23cc1b9a6447d11d9bd86361fcfb6534cf", + "0x54fa4bbcab952b44cd3cb6042d6ef87fd9131f1850b8de0a44f221ca20a490cc", + "0xa06748708ef2e6c391d0d11c6c8043d91f9f1abe8292d55d70d616ebc5a94ed6", + "0x64dd68699969109d334ab59d64d8d22e114382bf2ebec5fc7ec66875a795276e", + "0x6e66b02d463c76d3a217202c527f798a4c472b37b234bbe0d3d8e6c16a34719d", + "0x3773853e93233b5c39d7bd53b89b769aff1504d9ef433c46b3caca15637ffe93", + "0x817633f3cc0665d68f497362bba1d32d3512016b2490047a245175654cc3d851", + "0x41e14c9198fd548c4b70963eeb24679cd7138dc061988cdd452f2de7cb85c14b", + "0x9ef5c3f4acda962833a68cf1298198b68ad38cd3ef9f8dde0add0dce93e4925f", + "0x7336e43b284042dabf2326e15f9717399fe3d3aee9586118a6047024ce3fbaac", + "0xfd037d85e4f6d39887ea64406302acaedb64a72c1ebb122519c2fbd236d789ca", + "0xa28129819bdab4818cd82aa1bfb0d31d642f66b6f072a079bfc414cfa6d7385f", + "0x02b7d36f55c39b97e2a882d47bb150dc74bab3e3d3c44a13d0149bd87f653f82", + "0xdc6609b3e7e5acd44d8bdd69913d864061c4c5b5d34a24a25c04affed384e687", + "0x0c5adc52eb0e98c0945a821a270e00c1b8424fc88eab4e4e53d8b047c2990509", + "0xb47060a6278b3da926c799a4c01e9682b2c38b9a255427499c03ee9305156939", + "0x8cdfbe9548608021b7fbf4a9845bdc03d2187885a25972f434af7706d8e9743a", + "0xf29db31d7986d96f18766658ae38aaf4210b22bfb14ddd1ee7c8e6a534292fcf", + "0x2be2578382bf5a26aced019adf5e1be8eaada7226996ad0968b41e0211950064", + "0x0fdcf225eb3c840d6a9dab17976b86c02a3a2ad6c457d8ae90a90120cb71239a", + "0x04412b8786da3f17b29aefcd1de44359ca334d551e4b84ab93ef562c16c34bfe", + "0x0be08908e549fb47570db3f9850a43dc3bea22fb569e7e56763029c2612f28dc", + "0x43312d35db155b984f27756d5f74c5028a9d182c346287b6d22318d6d09fa287", + "0xd99d026f8d05e8301728fe546ac68d0b7161d4c5f39d321d81c2d84af8dd9479", + "0x2aa222445dc7ce013979a51aeccbb0331d0b9618bd44d6eeb41978402d787a4e", + "0x7106550433791e214c8d1bc44a6bb74c13cb04ef44d888e4e86618a7699a6c0d", + "0x4cafa83063379aa62aec4ab93ea53b6ee3340b567bd8bea89b1f576ab2b32def", + "0xaa19fc5e04747c49682a08a04e26588ff2097586546c7e6307ebae3faff31ccc", + "0xc95bd63ec24007b5bfb3f3b62b358e32b7c4b562a3904d858b30131ae5146df5", + "0x33aca1207ba456f03f62dc351c975ee927b48d2c9ba394a56e955ab1b2cda20d", + "0xa3d6317111e98d624e5a68256f142ad3c99c3d2fe997650fd65d584579f9d6dc", + "0xfa3d58b3b49da8411398ed8b288f70757be569475c02f9ba23a4d913679b8ae1", + "0xeb470c4d3513dc24664d00944e9fc6da9fbdaacad66900accf0467ecff11d6e4", + "0x9a339d9d68706dbb4300222a5ac8b5823ac55af237273e0aad0999aeab8c72b4", + "0x0b67fe0a96dd8688b8fa98ce128e025402173dc49e0de904c390ddb828f059ee", + "0x634ac8f82795f1cd08f8cafdf00f869100f84350157e12d5a87de7d013a856cd", + "0x1530833bee82f5fa0aa8dab062da230024ed503e352de3956831a92cdbe36199", + "0x69b26efea6cca6ac3ae1bba540db8fb9288e421163bcc50172669053e7751584", + "0x8a4fa2c094135582d17b7733f74e7fe4dbdd0ccd0e5671696739639b64752c5a", + "0xfbff6abda57f9b1689cb7ea8809555db3efd4b21b0b2b1351199654d044fcca4", + "0x16425718846535b46733b84761e16648fa7eabae0e5995108a2fc6c3f324ddf4", + "0xc72eb88c5161469517e7980f86ed414b4e5e54dcfa734e2255908100795078ee", + "0x91e0e6cf1fabea993097496cf7ccfb023e798363bdf8a85bb5e73866f1442ab4", + "0x2530aacd1b1238514aba9ac1d13de20aad119ac4994984bfa04518a31051b973", + "0x481970f2e7e34a0064d136e87cd59fbf6131341027ab27458b9803aeb7e79983", + "0x99beb276484210f5b55e2b3662304a73c86a46633f3ff5aedb133217b7b593b7", + "0x0541564d394f368aa15e88097bb26d951d099e103b5866a3186455f422af1b8f", + "0xdab00c8928bddd0b3773af6dda612de649c18e4029c54eaf8467f82b153af878", + "0x343a7e702237917aa5d06778a592d1f279eac470beb8f340ab338c41a31826e6", + "0xce9fb58528596c0da68cfcd52d4556c41d7d6e8b858d665bfd110bb95a76b3cf", + "0xd40e49ffc0eec56394bb73f469b0aa1e1667eb4f912f5c3e82cf395545af07b5", + "0xcccf0af25ebe7d4e84acedcc9a88e885a4b99ab77b9881c524bf0e7aab724192", + "0x0ff189bfed3b2f56a3448bc08ac2dc6eb1d64125c95971ea0ce0fd5b7ea74416", + "0x60d25468039d7e8a89117eb468b4f561ea072554520d7010047680c1ddf5e70c", + "0xcd7a3c31ab25c421547b379a508fa0cf6d86cb9ce96377a5174ddcc315fee2ee", + "0xf681f339b4698b7f5016e9c7cb9a516d230a3f769b0da08096372bc87664ce5b", + "0x93dfe64853f84944856a2b79789ac7c73d18826e9a4fa6d970dbef77d000f7c3", + "0xc599ae73c9dee91ddef71fe0303080403753e3610ab73f242f3f8fe49b598b4c", + "0xf87d38124c8014802c3f523d56eb08ddffe645ed5d84ec1f11d025a88c594cdb", + "0x556e5962355580a0c44e5d80b28abcbf5a55feb5c81bd7b7a74c4aa664a7bf6b", + "0xdbb37e17df80f67cb8958590469d6d8a602b11b4dd28c8bdf8cbe873a386e644", + "0xb4932582d58d113231ead5a2d31eb8ccc0aca98a8dbdd9a450bf66fb4d65e18c", + "0x91ef1100276650f3dcdf96395859c123ee6fcb4686eecbb97bbbd6ed6ec6a656", + "0xfd5d42dfcb6c00aed36fb6f5a38aea10198758e59fdc4ca80b6baef694793fd6", + "0xb9d56c16bc71828af33e2a58b504ad96c96ea445c4fa56ba3703d6c8a971d9b0", + "0xa6ea2c5703efc858f9ec4a96062d32cfa23feb7d7bce6c25a12535c23b395809", + "0x72c1fc542e61af3181e988774989c782875d3b978df6e837b3a601839225dbdd", + "0xf332d4922e029f84d9aa2f49f910191df88f7f1d96d59ffe03d8956b0a5d54ff", + "0xe45ca95879c07250f3a317bb34d7f5bd0188fc947bbeb04262afd9c78039e197", + "0xc8c33079ba577066cb8e5af8c0682ff5575aa64cb30e400e5ed73fc749933d9f", + "0xc3e6fa3de28bee05a531d588d4895e63452eca2a188385727d466b87462c54c0", + "0x6740e11063142bf755d0bef9c254673af1f72807c3be4c531212efff63636f6e", + "0xce52344424c05c60bc7130b05febd30f611a081fd287757442687ef4adda6948", + "0x99491636ce876cd89f40d38ead2ba1579a050c16400052d516dad0a89b092069", + "0xbf6cd1f7f026023683c23d9f0d891e765823885b211420b9a6b33947138776c9", + "0x7b478202b808e4a54037acc93daa1136c6fb27d89b9f897b9fd3fe9afba73ee8", + "0x2cb32599960b97177a94c84ad7a047967eb2e212415afb7f1626a75a75cf1b46", + "0x62ef86c77b59fc2261a10ff39d74aceb1b7f7051758e5372081bbd911f56ccb6", + "0xcdd56a98c6b30e17a3239158ff7d91a415a28e7bb7e9528cc9996c8db8745667", + "0x8e432c62c747d730b197d6462d9369e5e9c3fadb7f36702c4c76803c5dccaee3", + "0x9eca51d69547f45fac4b49f0c6f126e9b5c67259880d28112dab89ab8264ed9f", + "0xdfcf59e4a92c389ed131b40b048abcd0725aab626f4fdd3575a37b4a3a206549", + "0x5152046f56a54c8f926ed10300d516f30a4a624aa7fbb888e465ba7359c4f3cf", + "0x54135b5e02b568eeeae74e59f1796650424233966758fcd1d007a727145509bd", + "0x9253844423f0fb792a2248fb887ffd10be43114b810b2635486ca0f6d43bdbf5", + "0xf3394a79eb65ff0184fad992adf3d0a86b5e6df85b629abed224a85460261db3", + "0xa4a1b651f300133e86986fd3a881e6577c6fcac410bc58c63f4b031e2ee2bdbd", + "0x5e074eec6c53dc49c55b50c584b0855e8c5a3c64dc72e73e5cdc1b086d07596f", + "0xf110a1c5c23d3bb9ac48d2bb03972e11e04b52da5eb62db65a4f4a2ac8d2c068", + "0xad11be682bcc25d30ac1eb6ad15990499d488c402ac6ef78085ef8faa5d4a248", + "0x0e13e09b2e3b8de9e5fc9e93382f06b64f03f98c3e26a5b3af811d32136ed0d5", + "0x494944f0a5afa4efbd967941129275dd6046535ad489443db1a384798cd7a02b", + "0x38474b45706c7cc93dd2ce11c41ac7f12f494c38f3a00c9cd38e44bc8771e04d", + "0x9a986ee21db81a38be8d1ed319f2d2558eb22de3899942fdb6395a188320de30", + "0x13ba368a9882ee28efcdfe67f4bfbb263fc8bc1c07b6f1369d3bd5ffdcbb3a01", + "0x451ff9f8e52bedb6a0f47ca9093b83b7d9a61e94329403d8eb913868945e0b6e", + "0xa04bf418215767d2aa8e6a8c6bf6563c80fd6f439d8d8759d2a43d8f4fa69630", + "0x551df5f968cdd4d0b78c1927b20383ddb6183a62f80480983d23f734be98c265", + "0x0df43d41084f9aaead6b9d77cc8f7760772ea1d27bc574bcde7061985e2891eb", + "0xcd8fb777f3d81581c5ad765b4f6d7f9c8d45c92466c65fdfb02637f226aca9f8", + "0xe4a92928a67ce00b8569eebd95c446ab82ba5beefdf467ffb0ac1bb08f4f471e", + "0x3ae0b6e5ed51401ac85ed96a84326cc1e894fb89a24269c9f3cd25ca157cc698", + "0x8363e4315a1a914a3d98eaadc9d985324073cc04e55b5859264c997d6d22834a", + "0x1e77238479593a1ab25b61990f3876869d2d87c9817e061dd82eb43e6404e0e9", + "0xbf35e78bd78e97326d6cc6c87f9f9c89362234327d06a65344cc9e692cd0d739", + "0xdbfa8ae2f7df4c5c0391e50c5cf9e144b45763a13ee250033d133c08b33f8029", + "0x828df5dd874a8e47e198ef4751dfec528c34348378574baeb2cb3b85f2376dfa", + "0x60deecf89aa73bf16f800255387ce9b9b74e02820b335cd96eef4b41939461c8", + "0x4e6a6312ff2847e8e419be96cbaf266ffa7aa91139d9d59da4b29c7e28aa813f", + "0x6c0d32f28bd65f020ac3c803fbed871422d6c6f02cab380056721825cb05cc22", + "0x7639acfede0e940dcea1965352cacf2b08f8ba0cd4254608a1033e2c80b1f12b", + "0x235155d27105a7f73b46d0c4a91c5a4978eda6d69db1af58d13b89076ebb98d8", + "0xcd1cb877b7b138f598658a39d1e135ae211a2169b2afefcd80923f244630233c", + "0xe9744fc928cf00f5ce170b81d28f5bc8f324d37fa535f2cbc2a23d82406d0423", + "0xe376bdbf2b052cc9d5f00f36b0af4d360174ae54b52620439c25d3430f405cb5", + "0x5a00ca653123aa856545902da24e3066386d1df00be733f95a4d105bb722b085", + "0x8e7995454fa8c9e7da6f19d9860cd0ddcaf1232033d43325b211c39023ca4d7b", + "0x8047e3cf7584e57729cc92c406f2c9caf41d9f5b3fc3a1f14e9357c954972474", + "0x7de15b023b1f923008d08ef6312fe8c3db5f499a26fcb3594795f47a30d28c85", + "0x7924df166e716bd934f98797b4a7f344693bacef336bad132ce068c6b70e5ab8", + "0x9ba0b15b18f2735800255de7b9e52fa971f2ec7bdc7de455c2e989abd27d35c3", + "0x9a5707a0ee4ff0d88fd8f9b5382ffddc558dc6c21ed9c8daad043a4ff4a561e1", + "0x898ea840f2e1e07c23fb9e18045e8addf5291661a72d6517b029620b52b0eea2", + "0x8f5ff6dfcc7c8ea2022c7b5d8ebcdbf713d303f164230a74192ca06fcd2ef20b", + "0x1508febeb95c2d3ffc8f1d13787bb9883be3529f8d71accdd55e747211fa8c08", + "0x2c7e4797847fe62a55f64c64977462cb792d9ec899e16f1a46851aa670d09eb3", + "0x825588a04dc941ba395deb99c00c282373e042a064cfc1ff557f54d8e0479187", + "0xef56430f5950a91b9a2028a549d4aedefd7322e36793d3cfaad18f97b58e9e3a", + "0xb92537e03ab350a4fd855bbe5175e8ff0e0df0fa8588885fdfd33bd2e37650b8", + "0x57b54ecd05c5582b98b62caadaef9e3386962a15c302caadde0f3ab2de98ab8b", + "0xa3f9ebe4db242dbfe248bdf7f504fe1f92079c60babdfad99a1a1adf446b3750", + "0x0939ffdb6c07b240cc1448f7276d7c8b436051e9488942d4b1a5afe5a0103aa6", + "0x778210367f625571f9d075ba06aa1ef5a8b59a411ec25b4e9540e7dede11e013", + "0x12087182676e11950138448ec4258ba3bd6ae31662f13db6cbc46c52a266dec9", + "0x7dd65f0f816152a53d8221e5554f4d3dd293219b0537a600caa6c5b758deb4cf", + "0x060370c4afa823b9cac3b2a87af1a989f8478169da3e12ad4073731a6729112c", + "0xe57c5b36d7372b192549e2ed987cc16beb412db8e22c3acdaf1f1c95ce1af81b", + "0xa9946d302b6f3dc7ccae4e4a69c21c862da4dcb9df371a8b6486534d8d3c6e76", + "0x350669a215b44b8cabfb6019d89f5268b299d6fd9db56fbea93cdd9f4991a977", + "0x4bbfa211e42c2b92c1cc979f6303e2eb428292500c6b59f0ddeb87c3fdb4b314", + "0xd243e1fe99ff82487def980022b204794fe4eb5b8fd657b851f7f5f323eb81f6", + "0x0eba7b7031613d9c2cce87ae3a9ff6e7b57b8e537913657c5c97f80a65f774c8", + "0xa5ad33c7f0755f82a0d6f47ed774bd8f2a00a66f2a967a52372dcee62f52c099", + "0x36d42846ce8b3021f00a615c0423d1bb1f00ed05df1748249a79c8a515a5cff7", + "0x7808d7655fb173387cc5601c469a26402b631c1d3e490b1c1d25e2e2e4dc3807", + "0x533b133383362a66e34e9e261442d4b867ea762b4422d2ebae579c144621ce20", + "0x46e2dffa796139a441b4b2a2ecc9530924ba032bee783cfae1ea1623508d55a7", + "0x0acaaa36ef65ec28c8a5447a2d594e48e4382737fac248b7895d3521cf2730b7", + "0xf191dcf174b7a1b026a9e2ad51a49a684abbd84556988b8cef315c3c5804f032", + "0x940284119cf5d5667d45103ef0cc790cb6540926c0f645911c669ccb78f6f127", + "0xc8be6193a1a094924999b527d81561f1ab47966c6fee7699418aeff2e16dd27f", + "0x3aa137a876b08b74d0e507ec47e72ae5d2049e01a83c68b90860ed7e9b594f4c", + "0xe375dba7c6b94fef6314cf569f887010165f40f930156e15c2897ac50db96e4a", + "0x82c766f09a89d2d8644603c21005c342208e2a61922eb13b476dcfa9de9ebc4f", + "0x06bb8f251decb2ec72365235d98bb9c0e0d0a18f7ef7b069f70eb432455ebb7c", + "0xdc4d5d8aa9f4a4e224510a32df3ac984428b8bbf38a9638fad1c74a22cb32c0f", + "0xfa394e11c7ea81618a3735ff52c67d182a013caa52897b10e1057de7a95b6f92", + "0xbe3dfee256c7cea8b110e9915e167d56479f5593cc5a8bd7e6375539c9ca8984", + "0x3caf7941bd973212ba085982ea0707889aea831d3df45468060a1f8afff8da93", + "0x17ac6c1fa00755480ab3fdd4d5969e8477d55ecac99ad1b1dc123e677560062b", + "0xdaa4e5841582d605767a49d59dcdde3067a61681f40e55e19adf73fcabdc65a6", + "0x465b0a0f2c6dc1583d1517a303947d372af513284cf2fbbda30831032c45674b", + "0x450b14d7773bb9ce708f8dc12aa7b8a9a83161eb8086d6fbe91fdf940f24cea3", + "0x0893e90abc7481e9413d33560ee9087d5e39305c0ee7fd8168d09da19c9a9e26", + "0x3b3e3615b3cb2402f807b1f7568174a6972421f3c6fada50c489428ac6d3a3e0", + "0x8ca9eb6c550474b93362bc8eaf6cfd7f39808dc115242310ff4ff6e5acfc121a", + "0xc55d95d03f1359410a23debadc8691ea0b53f4cc50073b449546c4422b16c037", + "0x26adc021bed5d143a3933824ecea25e0b6c577d8cdb9b899a86fbf706338dbd5", + "0x81b350f0026673f871a8981d899a31e2892730fb58e4b0273351b256e74151df", + "0x8a97e6e927342a4b9ebfeda5f5eede61ddd23b8b4421a0d2a8baedfaca168cfc", + "0x96ac659b574a4e63a8874a91fbf045f90f460b6c5b1222d72d8ddc240c870907", + "0x77c0baada7e37994e9f91075fc8ec335ce0a5d4f1627ceeb0a79034bed0b0f41", + "0x3b626e112b641b7ac01efabb2faa0b0a9166be0f156becd1254f0365d6f08a12", + "0xa15072f15329fb0c090eb5f1f91299421abd81efb05a00efd1361fa10228d584", + "0xb44bd4b0648b95e0d427cc5173d605fe21b00a5ee2c26d44d7c9a4f49e0fb521", + "0x0794d131e1ad17eb35301fab7566269e99b48b2e4cddc5b75f0aa15996220f03", + "0x994a7c6159433a62ebae86bb4212983478372b94fb3712bf025fbe3c5169038f", + "0x154a2ac1a23bf367f6873a7b51014d4377dc1008767510440a490365c4c1fedc", + "0x5881a0306e88c24bff0354b5df839f86178d2ba5e54d3cb80889df8e72952c38", + "0x770ae9a90625a5424e470f484f2c97b4f191eed61e15813dd59cafcc5bd0f127", + "0x6eb956fc5c743e7a2e02d694cb9c643e5ef97f960e90b75989aa91d3da1edc5b", + "0x3100b5a08d157428c6c10271486d050f913f436fc99e6fcc9b8eb1be9dfc39fe", + "0x507a78e12cf89269bc156b2fe5d991cffcd6ca6d7d085aadf8fdbb44d7689b16", + "0x0d2d43bfc425c8686487ca97d7ae5888535f5bf4d5e4feff6769ac36e1ee0946", + "0xfe866c43ed650b6fb1d3719df09ccb5126c36add42428bb8048a6841a88b4520", + "0x73ee2d004147c22f7beb21ec84293d6cd5974289a6f4eaba670da364df657a9b", + "0xe20395be53c10d9885bb2c7cfd78927051903ff4ad8301cb6f4e54c471b79308", + "0xc039903cfa0af94172d211f2e5c2c653d7d31905a1c194aea0a4be85c2dae075", + "0x468490362f1a7781b4e08d05bc1417107daf8dbeb092f1ab1a9e2d8e604741cc", + "0x186a3a6e4e1ce30ec18c1d72ecc4fac270a7d1ba9cdca0b7937794913f25c603", + "0x2fad6bab068378729dc7edeaa8ed516b6274396f21d24382d889f1146deedf70", + "0x257f8eb447ab096ce41e774fc4874335e77f750cc0d6bf4bf3e6b9d699de203d", + "0x4ace53b3bf327fd95451be5144dd2d62d906a25234959e33410bfd28e615bf11", + "0x0dbe710b12cd27f1196c9d7f1c5a981194ffae507b36b287cb758c32e264cc17", + "0x2c6def5c3a93b3c718839efe26835b0096efea132f6870ece1c33a7e91a2ba8a", + "0x2781ca465483c0079336532daf646104b9260c29cba0b6f4399feb557760825f", + "0xfcdecd6aa3e2c1b4d9f1991894cfe5d75f198dd445cf61ccce1c32fa8ec19e98", + "0x951185273ba63162c2d920f5acc888a7e4c1c6e755ab1215d8df5089276caf43", + "0x3e092b4e7488ba0172ed20dd9189f06d19a74269231edb0a592979eaf7c0ab88", + "0xd03afe649dcaae2de18474e82cd88935f50091394511a1f334e7590249d2583b", + "0x20c54aac1af04178d8c6ad55dced6e5cd2b83963f53ca65cdcf503708206285f", + "0xd8102d6cb1ab6c9f5f13a38ad0c375587877b22a6836a882f128804d5577b527", + "0x323445a4e659b00a2abd18bbddfa87dbd824877eab5693930c63a4704f0072f8", + "0x21caf56fdbf708f486b7756928bb74f117cad771a850dabc2a69291faf2e8d6c", + "0x4227752d2a7118b37d2089ed9319095d388c9048c0082f337d62d5275abb1145", + "0x78b96472d555ffb616105b2b471e2893ad6e1f8b735c4596be9d74f028932693", + "0xb11adf3fa7f2922095d6811564831e7371f87f4d417c730927949cc6b5227bda", + "0xebc5565e3b1338fd34f4427bb60075f6461dc072b097ea9a95237a411cd8fc8f", + "0xf4becc05db259bcf2790f79cc1fd1c88396db483c2c85c127818374be47da818", + "0x8178c8a0e6eebe2be426cd30266ef6574973d200e84339196bf6401dff1fe746", + "0x3d5a6f60d5351d577ffd38306e3a12606a1a3aea9023f2b8b8bd2452847d6b9b", + "0xa80644fc78939a7e41d390c6156ddc0d2b96f80265e5ef333c49e167dc585ef9", + "0x3e141f89a256b3b45cae79ac0c604dd9a19c09af6f685157872b42031bd62e1b", + "0x01a6910b5403b23b6e0102f4e012e0a0c06dedb944d36ad4c4e2eba8cb3be4ba", + "0xea5bed79158402d5f0c295f363a211b26d9ddf4d4d04e95564cffcfadbcce518", + "0x3a9d2d41ee14a76564ccf9a56d7c6d1ce732475ffa64499706b50e8ecd0e2050", + "0x8be57936b28e208f26fd382bc1404ea474001287a2c4d21e5213bd9327253ce2", + "0x672af36bc6de92544997f7cde2ea8870ae0f09b4cb2c22e8fd2f64bd88911f60", + "0x0d8d34a4ca78aea4627d1439402d4f0c64f130043e45bd6db1a0511dd16328f1", + "0x376539fe4c0de33e48d4c308800fbcd3606b82482ef9addbf5bf9092d6a55f92", + "0x93a25650ba0615e36facc75fa2ec8e86d6135022a31d86722307432871d6b72a", + "0xe95b8505b1ab584e83efd0bfb62a0d3c45785ac2ab74ff5e58178b2e742aa6d7", + "0x6fb4db8b3eb5b55916e2b06536b179ffec93b7300e3be36234e4ebb915a840bc", + "0x5d7545abcd38bffaf08f6745872e0dec47b0867df5102f42d83fce722dfe4406", + "0xb6eb5b0ef418cd1158ce9588e003e944d8afbd704eaab53d2643defa365115c3", + "0xfcf5ae4e3d7e2ba5e29653d5b732a1d86f18e2aa79ea2354958ab5dda5c57f4b", + "0x95aaf721f3c015305eaa78a8879d2f33b9270deee9d03acce855f0f44480dad0", + "0x054b3629ed6ab0be7ad07d3c658acc3ecfba8e9ab68492838b35690556dd722c", + "0xd87e3fd945b27bc037299325752c775a76f1c3b5b7c825fb9b6e2f6dd3680975", + "0x827fb42c7548a9f034a835a54ccc598398d2a8281677638197bd8d2bba4fdd31", + "0x7db908e4263cf7cdb822e42acf0fc9aa94999a1ddc327b6535e0a33c5237d1e5", + "0xa022198a7f3027a864615df968dd6c77d03878e12b9f6adeee611deffc82f33c", + "0x19269380075fff6af87dd26b7824ea70398e3802ea3c6fb2b4c2ee630562dc75", + "0xa13f3c9a337d9aaf86b0a5e5d5bda796d2f1d99c7548278d0b752e304392c3c3", + "0x13067c9ed1f15b7365541cf00ee6d7790aa0cf24ef3c60b10f16d0b5d0d67266", + "0x8d17d62ac8abfbe2b9696f918d92912199177e94ec49628baba2ff3897ce8323", + "0xbf65bee541ac0ed5f7529637a156446214c77018c5c59f0774b410bc9d2812c3", + "0xb3980e23fd6ad0683e19db55b7a8837a14c5c809f52de2950788ddc7f6d2187c", + "0x2e633f27e48af14dbd484a42b002517456028a2323c49916d777ec5d00accd2a", + "0xa44bfae290d8ac9e0ade331b4c362f5008152a38199996bc71d17e41d4a90069", + "0x8cfa7989fe18f803b1fcd926ed6e835286acbcd4dda22ffefb24cd3fdacf2389", + "0xf5b997a3440078a7c1322b70bae558cffc1234bf459cd295d5cd3d9be135242f", + "0x2fb715d33fe3c624ed35cb931c0a5b38475c1b97b743c15d5f0835d4836c1e02", + "0x9d1f7e02c66eeb6a75899233c02467624b46b7720a0a38b9af62a363480bf8dd", + "0x0c0a8f695812e88e92db4304d43c7a12c4958350b4df66813235dd0a69fdc643", + "0xca7e816b73d005cf04f08dcb5fcba1657fb6d339a2435fd74670155d097d6fda", + "0x4160cfa822311731d67d0f23948b99abd2fab077dde4efabc3a9625686a5aa73", + "0xdf9702f40c2564b7d460c35d25642b58179e12e859f935f7b87d41bcdddb517f", + "0xd24e79820676effc95265384449ee4bd8edfc7b747f2285b99518a2658470c5f", + "0xc79e6494fb1d7f01a4e8c36b221956e16097e92da140c3d3ccf336d5d99252e4", + "0xff84f37720a37852a94d31e3552d7605e403ca42c74830cd2856055448bd60f6", + "0xef0c3c8ca70dd9227d2cac50c3c6dbc272124b74eade2f26e6d20e21de527f92", + "0x82a1e299f56312e65bb42a054c044d58914109a9e914792ae888fcd94e30897c", + "0x948894d3791476e20b63650460960af12d2a33a4d9b23b6509ebe216e77e1cc3", + "0xd7dc6732db63ff742830bd429766ae73ee21ff37fd3831f5ca0e39c3cc16e284", + "0x594af612776eaa16e4f10c2416d5912f025df7c1284653ba844bbb3985e53b1d", + "0x348ee29dea90b5e6cd96abe5aac2537734efc4f5564e854dfd8153408f6222d4", + "0x9eab3769bdda9b57cf3b2a8d07a6dc2e07c856a15a79faa7890582b43f26e6ac", + "0xb97f381205bb10d19ffa24dd62f64b8687422c1a2967ca3b1b1bd59e30f5b5b3", + "0xf2bad3504422193b7f8dec65b2edb5bae77a3ec12a6403be0cf98e6372c59886", + "0x36a4a3f86f14ddf99c0822988616018d1d569a55f3e51cceab26d2a5ed6d1f3e", + "0x2976ced02e0fd21ee9992f847e912e4cb480d676347c721a1d8cf088242d2208", + "0xc6fe83273f10de94767eb3d67bd5e7ded408d674248cd87ed64e1e8384f15998", + "0xbdbe5d93b2812f44914fcb97b0fcc61a6cce96b9bc811e3cfdd6c9ac05619faf", + "0x415e343e7ae318153d4a9930f9779aefdfed85eb31a5f63810836beee854a370", + "0x33767db7f68c7432d03ccc405554fcb662044f6e43a5e073a8dd473f012bba66", + "0x32a7cf4985194e23827f89e1589da83b9158e98219b173f7295fd0c25310fc79", + "0xa304a15516c340a220b119243565f8a75bf6edf678029e0344ed6c1a49fa96c2", + "0x88c0c9b589f7c89d38f3f83a18dc38d9a3bcd752c214805c0876ddf2a3b45b86", + "0x216643d8038ec1cb6809b8ac77cf909dd160cf433da853e0572705e00aa210f9", + "0x4e5bfb91e5929da7d07e2e4ec30ca006cfc8399439cbab8c0a612e1f951fe35e", + "0xb20afc9312798f01965cfd83deb2a254f477636a565eb0578d8b6a86abf16fe4", + "0x83ad6dabfd5de39138c7dbac41b9548ec3fd601487ef3215fd520b4d8fd505f0", + "0xe96fe232f32f9f4a45842d502ca714f933412210eda69d28eb11bfefe1f60786", + "0x838711b43402e0c6ffa32b6c96ff20d47d8e00cfa39cab1526e7a6a6ab48a239", + "0x1d29b1af9a80c63e675ce5e957a98f31c57975fd6ff48adc3f62192393881c9c", + "0xece5ad70b3b260c8c7247d1e29c95a6347ade7034c26e9a470c0469bc9a91900", + "0x2cac591b892b14911202dc80a32e50c1c80a82a6f78a8a704bbc3e0c4f726cf1", + "0x1999c48903a3a6ab132189d27889c19c29eb04e65aa7d9a8c35722dabbc66cde", + "0xd03f863788d323b508d695a6ac3fcbaf93b44401efaebd5b7942c635c10a7eb8", + "0x57e92bc43ab1a66e45c054e6b46240838422dcaed9701d65e3fe41035b7479ce", + "0x848a6f66c7f5c3c25ae9f0783891c5f004600f274967870a4e9aeb91c34f11cb", + "0x193448bef47c66cfdf060191e4bc58820a3e1c9424a8c9933a1315bbc874d4c6", + "0xb9821736ea8e93609f701ebd178f00e87d4c7931deb9287a76ee40424eb377fd", + "0x88b01f8ec4bed91861870404d1191cd0144e0615943c609e006aa7570462ca0b", + "0x4014996b1a6ec5e1bc625a304ff1bcbd310b7094065dc6a75cb4070f44fd343f", + "0x1b1db3c8dfd7843c993cc50b4dea25179310ba77d1ce0459bad775bad54c7cf8", + "0x7ac6bef10622a0863b979573f8b9b34b9008980a6752027838ba7a50e68b077b", + "0xcaf393ba83566504254674bb9e8cabec2b1c366f4e7a867b8da663fd0dee1a01", + "0x05769a695b0b171e849df667fd873d1de4d1b0fcf67588986569e631417df8ae", + "0x13c76a5de115bd5bf30c939e21504d27e10d7e0ac5ea1ba4e71cec387b469e1f", + "0xfa24eacdcb99a7d18c49e095649ca414b3477d4188a3129120847dd513083030", + "0x907c3b7af8b74131260997f69c41850437dd00ba24b660371f23a1706835336b", + "0x4e812bb9a20644e2c48296e39688409d3499bb2a250abfaf8b0cf56ad0125aab", + "0x3238205f0b9d4062ae1ad8a5191d65f2f50bb3c0b7e1351fb8b66fab97a314d4", + "0x9130f27aba4aae0e7d48375a67f25fff231998d7b7815f24a2a8e86fff39ed6f", + "0xcf32280598cd5a0579a5f250b8e418567d31f3334fe8245c0a874d508eac745f", + "0x150f4bcda2e49b6d09a975335d33dc480db17ac59a508f28f6f05dd1d3caa22e", + "0x379b96da6a733c88a0888fd3a270c889f5e2c0728272e3ed1d654c7fe582d9f2", + "0x8df473f7e356f0dabe0d6f917728732a3f9e0519cb8e399ade5dd98762d0c1fc", + "0xf8b8368aa697e7748404e589f2f2f4d2808e7cb35086dce48437702afb8b882b", + "0x2b3560074c07e7955151dfc09b1293fd759d286b65dcdcf7b2c9f3dbff404816", + "0xa6361ee7b8af32325cb36304f400c9c685767c96d0b5181e7503ddc8a36eafb2", + "0x51405ec92bb2c7fb57f95c555150afb6351035e7553a63d26fb87e1827a6c3b7", + "0xa0290cadd15d77123903184806de7f04723cbe2eb4bcc2da4c926bfb3195cd54", + "0x4bbfd31db415a8bcba7188529ccf09d7cc10037f2c3dc7671ace6d4dd60a35c1", + "0x918152123a239ae6c50d9895940626e7f77ea624596d1144989a5fb7e10ef48e", + "0xef73abb8745093394fc130c7145e2de31c9457151ed78bcf63171b7633e22dec", + "0x09f80e170b2a1d599185c562344821d0e36bb48f91d8205653eba143deea6cb6", + "0x793055e11ded973ae3b55bb95ef6e985ecef03497e76e4e23ac477f6ad070fc2", + "0x2ae7e9c72203cc2aacbb79cd7cb5cb7fc4b997c9c740578253cea957ffd847e0", + "0x9f8caf269df06cc8c81cde32f1ee4f081d8a2ea8d945663e0339456e583c4703", + "0xb8533ef2fdac7587034839d1ce877bbccee50c473d4546c3fceeb7ecbf661f77", + "0x31a51d443ca2a588596b3c6a0ddd5fddf7abe8138177babd8205d165de21e76a", + "0x0a60c5ce88246c2e999725b2be6c330dd2482145fb0859ac0dad38f11e24e5f9", + "0x87d81ca8b664f33920634c62eab8f0ba3fafdf28ca19279b4d0c60a71eb738cd", + "0x1070087084fc2cc2e47fe731b8f08736cbef46194d16f418c87befc693c8a8b4", + "0x09140a959753b2c1622f0ad55f8f5d34b5f52a5ad6de7b6112e4ea1b8fda9e1a", + "0xf3af8d94fba3f4a6e018ebc0fe5088710876209a39e37b85e6b6bfda70f097ca", + "0x3346983bc9ed1f7f4f112b38526a92e7b416f30e4d1c7a934c7d74974f86dfec", + "0x587472df09a53693596d6bd1f60485df25fdd54fdcfa4c20f3558107f3bd4588", + "0x4c408ab0922f27796fd4fef68bc20c6385647a8ad4397a4a553fb68c5ce1710d", + "0x2eddf19c4a6ea3c2ec855e5b90ef78f3f861bc6317369db137f1a7f89110e69e", + "0x30391283286a30ea6df7b5739c7955a1a659bb0c46f3ffef8a58c0140d7386c2", + "0x8ca8497844280911bd97ce06b69d9e09a86ea135ca0adce596614fb6c584d0e0", + "0x9a699d399b3ea784ecc1e4f2dedd9ebf9a383fe44f40b4cc67dcce4ce98cd61a", + "0x013681943970f17a86dacea448bdbcd0d0ff56b243ef2c147ba77e58f1b47c8a", + "0x8717f032bc745c9a16eeacd20f3d86872e9cef3c4c777a8dfd867ab898e73fee", + "0xe3d4059812ed8f3d4e23583544131dde2a56276dd513d2679be07a36ee08dc48", + "0x265ff09a3d0413bc7bef45d66e34180c432b5f66ca96f8c39d390a83c5821411", + "0xddcdf72b890fafd78daf04a9e2afa824de34b761c25876763d9814fe41a9fba0", + "0x75168bbb488d49dc440360206d5b36d8934b1d9c50d8d8239cbdcbd27f238796", + "0x57aeafa912ef24841935fbe295c7f922b61bd729afce4537ed4985d06fed8eb7", + "0x7be35f0ba773bbabb596b674d73d8f0b9e6746688322dc99536e52d6f0100183", + "0xceb32481ad49ec6c259273d2b302352f121fe3c0d6a38c2576fd0667ef1c1088", + "0x1e1a7e3edefa2943844e452e8d4959f06681449e91622a537e196c7f3c069f5f", + "0xc4c5f628c0e705d6ed6e84b26f74d76a4ae13b9a602f4ca8fec8d94318b1e05c", + "0x324a02a05df574b12be04d2ae137c409a87963d524eac913d2b671d950aecfed", + "0xb1c115671fde450792a1bf3541d8024e84fa4239b3fd894af3ffa25bf4d10da3", + "0x9e9db6ae30894084f36122ca1946b96851c0e2282cc4361fdcaec5381552c26d", + "0x230b1fdb77d049d548a6cbb9b4dc8ddb983c3225591a323820b908cb79ac5ffa", + "0x88bc17b5d10e4b474c9f85c935ae3cd914aa437185f9bc7c03d66cf407e102ff", + "0x6ee030f383a99122c498a9c43bb51ed46932be9cab7efad96fac65f3b39d032d", + "0xd600f1dfab24e5b671a68e56d2d27f288e9b15ecd870b0fb3d811c1cb6fe17ae", + "0xe892c488faa1e15b040acfee5411b0c6cc93d1d9082a605436a0757a0cec7a85", + "0x8607ed1eca84dcec9c9c2d9ca8f9dcc952de7ea3c54c051d0d41e78fe725cebf", + "0xd9f378c67ea3834d89a85d72bfab542d6877370c8b542d1be2766e867a25229e", + "0x725ca420d55211930c77e292f602f58c281c12a2d10d77ac70f128c122272485", + "0xc141d38375f3269e92d6ed85dde2cfff491b9fa60b3554ca9909b944838f7781", + "0x572f4aa12ec73e99f35c523c864ccc964422946a0ffc5606792cb65944a1c61c", + "0xfb2f827d05901a25debd15a6b5a45d6a42f2fa84e212f79493e46e760cf8d620", + "0x9f08663b613bf973e1861e244e61e4b842853b8a388360234c85982e94ad96e0", + "0x17ce1320123e19c42bf806a0f204c9475cb3340a0434eddf3d8954b08d8a3c26", + "0xb3d935cccef673064e94e186c4649d19dbd7d6fba4ab7802eeb44fe4e6448bb2", + "0x2a04d4c2b009e424a88196f109923ab308052c6709b0f37f31131a74db07ca2f", + "0xd30500ba7ad6548049313227f37e094507e03d2a71792fe28f2dabe6c7a477fd", + "0x133f0204075c4a44764bd55409878a85f730f412a64d8098bf26246ed89fb88d", + "0x0dd3f70cb92468b09475aa687e81d84b7b5551038813b1dcecf9ad62394bf29d", + "0xe9b2107b3efdfa5b52ebd9d25bc17cbf934190af323cbb821aa01454809cc5b7", + "0x5a10e855a18fb6e2beed325f9d4df38645e52c8098761996a455eb3320c2819c", + "0x7ff65f7a24f95a7408272ee4122f202e2d651c084495b5173bb046bc4618f96b", + "0x06b0e4bd3381c9983715fcfa8c3f48b4beb289754fe7bfe8caf5eb21901c8ad9", + "0x5ef4e799c3d7bc81fddaf790f00166b63255836f5e03bdf584ad2535e05d3cc1", + "0x9efde50127e985d2c255ef17a7a5c82b46242f18230cc68bac49867184e897e9", + "0x78309317ac6418cbf58090dc8091b3746ae1b5f05b8b082610eb28d101e519b8", + "0x81851a87801abc649ddf08e1e372e7d0a50c8d18661bb3a13193389b06854ca6", + "0xc5170992c381aff40d4d02f0b1978ee689dc9ea00d0665d53c642c6e1617f82d", + "0x9c4d06f36bfd2a08a02715c5eea44ca07adc04b1176f7a47a3404af181feefcb", + "0x7f1910a654df3160f91affee5f286299958a5665ed0d37e39ebf429b281f5b4e", + "0xb60950ce3005d7854f9f957b4f1f49f0b4e781728697ad312769ee4ab80433eb", + "0xda6666bca71087804de7b3567e1f0047bd69f8f62d0bc7f63aec65ce8222ca2d", + "0x7e9625d6fe07985ae5a378a35cd5108c1db05e429328f639504fc17527b2e04a", + "0xeb606494a39941d272aaa9cc3e18d2c502b0438de5ae974e6687e2c2c433104b", + "0xfbbdb8353f8288217930f085c51e0c67eb9fa268cc66c0a96673918501119802", + "0x071dde3764caad8163d85a5a7d9a05f31b857828db55819afc95b08e10d6c87b", + "0x262a03e39027887a11b93963c7ca4676cc2352fbe46a05ca2e432902ca4235ee", + "0x1366a718f5e2a2b328943afa839241903a4bdb776b6f732d6a0172ff8c9f544c", + "0xe04d325284bd27091857f289c6bc8ded91dd16ff7ecb157e39965c3c98058e34", + "0x648d5113a9c413874f2e8187905045f9d8e044e29cd4dca0658d283d0944a130", + "0xe7706395d101ed29949e59b10f69214eeed0377be7af3cfa8231b917c6793023", + "0x7d37f50db8c210bec2d202a7211565d53ccac0e9b17baf887a9b865f4a57ddb6", + "0x73302fd966c3e65c0d0e7d610dcfd1a87970d26fd2ac15deb73d812a878fb8d6", + "0x7cb0a793aa40ea9894377e0f941b284a792065a8fb20a0bf60e8dc51744f07cb", + "0x1c2435e5e922dbd482e3279cbf88a632e34fdfc1e7bbadba3247e11089871ef4", + "0x8fbf585e305c90965c47c190b2e125276a5cf5747ea57e60e9bd36feefc7225e", + "0x320d5616868006a5f311c79c86761b47f683ab7ea1025e794a9ee45b699793a2", + "0x8706208d64c31ebf34d6c4126f72787f3d604dc7c0f72ea74075bd21afe21686", + "0xac6a123d378afdcc284d34bf487714e4cf9a090da9d9f3d67bd5510ebde00415", + "0x623376328e2e3c6ffb9a25250a24a5b8486915317fab74c46c06cbda943dd74d", + "0xbbb4c4513c3902167bc14cb17738633113cfe22ed5846d409fde2446740f6b9a", + "0x62ce10523cbfd602cf3e3e5b8c09b310f4bf1d7c645e3a2cca9d20d156b51f4c", + "0xf427a9a8c4390d7a4237f0b72cd19343c4986e771b180421c21dfb37e6912c74", + "0x52980fbe4416be30e88b1fa6e3325a0037feec3b6c40ae66f9d5e884f2deb153", + "0x9aaf58f469e9c8362e3016de4b12350e8f3c28f86ce58702fda69be65267dd04", + "0x0fdf4d58461e0e9477d39c18eb528501eeaa066dd61aed414a50613182057934", + "0x708b1667152c18475d00a25c8b87de03dfa6b2270bda21278c0dc0faf21464cd", + "0xf7903da3c49bd894edc260ac372926d90763b459539eca32eb3865d4a16c9bd5", + "0xf9b6180481cb5b2f4692793de59cd707c71b3f6f7396a40e506fffecd3c4fe7d", + "0x6f298c8d88b0e5120805b453e0ad10f6d65809fb0558c4bb5a344ee00aab4745", + "0x4bb3b6e0cf86c6937668b4a298da229492d98d99212c88e3e60af9e89fe7a4b1", + "0x0e2b0211c17ff6e28c459ea410d3bf33838eeba869c4d46238a25994fcb9dfbf", + "0x113e8f5c4c21ba5909963c3e65b112c78c19b8f3d6526c55de1af9a4b1eb8d60", + "0xf19f2f2e0a8de0d04a26dd1a10e96257f4a6a764b92d7c360453db32d65e89ea", + "0xb20efac16095e63f5f530de22271ecebb1fa7bf4d8ce6f49057327d692caa5cc", + "0x8781f616535ce6b3352820758ea0ddc74ac97e49a3ae9eae6ab0bda4e8741606", + "0x205895b72b02e22c73c3fc2e814c121d6b899c821d72f1b02bfd8c122fd817dd", + "0xee8e1b3a255140333295253ecfbf9a2d375d5ba1ea2879bd72088f6c62b3f9a9", + "0x4d3c138f077007962fa3fc56c7e5bb409c860d11ba48ca9658e67473fc4c4417", + "0x283ee3738c2bda7631f3f30fa2c29d3f3bed26c63180c61e1de03504b48f7c38", + "0x900a45ce2bc0f4b331d3df872f3d34c350f6b7dcdd704e36670eba878776b303", + "0xcd148e1b7d3a4ed41c51129d14cb226ac20ff975de1de2a802ba93b0e872f2f6", + "0xeccc9ff6f75fc844cdc8a723ee3f168d3f54788aa99a5f81aa9e609f8b4e4ba4", + "0x9e4ba2027ba44f31bdeb8ef27db30474de2f3728fa0607f098eaf8f03faa2fee", + "0x8d7289beac6c06009f0b72c2634c176a0784afc8bbd484bcd8040500b15f902e", + "0x9624bce0632d9a49d9b040a45da65e1d686dc6e6eed7eb3ec1536384b5cb3530", + "0x8187e9b62c764ebb82f5bda0bde0cda2842c47dff910e81c03db5c83dcf02da2", + "0xab7be6424ecf0041a1a0aa6c57cc231270ee6e50b80e6a8e07f6e40e8e11931c", + "0x43d8ffb420ac0cfec24a8d378d7d35230aef8887268414779b09247543b2f044", + "0x185cd7124a200639a0f60f1412ec44083f742960e46897a85d45a04bf5ab2516", + "0x91025f84bb714cd201f4d3539f7c5e6c7cf9fa83b399704ed0130b311c6886ba", + "0x13100633274ce0d423732cbc1bc1610123959f15974868af0b1900b74ca4cda5", + "0x3b00927007417f0d762f6b37c7ec0441e963a9afcf3d54e5be1adfa4278010b7", + "0xa8e59f21955c983044955aca7bca29aad4d408a1c958ddbc2ae526a87e3fabbd", + "0xcb836def3579f067bc45c0dee5f9a80eba544348c7bda65964c6b1fa2866e0b2", + "0x404d40e1bcf36d7d4e34b32eadbcf5cfa858be1499b088fe8ace025a2e73d3a4", + "0x2d9a5f05bec8712d206349bdc8fb8ec897cf2ed28d295cd275c31c5ce46c4fea", + "0x48c577fcf9d050f2b35ba0195606d8b8d91ac17e524fe0b6ec16be1ce7cda0d0", + "0xcffe1c3ab5caf25224c870cdfd63b4faa738362299cd37cea8b66cb1542f0201", + "0x7bc007a452ddb66827cef27c5bad01e87265cb38cf8e111ee7eebb21cd263bb8", + "0x8c26cc0839859eba7744b73a03f6318e3ea249736ae20bd206461e79bd7e401d", + "0x165e4a10b343dc952ee54c56f21b74b6486929dbb59ff24e066115bf35c223b1", + "0x2ea42214e74cd75bea948323313453dc6242fb0593f7e267abf5e544e0ad7d2f", + "0x2caa11a0a255bb4db80e305ccff40608534e638a17cb8bbfe6580a035cbc8ffa", + "0x0ad0490a3008883d02cc92624352fb7caba9a97cc46f82d1e64480559778edd9", + "0xfb24953b551a2b544ed6c6cad2755e6aa634112c3e225607a0efcb0d811ffaa9", + "0x4ec8e3591d27b911b1495f6fcf5e6dcc9461e9e602b67a5bd536bb0e6bc68f88", + "0x790b7eecb797e391d27085b27cdc5d4be20bf78de9918c3d1ed72ece2738dfee", + "0x7b73acfbce9837bbc5f821412c92a1b58b3af2bdf08b4c4cbbd12e151efcc90a", + "0x16e576b05c5c95fd38ac7d53699ee8b8b3431d78a5f671535590cc1c59c78039", + "0x2b4bddc77ed675df91af490a565c6ece5247335c90de744d6863e24e624bacbf", + "0x277efde1689605ebdaaaf4b9364449345ac664b5fe270736b2a7f2a97301dbbf", + "0xf727799af7a95e92eaea1bb2e3a0f79cecea663113e4781797101acfde46c234", + "0x54eb62372f7c5893d6be0a031edd80a25cbea3db2a0edde69ef4bcbfeaa24b4d", + "0xcab1e0eaa0aa475de501b2e3fbb5ed790744040a465a4256c4397e85a31f9eca", + "0xa0c54864bb507baf47aeef61433ef7418f68295f08d24c8acfac1eb18982163c", + "0x9a76cba0046b4e4cc89aa333a0f633147056044624c1b4c1c61a8a62f1f98573", + "0x510d25772f6e14f8e14905b05d8cfd6384561994ec3c92cc76fd37ae6a9812dd", + "0x39ffb78991cfab4236e4bc04325331dd8be2e06c4162f8e51aa592b27e1fa0ed", + "0x45c4d7eed33f4be6f8c0aba3ef42ad6a6e5f654b104895d9d662ea28704d6b43", + "0x21887c54231da9d400b964c63cb2f5378ca3c15f118fa105c0b2545528cf302d", + "0xb71cd47b4a6d40f9b18133c456c2aa7eb2bfe6170ca723a0c584ea28483d13dc", + "0xfb3c2158485851f4f564370c590f4a6b8f6481e6e4736ce9280a89d946b0e016", + "0x5c3ff34c067986eea52db9443be346eb1576498cedefc4a66379b24a3244fcc3", + "0xb27349be4de4d9be3cc9e904f72455c2f131c0beae6757592f49b2f0efd546e1", + "0x15877d8cccfa9f9cfd60408c5a6a173597c2e091a47fcdbaaf0a944a2232edda", + "0xa004d11f0d305763a613cb6d3d44a493ff669c5098b63b3f03e6402adc207bb9", + "0xc033417010a0f390418ff55348055e8b3e676c1d060f0cca2dad80aadc3b253b", + "0x035224e9c4e562b1f0c080ae58a7e9b8d48e565ab0be332fe580303a6b3661ca", + "0x6c7f4fcba6dbe1150b5bc6ebcf176ec3427e555978ca7978bdafa674cd50f4fe", + "0x4f62b3544c9828f9b7aff8fd5991e32b4f18e72c12b1d582c671a71aab4cbacc", + "0x8124e36227c5788e3608c63a93a8a0d966e4d8e12a81e2fa2378a969dabe0ef2", + "0xfffb09addea705c2ae3583b45e80908640b728867cdb8d49b2b1150280795b49", + "0x6ff99c0f0c3b3e208373fa3b7f031b8023b6660801a8ddbde0fe8668310ba332", + "0xfff2fb5a358d3f2bcaf5040e7e0fb9ad96fc918f3be7fc077a8aba08edc64a9d", + "0x3d734511c149e8c1f617fc48fc9edbe27da5e2837dc634ad4a359cb4fc1ce32c", + "0x0c8903bcec94ac45ebe8ee7c5875c23216d9399f7d14fcae79b7af4efcb4e503", + "0xf020a8e3254695e8c5a7b0a952531af6c886719b9354d4142946304220f18b53", + "0x4e1b5e445e923e783b878b943b0d9c9d2427cd8b71c346b79968faaf2a3ad337", + "0xea488d31ea2b67854997c6a88db87a13b4594b429b0dcb531eefede8e22308c0", + "0xc5dd53b4f8c9379c0f86e6b1270b6838d6a6e689865542791917251273c5360e", + "0x1646e9b43ac92494a90ae04647a4047f8de9640aa6f2c2c137962bbcfc80c8bf", + "0xf2f64a9c2e2de9ea1e314d84d44769a114c7035722f5cf7633145c13c5986216", + "0x62f06eb562f3c838c3b24a3da792769e9de8e2bfeefbd70c7aeb9271f19f439a", + "0x1cb36e1cfcfc9e4d8292cccd8d8b8f0bf90db7b63878e147188b16ec19754110", + "0x0316d23ebb039aa69d6b3b9b4603d9092f800b191735abe2a8ea2937b943f725", + "0x4c85e7f1e285380f4d80efd1d572781a93234149b8628350df7d93cb7625155c", + "0xde0010a2a469394e8422f52d128b930aa52a773368c3b8bf38a0dc830f161f8b", + "0x05ef4316554e9e05ca9a16c20f178481b630322c8dd438cbbc18c2bda644fc7e", + "0x64673e06bfcbe84232442ed29179e0b235d29e398e2867a484c2b60727377bc0", + "0x8dfe2659a262b307fb1cfd68fb18925a310691dbadab254c0a81aa9f9ea05c7e", + "0xb0a9fd59b0cbf68d53654d131aff4449c0fdd18217970c3de8d1adfe58d1f4c9", + "0x4ba2ff3b6232b74f661271aa29654638b05ce829083f54be06d8ad4290182910", + "0xe087ab9202b948f3c20cf02cb21f5f1b97d508773d8d7c2e5baf14fd52845076", + "0x702e6b8f663d10c1054de9751594d33f9e0915f1d3c71b36cd9c974574ebc85d", + "0x4dbec1c6654555295d0dada515dc606c18fd72e55b3cdb63ae018b1661c4385a", + "0x151d1c8c60780242caf26e5aeb8860f0ee9bcc4968e96c8c540d3ed0690d9635", + "0xf385a1e79bf23ea44d14b3f8668175342846ebc31e5a6790fca01b52074aa6eb", + "0xf5e94b06a1fbff820e98af762dcbeab9d38a45fe4099728543dc4784ec34b1e4", + "0x2396c1dc9e8b6cb903f97aff55b026511d64b88b08a05c83bc2ffd6becf60ee3", + "0x4b76c7764b5b098c3168779d95ca4aef2b861201c427c416c97b81372436d9ce", + "0x1a5d26c1839a09d7116868abdb2626467ed948bda413adeeb09c1eb146863369", + "0x25d61eb2338186246b78e3a4c4857c89cc6df0c77ec0f19b2d58ee9277c02d38", + "0xb9fab6c7fe62208f5f9c2714747714883987a513f115ba8d4c6904df172e9b0f", + "0x44f2066089cbd0ebae33e1b58179db26332ae99534ae4f864abc94fbcbdf1acd", + "0x97ffcb0dc94906687481210847ad2522c7cbff5758f6242c8a6ead1a010c0423", + "0xd681901709d666912f87058a300cf15b0bad137f4f0993809c37372ae1a73bc8", + "0x1e89c647ffabf82e228aa2ad65a989da66fb9f4a8d0f3efc7d66d72ef75f449d", + "0x40177f69aa2c7f7711c6e2212c2278a861100f1a46a99c340992e776f278bd99", + "0x8c09a1a9e84305a94b702fe21ed39db90d2c0eee6ff21185c555496e99c9807f", + "0xe13af929bc3b6b693936cbe82ffec90cd2d2e177758af41d5c7c7f8b3922582b", + "0x4ed170e95d7b677fc97533837ea0e350a30df6a3862d7b7794e051fbba68adca", + "0x5603af56d81026197df080dc437f9dbedfc82f1acc26f2ade39db63033b7a053", + "0x815bce3f12b5c5b5ef1585ab98a025aaa8117efdb75d2b677abb4522e4b933eb", + "0x603c0103be82ae58d4af604be625016b64c4985e3f2aae31ed620d1635d85a7d", + "0xcec52fdf68b04fccc6c7dc2990412c955d08b6bd4a7a3f0f9fa77d77d1c3481e", + "0x1b3a7d5f6206a15645ed55669485dc4e1cdf7ba41f3488427e8b7202d6175552", + "0x59946fdb729dbda327e825d64932da21571c83e4170c1c7748c527bc81937fee", + "0x676793de267e7078dc3b6927cd472eb1babd4f537bdd8386ee65b88166cd592c", + "0xc5379a7f5ffd7942f9b7590ff83592d91fdbddfa09c040006564434379868110", + "0x44860e8cc625991899e5a5c16d805f6b1aab9e1a79fa462e4ff2f92d6c40e76a", + "0xaa31dc38a358e3a1fc78c4cabbf05517b2ff78e23befdfcf7595074bc0b5498d", + "0x9e7d9885b3a84dc90dc25f1a48987d8d4cc1cd08f51baf1c3f33e86fd17341fd", + "0xd6790620e79c46699c21b0bd61cd09baa1e2b350fddf6d125c4c06fe30a3244c", + "0x4f60d8a3dc5859f69f1b96507527d2afbf899854e72d0d12ef27086dce561a53", + "0x67bd7c84772d709e1276a1863ab4b26ec84eb02767a804ffbda23eba3a8af0d8", + "0x707155713c08309b0ce29e867a9c025e36876935398a87d1153a997801cd7b96", + "0xe94c592379266a58679af9df945fb443b790e1c5a7318a5a1738070ec479d1eb", + "0x00205e95873d1670a9212fdcae09b06fc941128e4db1427fae7b3de33105c292", + "0x0a730cf91406030fea04d74b78d1625a3e5c73a1e7f39fda6db9225e064697ec", + "0xc32b3134dab797f09bc4986a7d9a969b9331a99e431b4026abde8d06a7910f19", + "0x7b9fc8ad3f2bc9e4c680e2400fad27bd0de271f193cb4f7e9727a87e999aecf1", + "0x39d65165378d375fed612489145d41dd4f9d57fcdce1a5fbba35a09210edb201", + "0xebe86247c803ebe65de42feab2d95a8d45775f352a0079e6a868692f444fabfd", + "0x04eb04c01e29b4a0f96cc9072576a8f7f3cda3fbf9b4050f3853ebf763bd85f8", + "0x701a86ebe017b55312ad8277eee062bf0a1b1ea2595631c9c28c740da3d4c117", + "0x57d6119ae2469213c921ac6606f41ed137181c179d6e207d21693399d3b21e67", + "0xdc189a5837c11ead4c6a1b7530b718476a8d0ca879fa4e499d72f7d8fec348de", + "0x96511948f65eed76fd3e17c9f1201e605ad2ee59778df04fcfeab5206dd29192", + "0xdb3930b8a1e2a8eb35940084eb0e98dc53aa1d3aa563e3ca6b260a50cb3a68a9", + "0x806d567cb6fd15fb18007354be55fee1c2b5f0aa1b1e5229ed0e758910af617f", + "0x6e2e8273a970e21164be1e548b92963ab241a68da41e9e231c12ee08bfa4129d", + "0x168e45c60dec2496e48b471b7d2fe1b829e9111191e6bddc936d0787fd42eaf7", + "0xab1ec5c8aeee05f24428c291a4d8afe776a92826f6e58dde95f8bf63e5c8ea29", + "0xa9db30a831b1ff69e38b342ee4fd3c9a8c3f5cf7b647a0c7f5735a4682eb42db", + "0x2b55ec4fe76bde0bc4f8d769d3b182e4ac7fcfd85a28c89fd7fa5d511f41969d", + "0x74ca1b5889e8920833042da86aa8d1259463827bc0cc9e7796144927757e7db9", + "0x5a3d4a8bfd449265b74b85e62305c3184209f12f4f55271cebd7d2df56b9983c", + "0x0b450e356dedc2d73ce19c6028dc5d36818cd3714879e5a402dd8cf7465b2253", + "0x073f03a0316a886c4cd71d4cec42ee7705b6cd897932b6547612f3cbc5c6b8c6", + "0xff2b0244634cc4fc8cae0b44f737dd47db2cb60e05578a34b336c46d0ddc8f09", + "0xedf8c719f93e1bd0cd421bdc14c03f2795dce10bbec5647eb98f5a64da5e7f74", + "0xe9192cd76b33b1d4b09e7d8c3e1ccecdb7a532420dac942934ab76d6491fafb5", + "0x5fa7a590d22896c2ae781644ca8db3ecf779691609dee9d0554ce562624a1e9e", + "0xe6af198683501ff90b9d14a343553e0c5d7c5b9fdf653311e022ad4a33eab72f", + "0x3c28170602ddcb77078d6f715a6629aebe4a35b2498a2cad37057f3357598dd5", + "0x29aa81bc8d9c54f146917aca4b1ea1a0f147f6ced0d23a647a51af942826bbf1", + "0x0056b54bb953c389159a761d3a405b71cb54162481f5cae225b86c8d2f409960", + "0x3c4d9ec5c31c3c087545487bfcda5db713f1ad44450eb310a66d66330b67a0d0", + "0xbbf3002577b95053f241733cdf991602a570a6f33935d50ad64bd31ea9a8714b", + "0xed526f4ea68cbb5a15baaaf6ea698e2d293afe848f3056b803646046aa6d5526", + "0x0162b7210309d0144b8464d21afdbd80b5ac8bc3cf5a93f32fbb87565fd4c30c", + "0xb051288210e1d0ef546dffc2e52026815261e2ea866e1276809000a3e7e3d060", + "0x76397a5e4c77029699eb10959f51ab090437888ea06b1c5d0cdf16b74bc44d3a", + "0xb5cd5928e3dae6cee3ef0fdf7f1deff66628ca8ec29743bf1aedba2e10fcf9b7", + "0x6d1f9aa0f4ab673ca6d0d0f10bdb491882fd1d582c2489eddfe7084eaca0b034", + "0xc636f215b9918856a0ef971a2340dd3d3019ba671c0118c352a1bf64e50f0e61", + "0x8ed6b16c3b89411cdb2a92cd42f2ba4983b26a83eb3112a6a376015458aea55c", + "0xa964e5da59c92492270317ca6a0b86402cb22e0c568dcd20a90b3e826846e634", + "0x2f16af813410d4c3519d9bce71c3c31ff09799d42760f49790f3789a2d365046", + "0xefe1139708e6ec67886b9cc3d6efa9b2b67868c626c3541e7d7a17c75434f2ae", + "0x199135b37713cdf4e1ef3766e331ea84f8e4911552de1e3c133ce9a3a3b52e1f", + "0x400cd17cba12320d710833bc5089c070c482f6fd4188b704628ff47611ca12a3", + "0xaf26e7080fc110911a649b03f8212b43626cf75c867b2af9e70cf35fa99092b3", + "0x346dcdf1ea179f89187527d73747c6bad12ee0efe4c02eda34ad3704d24638a3", + "0xa6df7e1b1a8fc69ad26110c0166383e5d4db331e98fbebb1b56611e0f7539a46", + "0x9d2b7acf84de840c1cc035a355360919ab5599ffce825dcf9598b6c8c23bae24", + "0xf18a92492752d0a118efb2ea386767122acfaa728a39d788cbe1e836ea0f6378", + "0x28f49f4f5a61322658ca40035c0340af61bbde7bd42b74c4a1867b19992dc787", + "0x890dd6356256b7bcdcb27d415c10709c6e898e5f947ca209389b42872102b36b", + "0xa24f6907d5fef0a0c28e79c3be437bab1e4470d29365b9b4779378099a9c3007", + "0x7ce1d586d950a3875954ef50e2b6bacb51e8cb11db45c34b709868aa7eb6bb4f", + "0x5cd316a998fca726c58a56079b8793d208f2324e399413aad3fafae077d834c3", + "0xd367cca6c37fe087c9acf4cedc12ae875eccfa34a4798bf916a2ff1cb245a8b0", + "0x78a1dc488545388a618cfb6eb0047236adaf32c0b5bb3dd35a1843720e41afd3", + "0xb7bdc303b26e920a184e250c398ffae03fe29491523b68e2a9fd658c7f55a734", + "0x72ea58270b1512daa51c08840dfc33e657c4495a5f50bb6ade1fe4e7f2e5d35b", + "0x3af82e240d734c66ecf715b2fa6d42a5976f5451694a9669ed49cb4ce6d495c8", + "0xd875ad205979ae78c6d334e5c2c0c539574172be4f2113e53dce70ac6320e1d3", + "0xa808ff0a2eba422021f62c0de2cb9ea114dcf340fbd97ab0506461578db78104", + "0xc6d5c1cbcb505220f3f47fd100470180620e47cb5b7ea81b4e6b27976ae093e0", + "0x3f788657a09cc34dbf670108046d4debe140154ea8283f5a762b2a6f1927cc89", + "0x0441ef2e2865848be1d3bbf10dd99bd9b307dc6a3833cc8066f71fcc9fd4657c", + "0xa033b833635e284605c2a25cf4b9ed595a8f6b7b6928a60f849019b68e412197", + "0x0c6bf4f59f2369da915c5cda4358a1b84326c94cfde7886fa99c3cd8cce00d3a", + "0x16f8cd5f6cab6aa0968931090a06cd78804da1332ae794954e43e880e6436380", + "0xc44d1853d161e5970cc4b0541aa7498948da07226d9747191d677c1c6c61260a", + "0x63fa006b716a07a172580b605dec90a99f4eb1caa2b6272918e21206b3b08186", + "0xdb0d7fe87810eb83bad89d04f279a06a316e9cc9afd6b249f77ff8da54dcffcf", + "0x04a1e3ca62cc77963b58ef79a9e2ad8ef54216034bd160728a7fa4806c0ccb62", + "0x3db1db1cc10010514a98f45142815604a945544ecb6438c63de232009f525ddf", + "0xfd6619df5d873b255c6e516cf0e12ec1114613a5d803e877fbfff779ec20a1a4", + "0x581ba19ac99cbbcc948c61e0614c64008eda6a58604e9197aa8470266821f331", + "0x316dc2404582e1ab45bef960907fc16e6223639d1875f6cb7dca9c7744cbdd30", + "0xa5c585326fda6f89e33d470abeeeb12a6a65ce9624cf01c5e2ffe5e397ec8efd", + "0xf08862fef3ea5a98b6b4bcbf0b57b482dfa149ba4d5e530829eecef1b5e0ecf9", + "0x7bcb4c42db39ab193745ac34c75e68ab457aa03c83da11f7396df2491a300666", + "0x69424ab7bf19ccf3583048e9c315a5a5d4a7d85359d6b4a3a7ec001be96d7212", + "0xa686da5793c201b92867db72a5f8671ff473cc12617437874644012ff242984c", + "0xf8c11302b69a3b2ad86e7826f8cc85d0ebe21e6420ebab0a7093feb7f15b985c", + "0x6ed81186ae9545a36b50f9a0fa0c82f2f52bbda7e8e936819628629e29402018", + "0xa91851b0638a92d2733b63125085982e5ff2acfffe66f71d3b218ac4ddb4d268", + "0x895ec76e33463b1e9f6a38a15a787ba84812d8d3fa6385824618b7de7f8235d7", + "0xa2c45ceebbb227ca7396e407e26c88bbf0432483608dfd169a085c5372ebbe5d", + "0x8cd8558d7c920df4bff9226cb91dc674d8788376c694ecd27bd84291255b237a", + "0xd9e3c84a853e9b551d296c560048283aff22e0ea3a0853e60505932f06fc0b40", + "0x5148cbb68497c824a428f87cac9512dbe313abf6f4c2b9fe6ee78cf909d4322c", + "0xd5d0a750818cd28793a1238c194503635e07870a65d5a8eae084a6a7d152069e", + "0x83c94a89524371c5bfc66e3ebfdab49eafaeb77fddd5b31bf3eba609cdccb083", + "0x4c3e549fbc7854bb417e50dd281890c745e9748ac7d830acd9c867a2abc64db5", + "0x642f75489711b36d89b0432f92f1ee19d3b8cc1fa99d2c55e8659426068da0c0", + "0xa4a944abbeff1a3d718e28a194bee6bc066f01aafcd0d674919e19c4ce1f473e", + "0xc9336cd020b35855fc7c4c3febdc2a19d4466e22d76ea44977f50fcf00d30772", + "0x0ea3c8090512fea72c5d457e0f3aa72fa0fdda928124177fc07587db60ee4c8a", + "0x4792e45b5fe8a3e2179b0745521a8269d887f8751be3f2c8e1cc8aa9ea0ecb7c", + "0x7ecb169f378c9577eb1af269377c16d25b09dd2aae49705bef1d143b099ffd48", + "0xf9722b9bd88dd8712c2df0826798b903e4e46ebea1caacec33e626b1954bda88", + "0xc7596d6ba28215314a8c0cdda3929284a0f98b14b67eee8bdeeb245a042bf5b9", + "0xb14ae9ee5e30cdf8fcaa8839e06f1dd1c273b9a7f8aa33d6a7f8a2761d6411b6", + "0x160de9ec9947611c32bed5b39fb688fd8521e0be0c992f318e8ea596e932aa85", + "0x166b7e4682502a245b971d27420a50d028febe29a06ada52709290dce6ff65c0", + "0xb3c6774d9d1415508baa55827001283840a3cde35900f0274eb78cc169b20e48", + "0x067c6e4818cb6dc6e098d2f41a0f0d4d555d3079a271e15e24b40c2b33d48c91", + "0x5f43937304d8f1c5915bed915daf11310fe77358a83b3dd2579986e9e63a418d", + "0x361e8400ee55784c4edb63507bc047de04fef5e5c96c4f70c9a61cb5d2fd3f5d", + "0xd6e24a0733e82cdd74b1ac6ec0a54ef3bbad0f68461f804cefe07a4d7e15b359", + "0xa3ef3d7ed01caca083c8cd24b0b2e6b93f307ab3bcd7fb15cc49de6e76a85054", + "0xcb22fe8e323ef120f5ea5f6604ccf7d84adeef7b15f3d81247a676604d127979", + "0x39094ded1f8ba3edb8f9628d72375ba2700942e0870a267ccfa75419231f8ef5", + "0xcdcde1fbcfc0138689d35a44fc9dd9f0b9b43f6bfeb9fe29ca02018ee5e2c358", + "0x75759de7eafcd4114962bde0db7b64e175787ea56aecb37f5b1045900ee8cc0d", + "0x53cc30b0160d81c37e5b9ace29a55bf07beef84f1cd71307b140e2bfb533d0b0", + "0xea48a27931ef94e6babd0342424cafdc835663b381983dd325b00c8b12ef9f28", + "0x3189d2f6c9623c4570d93e4c26ec30cad659f8482fd4bfae5325932fe57afda0", + "0xf0822c0d02fdfa65e48362ca1915c07797df6f87e0a98391ab4046ee4266b758", + "0x4245d5e75abe515824bebc31ec8e2ed9e5ab027fae1c9c74b49e9522c496f00e", + "0xe4c84eb52baf4e9bade65b3711b6bab7e16fd8a21d1162a24911ecdda4ec4c97", + "0xd73d7c7f12b4dc0ef75f4aa6f006a2efd64a6f54f848daa05efaf9fbbc1743c9", + "0x3e73cab1286dcb25621a108bf70103b8a67aad50d03b2a27b15f32e74d2ecf76", + "0xeb61a019301e6d597516b59bc2314f75afd9f8c76ce5ee4b2abcea2d5af65d22", + "0x6e1beb679490b6480aea261f776194bc2943aa7b4aed0edcc06a96472b6a5012", + "0x5c753161fc23f9bb1fc76df8bdfaab24fe0091337a36a56d0f5f959e4a72d903", + "0xc60ec5c3fd1986c8478f5714691a31acf469a5ad47d31e1e6137969328e86707", + "0xae9bfdfb4a7e54835186e3f161249d435420f83a238786f23c261ff0705cefc0", + "0x3a7ca5b57771c703881e05743b76622360ffec308e21b649fa9d2b77eb0485e3", + "0x093ffff3c8d30950e82d67887d44844d21f5d0d333534c65115146d92d667778", + "0x6b460d7cdcced9aa43dd87660e073e6ad6c068c7ff84aeb86decae8a18f0b0ed", + "0x1e23074207fa45234ca76dff1a5b4d78ee87839029b9bf4235cf5484a14a2ef0", + "0x4236c643b14fe734a6fb1e4f9ccd7b6b502ee5d24fee3af1201d6fcd5e2a4991", + "0xebf1cabb6606d20194f82bdfc22fef39e8b73691c802c6421015615cb8651ae4", + "0xa065c07d917d768a40ef583dba8570be0e67c5c067286fa6ea55183ed17aff9e", + "0x2ffce3fba6265f1a82be15315ed6fbaf8710133f2b8242c6a3a3b40da66e98c4", + "0xc814a7b871102332fe8d4daf0c8f7333a9751e3f29b7b02ed4d15a8c217d1490", + "0x29a0b87325be7115d4605df2b65991421f6594b3d3348238a6101deccc88742c", + "0x1fa4239e68c4fb68ec4e8786801d25ccf225336d095888879953c4543a47ca57", + "0x2bc5a052f0832c656a03210175d28fdd0109676e5cd6daf08614b6d9380e0156", + "0xfbea1e39f1d77d1cab4b111962e1b0bc8580fa4d353efe89b95d1ff5f9d249ce", + "0x4e3c512ca97b1d6dc6ad8f0c17e336aadb740ac907924ca6e037c3820d484a90", + "0x26e3d31503539f6fb1220ec960fa450ba15db330a82b97584f48af03e71d3fe7", + "0x37c3e1d006c31c06526b0c02df45329ce4ecbae209231a2222dd835ead7bd813", + "0x9eec04ec09974b5bcea99b021c6fca264f32b3ac895dda421482b865e9d0c340", + "0xa7a9d9fee641431f2b2f217a57a32ec61f03a1c692304768d58d48ee1c7411c6", + "0x87a5638751fc6b716bc25e92292a977f0de1b5f53fabc89b342a3f8c096e509d", + "0x084dfd89d9e63f625d7bc139a9584182937321d0a5e2b61e280cfcce053813db", + "0x30b73b647de41f3e753770f967615d695df8b77fc0e1f770d9cfd8a8b7bfc1cf", + "0x8b05b1906879d64f6534f7231ae5aef00d86c62915537ee54956b2cadccd9c7f", + "0xf1c883baf6073d2244d5b1a40b7e7ab99a22252e6ed34627fdca985ab87d94cd", + "0xb6c207b47b98f0b550eec7dafb5e6bb23a4f1061055542bc1805b6e89dfe763f", + "0xb5a37524abfd343f821cef4a3d6c66d5343bb56dbb4f5217f7c32b888d72c3fe", + "0x326124edc233211d1dec747ca38045125b3891938e8b449b0980be57fab79a26", + "0x4857dc3260a16bba60639a37fe309f46351d2bdc15c1689b6b86c16ee8b4d2b0", + "0x6728195d486a624099eee5c9b07ff62cb8abc7a66aa7f2aa3cbc565ee614a17f", + "0x0a7ac687337258206323a3c49d88ad4ed495e9a18c848a3d8ff51be0eebfaf68", + "0xe0c1882697acb508290737788cfab9880ed09469e4093f6c95e7282f4bdae4cd", + "0x80f763c0e43b60aad58f01aac1275f310b3cde5e3e8f2fb47dc6587b4a5b21c3", + "0xf7b62180b642b826340dd1f69477a136146d341983e4bd875823d804ba205c94", + "0x6e775aba73a0596d398c5ccb9d0adb8d6236cd7dc235e833e69a0a2a369d225f", + "0xa3c65ff864601acedf9ebea681039ae9d19b961b84c39c40561c2ab42b9956dc", + "0x5f5dd206d841a2a0a85186e2dff2f7d862e47e1bc11fdf0c883412643cff72d2", + "0x39df5dbc5ebeb3d6e94e02e90f987070d9f73060e3751cb5fb6c00d737d53a24", + "0xf3a78e92493d0fdf6430671c820949fc39729a366b8b3355634522bccc6fc7fa", + "0xd12bf11fcd9ad2026a340671edf4e0fcdc6d107f338b5e8cd1e110ce8b2b1f97", + "0xf69a0ce968327b516a50bbad9d035e3eaf78e501c11807516ffbe6d847103c12", + "0xbdbe28bf74fbfc5eedbd363cf4cc2792e948ffd66df8006372396ab2b901d9b7", + "0x10fed02d557ad1ba3794d9e97efaa8bf7d6ec86b08c04c1a3c63e099ac3c6fdc", + "0x0735058d7226f806a87f80fe5a55bc6756c96da1fb92b058c08bb2dc6356f4a2", + "0x9c63cf37aa1e235f4fde0cf88c13c3e87396646136de26757dfce9373bbad078", + "0x54105bc5dae2cfc5860308caa5efddaf6d6fa16b6506900851bf8d9311d85945", + "0x26a920994c14e7ca38d62bbecc09c4885acd455160910ad3b778338fe08dba20", + "0xb7d2bd9ec2f0c1824ed85476d70eb3ae85c132545b09b5a3fc89bb647db61c29", + "0x44f8a25051ce2d5c3b6edd22364657af990fd2b327acdd258bd818dcea5d8f10", + "0xc504b1cc18b99305f83cfb82a9452ef1b6650acc7a7513771a9f1b9c4d258894", + "0xae14ce142031a2a1500aefe7d5bb5f2c48fef2d40bcb3cebc4465b5f588dec0d", + "0x26a6a67c3642f7b63505fba8bc8f4f2db35875820853a7e93b7015cb59ad5288", + "0xef2cebfed16dc3ec1ed7adf4d31a907b1c48986f3bc678f0e0d42260f3e5366d", + "0xcde8bd5a558e4b4aca53d0d164ab030a9206e0a3dc3d52750454cd5dbde67a87", + "0x80213b7c8404bcb599c6acd3d0c7b97c821f9eb36d1a261c7d59c66aaf783557", + "0x84974ac71d8599e8b481f4ef1ddd2365540c97d8a14bc55b036477b8b930a1b0", + "0x22d700ec6faf569754dace5bd720287156b44a7c647338568df8316e4a3a1590", + "0x0f174bb7672e56e087429fc4ada9fdfd4dea9f94abd976a2d9c1b3b2103883d8", + "0xa31dce1e1597f2603aba9b84f545c56947496b648b770ee9bee76b26b076ed0a", + "0x3bcdc44880d4cf88f9d3a107bb254607cd799cab841346ea3dd2e10dc461947e", + "0x54d99c8c46ffb8d4a6c2453cb2ef92abbea6cf8d666f627afcb1f7383e248c9b", + "0x4bad0aac0f99bbe49041b0d7b7da2d0b379cd9a1a4e845f04ee6c399020062f4", + "0xadb0bb1b69fb15d78f835ef5d2de20273faef16889952c0578d3be609573ad68", + "0x04adca8a68fa1db84b226f2e46d3328be74cb9596e037d9e2bc612e5bfa0910a", + "0x9630ded627a97f9641e9606a5ea8eb5e04e0a7e52dea484b2498049e26a596c9", + "0x146544215d83359045dd52eb7821325178f25f950585174c97ce6431e84c432b", + "0x743b7f7b7e0e4bd94ce1cf7fd26a42fe3e60946b46f12094336624b22799abfa", + "0xbe5842fcf8d27fd42b2dd344f4fa80a5ec75576ab0d3bf7df076d2c62c87ee63", + "0x0913189b9ea0086155d331989622986163ceb9d8df937b013466350d5b6cb9f0", + "0x179863d8ee06cc5012fde594f93fabd674cd718e529214acf0855ba7920e0e5d", + "0xaba24275c0e3fc84593d75c0ed0ef64562b2ca29a63c9651ce2972f466f588c6", + "0x59953a3a63270197712f70bc8c1f3fbb974f3373967c76c6ecb05b36624c4e9e", + "0xb03b28ea463ee70e33fe1431556e4186a773476100a61200a72dae7b5a917400", + "0xbe29685ad0f0e4f4e06f7aef6ac68716345a503096669c02f9a4cf2645b20fb4", + "0x77349196f4b655fdf90ac091bf217cb4afc46efd8b3738438fafea3ec8bf6afa", + "0xe0f3c1b6b1f9a822f765a8657ba73b6dac6856b86d73aee29ac8c67870cb5d49", + "0x1e9967c1aa6cae9e6d6ce588cc7be4458e30f004f07f0886bcea9f1894409541", + "0x48e90887d177e254c035c4e6341e43e2fd4b69934f357ef0633a4876af886ba2", + "0x18b962c2749d6fcc59615c7fe48242c4593b18d9c777bc8929f663bb2e500a62", + "0x437628a508e2589d87073ae2cce6867feceab7ed948913a5f367aba70ac752d8", + "0xc76db66e84e99a50d9d43255bd34937dd98666850f01c7abb61a59c61c48a51e", + "0x9c97b43a11c959976be2dfa43d3e427c81c9f65f0cec38a30174753911a0aa62", + "0xe7a8db25a547dc1ec612c3270d98ecc5d358edf0093e9a47f97bc162e2563c56", + "0xf8e9f99e26b147e30bd22a71a02c2e87a4f816947b23be23d7a998bab0bf42e3", + "0x9cc232de33ef4d9c2701403ee75627560a4a290ec00e9fe2bc3e48d22729e4f6", + "0x83b328313a8256d67a76a199607871c9d7d91ac4bba03e4c7eed2850b863f014", + "0xf785f6f42d160759627f956c381c0b2afe133191361126e1dfdcef8ef96a19b6", + "0xba15c02abdb13795b7ffbd05ae808df3ba6dd49d3f6bdbb7594301fdcdafefce", + "0x7cf481f442daaf09047af092254ea96b3e6fceff47e7354dca59ce92a7f0192f", + "0xaa09cc16199e82bf7ca1c664df1683dd68f60392383aa86f7a4d70db4fcc9ae5", + "0xf48584eb70849f03500c2992ca9d8a25c6b4af1dc6b267bf96b8daa844653671", + "0xaaea21fc3ffc8af49d5b6c8ff06d212fd5cecdcf1ee8bbbf11081b610e5efd56", + "0xc3b611e4a4769a4cd86fb97594b05eeaa1438a531661d0c46498ad1d5ff0533b", + "0x86ed5238ab44b097b901bbf7a2f76c4e554227377fd05cbde62ad678b9b40521", + "0xcecc96f7e1da3a85044251681174c283cdf818549338d0ac8c55ac32941c4c52", + "0x8e476a409ebebb50a6b4ea63a57fb97a94325048b98e9038155f44cad234c5b3", + "0xb0cdd01f69adb4482f4a95869c27e7f488b8d645e9da2a1eed7c50db91bddef4", + "0xd59c2ef502068560309402eeafba81b6104e4481d08d294fec8f4a14ebe421f8", + "0x117637dcdf602facd5ba4ebfb788cc6e894172a41ccd461371fb6dc3b29ed1e3", + "0x2088af0cc8a2d219cea2658be188bce545e095d526152531ae04a0c1026e15f7", + "0xbe9d09c236fc2464f9e96468304cb107c1015618c0777414048260ecf3073a80", + "0x0e21d49b429787ecc39920a7b1e57bbef8b54f6dff555afa96c6d664eba18002", + "0xe93a96a4f59c51c991822d4ee0ce843f194df8ef1df1aaa3b15ffd4a3deb2902", + "0xfe432910348f2ae69089ab89571297f755f70d9e52918b761b7cf059bc8fbfcd", + "0x7589450a89b93dd85dda9fad10249d5662653eeb34135a8c5dcfeee2723e714e", + "0xdbcbd8f60a88aec563061478b12c5ab4ceabe1deb3f2df53fd862fd6742c69ac", + "0x4c77ea8aa197a0446c2c85bac546f8eeb7bbce07abb092450f11bb3fb6410575", + "0x465ecdf71fee3c0e42f2dbddafa3cbfb53f4c9a886777cf13dc55064dd29b07b", + "0xd220779d8eba431d33a23b369241b357b399875205cc432069b445426d7a3099", + "0xc6b84a981cf211d41e16ad44b1e90fdcb71a92230c9ac679874f0cecaeb25254", + "0x31841dbf1cfba19ac78cd40136a8ed9f35a77d48fc927e049d58d62b3ff7592e", + "0x0dc4eef3839d33dd5a516a3d4227a3ce23a9a5532d146f37dee88898ee75e7f9", + "0x6859f52e3c1ceab008c2fd85fba4901d7543c99ce5aaf36ccd6534f4898894e6", + "0xd16539f006277c2a3dcd96d3f7e9fac7d5bb0d63afb1d208960e597ce29ac429", + "0xe0ef33cdd414f24ac2e67ab2329d3d728f3924c50032857e57dcc9999e37a182", + "0xf50b311a95bb72916c6d4dad0db9779144a85915a12f895829ca5de9d697fa52", + "0x3f773b516c1779a4c5cec58f6e3a0c1bbbefb939db70bd84ea4370548df29c06", + "0xa3348605b4ee98db29b6bf80eb8181f4200d691e27345732cdcdd09c395f0256", + "0x4f2970a9d6dac5eaabfbb17a916bef4571e1147ffb5e241360c6941ec5628815", + "0x1b7f448f52b39279d47b572e55bfbcf893e7d106436a46db2a0ecd888d7806c2", + "0x89196aa22dbf319c88fadac3c051c445c6d59eb60a62ee71158e4893bdff8706", + "0x1ecc71d15d386ece87caaab915d0a10ad763cdd38bdac269108e17da3183d0ec", + "0x99b80ec779eb253869cc4351371ac8f1896016de0c501271a0a15bc4130f40e0", + "0x09d601e2ef7b509d5343a8b6de63d70f99a453540138d0596b80e2f39212fe4d", + "0x2e0412de93ff148a1365719ef562f54addcfaffa64a630d2bebbe48275377d14", + "0xfcde011b08437d8db6c4e8661b98ec829e204729badd675782a7792648a32c40", + "0x075e3439595f2e5953419638c391ad68d634da037df91cd75ab062f5635232a0", + "0xe1c770b2b8f17b25736880a7d28e09845626879f61fa7bae77202178d26e2db4", + "0x10eb4649692dc022f7542da5156c8005f2a9d6c4b0ac81b5ef087bd989a83534", + "0x612745b3b43e42cb44d302016ab33eeb1924b8ed1a1bc4ea86985d88184a1704", + "0xbc23be71d7cc509307ebd055d02e396e867e74ff401583b5801546b12cfbce30", + "0x55be4d6f914bf5041a111b949ba61807b53707ad6aaaecb347e9bd53251cfc98", + "0x6207ddddfa073ecbeac270e0490bd4f1b126e25523350e45713f8f76074035ea", + "0x7c2806322ae925abe44606def3a91a9546ce5557e61517d22c94a6eb358aeea8", + "0x2660eb9fe82891120afbbf8d17c3a0c6e71a7373bdc961b398fb3924d769534c", + "0x8e94fda030985bee8161a349c74a10715ab29b4c404c4200332a124f8e6c8eb6", + "0x77c264bbd45e806388df32d1d30b7567af8463c310b2e00ac075f202594df289", + "0x11307dbd441966c22a78712e8026ef0be95c009a075b1d75881f45a9547c9469", + "0xd487cb10ea6f81c67836eefb9cf326cb01464b8a4c640359da0ffd0dfb5ddfab", + "0x32e5ceb716c69e4aa115de40404f0406841a43b9d1a7503629edfd830b8070c4", + "0xfc69abcbaaac051ad68462b2b6fb289f093cc8f965a31e4914fc1c3ecca0a62a", + "0xdb2c7749b7f5e8e60861730a3f39531c9fae68bc6d5cfd884b054b14ddfea8a3", + "0xa641637ef64ad91eaa7cb24851870874c04c74e3c57825cc00bcfca56cd671d5", + "0x6e55a7184ed79701a582293b72c847df32be67859a34cb73d1efddcf92c7f1ae", + "0x0d30de75a74723ccaf326a096048686a6236a5d9728e398b531ea34a20273e35", + "0xaf9e881b47ab25b2b667a9232cf562ddb07d30194f6a3358cd6aacc414e98f3a", + "0xbda5685b8567d1c43530fca95e4c671d4f090e50d0ae631eb7082f260036d5d9", + "0x21fe5a7e105e0e2f68698e20f88a9662bceb20bfcc884d493cfbed72fc78ae8a", + "0x1b45a77d8ce14a769f196ac4a195207a63241ac8c8ee42e17c3e0b340b1c1492", + "0xf8fc91a39b6e08d874500e240a6abea002794f104592d18ea01449589b06dc22", + "0x45d9330d6eecf2eaca322e83df77277c76f9a95b99c5fddd55bd77697cd1159d", + "0xbbd726c3aedf917c4741952ee3a21d3c1655aa27cdd98f44d15dddeda185c520", + "0xbce90dfdf79213f5e6c69adfd7efeabe74edd6e2f07a1af7324cea9d70615386", + "0xe50e0dbb2106fa5433506694325d6ebdfdf5270c17bfd255bf3e5e7c0177015f", + "0x22ff7ec5117adf2f0aae8532dd371ad9d902a69babe3b26cfce4a324854092a9", + "0x638b7c73e85e4aa5074daf2daf66c002c00de5e8196c2c01e6945d7aef6661a2", + "0x322d5f71ce4a0e743ce017f6ce76944023e858109a0c36fbab41c796b6f9c8ba", + "0xb55e7340a551bc76ec89ff3ce1c7bda807c75b6a89f0e97ff4a4ea59d232e91b", + "0xe7084bc046f4975a04be1ae50f4e46e69b7d0a3a3886e60f989ebac4a7d3ccd8", + "0xc540174cecd421363ed6b4a95fc554f0ed0a7e4622cb2c0643555eaddebf287a", + "0x03e84b7ce420aa276d9adce1da92c950688839cdd3dd621f797eba5b6986b3f8", + "0xb75090e43bc5790bdfc86a5c9eac4384d099daef3d40e9fde443409f4efe91ca", + "0x7e72b4a7ece28fef076331bac790e49ebf926423f2414c9cd78788c8cca28761", + "0x9b9b702deaa509fface95de5048fb864b80d7891fabdc7a9770af1b24777f5dc", + "0x1b056b381e1c60a3c126f2e5c4ed98252755a5d3b7f3528584dfd128eedfc89f", + "0x8711c4892f49f2c1fb0739de8eaf08ae8c8c279ec73e42fb4da5b25f22d73fc6", + "0x70ae1c1cd310003a4b4e36dfb0dc7351b6f49aafa2cfb5d691fb59a724fbd387", + "0x796d8689110932ef6582af180818bd11bb9df2b06ab1107879612dccc190c334", + "0x58ba45b6ff40da3f3b76da55a0ea9ca63aa135ce308c5d262886e6b1e8869621", + "0x8c2a83da544b209010c6b52618c3137c1066e4fec0e1731d6be408ee881d5844", + "0x1591af374ba5612ece1d642e9bd280a9318c5bda73ed67bc1e7d65ef5616cf6e", + "0x666b3f1a401843af2bfde18ce659965b5c200972da47752fc2b4bfce55625af8", + "0x23331ecfd36f8dc53c388ec3d97a1f364a55b8d701389fd56b867a828eedd187", + "0xd995e1e27b596233e33acabfe03adfeed6d34b421b16d5700fa4b3c234b91ef9", + "0x819d8d3a0471a292c89d0093c3458d12bf83b60394f8c03053bdde51cc08b217", + "0xca27ca64436b71096f37d6e0442a9a93097029d5f4b6d042e2a6bdb3edf94103", + "0x65d5ed59626e98c2bbd6350e4a10e3e45d7479eb2cb6538c5e020fbcb900fef9", + "0x812b423882226db0bfcf2bcb9f1bac80eec3388755dbcf6b613c9f6faf1517ff", + "0x000182526c28c1fb862e74300fa89181cb137a39dcc02fea67bd3a03900fdf4a", + "0x1cfc60d220c883c273603f885193858926f072d3e0094a337d12268007644d5d", + "0x453d43c8dfc8df47751045173fe9e5d200fff28042282d67c0ca9230728329be", + "0x591091aad61a44c41c91b9ddbd1b6159fc9eec6e9c5839c6a0252dfa11436e08", + "0x464a2b049caf36d77652c2d721850d1f8db2fa70ca0964c7f020152612bea380", + "0x8ba06aad1a433193692ffeba643a481e2932f8a2ac35ebeb04c9ff81866d294f", + "0x4d915cf4c14d518463805c6bc92edbec4e8e8689e141c542d743c40640559bab", + "0x0e72daf5ad4857e563921671bcc26eb186f37b9f9d44655341311a6b529200ed", + "0x07ee736bd010d419da4e5c37ed17cf5739a56a78947b4257264acea62b5d6334", + "0xfa03e571d821780ce501373b529ca3de36a53f58e197d64b57f0941288487734", + "0x3293babf49116d584283c915c0c8a26f9c696eff261e74d107dff21e8b2d08ac", + "0xb2f169d84ee6d4ba54b1d526282ab04b7539f216e62362fb20a569f129d2f89f", + "0xdfbdf7d63f67a6986a6c5f9ea2b49d375147b224dc1e489a45fd7731230038cb", + "0x827d46b120f6b1501977fd5ad96fd96090fda549d59922d8607c90ada10ec8c0", + "0x8e15c4714f44297868b988e72b2326eec72e148a849cd39c0447862a9f34fc9a", + "0x311aaecf73140d37dc35479828c96923690265c3591fca9b01b8cad0aa411f23", + "0x47de3df6c970ea79568dc7b2c65cdf8bb630d427d67ec9552cdc928b749a113e", + "0x72e70bd58cd9fe64b27016ea29637bc6d5f13507a803431a14465cdf371dd9f4", + "0x46367ab41a9815df566c20f6f0223ddfec61f02e087e5498402688770739f94e", + "0xf3238ded6fc3b6f389a84766a8ee6663f26a54c077b49ceab1661bd08b4a37af", + "0x0770db8ba56663e8590afb552b42e4db3748e44ff33cf19c483c2bd5cab61742", + "0xe88be10da232234c33a267b9b534417385bd21f9d670fdc0b3e73ad155871ec4", + "0x725cd4f97cd34753d7c39a5a072d2de361f41a4489720a99974df1b821e576ac", + "0x10778832a2f1bfb25ce014c78a2aadddfa245e5e539719fad270cbbed5958e55", + "0x4467fe919d607e0dfd78119a648aae22fc56e508eb68052ad1c9bae0d7c5a2e0", + "0xedcb7a0986dd70d8fed81c4a50c864bc3086a3b34ddaf437be7f445f454d7c88", + "0xb278f42c1518ba3b6d6aec679936d2130915f02f8002f8563b855d7cb3b79ff6", + "0xaa4b012061ef7e6073c95147a118266c6d3417ccd0133eb57d7fdb7b1ba3a5c4", + "0xaa263496af99304030953d11d771ae5e337bcc24050e9c944c9e89650f6ae256", + "0x3f99f4bb34f441ea82655d5ac40ae0a307c6ea000ae1a2eeb2709ffc0c624362", + "0xeedc934109c18a446c42cf36bb5d0b9755b439eb62c18c7d334c13c38d379707", + "0x663b6e16d36687a79cb14792580fd32a7c35bd15df6e6fd36bb498ca12b98b93", + "0xa4c2d103e57cc53f50c63066fb7802b6d77c474ef603e6e6b8ecd759c8161737", + "0x3d381365e830f7fcefa8a466f348f5be81a3dd5c72d918501881244417c67594", + "0xe3ee1ee45c13527eada86f390f69d112b97bb0bd20b40e609ac6be9dee116de4", + "0x9479836ff23cafc57b92900c5349180e90afc75571ec738021dff05f9e2681e3", + "0x7ec50e215e840a94aea029294fd6a48d27905886e53a1239699558631661dfd2", + "0x8c58dc1ee71c06c9a94d5fd15aa8fa4f7d90c8bc8d0eaab7d8d0bb2baa9ae4e5", + "0x017a3cf0c797ceedf53dec3cd522ffd6ad4f10ebf709b20dfe669ba1fe0a3287", + "0xe733cb71d8dca2d6e3c71d9cfdf792c8a6fd242af91fb17bf599eea1b6b75cfd", + "0x6e820e5269a6b6fb9e9c2f477cf796078a3c2edfb7ac8b99150d6660ffd22f0f", + "0xbf1d3b3dae3b10422e2c354533f8bd504b1f5852c942618a0f6b415c3b162175", + "0x12fc9bd3a29e5ceae601c6a4e7c92bfe6b22684cc1f828dbd2127ea56e1aa300", + "0xc19e28d20c121a0345d89b097acbb6c15d97253895d06b8dec219f11f84159a5", + "0x73f03ac8b09a769db2a30f44b77d4d5dd6d61fa97afebe6795acc9c5c10cd7a5", + "0xa92cac86cf8bfc4fda37a94e5f55763840084dabe413f2432c4b50ddcd3523b7", + "0xf7eb6d87cdbb534507ca9ce4cc42a03eb843d608d6e2bb42c79bde78d0dd05b9", + "0x3bffe93f111e1883a29b897fc4b33c50f32db2470d819316577bc38e1a5ed179", + "0xe44f4633ce949bd8312b23178b6ff0e3d72b30dabc546ed5b5f2dd97b490be38", + "0x5e6dd4f45c09aebeff5c87b5e8c3b7b77ce4991f230dc7f0dc62f460e684f371", + "0xf1e0440dc83803d73ae9a3bb6454a824194bf9ce4670adc598ee97d1e150dbe8", + "0xef43649067273a56948dcae0271f9a336067610769b2ca4553eb7bd891ff6731", + "0xd9bf0ef6e8c057bea8046402e5bdf0977eb34bfbfc9f14a37576a8ba09232dae", + "0x38196dcd11fd1c406b5201be0286eed3a94a263a1990b66272c9b8764a5f2f43", + "0xa7e55d25456b2cb9541239879d751e489adfc4c0e232445a9232f4462aa17294", + "0x379ea9b1194e78792ddb00740e0c87585ab9a1060e6a2239fa6c5a9130a2a490", + "0xea0d1449333060d955f4dbbd0c0e70593489585465b37202cb4936164296addd", + "0xac2adc5be7eae9e0a63b5758c964ed5b203f37309d92ffb1d22aaae041fd9f0b", + "0x37be79f2f0ebbd92f82502d12dfe42f98f2e75517f444a295426b6829a6b0739", + "0x51a86fba7b41a59b84cc56d264f5d6d83a40f233f7d316c143c29bf424fbf6d3", + "0x248215d9d66288e4c2ee0c182abece81ffdeabea2b16eb986c14d10d69ae4efe", + "0xd8affec4833fd827b2ec6d4c1905e8cc3266e8a825a7502b59585fe7d5ee653c", + "0x00cdc19f0fa69766a3aeae1dd17cd9f61afe15ef6128a957f72fb3cec4cdc02d", + "0x8c8b43d75591539f17fd442b604a58763abbf17a408958ca181c3593dcf0afe6", + "0x055f6cd0e80234feb885657182cd2fc44fea12c6041d20cad8d257f2b4f16319", + "0x487a48fce29c08736e352e4217ba5714f361f02fb8500ce6a2e9ece79b1ac783", + "0x807974b9c1da9879f8967e7dfe02e8e3fa23d08526963c8b22688ef10de36374", + "0x080fcd507842ea3176b14ca52d844df2f9796b4f1281f7d03180c0461d28b801", + "0x95e5e32410daebb3a023678845b2e1fb9097161681c150450c7b76fb8c5c1311", + "0x420611006cd3a391071c6fa22e82d836b5db225fc266b99e126934d5fdf4ac84", + "0x4bcb71688e5ac4271354485f2a28a3c63d67e028183db2a16b15dd718bb89762", + "0xd428d57137d70ec31c6299ed366f69057d9bf93ad06e62332db04db5c3cb425a", + "0xa384c72f5ac5864dca1aef91fb19d3233e4ae3333d68bb320a583f532cd7766e", + "0x9df6e7ec6a1f455ade59bf1cebf6ae1ffb94d1b05249c35964aece90f2ec9f80", + "0xe53ec67b4d7c04b2c7cc7abd797d6a7c8b759b24c8389d103222f3fc83ade921", + "0xf6031d3cc54fe050642891cb57466ad51e0e8f24a8ac52d592e531b0fb87c971", + "0x842c6b20d8a93c3b23e679094fa903feee295c933c9092ca444bb12f966dd650", + "0x38b30dce467bc4347f65f7c7cc4c8a17f58d58b1779e302954fea9e061bb16d4", + "0xe23303957fac2f117e5749e48e11842d6f5a03e97acefb4667630d281351da5a", + "0x47a9c1072f12cf0f42d209cdd33ec885e6e21d13587cd8f75eeb1f879ab55f05", + "0xaed88507af6c779fdce8b5afe124a51528828e734744d8c12cc289c21d7eaa47", + "0x1b6146a607cdc5dac7cc1a88f260ccc2f5883c8a95665b2c9761d9a119b09009", + "0x6ed83952b5bc9b18ea070cddbcca46e42d1f4419c17a51a2dbbe47a0fe7df731", + "0x7544a913c1e6bebe68a6c04dc903860e5e6fb66d4845dd0d98b3ff4e5c33e3ea", + "0xfb6eea6e7399be0c2673dda0ab64a6802d6b2eef1550341d894f1f4146ce9270", + "0xddb39bcae9dc685e7bee0757743f2dd67b56d26247931f4f184f9e8f0f603f28", + "0x363c1bca93f3ff58a48f7d233bf4617769da4774faef4154abc84a99f39c05d0", + "0xd3a56170fd60ab7c75b33943a5f56ec935471b45e9b31825da160498eeee4c69", + "0x347834e86b3ae5fba9a7873e36bd780317cbf7649c8c01875dce04db8e97f450", + "0xe2295dc1850609e564a072b4592b62ec6a0781477d929c9293e65ec494ff027c", + "0x4ecca654f4c6f701c975301f051efc05e9adf0e908fba6dbeec42dc99ea0c2f1", + "0x6b2662a790d931d1f22062a5dd2518b30d980c84d3bf5b69ff0182aaabb124cf", + "0xcf838b75182078fdd33855bec6cd789f0d4975edc3387aa04246cc73f423da0d", + "0x791a7252fa21bf3183b621d65d6a7b584ce1de93a05da8e44a52572fb72a4b4f", + "0x82cbedcb5b48e87ed79935f8a2f93fa5367c32fb14de3ffd2e8947fc8a61fd76", + "0x84a1a28a08d0b6cf71128636355ea3a045d564cacdf67fc29868deb32ba0df3b", + "0xf97f154b9d62135748f94d714ed0b87012584d784df893ad581c36b5b04ef2f5", + "0xc03cec8562c67e6bbf59f97590560141778f5a265b314a6213c440f5703db388", + "0x50735a0e040ca5596ded470e5068b9b7d93676d8f3d181edfc26b5a52981cf0f", + "0xbbb1b6b1366bef92cc978ce644cfcb951ed00d7969e7d89b77bf2de745210797", + "0x116d30e2696ee09337bf9e1a78ab4d8e2cee7c53505afe2b8f027cdeb34640cd", + "0x294855f629441397876e7a0649a1e5ec1cc3ae8f425c24be34ca45e005bcc3ae", + "0xe54763eb5c965fc0c6ff3e975802f9a5049fc3404fe790c31df8a3dd5b366a24", + "0x0413d30f913089871fa15d643ec78f2503d13d025d2b73a6b1a879a910da2ec1", + "0xa430e9153e8e0d9fbb50f0764a0b70e5add25fbd6d5d29bafa77ee93c483e4fd", + "0xa4c61e3928031abbc4b02a892f19706a313bbdfd5bb413eaf852ce84005f186c", + "0x4e242ca7106cf988584cc61bba6e2185f6b6c377a2c4db291e6a801a5b66e1d3", + "0x23b37072cd63dfe8ae9b84b9bb74130a90bd603a5b992ce78b6e2c068ef35b43", + "0xef7e50ea520ca6a595541606ad895beb80bd06cb68984572396e1ea0ceb2428e", + "0x29e48294e6dfc86bea2bf76ee9daa816a59840ad1c0878d77cca43a67a217891", + "0x419809205842b124efb16d84b5defd6985b3c774fb6bd443f1ef72a2801fffa9", + "0xb25461244545d4b6f9c1c846dd09dbf25459d6492b1209814f22a3323ba74832", + "0xee26501773c29c20a4e860047ce14e4af4f6234736e1156002ddfceadde41c79", + "0x3705a24875542eb6b893c0b48266b141af1b5eac2826e88ca4645cff47a75400", + "0xeeb8999c6eff73cee7ae33ddc065e3b3857f213e80a94d832693356f0bddf504", + "0xcddca06cab74354633b9fa50fcd22c838a9d69a129fbb3c17dd0008df9b23524", + "0xfdb23fdaaf80f26f0e95aee174446f7e7182283d652a332ec075d86f6f3f8730", + "0xb3cf34c2dde0952c0d46633ec3e4fca78a3ee8242f2b46b4fc4444afac7d611e", + "0x2d9485c467207fc78b2de05decaffb155b01446050b7a6679923181dc05a646f", + "0x508eb22f40e6e60ecefdde86c50c81f9e73253ca0658a63ffee65f6fa39d898f", + "0x4af2ccccefa90b3028576e09f522bb667a428560f8c94cb159477313b551e384", + "0xd85f3073e44e61bc52696ff86194679a1ebc3e7dce62805c8b03372e03dbafa8", + "0x86ed94dbc666a541088ec977764bc543ae892d73feb39b0b09dd47664768a53d", + "0x36934b9186a56e71ed0c0f51331a99b3f16f07d5b50a1b770fd0ad91562bd0c1", + "0xebe80ebae860665714be6e5b9e8e7cd5608c8b4466453a15ca2fdf5d21b193eb", + "0xcbdccd3919f1b52732a89ff592a6f1dc34da53f5dc409cfec7fc01ef1f61cfd8", + "0xac2a1fc08c3d4b20db35ed4f879921df5e61a6596e655dfb2c6d5ec916ad6bde", + "0x4e072a9ed4432b5f205808f79515fa1d023cf0e6c2137a2a8876b5aaebee28b5", + "0x096aaf5a90b5e6ed00510bb1af1c475c32fd3de2c800b281d2558c20c0288e08", + "0x0f60a5da86c795d88bc025909c8f4c9484ea6489e900c4070d851e91f27afbe5", + "0xc6532945ae1b3fe27002f5d035eff11c62f6b1e9866f23c52af52cdfc8c19c2e", + "0x7404e33f0864651428778f7a39fdaf11a236c8a68a30674d619546518c380928", + "0xc44a5ea175a1d64b02326e7e49782968d9f808a7854c1e338314766bd96b95d0", + "0x435c5d7e5f41b84a55a11606992a4d8ec543cb5062b46f897954035755f9c9ba", + "0x854e9945fb93e485d4da05069f354093750e8eae98a4ef140a4018f3baacd246", + "0xd9e43cac6d5ec4f110baa3c940c5cf35125ab44a102a621e78d824f1abfacde3", + "0x99e780c379a3a94186a99ce600fe88963e58d61d851c6437f7a5ec3c2a4cf6fa", + "0x32786b25ba696ca57c302d136bb7453a5dfc065fcd17e8c38a47a3806e8d4990", + "0xe4d0e757ec64fc8f485839bd34c5caa72ad0f33405fdea6fe437280b427ee6b1", + "0x65e36e757ffb5386f130d783da437e3c7eba37e80ecb8e3017fa6753cef1753b", + "0x3b5be8acf141f95673e207a7c4df7c81fe88767ade0f785f5165c7f03e284008", + "0x988ccc28f0fe0f667ccab304d7cd0d56354419ef8b7149099d1515aa384a0ab2", + "0xeb198fa97ce093081073e2f6d531df421a9692d086387221f215677e9626c6f0", + "0xd6b98b2c6ffbf467dfd0a6365ccc478aefdd8872cfff6f8176023be4ac1d00bc", + "0xa14078605f856243d5195898a5f1e91878bd5ce04458d2a64b0a6ea7f608a18f", + "0x9ccc3a6730ffaa7488c75a31772c956f911eb7002fc245d803e2ca8d45810a13", + "0xc220e09c2646b44edbc09b43748855653861e2211eadc84e7a9cf9b233c85483", + "0x64ffdfad8e5becd8a87aa11a5feec484fa9bf13ea9e73beb7d92e396589a4f93", + "0x791b62a9fec44f975f11e5e5ee56ca70202d0de728eb6a7acd7c40cdeabf0088", + "0xe0359eae31308bf682f09147977b20f40425ae465fddea0515c89a75cd569305", + "0x16199dc2b3e744a4928b767467d02053576f98a5963a9c123dc760c0e4944987", + "0xbb0a149368f44e9b033245d758f1d906d061bd7b226adc1ddffb9f6118e85339", + "0xc600086572f4ecef9f3388a1fc242b099807e61463a934a42dd6bb683193b8d5", + "0x5adca1ea45a4113c166eb85779efc6836c072293e47d2c746b73b2956237b05f", + "0x0bc8f8aa233108727de0e439264f9220a6d5f085112521868c10934dd4100f7c", + "0xeb9edb2bfc6d973c762e283348290da7f3ea45ac449a521e0b3bc41e818aa702", + "0x4684a177b066091979171a6d0ad0a3eab2e7fb19c1bd173786d2db8b1795e49b", + "0xc877565ea3cee7cc08aef811c986cb58d31358c5bc1595bf8f41da9d2b6833df", + "0xe56178ad5772adca0b3f5eebdaa03af33df4451e2797892d12ccc98caee4f401", + "0x3f02d423f1769519c746b6ff632ecc88f6c6161300579c05b704353a13225814", + "0xc2cb58c5152a16f20d9489af5c259483e46ea76f76778947dadf653fb17703cd", + "0x9598d6265c31d75e15323b7125eedb124361b08f1e695e573b4743a3b54bf137", + "0xd401867574d59042a58837137cae986c1ccf45051165816a28f77274d78e6e1c", + "0xd5bd34c381e34dc538839a4a20a5de9e5c87d944f05f889a6c0bf0abf39b583d", + "0x5802fa750e2a8b4ace972d927c4fee3db2c1c3e12f52a20bcc17a04d1f15b01b", + "0x9b13a2989252a0e796ee57e61889ca55bfcfa49d9285ec859e20ddbc8ae59f57", + "0x134da834b7cc2f81f2582366d270d566dd95fa1ad867c795fedc1d74f1dd78c0", + "0x3cc3ddced0ac6b0833ff5bc9763e5323c375a6c32d588b53b98c7e30b2660c05", + "0x8f79d40ed56567479f2510c4e1e81edaee9eb15c3fab934bbfb6c19583032f45", + "0x423e59300c8a57adb8a20cf17b6686238d3d24ed6b0887573539772d209c03f8", + "0xfb633f9f16d9d9f3889495193d5d5250c533b2d2feacfa8b77a598bd1573e59c", + "0x1a2c990aac12d4e85479edd998b7cd84419e64e1d64b71b6e5de354ac220aa5e", + "0x7d37124ba47aed15bd9f12aba6eb1e4ba760965cdb0b0b8049a2dd1a4590bd0d", + "0x5305defebd2a61fee315fbd92c33a971f901310a837b78a89132a3e6757d9ad5", + "0x90c9890e4e15d5285b15596d61471c5e699222bcab2c40d613a20b1e4d0a448a", + "0xa9f12a1a2b93a8f62ce5c31eafeaabd0f3053ca10382048f5493e2f4a3def390", + "0xd32998eb20d224ebfa0f2c87c23cf9cf707dea92f12dbb5c1cce2ee1ef010573", + "0x58259819f210344220294ce925298a770d4b945f69bf6e310d74428943d513a7", + "0x7a7e8cf127d88a93a5ab3e59f9fec2e0a35d9ddbf90396830c37c0a29352099a", + "0x27a39ae87afd6ea727aa75062cf53d35aa420787f0679a9817b15b77c2fd4243", + "0xea8404bc312c47dc19ecfd815780e1fddabed7e1c2268194de2755767f8c6c2b", + "0x2726489dedccf450d85a877501537c51b0037fd7fa3f46150bd5004160c56d24", + "0x1a6752f65e4199b1d7bfa5385a4de60ac0786a0c2276fcd98ec12480ce9ab3f6", + "0x2d6c57ca96d71f4d23b37bfcd63f70c8877afdcd20b9061372c5a9f4f5ec883b", + "0xd7d2d6c6b39a8bd276806810d77303e1fffbc2065f971462d3549b0841bc5159", + "0x72389b3e6dbb07c0cd4ec60f80d67ea24c5997e36457896c7047dba6bd388c0c", + "0xa683c35204e5d8378c5994a2b2cb66ef7cea7f72ce4a014f9de96e270d141f93", + "0xe73c7804f0a92e71739f049cc6d1f4296d6763694ce0f02222cce3a802b95e0c", + "0xe1d2a0db423aae642cf9e0d0a3a0e033ec287d72ad5d6775fb2ca0b754b5ccd1", + "0x2836a91b6f0a5da378fdcb358773b86fe4e2a497b5a8b0c6ea770f8168950cf5", + "0x207c070a56e477b151ac222d7d5582e4233a84f1760561b2c5ec26b6913b5be1", + "0xc6b82e66925ef9ac29b147459a0c7cf6810167b81d5a0d8119409bfde901e5fa", + "0x54f789a01b71afa8ea9a693866109c0fdbed99cbe60e976593a45ecaa2c51d86", + "0x67428f7da1b0ec6712491af063524e25bf846d1bcf1341fb5cd16de664e55253", + "0x9cb30239c73ca41a78aa23de7a5259e5c5320cb742d86e248e800cd4b7842f47", + "0x4ec478de462ba0bb5ee4f2bfcaafb9ee3fd65e2bcc18b39624db625d72ebbdb9", + "0xe9ba31abc5a0305325522cedfd3106cd0994a1be4462264ae630190ea3fd24e9", + "0xa293c713fa4280c0bc8febf0625bb7abe075f875e923cdeea554a48511eb1e57", + "0xa75d09ee8fa14ef49c5dbe05589f169ef70ee94963b7099fe61e4cc8b4c013ab", + "0xf0942330d11fdae546533e347054610329e3ea14b4f219d510f7e6535c9a3ee7", + "0x026d67e672413886db8a70f720b14cfdfb41adb82b7f439d5ba21b589b54e122", + "0xd49061710cb1c459d4a3386b2885cf835e9817d10381382ef8b4212c6d56d4a0", + "0xda04b4d64907968d284ca3072752af0cfc15ef3e5b866a22477bda9b1ad4bcf9", + "0xc3132e5a5899adf1daf3af4215cae7871cace74e8d876f450ebf0fdebe5372da", + "0x5305450d6a19385eec8c77fbf5be40e36551d7febcf1f7ebe6cabf3190e8fd76", + "0xbd7583e3d3d1af3619f54ae1824316f6d23a780647fb2b357db18076e602ae1b", + "0xcd515185622f58e69ad4f90618097d4c81177daad8719f046d3c14d6ce8375c3", + "0x5d518bf18a83f88660fdba41c8996b1e73dedd6cf5f0debd51703edb9e79296e", + "0xae7b3276b47d580f0275b8aeea0ed17f341a455275b5d8c321525a1258629dd5", + "0xf04a5b0379da532ef5a47e391f9db4a0224bd5de6661840ed9fea3b498bb3f69", + "0x617a8557906db76f6fbe284ef9df52298ecf840346589fc51f624b9686d5e218", + "0xc194d85f5a618d76aab6e49f5de491da2f602429dd772f364fe7fdfd3c6f0daf", + "0x6b138060c922aceeb0254e17c3a3548dd3e6904c61a67e058f961e080b3d9ad5", + "0x4de0534ace9c02822d3cf3d81d6dfbfcbd0964114503b56fba7db23b5f2befe9", + "0x06633e9de11b22610b6ef1fc1e8b952252099961f34d71789d8aee0e2f5785b6", + "0x8bfc843363eeb99dae04524455ae4df46ed6e6664edbb640c835305005dad194", + "0xf2f6f86a2e67a269cfdb62df43b9740b42a6eae3f52639acc93e9a8035194628", + "0x1584d00e4fa8d3f0e989f87002f9ff1851351044f99e6194fca52262da38f447", + "0xdc0801def9cf3897fd30f8200f0b6dc4966209e8879f26a7993154b135b4513d", + "0xb1b0fc31bfedf7bfbe445412e84ebdd76c3a09821a4436e72b95ffde019b955d", + "0x3c4e13e63d1bd76e1db089bec2acdc6fe39bbc6588bf4f4af117682aa8a7235f", + "0x2a6bb94e42fc21a26dff4db8004e9043a7a98d6d9583016cecad2baf37b4e882", + "0x7a0981e129e50d8abf6b5a8e0375b8631ca58ef7f9d39a455a4a4913b8951494", + "0x026e94b9b4b3fd407c2c39f8de81e0d0ecbdc0fc82c9ee8675e1a211ab24dc2f", + "0x60b20d6f87e1f3005df1b1bd5fb68ffe20f1fa54f21843ba5510c8169b917d72", + "0x8fa31f4aa8e666c9bd9d42395e08260525bf5ad2ff5719071ca84bdf6b671740", + "0x3e1e9d1a96c083b9e8c07e1ce163a13e5917db9731b6e29f51e2571fb4a8aadd", + "0x36645bfddd95120b6fbcdc9ad54ef1b1ffc8d0a3ab45851b692351ce2327d22d", + "0xc4589b30dc638fd5699e5e26300aac149843985846cec28590df72ab210c7145", + "0x6a050a8820f15c057644330083fa0b93deaf677a5569caeda70bc641051f9a38", + "0x9e2adb3df7bbb722d9ae61237166ba29ec84075f1e1c0b69077119222326803f", + "0x2e41470d47f517c606fe7cd40eb625fa20e07688e40cb1f9caddd80f27877547", + "0x248391e2db6d16b0d1fff77cfaafa82dd191e83ec7991c9a594a78b15b30183c", + "0x484e31e2b718d4803e71ce2223d1d24f1ea1e882ef0a01cc7704d6b306912e3b", + "0x0a14dc947165f37c01a8e225df6c0449347d987533f3aadcb25abe8066a31f5c", + "0x822ea0893ce74adf36d3138df4a6916e27d622abc1cb055ea8c82ddeb6f1b6c3", + "0x72ef874be609700ae58ae6706b6f4d6aadd5bd3fbfa5e017ac88125250ced8f0", + "0xf7e54a1ed7a15b3c5d99f09c5748d9e0944d93e88c7dbff78d33a9f0174f7856", + "0x5ae68f0dc97744f54a5e4aa402beaa4af17f8dedc81e5e98da566d802f6251df", + "0xa378c978831cf0853bdcd75e74218d0401eba6e8879a280d0f6552b7d4681c21", + "0x5229296eb8b7f594144a34635c87f1bf97f070249800af63827b8c3efc0d8426", + "0x3cecae54847f7732bd075cc4546c97d38963f633aeab68cac58a7d5a3177e6eb", + "0x7c14a4b4bd76b14f95a3cc9c046d609902090d7f15c694be9651ad437ac52683", + "0xb3f4b86defe35acb24a651602124c0595702de42fb3eed8d1366196e6c16402d", + "0xe50e7c9bf26de635ae23f434127b15f7640694988221b210969978a3fe8601e1", + "0xdd2fb9e00863ee8bd9e7f9b1f797aaa2127e66aa8d4cf6feeb7936fa3d46acbb", + "0xc543bb209f2682fbdefa8dacf51720954f37734dc3b1a34af1adfb6f0476bec1", + "0xd377c42d4e61fecde1ef150b4f2fd6fdbab18fc3c13bd6d3cda845e69516d3cb", + "0x622b34f8f3a6e6cdc035ae3359530551437c1e04aaa48c85d3da759b3afc7325", + "0x3e56eb277800889b4ca4a12a20eb33e17c78736636ed761882682ec91468de47", + "0x9c704ca0434b69c8c5731c139bb15f7fad0ac71b8c6863d5f85181e98d08a224", + "0x68499ddc9a08d967055b2e2faa974c93ec7da5d362912f7a164e8a022787f8bc", + "0xd2bb02824aba917a5ba22255e64f8576c72befd94daa60b7aad3065babbcebc8", + "0x8f6cb9bc8007964e4beca887943dc2ce64bd4bec91afb62d9d4449c5705c7086", + "0xd553a7e7d878b1747b87e6306b3a822167a945bc63ce650c57e194d8cd41beb2", + "0xc62ac1e135b490551bc99c70ca634bc3e47502b4be25d7a0e406cb26ba03ca18", + "0x4327232514afa77b8fe208a7a2094051b78b8c16b8eaf9da6dc30403c4c9896d", + "0x6b888ffa7a69d53fa6f70a9b083f7b49de19f680e29f838309aeec7f1821b00e", + "0xd3019c640f0413a1b787e99cbdf7f9d45f9a2c0afcce3288402cc797ce4f06f3", + "0x1baa3e5575457458859b2f2fc0f2bb09ae3f593787c62f1479e84842f69de91e", + "0xad1b8e08cf8cbf3d717e6766123974cf2450dcc0bf746133d71c2f15077eb8d1", + "0x817174986957d2d04f538fe5ca307d1f524a69c80cf97831002d1ddfe56bcb5f", + "0xaa2892eb967f4e588dfc6b6634e5b2aa88263f4b1e1e85998bea7f54f5015664", + "0x7bcaef11f9680e02b0008fc057819f06a1d117e318a43aee196dcdbc6b991dce", + "0xe56ad921fe297cdf000f04756cefabd75d309add549622cf3a7604d0d02d4d1f", + "0x988d447115c47d44f9d7abfdb380fe8927bce830a37b9be320d5154db934df2b", + "0x431001a2fc696bdc0e682f591434dde3344d994232191931c0a6e5d2e5498e90", + "0x6ed8c0e4597fca7c1c74ac524dedfb830714330b020dc1d1b2aea51bc311c4e4", + "0x8fb32fdb2670a4796df796379fb142e6ed6fa2e5f1fd51fb582a60befaf7df55", + "0xfcb88679cc8b85dbdb25dfc1b9f0a4602aa0d787e9e70ebd0a5728ff2e3b9572", + "0x00d82f45bf1088446a2706e923d8f43c800071c8f988239cfce7ad6a8c31b6dd", + "0xdf684190b2ce730df2b1cd78563dde0cab5539b30d0a06247d79f3aec73d617e", + "0xb0f93511970266249814b3073424d5ecf9b47edf7133009deacd317435940676", + "0x073ec7ff65ee722dcc829b69e80791a856a2200560f992316be6bdf497b5eac4", + "0x2d2a90d480df14e521db3dd380b470c29232e44e12838b54b51216a95659733c", + "0xd72e78f576726e546906e0e936baa1fc6625777edebf69da76c489b9ac057029", + "0x03ff5273dc2b190a1f52fa97e28945dda7b88c6d866551c9928a73d6ffb3f133", + "0xe23267e18401d49d5c2d130d91757d17d7dc074d055665fb33d4778559504f17", + "0x89fd9be047d599e128f9ab20b96fc506ddb8c30dd5a9b6782b05f18165f939a4", + "0x732b8ef837394ff6a580c3c21e72a72a2976fa7ee07a7152e0ba5101d5891f7c", + "0xe9999336ab64957ddaea70edad6e72a29b37bec1498deabc5d8341a93ee67197", + "0x49f60577477613545b37efb5317d9142d9f5d6d081908e1c061f6be452216b73", + "0x6fff08789f48c852189fcfb0327acce4e20281ae54c3b821790b2856c7ec1ff3", + "0x447f89ebe76365d8e308034e90241562bde8834dc1075eac89e28183b2a4769b", + "0x469eb409c46e96cd0e75878cde67974e319f00b0d336bdfedc098021ddc4f407", + "0xdd8365129aa6aa4ce914b5f1a917a573b7ee3a3ced4de5318859e8ea2d512de4", + "0x1ccda602493afe6ec11be1d523d3d76c7e79bb93aaa8dcb298e8bf3b9d5a13bd", + "0xfa3a4de9d5c620eb4d160ca7b49e86d99d109bf7866f2baa3d9c99346174dad9", + "0x7b9fb6a8d32f956fe50bec11e142cbfc320221a89e25ea1f579d76b4b2c9bf1a", + "0x01bacc1068711052a28f3e4f7e9fd80b996fe89a0a2bac647ecdc9d9b83e8b1e", + "0xd24d7c8b06dbf1db024c250d7ac4c8d2bfc8be39a0e8990de46b0ddd79aa4cec", + "0x422fd18a2b8735f348c092ca2bda2b69c676613b595f3906944f869e28070d23", + "0x938a51069120a3b4f3081fe083d9246d32b811d9f2e37a0fe6e1cef0e7ff4792", + "0xa9116e660bfc36372df2d1b87c309781403b48116c95f2f73669048bebddf81b", + "0x858728b26fcc100ae1a2bf373e2cac05537fc347790a9169710974efea7be830", + "0xe17c0bafaf4a96427becb15242bed29534970937cebbf3b6759bf470a9884b4e", + "0xe40f175756e1815e0d514af34a8da49518173c7f0b9fe1ef24b1a46d2aeb1ee9", + "0xc29562af361c92883d4ce12f04170e189eb62f473c2a24ccef7145a26e1de030", + "0xf8d3f3f63b252b8bd0a7ec90d5694c36cc1472c261bd45382bb485d11ede5a56", + "0xfcf7d3ab6cc4ea23882638e9de6531459ee27a3140ab491f756c723a52378ab4", + "0xe74cf40070946b562555a93e868313d46613164c5e23236851c8c35a7258947c", + "0xa79ccf4a86e8a34faa518079edabfc8884c52aa41571c45e05b171acb2c53f15", + "0xbcbc83dab8dbcf748bcad7f14c08340ca4f07318a09c9a32399f47dab5e60a47", + "0x51dd90b2af2f1766134ae9b2a82d885a4a194bce1213369ebf3e315d03ebaa73", + "0xcf18e42db84f9501927d969e9a7e4b42553473c63c3995d8e761b76f79c6d3f4", + "0x95d14b250f97721031748210fb7845f4ec78e05804a87e1ddd1269a220758643", + "0x1c73593545255b2bea59520ee29d30291b4731112d39f507ccb8c98252a8d39e", + "0xf6d582117cabecb8408ae4e9520369d72dbca7eaab8ce6842d2febb5a1b22354", + "0xa2c0b519f6b635f06e64f697948248e57eddcdc5919be502ec1a53e7501297b6", + "0xf2268cc03cba0244623a414fc7550f868157deef46a8c424bc1e6f4b70595975", + "0x16f40825d69784d4299039d7b361f075d1336f29b93947e57ae963f119de68aa", + "0x7d63f07c24dc55307dcfc3160433e7d382272ea411b931221ae30dcebc3068c2", + "0xe469c2b1e0a2370b5a9fd6db791e0ffc5bed870df922684706fc6dd425176c02", + "0x13c52a53e3d7d5524f163d70de3be5dc4a5c8bc95c64041aa21fbd14fc0bddb4", + "0x094a9ed475b0cf2c3d845cfbed5104adbb97b8e233c860470bd9c2f967fafc81", + "0x15f1e7ff285656c4b445af048f4c95224345c4879ebe4c753f3f7b3ba4e625c1", + "0x58128af04dd68678ec8a9cdc54183f495fea8353a89fb304ecb674d1312dbc2e", + "0x32081afac331a70b6174ec52c776de2ec27369136dee0a25b58985a4607a7935", + "0x7f48dc400b525c33b2ea17d47260032965a03b6d076ab4d02cebb7b571d82549", + "0x3321b772ad4ffbb3466734db9ab81e4aa749916ce8ae56349698dcc0834dfa1b", + "0x79846e34b081b22517d5514f26bd67190812501c430042b28e510d5fea386442", + "0x8fa6d5ca4cd3b175ba6fee940a941bd149b050c46a0661ac52774652fbef045d", + "0x506db869b12f2c0b153f314477ecaffa9b7c53df20d5b2dbcdcd073a3c76141b", + "0xe69339d7a63e25eac8dcdd9a70c621561bf32ccc1f89624e235819d39cfe5ca4", + "0xd506504ddbcfd1f91ec9d5d71fb5eb6c05566da7c4631f58cb99d20e7bc1d846", + "0xf20c78eb7a7560c9933d6a583ea23f403e6cb9176e0fc9807752633fce2bff7b", + "0x16392a1f31ba9f84eab7172705e01567853808f17748c87d3d2b112bd297696c", + "0xf55d43b56a371be8e174d3f617d662e7b45eb1326c8cc878409180cb516abb00", + "0xf9df7d04c863b1aa10e03c68dee16d0e17f7e514de9847a20a63affc6e1211ba", + "0xef814a0a1681df3972a6b20187ffbf58ca58f9fea6df0de32c1036723164d9fb", + "0xf8b49fffd0ffb70ff19c3c3781ab43e121f90c447d73ce242dd0a0e2bce56336", + "0xa6e89a02913d0e909104b67e7422339d3c93a564b97171db0260c3a8540be2ab", + "0x5216d9be46b9697a34181ca7b0d4627ad99311fe84c8fbf1da4e804bdd91d39e", + "0xd30d40124a55222fd69799407da38503c04f742b45f0127fc273be3fd5cb35ee", + "0xcf121f66227509e3829949153738f6cd1eba7210a4f4b960510a86d999cb9118", + "0x2e1f8a60fc9427a0325fd8150a8ea6fdcde91a13b40e999400c586c672798a49", + "0xb014af1c33675b75ff8c965b0f7f8eeb32320e42ba14db790a5c60896d774282", + "0xbc4867d1c344c81c33554abdf3384b544ee616f5909143ddb6b2bf4a0ba3d41d", + "0x0079e37734bb661b5bed93acfaa18179fda2617c4c37bedcee6654f79f0b2d9a", + "0x2d3cc57aff3730fcfb2e5552376cdff7cbd452842e5256dbe115aa3b1ad18dee", + "0x15288da0a82c6d0146bd29b8d31aa31b6f516f9997156ce91fdb367399e5b81d", + "0xb344ac87a84a52e90de58bab979ec4a2e5fd935836405880dd1151e5683085e4", + "0xde8156dd2e7abb20044a23844a06ddc1590c9ac6732923c21269dabc36bb246a", + "0x6580171454e664a67c320e63ffe7b950df9173af211983c730f40888db58643a", + "0x5ad58caa9bb6f379dc30ef06b339d724a91000acc92a15486c86b2271396bb3e", + "0x0479a5fdaf588b170bc2d8c11301a463448249c848a4f2ecd39cdd5f6fd94a09", + "0xed9335181e2fefe38459807029ae5614e98d1ed80fc5bcad68046d63fa7bd965", + "0xacef0d3fad5cc33c98daff6f5580a7e843c5445007b3edd4508372f221992901", + "0xa147d774480b83904768d78b654f01de94c50d54c2112900b23cc18df088c14e", + "0x620ce3590e2996f10089121597a6c05f2f8ccc94dde95fda12a194492f4a96a0", + "0x606815f9dcd9fc31a2485fd5bb82ab9c4e9edf31c7e31770e89365d643f32a71", + "0x0a8b6fc63adbc84796423326834fb9876a91b585300310964119019182d420b1", + "0xded997869b600c4fcc61119595da1b8574027d64f9c678f442e9f7a33ac90fef", + "0x448ee745b1cab75979a3ac3f99e941ec291c921af8f65f10cec4707fab2aa97c", + "0xa3c7a6580857935652f73fdfdffc5a315020a22a778e584e0b78eddd70a6f59c", + "0xd56555316bb971bcd4ed2dc26b53a667e0def14eec160230b3bc18cd03a3c65a", + "0x030f8abafc222277b1c9e39e2b75ca6c09afeda33517d8cb5fbba73af7e1e1de", + "0xce35fea1dbc514f8d540a72295e2457863d7ae2afb76ee3bf1cfae1a8ef91fcd", + "0x8d890590196c7af780fdd854989e2c776d472a6e04c82b4fc3c3bd3e30d01aa1", + "0x7fbdddf9f6d14fbd3e6217b184e9b43450ac3109da621c919a499db6575dd34a", + "0x41e0a2e9ca2781a6722b1ea5b302e1f01d1b34c80c6f494e248c030f375ba1ec", + "0x7991a805d4f1237190f5b28a55fa603dd5c7a7cf3325024bd2eaad981ca0d70b", + "0x27537dd0a5d7084451cedb82bbba192fc59dfb60bee59bfecb5f26c49019396f", + "0xd3e67cc97c90c09f19b528908d9a60fef68fde3335c041434960405210ccf860", + "0x68b51ea61f57127d3a75b46e44c97d588904bfb880f5774e21440b902c1b7831", + "0xce0b41fa28c47f7a420ea5efe6ec77e413f22b6f67e9fd8f6728ddd73e5c6baa", + "0x9e7b2c49c92a224a444f4f91221ac2173993decf40b21118ff5962dea3969fd1", + "0x6a611eaca85f609f1f79bfce34df97fb975f450e87e1f24d9a93b59ee0b0083f", + "0x70ec7e2b800c43d093f7b1dec60e6743244b4516394ff861e8fa9f265efdd28d" + ] + }, "accounts": { "0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 6aad92505d..065e336443 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -52,6 +52,1528 @@ "extraData": "0x3535353535353535353535353535353535353535353535353535353535353535", "gasLimit": "0x1000000" }, + "hardcodedSync": { + "header": "f90214a0e11154bd22ac6a45e9569882d75fca57d12e44e5def1050de0a7b99452fb80d9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794006b2b96ab71a8df73dfabc11ae790f9c8c259a1a0d6216dd88ad006659c6214fd81887150e1bd1f87b248316d3a58cbfe40f521eea026802d5f81a58db8519436e768eae8b11f7de071d7f274487e5b5dd9e6954d7fa03ab8cae24350c9290ed5bb29777ae22498e0b8aa87f0ca85f2bfa74fd95c61b3b901000000000000004002000001000010000004000000000000010000001060000000000000040000000000000000004000040202000c0000000000000421002681102000000001000000000000080010000000010400000410900000000000000210000000025040080000000100000220100010000010000000200000100048008000000000000400800420020004000000208010000000002000000000800000000000000000005000800000000100200000100000000000000000000000000220802180020000000100040000010200000200000000000000000904000000420000008000000022000000000000000000001800000000100000000000008000108412d5f8f8832f60018347b78483449c5b845ae0127896d5830109058650617269747986312e32342e31827769a04a1c4062b2593568cf5fe861cd1b9b9024189927a3c75d09471efa029f7483b08863e584beff5c7905", + "totalDifficulty": "8154014315272113", + "CHTs": [ + "0x614648fc0a459451850bdfe353a932b5ff824e1b568478394f78b3ed5427e37a", + "0x1eae561c582dbb7f4e041998e084e165d0332c915d3a6da367638a8d24f3fafc", + "0x6fdc50234f74fd6eb5b8bb28378583da28963d26c7226e1254e04b676951c4b4", + "0x0d40b71e8f08c4d93a0f62d93eaee4c6ba92ee1ff6e46dab57dc64c992873245", + "0x7f129d232456d600332b59fb30434e4c71aa95b0e3a4f9328c74ec5b97102ecc", + "0x0aff522a9d28bb1a32af4524d049ce9b3e66149e8d2644efbad5736c9fa044ba", + "0xf9adf08eb7bca9237babc37df559297c6e1b54b585867867a2aed7c10cd191b9", + "0x5b90ca8fa35cad63ad662e3696f41c4159fa871e5f77637e018595a626282150", + "0xf33aa648935eb7dd99906d0855c71893b4c0d0c9b32ab8c8b7ae316e503ba35f", + "0x79946d20c81f7aae18f427d991f21888169c96424813461d04a61758bbe9f214", + "0x80950805fc209691ddaea24e8afecd0096e84e3c465940508131f41f569d559e", + "0xd58de59cb3b7f0323ff3edaf9e3af56843258c457f490346cf25a73a35163ed1", + "0xcf52cf0f195caa769e2d5857231f31bf17efed369c358e7ade257f6278b1df0b", + "0xce570fce622e9f3bd03942c63537417f96250bb3605d2182e5a567e961739e46", + "0xe6add695b25d4b06bfa08a80e9e9295c84948fc34202cf24b42c1cc325075d04", + "0x4699a5f1df0d7b2dab8ba282b6e83af0d0b31b604443e13ccf097fd46f346bcb", + "0x1a16f27083787c5dc1dd8f0be868338c78ce147d0cc043b299870f568de20a3b", + "0x2dc5c4538c1812e892e0a53c112e8e4c3fd9f6f60d1e8531a9df5419df86d013", + "0x40de720fa5ec3b58b3be838f189ae59bc4f21bc8d8f406e569339ff054f93459", + "0xc7274c13bc7462d09cbe60044ea6c9e92622204c41dfddfe864d388f830ab35e", + "0xfb6b099472c5457a813698944d4901b766b4bb8a177c4d357897f1974ba6c431", + "0x9e6104a79f7bbf96d117607ec87be8604417d80af11f558ef1e74067168dff0d", + "0xb8deb38b0b58be7b3eb89a5a3ca1eedc5726ab14186baba17ac520a592f68827", + "0x59a58beef1250fb3315291f0b84480b947672deb331980cda261c94ba544e22f", + "0x0fa4b28513f4a3639b427b5abb87902273fdc4077cc0a51361c3dddc264871f5", + "0xf9e1e92a1de2346fbd8b54987960f08a8b21cb0a8a6c561edcccd6cdfacb46b0", + "0x89f4a9590d0865e126622cc47ce2a1ba50aad880161335e8c88c8a24af709fd9", + "0x5f014ca414e0663c92fcbda0c7250153445a04808c7d062859d000c970003834", + "0xbdfc2347806fb9641788978b5d0a6bccc81b11203cd751dfae45a8dfd3bde7ea", + "0x41420d311b7b527ec68770306d97ce3352d7fee50fdba3b05bb54e70c7250459", + "0x3ad7001f1b2b2635266141327ed45b017f334fc3a5f410e3e99624492c489def", + "0x2beb717939cc0404dc173e50dfbe1477ff32c1ccb59f40d7900c2337021e2d6e", + "0x558b53c5eda0866f7515f113ea3254cb85424b739a5dd6ad48bd4d9221006985", + "0x294c62ce078bf950361111adbca5ebc963d5f12c7014b04e3d86d3cc95c6faba", + "0xec18a7c338bbebfdfbd03f1896d726dbb1d21a29e32e92fd9949478078bb19d9", + "0x6e61bb0641c13be0e0858bc3da3a0b06f6a8ac462301a33fab7425e99d6ae14e", + "0x7a4378c70cb339cb4e3805d013f6ecd66ebcfed3dd1df972c8124bd7b888c8e3", + "0x5911bdce0868655abb581c9ce87a51b85b449101d6d52350c05ff1db30deb900", + "0x081f65d017c48967f02efec9781ac4bc124f42a31ad20104cf4ac6553fe788e4", + "0x89a055c33ecf13f71637fc1dd818c6c26e86f4751c2e09c5b8970195b39ddcfe", + "0x83d33e35f31824d849e27d2cd1d4d02812cb84c8508bbb391ba563264ba2a429", + "0x144d66cd98cbac72f3dd9af9b2656529a00fe7fda8f70e02d0ee025fdf2de9d1", + "0x35d44c6849d379e58398189d06b149eee34a267e94230ae5e24a0c58ba3b7d30", + "0xe4d67e58b9be3711015ac016983bcbfeaf2ec71ee85bc08fc2e53e6d173ff348", + "0x67f7bfc9457f1a1566d9acd3700c399a2fbeb2e1071b3f5c908eb56f2bbb9716", + "0x2546b96a4a88411aa7b3aaffd71a0e22484cf526a099d58f1dd330b3209e4aca", + "0x91f9c4aa8357a4835ae2fc913ff21eb4790b711d2a813e94b38fbf52ced0c4f6", + "0xb4623b136bd01bbf2dfe3ccdcda850cdbc6da79b69324a582d3e1c29703a70ac", + "0x68649bddb9b142d43905ef85df986ccc35c5b0796d860b367c21085c9f1d0220", + "0xa007ebec8e3242c209a178e01eb7aac3666fe09370dc1064bfbc46651c5c4e01", + "0x614125ba7478c7ba2ecd062eb8014ad3b50f4d9a7ba546c932e3f0a3c43c13c9", + "0xfa579127b6d13731bddb5c27cff6bea2d0ec13bb6d17679d4d9e1ffce8d7dc2e", + "0xdb11e78fced06b1bd768da0d345f19c023d5708e7b57bf09c37009887e0bcde8", + "0xda9a47b636cebceb2f378d9149a4a5bdeb6841746e7f677942c26629d3d1d4ba", + "0xeaf7cf3816297b48236ea2cf3f60ece988ca7cc97f5c8efaac1433d23c3a5ae2", + "0x1b7746aeeeb0651a867a3f1d34eb0662660aa667847c04d6761507f043d0eb71", + "0x4e6a1631fc6702fef39cc0e383f4fb5608e8a1f0c721b1622c8f25ea14aa86ce", + "0x9e96f3b348c2170685fbaa99c968fadb4bd9dd621f6e913784851ab1bcad60a2", + "0x65df62cc768c87ec256f7308d9f199040aafc24c03d5c6d527bdaef9da365e4e", + "0xdf067410f903d878471fc3b53d020bce9d0b672ebd51df16ad65f4a3468be124", + "0x358cecbaca6506567a60b08d00c888c7b1dd66ccc292ba7c4c9aa3e37b018391", + "0x5102782ac246337226e6527ce651294bb5c3787cc68219208d6dfe6ce398f0b5", + "0xe6a48cff6189dc26c3d7242eacaf1e34c81503327b18087840a755c322665ca7", + "0xbf599651ec19034ca45bec20673f41813b43387ebbc596a57384a813eb6a21b2", + "0xa5a5242eb4e6fecf1b497a62de8138401cae35cad4a9c136d9efdfc12fd53d60", + "0x05eddef47694a7dfc61e79f78b65bcf9c5e0e65513cfadd2957ac3a324f54b55", + "0xa4b5589bca8121c6bc00a846ec459faa99441d0ffa4b577a45984c32d63128ac", + "0xc8a2f9d7974a1aa77b35188d9dbb3fd56d5a2f6c796d2a665360374886c5a386", + "0xe9d430f782c0275eab831108f934ea3bd589c6c72f9da930e9fd392de833e486", + "0x71e85321e2d1a4b0eb48d8493a97ee3634fe153f30a85d1dd55fb0f5f8c82b91", + "0xfed03a8dffe6cb8043a11ccad791096151f0803b020e4dcf33adc4b180551fa1", + "0xaf1beb7795169537916bf4c9b1515effd365cc0e3988cd3e296fa075831fb63d", + "0x06ffb84050198793b580803a41e78d4a6fbcaaba0901a6f938a5ac5f9982f1e2", + "0xb416bb6b94d5076df719edfd2e2bb9237eb2171b9ebbcdb082e1bb1016244371", + "0x60d6170c0fe77eada1dd85af74079ea0387a167341df0ee8ae110d0047c00fef", + "0x15f03d5f617db0bbf963d2daa06816a768b21794d05873131deb677bc3ff2a07", + "0x0b9fa1e7fb11e3c0b33cc609a87dba8c1acca7476a15da2116518d72ea019e0e", + "0x9bba5ba8b88b76613a52504bdde96ccc1064f3e868881cfb4b155d24d237e093", + "0xa8a77eb3fa43914feb609274d1ed96d51ae29028fa59e7f0d174b085d106fd27", + "0x142d2e126b1faaa6997553835ce1933083a5c2cfc9818ae71d559c8571757fab", + "0xe9241f795bd887173fa93f9e72bd7f07ee58d69dede512fc31f9faf0ddea8e29", + "0x526d5379c00d1a318409ea42ceeb7fa9d33a4bdb71793c940e0d1b42cc848d36", + "0x2045cd5b32670fc4c36fd32e45437db69f468aab51e10e32da423ad28bdf85b1", + "0xf0d0bdc64abd76e66be96239efbd0f25ae30bcad096a4cf28b8b5bd9658c8c3c", + "0xfa5cf979a921b2c5ba8fddc330cf1df7a445936f7bc990553c578dc3ca45de49", + "0xdf2ccce3cf15b30d7bef7ca83b45875e96f02e41c6aee9a1a97025f0dc75585a", + "0xb61fe42d47707d473a2ba8483dbd4b9a40c1e7b79c2bff15ff52aec560d505a6", + "0x068ce2cc3d65a152aa574be6f0617ff7e2f688db97b020d8ba84e81ae9037f57", + "0xef3c631c846ef30f6dfdaa901d8d1424cd100710335805e14226976e719cc2b2", + "0xd582c2e6adb0d112786bdf27dbf1c77fc7bd002511e53d0a10f4dbe780156478", + "0x8a028e29f728e414cf7e3d403bce9de7766feae6090ae0f7f787944569f2b001", + "0xafa8f78b22031dfb0b06004d32b6699421586ae779624fdb7153854d1ea5bd4a", + "0x7ff5e562415a97c4f731c7f8a6b82e401705e34a78751a6e8039b0930eb0dc59", + "0x4cff7c84dfe821e917e48089d3a25a88a84983fa5836d7a78fe050915ea86374", + "0x2ba7416bb329d81424f9fb12b43a285eb3077799e71cd21f0095845d2d165c87", + "0x613ca539b0ec3a5819424d8df2f4ee08e03e5e95a2607503bfaa8574270d163d", + "0x3f6ce1315b8feca300da0bd990b582c647b4440d4a218fb4bb6c841a789da37e", + "0xba8b0c45d55e44cec801c724ad6b6b699fa78505d87a5f356f6ef054628f0e0f", + "0xed1069e471b099408ceb19fdca42cb57bca2389dec54b8fd283db0a53ebe2c30", + "0xcbb375230e9aa4f7aa8536f42f4df3a6bd7572f603c03e716a934b0d3bbe475e", + "0xa8954ae2e84ed2c0f45db6e41731a09ebffec9b064cbd12e020e66b7575d2c9a", + "0x9229f2300310a0675f281f76c695b06214960621aaa4592e3bba558c23b5bad3", + "0xe821e771c08bd42b6d926bc1ecef87dd846110693f59d71cc79a55d7bdec4cf4", + "0xa7e54537a3a01524894a0f602bf010043a52c8c7ac7f6cba10a6ebf86ca11820", + "0x3ef166570a593e608afe6b848ab8543957963e63448b7a1d0febb8127003b527", + "0x1308ea66fbc0fdf84680f227d6425e63dd850286de1783300b64ce77deb696ce", + "0x14676109d2f68c5cee4f58c27f40579cc04663dcd01017963402aa2f06fd315b", + "0xfb9434241629e83ec929e1f3feeb1943945e8ce87590eb69a9ae44e3fdbdcb4e", + "0xb695c39514548fe5240723355a6a2eb2d233a48018485435b2d9a63a1097ef55", + "0x9caf7a3660201b0118736033e479b74e488f64a07a79e33f4782048af424840d", + "0x82f188de672c6e1826d70aa5f7d54f499aac011139ecde9d4d05360cd8b9aed7", + "0xdf7367edfa34b79be80c06aab16a54e7d1f74eb9f813a080a8c4af916e3a61c5", + "0xbd7cf6ed130f745c853777d762706e9050c2a45d01839b124d517e3e73206c6f", + "0x474b7557c158d93d732fa0b8829b40c2d9e593206c3c36d7743b6eadb0067689", + "0x1ff6d56aa85903b2a9710b56ad4760825edc5343cab855bc966cad9bd11aef7b", + "0x52c4c3990413706a86714b1dcac8d9c4e55a36eddd176dc55066cc39e308175c", + "0x7a63b6427abc9780a14a4826c45a313fa2d020ea33ae91d48e4cea28ebda51a5", + "0xfa7ec58ce730e3d66c79b2616e14f11b87077c5d911db6bd89cf7c69f9fb2559", + "0x58f1b88f3ae0b76dbaae0ac58673ab38118f5253b07ee2a309cffa1c3f9f3a30", + "0xca98407f9cbb2911422f5a0716c325e1c2ef053355796e47eb619094790da45f", + "0xad072d0b4fcb8ab2662e3d27f6c6baa2f914bedcb91d178a9ab02b9646e6203a", + "0xd8319f885666fd19a5a9801005530e4a490fe29765f9d60c38b60c5b9ea92d5e", + "0xe95daec9ea36ec00b4f9f7478ae136c1453bbbc3530f839e93483fdef4a61cc9", + "0x6eeb1a044cf3cddaa87f70dbca704fe9cad675e82659380fb733153ad452761d", + "0x89c53801a896ebb9cb6c3a881269a93f610122fe9c3132ec19d64a6f22e9f7bf", + "0x81e57e25ce8817d0cf3ca17d099ec20e75f11d32464c2480d2f63a53a22dbe47", + "0x42ddde6c79ae71e64ab091b24e3db68c0c3b560669aeda58107d07f61d9bd39d", + "0x6936a2002771717810dacc23da43097c7c1bf5c2619975f55132b5f450c03047", + "0x0dbc448620312bdf04e118caad4ce1fc5058d0c14b1bf655b650677a2d1eaaa6", + "0x108dc62f87065752fb77f6a3f00e9141e1fd170b9c0538124739bc75d5632b4b", + "0x9b555f75bbc6b9fa5ab1b63b5e7a4f6efc7e9c659a8829a69ec591b968133478", + "0x3f31b6d6e18c7afa96a95ba0855b52a2b0e3158d338ce3a20f14c14078abbeff", + "0x78940ccb7637be74bf6f1735c615054e632ce53410b77e9b1d9f256699a54861", + "0x71b5505cf3b75c328113ffdc94e8ef89b673838a26bee4bd7ce582049592e54a", + "0x68ecd3b26c50447e6483aa0adfd4187a4f99bd1b8517772a9b90f939b322687e", + "0x6c291cfad552325bb806ce314f066f3a7af0ccb5950fede839023b8140b3d06a", + "0xa32f442c4134ff4559c3411aafc87649ba6776f54e0148469b7538c243c19787", + "0x06ab81f6da34fadcc2d1b52982cfc69e20d9451801da18672dbbabe4abfb6983", + "0x8ad902710d008f2b7bf8dc50b66a11045c7e10f80be12f6c5e622c05ad48f2dc", + "0xb85a2abe729f4f7bfebc6a7eddf085c99992d6af700f487a9a2a64164dd14abe", + "0x11039611b2f406125519fa4d3f1cc7f4a89a284be02f0d23971b2990883b4b1b", + "0x69e21960b1ed6da34778848a92b200c8275ec8ae1763e07b8edab481cbd5c1cb", + "0xab4a7ffbe54a07e8b1af0eccdd1fda88d72a25d61bf6b12c9f5022afae936fc1", + "0x8d8fef9f7b0df3e2cbe6cd99ae3ec231c3bf7a583028c0f6accc38d2ac294019", + "0xf8c75352c289c74a797e8673193c505600611433730e415ed877087cad99d3fd", + "0x28b756fe2c8e5c6cfb5df29e8c4f3a9ae149c9d7408efc31c57e5164e9333da1", + "0x3912bfa54cdcb8e6eb1900d7b8d464fab0aa97593b9795802d8a084d66d82288", + "0x0db191d64e9a75039a2fe0817308692f3a163bcd1cd6b476fb5e04cdc8af7808", + "0x7df00cf34abc055979b1dd70e38b364f0b1f9b6ca8a2cdaa8e72dc1c30bf5471", + "0xc4ebe3625665babdf6b8862da0ab84be8fd7b5c1e4849e9c0c2277df99c1ce4e", + "0xd6b86c60afd43553bced67a5e202b5dfdd62e668359eb25e29c4768328136fb8", + "0x46be2d0335c8157496ce74edc96bba09b3873acbe46c285c54e6985615519fb7", + "0x876940ef8cbf54dfda6ffe0d469ac0fc9adb375fdfeaafe3da8345a9db0c964d", + "0xde7c02533643f05dcefdefa9c7cce1f0583a655fa2a9b4a5040ba6a7489c650e", + "0xdfb9bea572e6a60edf6406a5e87ef3fe60f5e5884ff2fdbd9ab5ccc7f0bc602b", + "0x56b30ee04caa1d1e8367f58855c361b43c2c17361e5b242e3b6dc1e53778df5e", + "0x5da53224eafabe23f1a5637ae74cac54adffca2f18fb4a2f506a617370f06378", + "0xe1f7ba27cc89f68862c9cdefcebd4b63419d01e6cc49122f7e6187912f3298df", + "0x67d0b1d84379e0f67466a6ea295a94cd55ed67392e51a6012994218be921d805", + "0x9db5e16e54e0f9310e578d5dc943a5e45ef5b3f5e66bf758d99eb8a7528d2013", + "0x4e0b154a0b06d6544950634de6bbdf511735226649bd694b4194c43aa7e89bc6", + "0x8146ae0e77da83a036ed8b78046f204defbc771ae61bff4016cda3ccb6597cc2", + "0x00cd2da8855d464a368ccbd92907baef0fd0fe2aa8c24e48e4bb6854a011d746", + "0x261fe32ea2985be3ac260b68aea223c4b8e4db240e5fb182490407a062acea5d", + "0x65eee7ac2b1b90a0f5a4e0950b2a0f3a9b32e0928aad7f4243d4bea2f056641a", + "0x7d9e7db3a97919ff2204736eb3920587d8fdbdc97d91f14049f1d41a1eeb78d7", + "0x9c2edb4a5bb85fe484094b0e033cd7d31408a2e2d4b801a001f6f886b92e73ef", + "0x1e191b4674a3a80e09b68efe4c4dd4f38d344ac0b42a1fa152aa1242a5b53e1d", + "0xf498295a3d4e3b72ae1a11fc1d1f031cdcb68aed705be3fd698b5b92bcdc8cf3", + "0xcc89f9c163149bc17d5b0a1d79bf5538a86c4aaa3374e202a7b41cd4a562c6e1", + "0x11b5219b9b2daa6832f206bba106c64a2b9c3aba39f7dbad1feaefd788c9ee42", + "0xd936254f54f45c34c79c8a1ded63133c9437e82c99a26a8bf3efb95ad9b5cf54", + "0x8e8b502743a0ea7075c89a88bd149b8f97846dd915918ab8cb21c7b7b710a4da", + "0xdf0e67381564465619d90165d5677c19a396674d832530c18cef2a348f9671bf", + "0x6481f7abc12e1a5655b0c88a693ecbbe5ab2685c776eb5a9a3485167eeaf95c2", + "0xe9ebad32fa87a2a77c82a6d276a18b0efd6f615361f0d6e72c0a037b35bb396a", + "0x3e052b0aed9cee87f4d70626837c1a49ec169b2e8e03c37fc5616bb0573fe35a", + "0x15245833a84147b5df07f999c6baf27655bda682a5a4db93879f41a2ea023f31", + "0x4820d25f27aec110817a81bea0d7b9bedeeb8d9af55ace79de81380093a02176", + "0x4e156aedc00095dfff29092326b02fe2863a6aba3ebf8add79485096f20267ff", + "0x3b63cf9b1decf710ac331a5db829a5fd2eb0a7da6724c0a90b9525334092d6e9", + "0xb54145d2b41dd0142f5d2487b0db7fa96f42621c08d63edc036dee4b072eda08", + "0x8084c6690651740db4e67dbb0623b5d1342cec0ce95b6349058d7051fbf186c9", + "0x9c6b1c3b15784111ae80cdf7398e1283f4d68a9c2a6a2cd95b8594e0acee752d", + "0x71322541265c9b5d5404e9f089e505ef1814fcad641a81ba3e1bec009abcb920", + "0x1e028666b6fe44f8c8b2c9f3fa8c8ae5f062a7e117d79d661446fcb8a72b5db7", + "0x3a6cd5395b4be2aa1ee4f7d24d1d1433f46db1307c7ae823803ca1df7843ac6c", + "0x64b8b040c6c0cc2ebb2f011039dcb091d4c8f4d338b82fc1a68235c6eeb8c8a1", + "0x89f98b1f7e78b539f83d45c5ce8cb455e8ad7686f42d39f9c195d37ee9cf5fe4", + "0x14abc82071dae6f563f272da9e1ba7f9ac6f0547544cf9cdec088ac6283eb464", + "0x6aa6490aa64733dab57d954b9907f421c6c571ab2b2cebbd833d59d74ba19be3", + "0x62e4524b07b9b8d8a53cd29e457a58dd9f940141797f847b889023c22330db0d", + "0x534a4c4ffd28cc8c3f9823826644138c9207255958f3dac5d0a5f279d57508d5", + "0x3e7f74f25707ae6686334c585603253a21764cc1adc730353c02a56f6b7f3e81", + "0x59cc225b1c9cee2ece86b3093a8bf6ad3ae0260ee760384f1299b5af75eaa1ff", + "0x15ee9a6c566674f1f7742d1e07015fcd66e22d7648ba25be50428006efccd026", + "0xc0668ec3f88e6a9f1097050e999f0082e9a39ba43fccb194790e51a41602e704", + "0x03b0cdd4ca4ca3d8b1270eb9b73dd28f22ce5681c3e0dd5d11107719d2614de5", + "0xffad54056c851b02f83948e7d665980f623643ef40aebe91936c3bf0d24a3a2e", + "0xdd587650149a81f7a5e92739c18af1216bf32ff2cd7b1c908a6d3100c052b0b0", + "0x1fb346da4fa3c0b7d1acf87e4e8b9c0b05cf41d21794d9db58b14e321f9b6bbb", + "0xc15a230b3105e4c549291228b28a3ded073e7061f56bd31a8bbe4570e2e11910", + "0x9c01dbeda0dd9cfb4e70e8b63551c590edf5be26c879d319781154c44520aba9", + "0x8b418cd11db8823868c9495d213b9e5c5e0d8b25d5f7c262f21b3d2b9f591ea2", + "0xff7cbadcb60f8e9574e1a1ca57c0cf1b5b26725a7683a870b581734ce906df73", + "0x0efe88c68a8404cf9e1cee6d4b863c48ba502c5b5f504dd8a6f251122138e651", + "0x87994dbe88b7749a347e438c76273ba5a7b8835449d32ba75bbc877979e5a3b8", + "0x366779f7f70fc10da80427ba5f0f6af0e1b5d60c37c0c7e524e408a1e2f261eb", + "0x616c1a9eeb13a026372b099a101eece0cf0d1715dddf192147d401c722b6a6f8", + "0xb35494e9758f3bd7bb23fdd9c86f60a8bc73e3422cc9be80c7f592fbcef26b9e", + "0xbfcf52fcbd301f4b5d32e62f284f95d01bc545e16f806ab64038d11be74f8638", + "0x3f155939a40b556e30ccc4b32273a3586fd5aa89c4209337da1ecf145416c6f6", + "0xc23227be04320beca30ce9ee2b9f74bc8802414ee78754d7af1bc887e1e260f0", + "0xbc45e7b6bab510e72479ed0a675a05217244a9879be26d24780a39537c233f10", + "0xf651ff7ae3c7570a95245216c9461fbf90293a3962f8883d502a92277f0e4ecc", + "0x92b1b6ba3f6bb8a949225e51a480dd63152147e98d96ff5aca2ddc81eadac6c5", + "0x368b2b21a1411fd2d651c12cba2f2c3d4d9dee020e98a63aeea861e4b6837e12", + "0xe52565a7d159275cbe9e024130faeec3ddc3c3e27507d35d92565c8a56e13c64", + "0x3252703f9e4b7ba715810126ba57d87bf585fbec8e5928aa598c577f11daf792", + "0x6283fbe3a436d7860c0b564f2c7a32814c189093c775a8d800ae24160dd3e72e", + "0xe76378b3adf8f756728c553a5d822afa016d8117cb04a24b1c2a1eadd62421a3", + "0xc0a2504fcbb69d1adce70da836a73fe8e8fd74aa7aa4cb7d22bf844e7b91aa89", + "0x4d3e70bd5f122962b3cf64de57c69d85194126d71e79c964fc4397afe252da25", + "0x7efda1eb1564ba1d295eb6d403d9900b3336f081f2bb6de2c375889883f64097", + "0x6bdce19bc957c2bfc7e49f91d436367374847fdc6daae2e621f00aa024f78094", + "0xf42d152632eb0a55173ce7ce4cca3a91c7d7971a7456eb6ffe88dea54c3182df", + "0xa6a2353ab4a3bda46687cfd3ec8e349f2ed61e449875b9d1580d9a2370ccd54d", + "0x3aa4b80ff21dc79fac0b4f913d46687c4f991e5005fa6af731c9b2d10dad9c81", + "0x7d1022dc5a7fad9c0291448c56eb99283e1e64c37f6a55431843644102959d6b", + "0xa918366830e62330c423ce2f03f99206f6f3c1bf7660e01fafdddc40c8a0b650", + "0xace8ee8ad7fb40d481f20b165ac8012f3ff69f0bd8fd3ee290d894236549d065", + "0xb03858a13f584d7128989a47ae71d945dd67a3c2f54ecb3368ab76371d944c6d", + "0x56c78acc4c4dab9994018a969c3d3451300f8229d018f6af2de91fa4da6d4230", + "0xfb4313d83488e1003d38869fd8e8788d7e74c124542774ad7fa75971bdc61131", + "0x1decf505cb4473ffb91dc428710d2a2188d57bbcca71b7b5e277eaba0c7252cd", + "0x9db499b44cf0bd96713ec99cc769c8454fba3729014d87b67c18b55f0b4b9fc0", + "0x3cc717a489465b21a09c3fa19453d2a8cddb914b7d2789c21db6c311386e0f80", + "0xce4868287d923f8b22aca7a1df1ee11685d7c50c6384994ded2e99fcd2c01906", + "0x06b502cc70d1ae3c79e44a421b6ffb9a1a6f0bc647b4421cb375ab5d8474c713", + "0x4803b5e78af29ff140e37b23bd2f3de9fa6cda3a1bea2361e838061490708d0f", + "0x874051f592d34ea3684460f094a78d0e1be3bcf49586b1467be0386f1f9e3d94", + "0x8b66caf3a57d9998e2d88b0e4ff296825b6dbafbded01e384fd87bf4a92c5bbb", + "0x61f6244709692f492cf345586212374f4b209f1d2f92d3ba0e4000ad0634bda2", + "0xc58788c015dda34717586db2395a654f49ef0bfb4642459cc0ac5a5d74a2fb67", + "0x5161b49a84d5c614d72bb3e220878afa94d9acd30cdeef78873dcd91233de390", + "0x5e358365657197bab7481eab0dfbf8a6d66eec8dc62aa345c5364f75c07b8675", + "0xb358c9e7d218bdbb42f91752d03365945a474d49e84dbb15982e368def01cffc", + "0x908bf24327cfa0001d13fb5a0a73b536132e7ecf66d47f2c77215b03bb5b1693", + "0xb041e9e1a1087afbf41d87aa9e56195cc548527c81023d43416720c025b896ef", + "0x48ff5fcf252fa38a00aaf887e108928755932f45d7cef5a8fa0b72d711789f66", + "0x16f99b5d528b9ea7a92e5f7ac59e60d4305b71c9b20485c7911f84e3ddd1802a", + "0xeadc395d16b240b8412e14d5065a33847fcf8ae122d22f24438d7f79d8cfc40f", + "0x560faaf4e0471cfe39aafa10c9660d61c8489d2c5d49eff2a8e62ab31b7ec08d", + "0xf1c8bac46e0764d0faf89556b0080cc7b16433070e1e945e83f1ae36595da7fe", + "0xcb7409cbd3d3104a4b5d856887fe6d390643b4c433de855644f2184218631662", + "0x6eec345c4baf4e699f0ea48bdf54b2e74f98020395759e275e7cda0138424ab0", + "0x48a8bb061ad00561541b4e19009d3e8c2e2b9064337ef431fde45fb2988136c3", + "0x458b21c6ca362ec731487499486c4c0ea69905c8f36617810009edac608b9e20", + "0xb338584ad517b679ea52ea9abfc8d786ce1eb55cd3f221782de658f75b23ed47", + "0xdfe64bd8632a87d995972376311f78a0fd390fd2635e002e3dcd7838a3b28516", + "0x49d9ca4420847c21e2969911b7b5f321fbdac5037d0d8644d6f357444f91238f", + "0xd654571d72fc11d7a86ed2408cd1f78e8009dcd117323c8970614ed8731d66d4", + "0x2133c8e084efa57df6e1b4f1af5515a4662809d722ec002676eaa99987a2607d", + "0x5bc530b5fae32bc84127fbe7feb7eb07432313915e2d579a668f46fdbe46bd1d", + "0x8070890263bff747db0122240249361f5aa66cf121c3b6c4ac40deff6e42af5a", + "0xecd7aef2e4b4419539fa40570a61a967a0f296f524c25de9cdbb012b03d8d837", + "0x4376d56fa5e09c64156c6d1371151a33f7ac1e46635afb37823ed75287083bf1", + "0x50d32b39873466597d5fd29a2bc3596f54051d064559c46510f643f2c24e6319", + "0xc44c4284e5cb873846761cd012e0d221763c972242c0c4a161f3fe0e2da74026", + "0x141d2894e4cebe94df908cf463d5aa6a95e22624f5183d03cb60011c0677eaab", + "0x1bb68700d0f6e052ca64c983352731ccb0c3947ec73d67ecbbcb72c5ae3791e5", + "0x73095bc9acdbad7044390e72ae6c471c8636dc0116e2ec322198bc080af7fb11", + "0x66bbec6ab32528486c3ad89c36fe750d9c6e5bec862ea683988ba578302db503", + "0x979820d20c32a076297e3a940ef4b9f3ef02c9ed551996fa106b6db778852e52", + "0x4da1d4babd26763bb29976f0f2c439d3cdc06089951d0eeab7df2da59c128454", + "0x4c70dd6d755e7fe3da5f94dd2af53d037bda9d7b1eabb68bdb75111ecd190e04", + "0x87ff13d01ebf46a5a45f5b29e7026117e8b41d135829457d80918dc00a325f0b", + "0x78d573b16ad8a3c3b0a704a01fa79915907fbddeaca6c7e189c5c586855ea882", + "0x95b9c87ed9b7365b1ac15b02a388d47f75ae8036bf658850ebbd8b829ded9186", + "0x812fb8d5c2d962725245a182d0d267fbf97358d5c236cfece3fb398fe641f78b", + "0x31db1fe9db91df6684660f1eed0928bbdac477bd1bd376399e27a53ce760ffd8", + "0x4bb0cc2765ae336b21fd1f983f21464e907c6fa4831b047386f64e021550b2e7", + "0x7f6317d849a40784edf0d2c7b32f57569e561efcb4fb3c5f857b30319a93e2e6", + "0x5921a9e8ccdb11e574a012cafcb05a6dcf86ff8006595837fce805675202b8df", + "0x5357bc6834cde24334aa697f050c51c0456f7b03f938819baaf8c5be1dc10df5", + "0x8fb8b01b64eab496c9496179016adac0dae5ff6793970b3c307202fb17a93af1", + "0xd4ad4478bee0d5bb0852461107c3bef946f147f66a478789b39f7efb517b3bea", + "0x630bd6a0422ab626b28f205ec9bca83c499462556cd8116556bb40ad0cdf0e66", + "0xb2d07716e5e20312f314cde99480110794d3cf70ccc786828fa25ebf97ffdcad", + "0x87fc5c3371e3ed8f9201f61768fb2683bdadf8c3f6a3039c3504107b07b508d0", + "0x9e67bf7118e42faff0aaf8aae3118867c692b27c35efcbfd057d562e8d4390d9", + "0xd96833f813ac20074274531949bce0637e06636b6ee8b875b4811f09cbc8c116", + "0x4e9f29f98bee2fdb5c5692d94bad8f87b6b2904258549a937603da0ab5d36b65", + "0x77c3b0bee822bab79529cbe96d6847649d9528399a488ba9e94484f7059c46c4", + "0x948d3eca01db52a52679fbc33ca30aceb7e3ff6449463a2748fad0982b75313b", + "0xb3084fdf4a2ea5228c35adb20017039f4ef01e97d99aae08d4adf591b96330c0", + "0x5bfb4369df41aa75c957c1fffd6b498be3e7ae858cd53f67c1c688b9c78afc4e", + "0x6a2092f54cfb6c26b0d5c8f559e5e9995c79873db7631a8f6397ef5ef815352c", + "0xb286ce1787331698f1f860e1232f6766a658d27390b7623d460136a6be90a444", + "0xf84ba9ae60fe7bae5d3eb5be6c6b85aa564f8d0a7ffc479d4b0d1c8bd69a2adf", + "0x467550339dad58cba021e3fe967bd5d81be04e6670488adfcfeeb0dab07d6b2f", + "0x5150476eb3075df5b6ab3fb54ded34ce76e06660ee401951652e484e9a3fbd62", + "0x80845f54e9c21ee96f4aebacad6d199416a6b30fd741d6e6c9966f58c54f1364", + "0x8264045a020782a7dfc047efdfaa103bc186e88c920f2c25a016911fcf33fa2c", + "0x52399e942b721929b9875c274ec6b5034c26f7749f6d26eddd99972370dad3ca", + "0xf03d8bd2bdb8ea0b6ae2e7bb55703520cff714143501f291a3e7199be5d466a8", + "0x40eed1aa25f1a87c849f5e02f846c991e7473af9fa0985e3d61bdee01cf0a5b8", + "0x3d18c888cc8729f63ee415348121e10b5d990c8f091fccce7e2d8f5c0132a20a", + "0x2e72d969de06d28196506263e6dba8310b6854b5069fdf94317a6d3e90752560", + "0x2bf249dd628dec9d4cb267a9013e050f0710daa2915e468a623748dde1a036e1", + "0x91c578ed45a55d0108656d1533d209de851f77d9abdb58265bf867d7aeeac5e9", + "0x88dabe83eea11db59d67db99a159c623498cbc648c79d829a317719b836540bf", + "0x5fac0c3efa49004a1af631263097978f16f7e6710ee7a1557432aa727e44e09d", + "0xa8506487d3c54e70b3d6e83eb72af7858f583527ba6f6a6aee6a3eb33750e538", + "0x62641830df38adc76a043baad1fbbdd8e49356c11b6565ae0b04429743011b08", + "0xf053195e1bc2db0d0451ab69471520d0a03370a8f27a4f62a1885702a36d583d", + "0x7197d7a7897505dde22c7a518054d9df7f3368fcbd109cb596872d92f6a86fcf", + "0xa5092fedfd64b4985e70ffbcd7b4522eb45f9bcabe4c478b1f1452b063d6d551", + "0x027251c22748451514c27aed0f091e7589600bdfe816ffb0a5ba99d55265b65e", + "0x590271f52852c220ae38b56cca9960a1fb94d5343a0090bfeca5e8b5bf82b2c5", + "0xf8df310ab62fd52c452122deb0f2e79bfb85bbcd0bcba7e6aa5a99a541233431", + "0x5d313f0071f2d885da1b1b5d104b8d78ae49842ff9a636ad2613ad9e90b4ea52", + "0x2672988155e5c27a3af3ae26e74d164d9f52b4c71b74905ae90466113e991692", + "0x330c8cb081da0372f6dded08c0036199e11aa8ab51f6f9869995cecd3eb16f24", + "0xd65721d9678bf4667c6688af76d2dba106fc51e8396b0af78bcc80bf4149629a", + "0xf5019f4da39e5ca6102679e5a0388a3850eae7bcd91c632d26515caef12c472f", + "0xe9c747dfd6af4dc29b5836495be42673a20bb2475264a2f9bed00eb8250fea7f", + "0x2486ab886ced7bbdd774371aa0ed1c177d6d187bda235a4a8fa390b704eeee8e", + "0xa91824527f5a40050aafe359817594b43cfddbe3977113207a7d5868507caa19", + "0xd44591357b62e80b8f5606eebd4cac5052efddfc3e6a8c5689660d6617f93b33", + "0xfe5628e6d9dc75f413cb12ee1004e1514769ad7085b5434f762e93db9115b78e", + "0xd0393986e30a8961e01ede613787fd2e6fab42db329d0e57bfd16b42cacc4045", + "0xbe40cc6ffd2d51f7658f48359d4b726c64a354a9d1becf189ed83775f8fb4086", + "0x1d06de0ea61fd233ed701c9520f18012143277ca9b379d39db62fcd0a4e7681c", + "0x463ffe1d54544945f4abd7e35cb7c90a4a809c25e1919215207b7d2a8d3b4fe9", + "0xdf128c4d6c4048d4fb0f7db6db091ce4de10d509c45736f5521ebc4ac93a7ddc", + "0x5ed827eae4b7e95cac552d60b60fa209157f1a8c6e3611c1a5f6f7a49e8a6a92", + "0xd7fd28964beb50a410de115f290a0140fbc78d0d4c47ba02afe9f47d80df5e53", + "0x1996f9b8f7efa3d860233141774f46c00b63f207219c2eac5e61318a9464d7a7", + "0x4cfccfc8a9623fc9b5ab38c991999f8a52c6537d984ecbb0c490ff37559cc51b", + "0x4aeec05c7d47781008273281bd01b36c5ce21916cf7fc9dbf79aa2c477923c1f", + "0x96cb38c2449f97c92c81f5f4317b15267c9c2f4ab62240885280ced5f54bbc53", + "0xab5e6b9e4c4a27aa725183699ae30a6f8bc8148bfe85d1e4d0bb8565502e6e73", + "0x23fcdee9cd75706e640aa55c4e8acccd7ba9591e724bf351a7070104cdc698bf", + "0x5f3433fb2aff1e3843785b2f2cba22811cac84061803a2c5fd045b1983c8ba81", + "0x5613366fa3c323b091a44d10ffdfb1f485160fb45094cbd52707484f820cdae5", + "0xfc43bffcd36963706e2bac564dea4d593c35c5156de02eb747bc557988d628cb", + "0x4f23fab93388bc79a879f85c3efe0f15606828e6034cdc6b66810a90cdacb793", + "0x62ebc41d0592d1569001358ff3f1641c0a6ad89e66b0fd1e784f060c9101dee3", + "0x12bc43cf16c8965f106f3749bb6b5d9ff3936a205d2ef5719ee637308f81ea24", + "0xe991829e5d9c26cd365f6907de1fe2f2153cd88a7d7e8e56224c9dacce442fa8", + "0x55679ce947be929966abf9953031fd172480b7da8be0b34344512406d93764ac", + "0xae1f80cf386c6cbdd1ee0a1241e738c245eb12665f2fd1a614391ba54c741847", + "0xad12a941df30e25584f19f5aa65069d919a2e0dcbcce73de8724f975abdceef9", + "0xb3478980a68ed409b58d35759d4648ce21ed97758a1eaa0d0f1ce6b059b6da41", + "0xbec5fc3e9184d2e46bf0ae39c408a7cc243a41b69a923fb2d1224638153b3ce0", + "0xec95c1df965aef7e6061a770e0c82b6dab0027dccca5ea3791ed207b868098ed", + "0x2bd64bac83283cbb0bb5f7c1d461261a089a40904574e2daaee97110425092cd", + "0xeed53a58f04a07af388b098bb8c1e49abab852736c84d69bcbb78b945f23b86e", + "0x2c2c81b8a0c362105ccd0251119ddb406b65562611b2c3b3fb9825dba0cf6ac7", + "0x91c93ff5548a0462f1cc7cdf0a5c57dfc1f21932dee38e25759c9e5719036fbe", + "0xbb1c1bea058893b30e38cf0ea2f53b943fd6bcafb86b0eb647ccd152aa42dad8", + "0x079da567e28f61687250a49aa9fca4c465245cb0ce02ff075b500b203c459605", + "0x691de81b04aab67b3276168be7dc43e220114005a4d66a1ce9ef2665cd2bc867", + "0x3deccfb1fdf3e57aa2d63d0692cb37f375aa457da52d88cc9cf277c32021bf45", + "0x6cd1a84bb6976f2599898aa46fc67627663738cdeeb815ef1f45762cbb14dae5", + "0x29c96ea5d11a5a761ff7c64b24a0892daeed506b8f7ab33e93d6eb6023b9b37c", + "0x0bd8890f06cc6187a1d1a029cb319df75018b067bf796591b0b0a07a2c33c008", + "0x6a3d0b949241a493d2eab974adb173daee1e3c791c2dce6bfe59b127f8557ba8", + "0xd102ccc0476081c8d399083930dfa59486a51f83d33096ce77897b9b0fe41b1b", + "0xf9ddd66ee324bc7f06544cd53f792dba6697c1ecfd4c40a44733944f7e7ebc91", + "0xc14b245a2f2d02ecb944acb218d76e311659cfabcf72f9eb49db59541550b6d9", + "0x190781209df0cb64a4ed6ceb15428699e6b67f3cff28b7a987988a8e29829171", + "0x46605aba1cbee0bfdf90b57e320823ad4607d9ea1d6698005820021128c472b0", + "0xfac04645717514b9ec56f85cf0e6cae5aab46e25e69e3cd010513d9598d56609", + "0xfd0c9f959513a72149bfa23b32c5006ea766ba2e41edd47f450090568d44cef6", + "0xf0560a14936e66cced54d4002599808b127f9e56260f04f144fe9da412577c61", + "0xc9448c9e8a3b09fd51ee93b77feecb8a8ba03e1781a3f5bccc93b4d1815232fd", + "0x3c41d49f2aa53e90f5fed6f372c620fff5a80f442894c71bd7b6c2f55ed76f47", + "0x0d9517fddbd945294c72ed49bf6bcbd88d84c9b3b2e257c05f64bb69c4d7815f", + "0x1a67fe64cb906429f47250e1a30858366e0204c3f39b7d4b3f121a46a51566a4", + "0x9833e385110465d72ab133f02348cb33433f38454f6e985b022720a9836e5015", + "0x89f653efbe7bdc469e2896aedb2a22ce5982b919a7c6dd14046db4eee3950b6d", + "0xe92427a7878630f65cd4f38dcee4c5d87ea0dc3d0ba1720c0d9f53cd84411b7f", + "0x1f692c127e4d0e37f55f24f5c20516c804dad968b5dfcfa000595b4682aabab6", + "0xa3557041302da75734accb2e95db335abb208626e1b9d20a54ec0e0d23a5e003", + "0x96bfe30b54d1f39b5693272ec7cea523e0531cb7fb805e69a820888ea747b3ba", + "0xca8f5d8fdd17be423ad5bf84d7f591466137a54388b65f5d853aa83ef25e9b42", + "0xafd729d01c437b299b29da02e34eef0b8a762a24447b96c0499231a17a84fe7b", + "0xf95f528a8abcdc0eeb66250fc3d1df11d0831a08b30d11f0f6f0f96b02f7ef82", + "0x483de90f340fd0035676305359fb8c83b709374676796c86c4d4b615ac779b5e", + "0x433f6ce08d28351388ef6310847d7949f4e92ec99d585c3cbb5fd7152baa507f", + "0x77dc56a6b802ffae812c3e4d8768fc3d80bf96b95a55b1b9736a9073ed0093ab", + "0x5c3c2bfb8cda1218a08084c4645e2a84fde3aad03ce00c3310b3ae5d80e25be2", + "0x3321f6475c8ed111a1373bdeb68609f52c4740f22e4f13952e8a6d98fbfae542", + "0x7a0c172b717acba8a7b874e6c88257cfe68d41855506ee909d84d23b028a7ffb", + "0x7ae3757e9cb71b9063d79db76109af96ff1a5e6aa1183b1b70150757243a94e1", + "0x4ce794f4c0c9273c14e6faa680e8837247c6a0ab503a82432f69529d4f5530b0", + "0x8a0ff3d87111ac19f2d95d813e384a96dae3cb15caf12e50b99816393db3a374", + "0x35adc4577b9532f5e821d6a39029cb898886ec9a8b938bde92ccb1df67d2dc2c", + "0x84976050b7ccc3c953976162a6406d125edae798bc1bf850b8867b3242076a30", + "0xa64d9c9681b1192185c9570a6512d8b21483534bf0ca7f457acc96f91070358d", + "0xb27f0ed2428dde6c5506770651e3cab0fc62b71be0f245a8f6a84c326ebdf327", + "0x4f71b19b200ccaf3d359eee3ad5d7c155616b86495a43e2a7c18d0740304aa2a", + "0xf22988f8c5443f4400af9895f655a84b31e871a68e74a396ea5334297c0fa190", + "0x37dbed2e2f7408ce439ab0ab09af040972021ecd606f517af45c195a80e3f3f6", + "0x5165c41b008baa5fdd010a9a17f0c2fae2a0f16b4d230c21bdcfc737e9279c23", + "0x96ebfdbfbc02fbf12acdf622ad7ffb8dc10299ee66c4ca956eacebc6073fad75", + "0x47ff8c523b69bd123ebc4ee8a81240f2bc1c4e8dafcf9b9cb5db5b7a8f4c884c", + "0xcc3a09c1108d216199d7b3412f86d73d4fa7585c393dd3ed95ef0320f0f9bba6", + "0xa79133fa77c790f4f12a9bebaf21531c831c72db93e4a36a8f2ea672260d74a6", + "0xfaaa6544245fbf22f3016befbd4acf93135e64f69a7aeab07599af3a52f6323a", + "0xf489992872d1dddbba3c6b2fee1eed0f604f02e7350d747398944bcf4fac3171", + "0xb49c4387382e339ed00cba9469275920e116ea556bbefeecfc9c154d2f1c1f77", + "0xfff493a58d86d6160d9bdaf60504b07d6f33412fee522af09c1a7de8ec9fcb05", + "0x584d1e0a2569cff0fc1b71c850eee0c1f680037cbb678bbaff035c49ea5a6275", + "0x91682c3606944042c10a5fed5e6b5662c39cf980471b8bc603042cf0d455842c", + "0xb979f301dc2bed6c7e60bafb112b92b22b5f173f1d9e8fd665415bace1a580e0", + "0x71d439075aede2a781f1a872dcb8c89846056f5317be5df5dbf47904d106938b", + "0x9c2353de49861c4d10309f99457e6f6d9e5b7a57360837aaf0a1942c0440fe9a", + "0xc2c08c3e2d8741a4b4bb180fee1b1d0cb54f87f2739aa3881d534a9c73fd2d1d", + "0xcd75923a659ed6e79c9a1e22201374bada6bb2e030e3664763dda54552bddb15", + "0x60749dd09da7517a03cf6baa9b4623198f4209f1274c00bfb234c61d467da12d", + "0x11b1893d89913c9c57f32ab875ed403fd9802475e3c861472dab770d4882192c", + "0x26ddfbfde82876e17d6872f31aca7f233f790b3ec0618d6b5c51871c9700039f", + "0x8c9ceba1e4cc81ee6103acda0bceebf5b0413023966dd5c3c5641453c96c29b4", + "0xf30e9e6f8456fb427f96f356eac399fbee64dee3ec4a2806701c3484608c0edb", + "0x7773f80e3cadcae69cabda956228cac8cf774bfa84e2ce92ab2872ed19946858", + "0x4d510670cd4036f534fda9c7b4ddc14aba28ac985b90a0bc831483621d44996b", + "0x4e7d6a0fef6ac54f4f0336961561398600d0c6a04862f613ed6eb648d45bd348", + "0x55c0bb04ee6e1aa15ae55e1de229ab5a4b553864c43cf527f2ee42d441bb0bd6", + "0x92a9c4000171a6534d7546749d7392a9a18974be969bd773b4ff3f5c39c91a17", + "0x892daebee1b6c833ad425d5606ac7562c135688ba8e83178c0f8438679e84e7f", + "0xfb1438e6e00a88a26dc46bdb1ff1696cfac94bebd02f16891c08b52de7accd84", + "0x46404590a94fdd59cdd4ce607c1ba016a78be8bfd8dac361b8cccf6191aa0bdb", + "0xc1a63495f12681da588396c2d30096cdc8c52fafbc0bb0d6f11de5ee2c5a7c51", + "0x86ce595e0805026d106024d9d13e0fca7b208155901b67cb0011138b31bd947d", + "0x7bd81277da5da97359e67e2d5c12cb238daa009f4220166e13ba1f067125888e", + "0x2dbf4b23c2178c8dea6066d43b5f1285894d9e74a8b1056d0ee02091b84dee50", + "0xe983e1211c5b12ccb547dffe850e4adff01eadbb6717adb150248900332482ae", + "0x2f42bd119e06fde6cf7e95c59caeb189afcec85ee9968196f7a15917f98962c9", + "0x1e54e7e17e28b7c2de1c8391684a938e1adc2011fdf8f4a6da900f3664f2f25a", + "0x657e31fe41599356929abc24f7d751e49aa769ef9a4b9d5b37e6bf019dd567a7", + "0x33de4f2776dcd8b17b846816e02c4dd1694891b6827f87a80b31ed37ac0c6048", + "0x2b3b692269fd869b7797c78de9a521705aa223d78652dfbb32c1b8b612bc4351", + "0xa57d205b64565acb103e962a83d300a302efdcd96a13f4c79e80e2733341a70c", + "0xbcdcd2d22c7e21d24e48d28c43d09186a15568feaa24f44f126e5bb96ffbde99", + "0x3a6de68513eb363878604d054f46224e8567f2654cbcc0d9f81fd37fda804a65", + "0xb762285a5d8172a6df584ed15e954f432ddd8f41ca342db7d1d14c54af21e420", + "0x97702988d087056b85f9046bb8d3e37365f4e5811507c1e2daf544af76f1825b", + "0x8d1dbce8efa6eeb4269e22b45c2a9e7c53f7ecafb83e8219b14d43f66b6fa68b", + "0x54a2b87cc430e350eba1271a9161fd08157e196a4d4a7ea29a7461dfab6370a1", + "0x253d68032f383891fbf9c1898fe7d41c6362ebf759b3e3216bc14bad63250181", + "0x175102f1ccd3712675505c3d74609f2c46053c2501998a91b69b2eac9e1e476b", + "0xb07dfe916a1c61b07571327de80a478aeccd3f6f26aa4ecd7081a5f16556e946", + "0x0c87d079935642a1d3673d9b41ed2d3da33ef124acc081e236b23c50d78ac968", + "0x0f3718936f3be6ac78445fe56dc92e4806032d67e014cbe0a92e3193999c8acf", + "0x88bc8add9c916ec21c2f83e398bee626533eb038900c787eed34cdc1ef273a2c", + "0xccd4eebce003d0415c0ecf2d40916651b5f336e5ac64652b69a2ef653d777995", + "0xb9bbc12a4b92aad64875c00d7536c7dee7d62b87813b99a9a77bdc066c169a89", + "0x9ec43027a7229ab550391eb6dfd0cd5cc9b3b103eeb0b79dc9d2f4d8ce3c0aa3", + "0xb4e8c06e7424fdeee2f241365828d9a407f117a0811cced5ac35dbe9abe70a81", + "0xa5a9149f1002457f7c9c3dc2a4aebf7d5453f20c1d7e3a3a732ae92b04b8c00a", + "0x28d20d654b1e7a024956a6c8f53bd1c097d1df3a6de91036092c88c8070474f4", + "0xa11eebe47ce50f4076209307fd58c75b0ff725469ea0875c658119f7abc644de", + "0xfff2020661ecfbb50cd6263686f903127b9d1e5f43dd8bd2d5ecb09eccf6090c", + "0x253576932466ee619cbd3f012915380f1e7a79972864fa0e98a755f902f1199c", + "0x554258855ef348fa770e3af434da722350e998e930f234b5b8c33d3d2f806595", + "0xad11b76ad542ca1e825b251a6cf410b6f86c8c4b42b3c8690a2871e7cfb27882", + "0x3c3d7cddca90448af6119481e08b388df75389ac3c7dcc26ac532680b23ce2a3", + "0x94c4ede45ad5b27c5a6b051fca3b055d548e4c29d2541a9cb4c37bcfff4f19a2", + "0xabf8f7c1b9828d61e3aa72ded1ceeafd6ad539b79b5d56c5eb93c3327b9d83ee", + "0x6e2aa49e5942f19f19181ae911e7951534aec1a7fe295bbf921d8f28a4b7c0aa", + "0x0f49df5c80ca4ff33623bcab40e9ded6159d3f167f7754c3dfaa2eea0ccc368f", + "0x070b14922cfbdf78ead68019e520a08b987ad203db005f4085cd25e6ab587016", + "0x8501cdc568d6c64cef9b87e639d5a0e3f5a4b7d77e8510df07bf0fc50d89d020", + "0xacb70d4cd2010d149f382dbc0f7fc1b74f0fa6bfb5e770017fad960aeb7c80e8", + "0xf49878d3473b21f4ff2c331fe48074ba47ff78198f839dfc7d1d69abab81e499", + "0x9a11ca4ae2a7a68bfdbf54d7f0978150176aa4012ccb8d1781c10b58e01b851c", + "0x58729c03b10b2ec8b4abd91b876ab57a2c0bf05ff02218bae9765a90037562b3", + "0x3b5b033d76798ad041842b9ecbe223dbcfc2d5babdbe864480126dd932d29fa5", + "0xe08ce9149dae8cbc8968dbabbd97624f917148f26f45b858e49c2c389bb22f20", + "0x6b532db41ccc7cdd970d5cb0166dee2272346f23e0acfd8d751491d0c3ecaec0", + "0x99fbdf39928b3f855b2390bb845a96478221330b7c350e83e7b4dbf7a35e2685", + "0xd2a2a108c0a4dfe5ba0d0488da0de7f6d15994f6c14b511712dff4af33bbcf8d", + "0x75ddbc2ad15fc25c2ae71750f1d5bde5e825b40d29d631a27d8801590d5e1321", + "0x226995d806f5d03722266554109395921f63ba1f66f5ed1ece7341bd860a635f", + "0xf78d4178efcc128e86b2e1df767e59c76a4bc9db0ea294bec79b08448133568c", + "0x160e1fa8fde835d6e91187a3da5caee245d4d0b9ee30894170617b680d275166", + "0x361d71c972953283f8ddbab4a45a01b39f30290dc1dbf1b6b744af5afb2e70d0", + "0xb8394cc0d42a0b60ec40984f753b8eb5b9175022bc2ca7f80d64d26106ce86b5", + "0xa0f6ff5ee727a3106e045468b5ed9ee8ef387eb9a0355f2249a71441819b7bd8", + "0xf441bc00d94f06485368e043f933ec9f8e181b11ab0212d728d83e2d039edfb6", + "0x1da12d2213cd65f5fce71c06e44b40a487d5e676558e6f617372244f8e98d549", + "0x7d988011d5c7da97b37c6a6936aa499a70aee8b38f8ed60959f576c108c54d1a", + "0x3d5ff693e4ec163fecbfffc95024cdddc4d2c561297124bb69c8d6aad4ae85b9", + "0xf7db67de101d00409e1ce3430445fe3d38a073e1c81e1453d63f4228a51615ce", + "0x335a94506606e70ca259348ae7157066b55faf09a4ac11bcc34a0b865f4a8057", + "0x137d0de6cfa1e475f6d94248c1e30bc10c17b98d40829974ed4ccfd7de0ffec4", + "0x1d63a7c1c54bc740875f3b5d8750aa6bc85d1c10e3caa4c9d67b4b010a83c29a", + "0x04e0208220bd1218b6180dcdfada95b3a8391bb380b0b0ad5a1a8a02f1a3687b", + "0x02a3dbb2d221bb8e8be58e12982445246928b9965caee73383e54edadc017315", + "0x549dfa1efb8c32071dac220aa4c76ccc038cde6ec9a39e2745a2d55e92bc0890", + "0x1f9bec0a6b3415194528a23443c9904f578d57d7024ceb964ab09a9e8e3d9c03", + "0xbfb25a68c40fcc0dd996e992b18dc73a48525a323995a0eee03a0a04c572b68f", + "0x7244057fe32846105479bf704b871bd1a081acefc57b37aea76116442805a70d", + "0xe6a48159dc041cc9a0d8eb124aebcffad394a400724410e956f8f46e1d89e8b7", + "0x812d9147b6661f54af0c39c1f4de79588ad9cb62b25befd4334ef5f3ebbc2cff", + "0xf9aa945fe2eb3d1e2a01db68d4502a4f33afcfa967fc06944e035c582dbf383f", + "0x63a437b920c6b916eed44003b8d35872acbd0d1859b6596b4f45e39d04057e0c", + "0xffbaa46c582530498f30e51d18deb6973824b850d09bf4a4535699890a548eca", + "0x6ab7423011299d3a82d2037cfac752bc0e88a82696f6aead69ae940bf202792a", + "0x2fc6f5dbcccf16340f2b3a5e341e364c3cb1dbb3e899c7acd6e50e7ab333f45a", + "0xd354b48b2d3cf13487ac8138caca0740408b42613b50f056ea595741ba275d7c", + "0x8e1cbf4bb7a83b1e47f69c08f3fbb133bd36d8fbce923db79a248c21e9657f8e", + "0x414c7f4d86ecf78c3988723ab584ff735633a37267b1f5986d0c2e6375f878b8", + "0xe0b0dc519fccf20ef45b2b185d791575d88f93011bcf5205f4880f7ed755a54d", + "0x528a7ac7c6a17775d207a983b76ff54f8fbb84b8ceb3f6fbb60a80d9f306c497", + "0x458bfe441e32d15fd95a33de1665a94ff4f2a4c357f4fdef5c9e7c82013f59be", + "0xd478a55408477b3559d50bcc4b5c4cc2713e0666f40d87c5faa7328c5b7db489", + "0x9977a36db4a48e7e1f4029efc494a341b8eb2e40c73fa9ed3be2f16065df8900", + "0xe2cb22eaad423da374bbe1cfb8f4f353eab0f9874084aac4f42578525e26586c", + "0x0225069114efef02e188a1a35320d6522c115706c7b87b3b54805aeeb9e60db7", + "0xf82e17b405c2e19957b63706c0d7405e09be93b129ecf850e1941d62f1c309eb", + "0xe26f6f439b0d33f00a973b12f5d3c619bc4cae8662ba25173fa3398b8fa19d02", + "0xeec38666a51fc161736b7b48c8befc98cf9683975abb8432cf735edb907b05d7", + "0x8d8c5ec1f83108372f361b0679a65bc72f1b5055a3b9a12f01855a61437c9ebf", + "0xb53f85551f811c60b17b48df2125648aacef9a74af403cbd877c1e539c045ede", + "0x498d608f0ebf85809b9f5a9270e481d03f4e26cfa38600e50347b968cc05b13c", + "0x8e6d9c2693bb876101c2c0ced0976fe71db31b0a725fcccc88cf9a69b47cc9bd", + "0x5ac71d4859c028d90da98406f2c739ce6280cc227529ef8f1be3d3547ef84da0", + "0x5e72e33c2d66fb9b31bfd4d423aa1ae7d4aa88a30758e29610eaaee778ad75ef", + "0x97345508a573bf5036243f384e1584dea6a723ae342a876b572526cf992f956e", + "0xccb2773ad04c605e9b4a6dede3cc41d69f43439f19e4cd97f54de3a28052d0e6", + "0x0d48cd6317b72fcdd315a6f912646831ed52257ebeb03fa70576a918282e43ae", + "0x688754d57dc88205d6223c88e802461852c5f930252bf74e08b73a79e4f0ebd9", + "0x2860c5f26b4eb0896b4ce041582a8d38b1c8aa21b6c163784277df2658d7e191", + "0x35257fb9aa6c9e8ac16068786fda9c06ece1cb2219106da3216ef4648d28be29", + "0x1b81179c25932e14098aad725e59bcb8da8867dc4a5d145e90103beff868f2ca", + "0x60309b91add03a291fce9fc3f8804eeb993508d7cd5ec4c13a41d31b71d09997", + "0x04d2e5e78c8d8c0059d829c16ea7397834cff5914a5c0618e5904a9037338deb", + "0xd6d345d35827336d086eeb801e331fe77491d47f0df668234e05c3755e413e13", + "0x7f29ddcbfc971fa8ec8e73ed1e77301310e99f677c17320a62fa32ca225e3e97", + "0x036d5fdecca68a54be820fd086e1185312bc9d434b332db547d65d9fd0adc5d8", + "0x07d7ebf143ec977f4134d782bbb3da778b1add224fc3617987d9b21c7bf7d09c", + "0xf27fcee747ad3f1acfee97988403537b85f51ac1157aba723ace11945bcb5115", + "0x5cb6c6cf872823930abb5798d4f1db9d0ae200d21ca3716445fcfe675432cb68", + "0x8226cce1ff6639ac646ec09fd71a0de3d6ffd323df6ea24446dbae7eba66a69c", + "0x6e07367cd7df8d5e756e9e4c535f0933df76941640a7bee501f8af8b653543b0", + "0xa60f86078624b3c727784d4a95bd6dee72210c801e7cd0a4fb01a2ef5f7e24e5", + "0xe3ff30fa3e754fec8605305377cf6a3842d2cb323950db58e5bf02794135bb2a", + "0x74203c76eba1b90e3e76fd493f66fe46130e13359547ce4c94919e9c8909ddec", + "0x4ad657902a564df2f15d7fcad6e4171c96c65798d8b49d3976c7d77869c06ab9", + "0x043cf965b0b5b2dae096d8c73190ad9b834b665097e6b77212359c5029fe8f1a", + "0xb370bc64167f8c6be57238f35a56b840688138e860b08c2c8694401ca32d22ad", + "0x1c242203268f4d543b7087b0b4506f4b5e5e6fa4f4b495c6bd15f94c7ccad31b", + "0x1250c4ef1fd54888a4e377127c9f27889fc5bae3455010733e8f48d7aef65c99", + "0x83bd5c6109c0937f109307dfae9b347fe7da69fceac9444da2d6394d26911956", + "0xbc25fde0522d9ded3c69f9ce8233145b5b15242a8f5d6d6feb2b7aaf0aec5cc8", + "0x0b7fd860e34f21a54293ba2dbd61b28fe5ea3399a29ff7af4f577e681ed579c5", + "0xb2d96f1f4fd0f26e226386aa94e306d8a4a2a3be2860951e0c2e39c77dc31bb8", + "0x4b9794e3a3fa08b8a71f55afd71f2c5ba34fc9d773c32242246c721c87e4b14d", + "0x01d6ab151bd597e2681e9c67a0c3f445c85bfca4f8cd73e3d088f49dd669ed2c", + "0x686280902ed294c99c49b8c2366686af45b9c6ad0e7bfdb1c52f1c901a6be2b6", + "0xe0a05a29c78f04794b3957ccb343be88cf11b00f5d2454a6003e2b363f88d5aa", + "0x798aead8eccab3a4d4dc1283cda04057038bbf80944a87c9e796fa7565e34ad8", + "0x866ba6664beb3b953f5b5524190685eacdd1830248bcb5b0cdcf686101be0ab0", + "0xf31b7929f0cd73d652d1ded75d5ac19d95720b386fdc660e0829d122e66a576f", + "0x20fb041619114e9beb6d70ed0a488a1ed8aa149ab506e7bf62244934441fe0a2", + "0x91f9dfc54ea16eea1700cf1d729e77408d037f43238545136f6cd9c72bb2d260", + "0x7f633029a0d96a3e4232ca3b02189b59b10e6edeafa9756f8db1e8844e9cba44", + "0x0b4f8a2e3547fb13fb7ee5555281ee325d068a76a67ddb1dcef60a6ae4b41597", + "0x35b3e9e377449e7b1a023573123f5d132b50a829091183d279590edc73df67a3", + "0x8ac0d74f10c0f6a60d2e5729d150ffef0467934f8c3e0b37eb7112eaff246a60", + "0xa8f65245b7fea166560a0d775db32688a0249ae3df937a42847f4f0f358af085", + "0x6d5812337f22e0e436ee2dee8bd3a45b237df7e045a4bee1458c55a1a269cfbb", + "0x6f79965282b544af683f2cd74cb056c092d5aeadea1d16e34382cd97113f4436", + "0xf91f555495a762ed98f946487f9aac89b4485c71fde9d700cf562164773b119f", + "0x92397cb86fcd4bdfd448fce9e3fd6fcda60586482217ab74884182d91f3a33e2", + "0x3f694bc4515ce3389bb57feb21ffeb3078e67c3a13bb53a345f7d837d92e91d4", + "0x81694d138eb5afbb7137ed7de9e4fd7010528da30014d06feded8cb2db307994", + "0x56d59ea9f640664f6a1ea3d92860f15ac38ec313d520b24b0ff4e365dff53b4b", + "0x5056000d0e11cf10bf36c57b44eff8fe9560e261264ba2b29e97323c3fdda5b6", + "0x427230af29e403291fed2784ea8852a68d4bb0c07a514dba4797644c8150ddad", + "0x21d5f70bde1ffe09c38545103cb9e6a349e62c1316f1e7e78c2f93e577a6dad1", + "0x385df64391152fe6e1f574efc1be371bf46606ba571420c601877dacfc3d1458", + "0x4076eeac8e1b22684b6fd996a11db49ef6b52539e481c1dbee3f1ad3f59d4872", + "0xa8239c7d2d32a3ef6f887799bef8b470dc52d0c82af8de31bf3a8e4a6bdf3535", + "0x52a6ab7c89019f8fed6761845f9071bed1748aa461b87b0a587b7f59489b2dbd", + "0xbf80c8df3c0202192d1b888f80668c5ebb9d4f8c7d168570afc54276af4de578", + "0xddb5784df235570dcbb1a08fd293d58f63b7afac494b1f8f947677f2dd36a87d", + "0xa741791df39f377bec8cede1f1c491eae35a710de095b5ca5c56d77f4431e87b", + "0xb119d39b47e1cdffe5a4f912d7bb19c6e7776803a386ef62226f08ac1fa0f4ad", + "0xf71e68699da769cf06d77c0432ecff635cedbed284256336c682d542e33c96ac", + "0xb600381fb3bbfa7f7c3b555c51999446b148a1507bd6279752e7059e2e0052a9", + "0xa596f51a92c38e63a7172461962834dd700bc847b1e29c03e27b8e49cca19b4a", + "0xee28f2ef5162f0dedb5de1c4b38a1049e98c82a34570b8bfa19735e915909579", + "0x1672d010862647d074aeddc4189a5bc3a128b8084eba6d011046b11ad23f445b", + "0xc99102d4079edccd947367846ae35e2b40ab3f0e1aae8d68885b1753c2c64177", + "0xcd1003ed721269cc94a0736f70714394c191e7a663191268e2daadeeae2790f9", + "0xd33a0f2338d2d95eff701d0bd287e70e0093c6954455bbc63be7de7c39f6d9c1", + "0x97fb57fab06fee889ca8db09d5dad12007024c3dc59f867170d65540d64808e5", + "0xc4a6963627634d4baf5697343904c4c803b2f875f05260602d9ecd45e0e34d4b", + "0xdf3bafd9380eda31fa5f606fa915253ee8b9a41cdbc0ad12e2dc1cbdb76ccf88", + "0x141dc873ceca100df1127451dbd96e117ffefd054076327b68b1c76a4651cb92", + "0xebcfc5da5a1e1882637b9714fd899d59fb957dc9e4afdaac199264e8d29fe5a3", + "0x087504ed686f8e598560ba1f70dbfc72eeefb7cbee9559927a98bbb31b7bb9fd", + "0x767d65e905169fc44546a7c7828c2f1b76898d93df663291db08a0a6f0fd8610", + "0x0ce5170b5c9ec6377c3ef465d986159f12e65c32ad577d8005fba498fc6e5d9f", + "0x76a78e8c3799f93f1359313a6b42f3a4bf92a9c52c7b495b8d82946d471ca965", + "0x1b5006aceffd1d61936cb327b7420f3a88ecc4ed8808db9f245cabdcf3da6fe0", + "0x5588ef96fb1e960284211b143bb5b5a1e431a015b5ae8aad1a86ba1b49fad459", + "0xce5cf0c647eadd6de376cfa52e4a3008bdc0ea3e09beef3be5e2369978bdadf2", + "0x2e55c31e3dec040cbf0f2bd0816bcf6d41ea29376b9958a40bd799c7c788d8d5", + "0x871c62991b05eaece3ac9fd843c62f6a635230d885b075df28f3421c64fafa55", + "0x36004f4df1cd2809aa89c4edfe3ce3df7a70c1cea1b99d906a64491f002b0374", + "0x91ce82776a39a4a32979f0df16d17c4ca0544e7086c90562c66868b588058106", + "0x23d8c25e9c94779c445bc7aa84ed86189617463e3a9e62dd974a23a29eada969", + "0x249e41cd4fd36f6bd6860286bd29945bb98cf66c0348f73b26bb4a28c3103a52", + "0xf158ef6bbe5a54a85f11c58e5c569dc927089ebb641c9d0f6a4641770e551cca", + "0x4e30a215bc185573c02cddf66c40a1c829b86dc639c2eca7e6a4026fd8a27933", + "0x15f0ad2cf92788cf0905aa6f8d092b1350e3f1530f1b06e07ffd8f37d9d867ee", + "0xe7d081057d6d3f5d85be6e28cff22e4f4e2c842d31599885f4e3f1c96049c101", + "0x342f966910c67104f934395a34ffddb97260920bd9043e2f1aace5062520ceee", + "0xd09b337b1ec7e7a3188b2a8981d14dfb89bed807807a6fc40a21ce82a3814b63", + "0x5bfcb62ce51ed31f94636e5e55a4fbbb8d63342818814d9167d690f96ebd9153", + "0x9f46f879a2b469812d61674250053eb01ff91b3d61b66ccffcf8b0566bb0ab0a", + "0x9e7c1698af64e08be4d5d2bc9262a7e0d2ddbab9b5c9499b505245869a1e791e", + "0xddc3dde6d397fdc437fc95bdc98b1bac052a1b4fb1bd81b90d18d63093bc0efc", + "0xb8180ff01aa196209573375a70c590e9ca8fb5eb94c921436c534fa57b93c802", + "0x795c03cb817afda30f993770ee0718774aaec6d0c9c01cb91ab2061539ab7349", + "0x45cbd728f2329f5bca7f7d188e64b9b307eabbd816365d0352e2ea661d923511", + "0xbc1e8acc0b620fe7c44f4d661950981e8388e3f8bbd58546157a1dc716d43414", + "0x4e796ee801061efacf4d84372f6daab14a98c3e91b569a0d580217442e1b821f", + "0xda432dc7a649547983d6ccba6ad31b7cf97ba3c7eebb5eab05f34561759e6090", + "0xd51b0632c736b3403bcc07399e9be4e40e04928ee4e63e87710002b066e462ff", + "0xa3076a6242b4e2e450f227294940d5aaef5b62ad68d63affc390f874958c0c0a", + "0xeed1d4e115039d92f2d82401aa631248a9c5b8de06bcf784adb918ff28d70bd2", + "0x6267b83c5d6acf41cbe965d1bbb8871228a060e46435a29c6a7ade18e44f3ce7", + "0xbe79880b453639b576dfc891353dcabbff3d16479ceb74ad2184a1dc89daadeb", + "0xd5356e5ff86c455718ddc8527750b69b3658c9746c0e47ac93291b039bc2db8a", + "0x079545539cfb2ab2b1d5341de50c6c71b8725cbf3a6ef168869d392c2e6f6ad5", + "0x0e3aaea1d36e3945580c3cd8e26456260a19ec0630476dc3ed444c517baaf5dd", + "0x28d6d2c1e9e4080e0bfdfa907f6d7c9f533cc477a729eb83ffd0f96f6d6f5018", + "0xebb8535debdfb417acf2c13e3ce6107d7e286cc573ec1c06ea28ef4cf3729c8c", + "0x96440ac46648fcf69de403e4c146dd1a37eecea957370f223753ec93f32298e3", + "0xca28ae763d5602c91d437349aebdb5cf9dbc89e6cfc53c124370b67e31fe8f9f", + "0xe27ba10642ff994e47ab1fc5a29ce071d80b82d6f584eaa56ac1a62a771eb21a", + "0x34e7db6c5ad2d646e6791b58ec4d429b8bfd69f76b1d9bf71f860b1faa4911ad", + "0x0b83663dee1daa173203e106ee4996ef147a9940f2318b912364bcfefcb07271", + "0xb164c1d879ad665dafe81929e0db557cf2c573f188cd86fe35ef24271cfd9b26", + "0x6587efc2bfa2ebd6da9816538e3abc5f03c75b5bc425f7e5e9c676f97b1449ff", + "0x668316bbac3e4cfd0c4fee48957d9c8fda962bc556c5ca35246b88b6c43fe291", + "0x264917f66c2d927b7f632744f9dd7b844514af80bf3729f30832b222410a08aa", + "0x38b162eecc129bb2e1c82e65d785e84b5a4a9822bf1e6506492a25b082309bf6", + "0xeaa3ee39cfaed2aca6c1560608bc1a2ae32805812d792471c9c6a9ebc80aabe2", + "0xd7738ea58e4319f98250874c16bc4ba12f2362a8f09a7158ca4e2ecacd954d99", + "0xd26d6e2dd1b62f7086673cf153c3249b15c652a7bd43a4ef7b796dcc2bc44a96", + "0x11a9a4f1f8d10712e79a219eac2fc81b3360c60aaa9bf179e720ec04d69956ec", + "0x6ea3422e40bbd52abd6660d9ee8ff351ccc61d997082e470197a474509ae1383", + "0x1ab854452eb96365cc3ab33c6c45b296864ee61b3a477716dd9eb715529787b6", + "0xeecb8949e3be53db9ab660c71d1bf702d8e919ae6487812181858992e7668c8b", + "0x2a2ee4c33009656e5e38e44a7314c40254639bd46e32cb09eb1b9643d92f9ffb", + "0xa14c5b1993fb968f7e1dfe4ad24716e8d9a5be662cb0af13f43e174e0bc2c5b6", + "0xd5603250b1933ef1cd1b27932627f27599f81ca29c9f02e3627eb621f613c935", + "0xcca950815341af147085a53b4108ce368db1a634f204ad75f3c687b5b7ea3985", + "0xe14e1ce237fe627e8047d5d8f8153157ff1ff3d2650e0e2ba870ece940421470", + "0xfe2bd09d81d1525b996c67fb8407636e06723b4327803a106c19ee60a4a960ce", + "0x995cd4b1f16450b64098fda2e678b14833a3b382f76e14cea71a0d297ade2080", + "0xefbf5dfa769a1e6132741600fa9459b8a1d11b11c3b2563b22c79cddb34b2ff3", + "0x1618c918d173a9af0daf3af314d576a6419456636a46e2c6b8126f2365d627ec", + "0x3b9a773b1c0e16037a429ab42fa3883803f320beb9a34c8e36c80b2b7b814331", + "0xbe3b816b72cc63cdb63e2897064965c1b4e9cbca1ae26c770a20508be1d9695a", + "0xc57f2c5ff8087d6cc2039910f00323a90a0bdc3d2164e0f52bbfa920d62a15a0", + "0x0f11a1d5bf509afb2694bc08584718bb93288355a7bf0f801e478eeb9ef52da2", + "0x829bcd6a2392c957300253f7e9abcba7513908d3013a74387e918dc57053c035", + "0xae4d9d51eabed53e9ba4dcfecfc449bc165b3bd40d87830fe044811f4056580d", + "0x2a8a21d59547009a533695b5808d928992547937478ff9a61fa4388e9afc1147", + "0xcca2ff6985f20f7d1633c35447f45a5b27fd5a93802688e2afe494a2c350917f", + "0x2b8a2080fdcdafddc5d94292ab4fde01d91e7ad2c1b5b5a2f04dca9a729c3778", + "0x211074e33dcaf13183115f89252435b4efd8e1f01c38ed484ca69c14bac72eaf", + "0x5de84a9ddb48a4e2134be8cdd5c274471055234d428daaa1039ae2500e59ebd3", + "0x3f71bb8768f5c8d0db2ec8360278279f4382f3a50a939842d80be98685c536df", + "0xd26b7cf7c6f987f4975010eb9e77becf7c0c93ace9eb53d289beab868ab5c93b", + "0x889d8c294f942cc322a197b4f746c688a15e1692cad0d2d9fa9a125f4998a6d8", + "0x7a0c807c41e209d12128445df83dc1931d5a24923b38d259a7bb9e8e4459db43", + "0x564e904caabec0630b52e056ef9ac08a2fd276ec99d81644bf38dc0b09eaf820", + "0xd5804d2547786f7d26282726d3f9f22e53e0ee2390ff0de8b97c33a4e4237535", + "0x5999f87486f0c721b038c659831c836980a2f7ee9c887c759710d62691588670", + "0x9fa08ce53c180bb53d5352dbb2312603a0c3a5087cb32f81bcff368c457a498b", + "0xb1279296a8cef2e6b80117a48db7291169ad35b39140debe3ee71465b2a93f85", + "0xd3ca8ebe2a6ce6db208b4bf1853b8625e8b12f7792df1ece14f696d1694addbc", + "0x7fea211ff413b60098ababd9e3077f58325ec14d9fe23bbb1cea0025d95896dc", + "0x270f61667793c26f67cbae50931919b8370c0b395704640837d66aba90a393b3", + "0xe81214151eae79a310d5bd8fbee6358a3d897b2b9ed1282337b71a653db17384", + "0x5f2928cf34dc3da9a559ab89d7496510b3c2b5d00d8de730b6df083d03103abd", + "0x619e0c1627f0802d660f1b06bb55c39c0b570514e71c69d5de41232fc6bca961", + "0xc8384233eaacb714f29163a0a9b507b9c9d0ad537dd64c25bce91cec6fa6c2c9", + "0x54c2e035312faaff2fd08fea36df91f2add2ce39298a1987f4286f3592405e8d", + "0x32bd9a7d486a43926319510505b5018b9ae951f4ff0837f8b9058e93bc303876", + "0x6df5062af0c06aed44dc45026fd74a287e15f5a60f122e49343e5a1d10e5f371", + "0x6b3ffbe23bec6a576dcac6756375e6420123ef1eb39750aa6fdce9d874ab790b", + "0xcdd08aecaa642133a9b93ef888c5a808cb2c84c48943e7ffb6d531dfc1c6c205", + "0x563f9e429bcfdaca1ec2ee7007f286b1b3e4358b76d12d94015d9989dd50b2da", + "0xd3a709568bc87059c1a11909396d655c2f107c999bd75ff5104449f53d590f99", + "0xaadf85b25fd426d50f3a22404616141211dbe541eb116b71c6ad960fa453e172", + "0xc411d65a0dd44d5725a401d4a479f9b5aec10334938bbec7ec216572bddd84fb", + "0x4ba49c0fcf4dc7858eb6b77c942b528a349ad39859a2a1f8995593f04ae8cb2e", + "0x17f327906a7bcee96532e912374523b88f474beca4e40661113121ea626a209f", + "0xb0fce9690ee2a2cd55a0e088c0e96fa0e922b4119df230d4b903c4b18cd6da7d", + "0xf7070d16a82595a5782717429dc6d00b1f8abf6778db1836a23954cf66bcdac9", + "0xceae3600d842c5d03611dcdfd0a0231e469c65b151e247b2205cba2916324707", + "0x6d1e0d4ef9387d070ccfb68f0866937d44ffe7d9c4059a21bbb4b0c87b7a6461", + "0xa7c125405cda699de778318152df327cfe79cfbd999c5cc45db15bfed216b146", + "0x5d90e851ff50eff60b8c92d63274c9f9b5efec6efec3c2a412b003693ff014c6", + "0x03efe16b91c66ac58204c952a9cd24818ca61fc6b1ce4d81a31263a7c045aabb", + "0xfe9324d99b23bd0502d6c1020564a850c932a0d010593e1894ae21641ac5c248", + "0x969138be8e3cf0bf9bd0963d2cc6467d8690fc40797bb2c2950de0df1a8329bd", + "0xdefc0e0c25782165aeca15723fb74d95d96d1ed7420be7f3c85ce7cf7440322e", + "0x0bf69f52b595f75df550078e4293602593e3bc2d7ac528b7be44f556435d9e42", + "0x142f2883383cb22f5aa8e863756bcdd154ff3ed8a02d5cde8fc1572db65003bf", + "0x0fc8980e2ce7498656aa9012eff375b6b32216a3142fb974c357a553bc9b248d", + "0x2714b77d484d7639adb40e1158734058dc02dc761c7349c4f3818c70347b348d", + "0xaac5d4ca615ede62571ea4150e4c01cf31dc410b06d5b443267117197e60478a", + "0xcf9f45357d06955730a934d2de24b859d39ac0ac40c8b29430ffe061e3bbe4e7", + "0x52330a846f5d2fbfc26c48a5a95c9d2e3c88a654ee8f5fcb7f9eeed39b2eeb17", + "0x807c2b8bbeec7e6d43bb781f2d7405f9389cef647751c1fd30fccde0f004aaaa", + "0x8cceb13ddcdb1b080075083091120c394a94d6f8f00a2eb4c4498a3b1a7d2f5e", + "0xef770e4d62f2912430987ad5ea59974aae40a81771295fa1380e417b3df88562", + "0x92cefcd22fbf95dbfa766e7c49a4e211596cc6d997976b04efd818ba8ab49bd9", + "0x809d91cdc51f42438312ae27ea1fa94fea4bcb2c9341c274ea18513ba20ec931", + "0x10538534fabee44df110346114f62797a31cf363d4979f881b721043b2250e82", + "0xe252558398e892e85351274a5064fff650f0323f38b0a4456b14a435c9a40d82", + "0x7d313335d362826f589dae0164a04ea681cfcd54f10d8e339ad1978ee63d7045", + "0x713414b22fd3719c42775449895089e6122064b90258a1b495704fbc4677d92c", + "0x748b6883462e9706a8fcab3b0c71272fb0bedac622144d5d81fe710562b8dedd", + "0x2945d4809258eba164089c2a5605a7c9e72759bf615bdce0aacf96ceb7d6ec12", + "0xfd89a991d0e20bc05d484b9cab61d27a0406fa741e0be6c8c1c2655d1310cdf6", + "0xaa296f6295ade70466ed9c185480e186596f2183947f65bd04fb5644dec93d33", + "0x5286efb4ae287693b85bb3eb47ac0b697ceb72ed6331aaaa521d58ad7dcd7974", + "0x6b3a5802ba251becdf8ba2508a6fb1d3db0b5b99646465b12844b8bc23f062fe", + "0xfbeff1e7cea22e0563407d57d9b16518a0355b676c48605adfb13945d7bb2f60", + "0x7c0764932e56518167f4ee45d912c1a7c78f30271b41ee16038f358d9865258b", + "0xfcb998af040eb99c3393b165dbc904a197341fb7dec2d8430346b7772935dfd0", + "0xe46aec72c95d0accef6ebf564e9264de932458fc1143570ddc28eef3801430c0", + "0x08f97afe124dfb2a18c6c624d9d1bac4cdb5dd102da6bec9c676e7fa000a43fb", + "0x50a62c4cd65e3591651f8fa56831ddb37ff966cba87c12d83708aba72591a060", + "0x1abe248da61411aa6b6801dc188e3f834c3fc4600ccef36ad9d7bc517441a61d", + "0x07e38e7dee4062c20f4b3f221df72590c0838619617e051243087250defd0028", + "0xbab90921cb56563d69347a4197b869a8c8bc34d01d753b509eeb5895e77eac81", + "0x620404dca85a89624483cdd7e2b143b12a38b737c0eb783f5e4b378fa1d578e9", + "0xd70f44dbb657c8fcdb90bcc24a47485fdc99c35ce746d8eb2302d529be43bdf0", + "0x425c47cba9cde3b337c451eb7828b0789a76bdbe1f86757292e7c3768cc51b6f", + "0x11b521b56aecb173dff0358678298ac7f55015dd8b217d81dfe52129d03b54b7", + "0x98ef31c7277a68ba0a2a2809f8e7b4099c0e50cd47ab030f5e1c3ea38b92d39e", + "0x82ae5ef4f71c43cc296f1f6279eddc71766102997b0534ca737c0c1a63b0b3cf", + "0x44e2f38922e64f0aaf27607673724e5c91ed5a8176899e935c73c0fc09826355", + "0xa0361b8e3d7709c4a68ff24623856c54d16ead1762578eb562c295f86f453b14", + "0x91726ead73260dcf30eb478615968be91e4e2b6aee522ff6d814bae4aa595c64", + "0x8afe8954bd7cf7a6c40e3903015830f516ecb1a98c1b028b6799e1605892b49c", + "0x142bfadd2c9e988cb07d36bab795231b9582fe424a62de129a24fac85fc47b88", + "0xe369b5c6a44aa592c1d2c55a6fb9e2a0ec3274be74fea84d2e05451db7ff9b8c", + "0x10030041949c30aed18afceb0b6ba1b9bf58c338e275ae6ed9f2dead02a1b6d1", + "0x993fb9325d7be082347cf9361f665efd4d38466de4234233f272b1c09854657a", + "0xe2cdddac0a6984c0ed9d4232d8b58bc2c61e404c3e60b58b90b5876640e8e19d", + "0x4adb2f59c6704b8be33a046a07d2585328465dc1b45a41bf30fba1ebf6b2f7a4", + "0x2c47e906f61c60bbe994a54e3d0a68ba8dfb519928cf350b6cf8421e5c1779f2", + "0x4b712c7fc97f4784b2f562ffad648d29884ce68c505644e2eb4195fc43c00d9a", + "0xcc0fd5276fae744a1ebf274df70eeefbf301ca7e3d1bdd6cbaf425fe0d400758", + "0x0d3e81f37d9d96efad22ded24f6cb7174606c3b2d294259f37e4f754b28fa2e1", + "0xf80aae34aff371a9911fefdcae1289c126c5876b3e4d2477784196a4ed6dc156", + "0x916469d84a13c2971d02ceb166dbe0c9cdaa88c23e57772cd3c260db7d2f9ea0", + "0x37a5b98e5934c2bf16b048f76c06b4ab17945c1f549a20b76ecbf99ac99c3698", + "0x1dcff6c4816141355ac06f9e31a73f31e4b1cd947de42a078eb60ae828d5cf58", + "0x099bbbaa5915dcbc3f975ef1ee1e5da2bf248e96e87856323151a08dee9b5e7d", + "0xd0f2f3478ed51f2454d21cb838b89a3569b3b2704af4d702526af646b42dfbfb", + "0xd906aac9b70f76522bdaff3840df5d9714d352c8a632f44e52370786ab631167", + "0x7f99f6d3add64e2381d7ddbdee1306e6f6749ce116642f993bc4c06970295663", + "0x58988b3a6a1437814e0057b08ce6e86f58cef845f8df78a6ec563d056592b81f", + "0x7476333d9709b4295a63b55e1d5eeb7c23a752c4211bc8696016b70a4c13dadf", + "0xcbe4bdbaa8e34a22b883371b21d5e7cd474368ef0df5ccfeea3edcb377e071ac", + "0xffc358eec58c4c6cc0031562809154edc13b9aa091674e473304682dcc4c2c1e", + "0x9dadda32c544767bd65dce5804a695b8e5c35d2f96c203c350001e5be78c044a", + "0xce2a6bb7c0bceedce3111d97294b8672d0f6ae8eb537ea785398fdf06d6ca2a8", + "0x5ed79a31acc649619c09c9b5df4d595c806a02e93e92c4fdbe882899832f3cff", + "0xb3e94be6cf733ad114b1c1fe76565c448faa9f14131b30aa79aa36a0edc615c8", + "0xeb33e3a43cc5068b611f7a95fef45d5a83d0219906515a9ff02e31c0f1aa4e39", + "0x63a2f545af614f075469aa9f8d4e49fcac12336722936def26c0a4cd01a31b6c", + "0xa6d5ba412c63ff5903e2f30bdf2d1e93118514a8c82b532fda0259b5c3c21986", + "0xd170edc5d55910ee2671397a9b04890faf8b4a3aed0e98852d5732af897989d5", + "0x508e7b9e80ea2fee221ee8a527ded1d480d6bda70d7fcc2d8d521e35c184deec", + "0xeb07494e1b639b09c49b145d51ecb9c2f8b98ea596779d1a14a71e2eed22975d", + "0x50b37a16f4233ba9287fcda52030e2a7d92db254746bc42f7358c9fa0d4e3116", + "0x447b12ecbd02d12bc80c990d632cc2032b72a441b418b74dcbcf3a76ad8d69a0", + "0xdfa6b21b930c94454ae6845041fb6f4e345a11440077c905b4f3386bf4824ecf", + "0x7eab803353df60fa522a5c1c7d155939e1059ce4d6c83d7e4e3ca756bd0fd9d0", + "0x25a35bba3fb585339e9c9df30a10246774a72f47e99fc329d64d36c67df4fa59", + "0x17ca37df7ec4f94f41dfa272553fd5dd3d641a986fa5a9dbb262fc395dac8ea2", + "0x766bb71133abdf384d8c24aac3f663f858bc8283817ec2dc082bb008739eeb37", + "0x5748e015a55f336461f5b1c4bfc80e5d76dcd9bb3c72d583cb7e585c35d67111", + "0x39909825449948d25a7f9346dd07d83f087e50c82e9fe9b9d474c10eb7bab0ea", + "0x441bf9c03a11ecb3b0472fcbed6aff62ce1c44b237c3357a4c3f5e8ca190dba7", + "0xa0456b6f725f0c4cd0917cc463ad42e8d7ac9496cb0c34f067b691d89dc1f2dd", + "0x6571a9b298c2180c91a8436c7ed81da8a69cde6c1a20c78f8327e9cb7bf9d929", + "0x152f3642af6d21630770d739d3f86b5a0a8b8ae5806be4e1b568499349d36882", + "0xa7dad74a9ed1bde34b6cb0baa940b7d565afb8dd6c4e2bb7fabcc30673f255b5", + "0xaa829dc659ea777c2d84851ca7eeaf8fa1e1409df8ec151ff9d9a87bbc8cd848", + "0xf70ff1f39678b75cd7e9c7cf7de35bab6d54997cce23b769ae452cbaf13db690", + "0x2ebfa2e52ab6f68c8b7f2a8d656c1fd997df4cb680ab4106cacbc50c4f1beec7", + "0xdcc2ac91b7ba5294b3de1eb7db158cfa53db057a4956d403732be9aee6899fbb", + "0x65dd99a245b52befb5099b69afa332a9a529bdb5c3b57dedb3fee52bc11ec426", + "0x83f08c95ecaee8710f687b9ef06fdae143fb7581ff1498bce187acdcc1af566e", + "0xffd22fe4049110b55b117b38f5ea4c268737db4fe92b9b5fe691630b39092dfc", + "0x7b4dbfce2925a674b0de23746b226bd901b7aa49140e400af6209e9877d11617", + "0x8c8d8762e05effacf2e70742f9c563458065f7a0abcf9cb6d6f605450aef08bd", + "0xb97df188cf546690574e316b144c8db55c7fee2d241ebfdba1424739b96a4197", + "0x83cb74821c0295a9d11e4be54cb7f2fd4fdcdeecf9a61a3cf7d168338194342e", + "0xc05d2a626a448cd6b89824fc6ceca1b2295361d7e94ce86005f7d527a0bbf10c", + "0xd0fb8122dfe38416a100bbf00ec04cfb14526296e746da85dc4487f2c7597efd", + "0xdef0c26f8ac9f6704a016635dc46386a95e014a8637733f054cbe87e59e0089b", + "0x084e741565cde3ad7fb2c60e0cb1244b1f8f6b87b210993abf2959fd380127c5", + "0x7986d8c793b5bcf0977260c761f5ab4af1d0bdec8a5dc49230f63258f6a0f403", + "0x584a5726cfe9772deb22093a30ff2b9b30ebc018cf861b8aa0fb28bed97ee0ed", + "0xf046b4649898fbdce79870896dbc2752050b5f654faeff320ed2184c7bab659e", + "0x744c1495610301a14d82e49dafbfce8c70f7f78bc0679f2c6fb964a476fcbecf", + "0x4edf5a73306621d2c4966d4aa6cb2935cd9484f1f0ba709ed5d5b91160a5de2c", + "0xb5faa128c00d7f97a3e5204995065e99aebc76706e2e96ccf4b37d7641690045", + "0x729bbb468965401fbb0f2ad1ba0b8ffc7072f9b18ef63e95f47cd98285b89854", + "0x0550d90dc0f6e8d2017e14324d404ec8a200c45ab4a17ac24cb17ca9b68881c2", + "0xdbc02a7ebd9bf74121fa2b4b05c1abf4bdf00a973b43e27faefd095d6cf80390", + "0xabd6ef9629eaafe2d8170d511a39ea29c30d9ca0f071d5ea0b80fcbaffbebabd", + "0xa9dad7abbf1bdbc32d229a67dac65cb5a14cb0e25e8dc57ef7538122471909fb", + "0xd1e063a59f032a9e0ccd9b926bcd6639e197fce15e28dc6b1bb1a4aae5862e75", + "0xe3187db1ce4e4faf95ae3b2136c34ec2ecf028e4054995fa59aacb94d0e16d75", + "0x4aaff2417ccb6bb6be1e3bb759f745053a3d45ce144db0fb627edd9900000276", + "0x3b108aeee36e6fef8d74ec08c937143facb90cfa5616ab7af6d37c00b3a4f1b1", + "0x1ad317c91fcc12235526ed9d6a45c3854f2fd421ce36a2d475fdf92d8afcb524", + "0xe39f66c3ab33ddb0d1fb51b969bacda7ce0f0f53af7012dcd4530435666b7dae", + "0xe071c158a9c418c34270cf27035afb0896251616ebbc57e7e5a2fbd503cb30c2", + "0x41dae0f056d18719bb5568f0893fae512f623e16effae772d35398da2bd8931f", + "0x426b1e3b67fb576cca9a180523ef9979aaf4d14649637f69347ad3876bdb6fee", + "0x2678a16324ded3abcc20b8545ad9a4155184e63b12d1d3a1959fc9d08dda781c", + "0x3f18f5def267a73abf0543135da57d752c57e4344ea941199055a38a46758ae3", + "0x031b50935a859999c1de5b772eb4363615388dbb9d12bfa6ca72111a069052a2", + "0x57bfecf554524f9dee811f59e9ddb287b04338323e4932c44b208913611533ea", + "0x870b1bf5feb1bb5297f34a80b058c81db9c97cb79609c537641f02753f665b68", + "0x3bcadf9d3dba81c74a178f533c75f1e77c64baa6ae274bd25a0cee762da43a26", + "0x38cb775e5437c113ad72ee04f0721390b7b8fdec2efd0eeae24d22cfd3f0abb0", + "0xc6b545762e567ad0fb73b49e3af783035e77e252f5f26fb56c39f2ba280e4937", + "0x922ba1cbae3ae6beb2e01ce1ac2b3a73383aeda9cd3825cdc6206d04fa04cbf4", + "0x9e5899be114b856b51e0de7a25cc1c5c6247fd2c06f0381d5cedb2c26c2081e4", + "0xc7c57fa4cfd2f5d2df0bbca134f48d152d8e284f1c0d946fcab4fdfde9235b22", + "0xf35e4daf46b5b181b6c6adb53f5d2f93acc93b76b422ad82ad996fcf95d5a942", + "0x0cf08cbe8ab573727328f5e5809baba6b8620536053d023dddbb9cc310df3246", + "0x6ab0f99c1cb99bd763af36647d29d6caafafa4aa119ec34527999f992de25104", + "0xa8aabd97d98e4a657980b581b26abbc9280a288301c33c45961f5e35303c31fd", + "0x3c92814886acb8f2af1342904d0b2688be4f269a24849507ffc0a7fd0d67584d", + "0x582781b1bfd4cd4d619ee98db64eed9a11c0562565fedb6613accc03670dc376", + "0x832c0574c81bc58cadbedff928fd08fcf1b4c80d7b323670bf67a29e312f4151", + "0x932b7bd4b919fdd18acaad39228563d65d19da6c7e8737f9c34fa3d58a57c7fe", + "0x153059b97cc89de7bdf0171150670085b850a63125d3e51525bba6765be313b0", + "0xba341526b613c0f3927d604bac37232dcd5ac104bf256720c62ed14ab05370a4", + "0x2b015d7a5486e2023aa93a00261be3ab97d38a1e7e1b14d8878e6c109d28ba51", + "0x554e29e53bd94dfe253d703050d8f54c703a009b412232847fe01e1b138f64db", + "0xfc603400b18e2570276dd994aa168b7ebf2fa9c8a3d7f4edcc8bd6bf5c008109", + "0x66e1cb6677eb595cad35fd028a36aa416f698b6366c73d179b8bd451b0dc3ce2", + "0x9219571b2c2860cfd4bf49b92439dd76304c2b5b2542f036392566b2b431db86", + "0x84c510b2dcbadb5562a66a1312b6016a4d6fdba205b5ee698978f2570fa191a7", + "0x483e7d9599fe6da557b4f5e35bc66b9d4bbaee82e2bcf29aa245c4aa679918e8", + "0x84dddf3ab9a135de68eb188476c23d1460c45c377e9a62c14015b2fcae515d94", + "0xe03b4b8470073abefcb0d4db364624116a046e85be9a28a52bd6fa5b4d2264a9", + "0x342a467e79121dae9c3d203615f772383d1e700fb05ff8ccb5a48961b423ec9e", + "0x025c53fc663b8cb0bae6a439bc0d4f3996618926337bd80797510b67000c6f94", + "0x0ebcae3ede50801c88b517af406fec7a3922b4876f28b3096425d4dec3f2ec1c", + "0xff78e7b509fbac13400ebbb8955bfadc0f35a4b568549dae44b55d15bdcf2a9f", + "0xe19e3bb2648377f25d4a190fc44b14e80b3e2c8dd17427fdcf50451af8b5a8b9", + "0x50ad2c5b2732b7f2c34fc0e2e103884effb23f7672a5290c7a3ee7f7c4609fd7", + "0xe5a000a849f39efb9bfa550d959e86d2d0d92b6f4034a3e75a84a4bcd34b647a", + "0x56fe17466ab440baaa576898ffb22735f4fb680db4ccb9a7dc6f19a060fe81e0", + "0x1ba71ed6a71d823c35464cafd2f4b35a047de73666f0bddc272398d1758b4aa0", + "0x801ac73a07eb37ee08ec538f723dcf2c41ba8f0f0e553c740a73c1b486b29567", + "0x732703b2b96778d10970cd6f90634e8e383d41f3b863c424a71aacdf3d567ef0", + "0x5295a9cea073059a0c806b5d84e95dd449bd15e081ec1543f04709737e12665a", + "0x25aa778a07dfa614a7554d7b00ed9c5360e1bda16df694279d45fb4c0a4ce11f", + "0x3a9e9b5dcda51fd92f8dbd18caa817f53f096f3b66f953a1f731adf41577eef9", + "0x554d4c03a8f7f4b16bee2ecc809a4a03b3e6bec0b0dfeffb45acbeac698241cf", + "0x567f2220013d4694394b054b9f93fd33f9b24d165ec92eb86eb216f2658a35a6", + "0xfec8e9f64cbf08d5dd3e19ecf7e685ac89e8430221f05166f84eed16e6e42935", + "0x1398f794bb66f9bb26eb2a17b32bcff6c6c8796df52e7a5f8c2b58a94e2d8912", + "0xd32d51d30aa51d571b89bea7eadbb3d32792c5971832880053e6da18a6644f77", + "0x753244cb3d3813f9a59b396fff82253ecafa836b37dd4f4572d2ae033142436c", + "0x74077018c89bbebdba21b096ddeb988a40943985fd479a4a95b172d6d89b3f12", + "0x20ca619770c23b5522ee50b629697763767a61f17652ae06f3f30bef7f300605", + "0xbe0de8f6eef387c01546944519c3bd9761c69bce0e9620d9995dfd4dc66e10ec", + "0x101bc2c69d14c170de6b3ecab9208f68b7b1b8ff0001a400f7373b77454113a7", + "0x8cf7437d2474278b2646a71baf196c21994f640e9baf0be059d820f57e0c66cc", + "0xc5751a0d6f9f5b859382b9840127d837a015a7b33d0a775e935ac2f2e57b1488", + "0xbabcfa88c03ae1d413a6165c7dfbf204d5511999a4fc74ea33a694aabb55e054", + "0x66b70f7c56c40e818fb1cb842a13be3e44d864d9ac5f1a4336dd00330685cb80", + "0x790a401845ed04ea517fe4721da3cda115adba8cbd28775e8fdc9bbe7a5bc670", + "0x2696bb11d905914f93ed07d71b99a6a4f2e90aa7bd5eca5e32275bd4870ac95d", + "0x5aea5a8a2b8586491f85ba8a387e6a6cfe8970c5f47a77f517afafef9a009fc1", + "0x7ccf035e2483a2dfdf068c0cbba769d25e21347dbb40302dd2a5c396cc082237", + "0xc7cfd5568e4d9769465645a1726b4889656c99befb7aa02a5b8ef8daaa8b03b4", + "0x5d5436654bf6c9b428c8ad12645ea5d5fe95aeb5e639ec46d4324dd54b0e7e8f", + "0x82f4a8a018dffaa850312b375503a6325562e75786393810a383498e71dc2c6c", + "0xcb82be0f881fb2794314fc3e2cfdd57ea5e12fa7105a824ed033615c4ae22f34", + "0xefe0e3f97c4e6b5be518d58f398ded35421d54c33e0c93e3ca0b527ca50e927b", + "0xe6ebb787f18f2d0d042eec05f2886020262ac20f3c14e8c03885e04136028823", + "0x1e41e40d2da6017775457223d1cdfb06bf41762b8bf47040357592315f627dea", + "0xada6d7bcc5013069b5d0676df3b067110db631d07020104a556b61423a26d3b3", + "0x8e0840f9e38908e49fd12635be7735c7293833c65929d5aeb5035d45942301d0", + "0xb01ea85a249d3c640f5e2ae43b340a5f0455350719b13cc8bf1a50c8941a8ad3", + "0x4e5524cca029a2729d27a3d2a712979f35e07cf9d436ca7dfc8c414eaf5d5a52", + "0x72208f2a837b1fe9e7445a72f7d57e414db9e0bd87f7e5daa8de14752a2a87c2", + "0xfcf05de95385cee5449c1ffc63cff009b585ea5896b2ad96d43e747bed4aec71", + "0xb9ba0e212f4dc38e5a0c2b62bd0c1bda73459e72233ea38cae8f4a91f0a6d764", + "0xa8946ec7aef9ee1402442e7cfb4363df529b915c96698110ec1e3c15d445299d", + "0x07349344fc0ac74be9acd9f616a08b3d1bcfbb08c2f95d079c235f52a0322fcc", + "0x223fbcf9b3a552057f728cc0e4dd283176735668beabba942f62006a902249b3", + "0x0e28903b5f5db741536eaff97cca54fb98357ffa69b84bbe365312d77374e47e", + "0x6588620c06642d029a1f8dc0b95a14c198b7af2648acdf1c8d73c80d87cdfda6", + "0x021f66c28e1fc7678af4f05726d8670bd88a143e749a96edcf7cf8239607e9f3", + "0x339ca9feebab8de1672036fe85ef63bb591f5466da074793436a07919a7740d5", + "0xee504bd35830555e345301e108b4ee3698c9a0739a8d4210ac975f1aebdfb944", + "0x61a020081cf4fd487b0e9b694465b94016d461897d4e18990e2d34a26e6a6541", + "0x539ed46b92da9b97e94f0bb089b034af3e6c85b9812f5ac18b64026906ef4f33", + "0xd244eaa108e905c9160cba9f75b3d4f46e428749c0a2de7b165e95992e63caf5", + "0xd88315191813c72230222f636d5de64bf5ed7bbeefd574b1d0c2fa61e16d5919", + "0xd428f280ca6b4ba0ff8bdc58a1b5c8ca5991f9d2dcb8522b17b3c09647a9c8a4", + "0x0744cac8522e0366aa470de75f1dc92e307f82e2e300fac1f8adb359e7f5d9ef", + "0x6e504ac6d3e63679f9db61c3e37bc9416d687156354d1fe82f7f434c4e43708a", + "0x34a5c50161a9b06229234a23f210458cf64fbb5531298735826599bc46179e87", + "0x03a94978bc793490395c9cbbae9fba0f7a725f5de2737e65f7e4f55763631585", + "0x183f981a62d19c3a4edc055aba9d04e642f89f203381a4e63ed7496ba7a1074c", + "0xae5492ed7758112e7fd6c21582df31dfe0b1d6b3fcece4d2e8bcb7d5bf56a00d", + "0x8f5062a00e823791785fac6c0eb7c1aa732a70cb1fdd23d4336b2323a99d9f5e", + "0x74584b0ad5236526dc1a4dce8f4e65f87ba3d529749a702217f46ac9a6acef7d", + "0x06f7debcf4fa4511a1182d992fb0ee265714e70354a08fd496f2550a9e268b70", + "0x8a6b101b16aefa233c158e0392f0897efea6b4144a98ab3050551f8f530ffc94", + "0xc65d3267fb49c21636e1cee8d39c515b9028058e8b9e0ec5c2d6e7adc9293e45", + "0xb9286dcd79def251104af4f3b68de8b9e5717ad5275665b6c079f49afab7770d", + "0xfa735c22373482f2017aea5547def3bbe6f0b8f08b7054b775dcd04c3a3b8597", + "0xe3d360213b5720573864c6a1d9204151491bad4235e56c35b340b22e8c29f5c4", + "0x87ee0e69a5db0bf2dcf753e2e1dccb92725f9d1d597aae378743038121071b9b", + "0xda446379789bac65f03bc0d2bddf4da37867069743ddbc4f2e846c90db8ab568", + "0x553465cc2c0ab7fca15424c8507d216d95f53a25e053657fd8eaad58efd45346", + "0xd3eda9aac5e84aa9cb845cbbaa180854868f497fb79c5053becd16f6d9ff13a2", + "0xf8bff7af9e6fc79a875bd7cc4c1a0a347572c5f83c8a6864313e5f182a8bcd96", + "0x3d49c1fc6ca0f9eef57064a5c125c24464d1ae6f29989f2e7f4942c50128f31c", + "0xfa78f4fff3ce4c2b34935ec5692b9bb0f326a65ec6b14299f990e697ceb89a34", + "0xd7de5c5c86a0ada9f328e8b67393f4002714c5d5f0d1ff68129c68b882d5c6d3", + "0x89f2fb3dc33363365ce597c0e5c4d14c0f66b60a8c6ae3f6d45d72af301cef4b", + "0x218c78843492895ae5ab088ed80e82eed320cb6f98595a211340b19428d94985", + "0x5380a88382839684d7d9fc7047eca486ec0383966b262e5e46b9aa0859ec1547", + "0x19cc514f0518b3cedbe31529f8506fe60c93122cc7da49ac6f855abdbb729e9d", + "0x93e2d29e5c272ba8dd20f621132c60ddeea7779309a4d14fde6e6d58b0643f98", + "0x3158d8140bea277184329a7f2f2bd7e956725dc80573ccb169c40bfdcf3f2c70", + "0x7505475407491f5a4619a25b97b1d5cc1e1ba38764be61b694b6c1d3ca51c216", + "0x40c556618336fdf46e581183b7e57a2f6e2665d8adf0d44b39d9a5150a56a13c", + "0xe8d0da5275d1280e0906d62421bd64a3397b5fade799a701e0a37111d13602f9", + "0x28fc4cfdd74093fc78d100681b770d7aead4d57552c9366d56bee6e7776653ce", + "0x81eb57db158fe3ae4e62785ab8a5c4fa07bf5a7815f1dcbe25bb997b89392691", + "0x361a76dda932befd901f101507a238fe1dd43ab563d09e5e3c6ca43e6de48f19", + "0x9931f8e7444209b91572ff581bee13380706e6d6de933ad96f185f71eeb1ca9f", + "0xf9b544a3c3090c494eda2657a527288e48b5f4c9032ed26eba3dcc6558508d79", + "0x16936de0caabfbe2e395583091c3b90305cd1fa734a5ecacc8db0ba8c40fa89b", + "0x998492ec7efc0178ad691288e36758800b139a26aa493bef28f2e96c460be402", + "0x626f93a0163fffb94c1cf227e6a0ef125f7930f3a21971dd3a9d443162a0b176", + "0x64a7ed78b519d1f04b5b3b46c6804c0647889475d4fe991c8a7e405a4a2334f8", + "0x4aedeb8f7470b9c97c2fec75b4c44252a855d36b73c6a4550d15368dbee9d0c2", + "0x17095f0fb67a7d24910c086ad4cac72e493bd7276afef463d05e26fec1f39381", + "0x05b5fc483f428f6c854403b365ad11f4cb170a2229ec66ba671b94ed50686858", + "0x76bd14300b8f845500b2991e8a78df8dca3054016ef6b5069b77ef05b806caab", + "0x718aafdcb0223d7010c9b6c012c38aaf82e02c8737488bace9a7f8db15c60047", + "0xeedb09efda45baaa9034a18259f1aae1275a86fc81a218d9982e0b17f8d743fe", + "0x2608c1d2f2f8513ff1ac6e33d21659624c16e00218f984ce971eb9bee4825101", + "0xa5331637e8221d95d318cd4f32d5d37698731f569c4879c151086974e2cd4e95", + "0x2f9faaf3d219ae56a94fb4ab12f940d63a1d86776aef6541d40ed63d03d44682", + "0xd91d881ed4fd4b6197d77713d2c42758d9e550343ab67fd761c7c3e7a3724fe5", + "0x2404c00a40e6d67254ded0ff5a5413776351b8587ab1fdc4cde74c316435a9df", + "0x8591c719906e31c2150ff3183382f665f756c9a324ed470d0916deaddc240edf", + "0x8d670ef59f2237573019bb60cceb14f7198698773b572f6acfe3d3bad6c33d3a", + "0x3631004b8ebaff324494cc7320bb3c0deca53480a21d2d7fdd516271af7c97ab", + "0x4dc37b8650d5e49ab1a87a9e88912a98a60099cdcfc33a5c21627f0bb05ff124", + "0x95a8b189f6335a7d1523c470aedd2fd41f66043019da9a1ea46b379372ad4d6b", + "0x7219f1318a197b919a83dd51417803c752c24dc3a005cd08c091b0339634e806", + "0x81d850ed79388dd32265463d5283b02b11f012e08eddddfe389d55790cd1ff52", + "0xe170a7511431b18ed7330446569a253047f4fd0653915e107104380ac40affb3", + "0x9c38e78c1851edfe159971a455a70e1d61b1ae71ea0cf828ef40d4166741fad4", + "0x1ee49fd6dc9fc4f6e8bdee61a3e010a0eb9d06597c256200538ec73580c42bec", + "0xc0e415e7a108c241fe301e6ac22c81738470b499aa65317fb9344d59ed763a09", + "0x4fd8e4224aa6f2863ec655c10e829e113882646230a3dc753d80c111093ba167", + "0xcd7f4ab1b3900488068618eca688f2fbf85e58b265ec0dc4c0ea55f8892be5a4", + "0xddcfaa6613a08b4d0a5f4259abae86cbe95fd5ec5ec77fad9ff2c5662efd4025", + "0xf8bc573cc98ace8805ea12e49c664d8d9cccd650038a4c6ad559780d1d2392cc", + "0x65d8dda84a5666f872d4a744a7c98b6dac5e1082e06625d49d32212a37bb1291", + "0xffc19cd76943cd82bd7aeb8d25d6dc4bb71f834cafe50a5ca2ae257d76a93db2", + "0x3efd8f977e31b77007ae5f290a63c22cb417b52d9bb36899baf826049d169785", + "0x9e225513beea6034be1edc5c51a3f12718713578a2a69bafe7af00bdfc477d02", + "0xebd0e1994eb8dc81f7ed767aa664ee7fc0514caf96fa5080c1ea120bc9803ce0", + "0x340d016d76c6f0db1853ef43ac32c2ebcca11a936c19f0f6814d64aff8d63ee7", + "0x57ba48a6bee7cc99a609f5ec1c9dc2aa1ad26589b292d0e913bbb7e6700895f4", + "0xb0b3f638edd6161784754f858844e77f9dc13a52943120680171deba7272e9d4", + "0x901ab47b6f412b57c0b09020defa44b5375c4e80749199c084f6ce0ecb89ab0c", + "0xb8c7e255dffdbe496fa3d949ed552e36ebdd6d14acc4049491ec6a033c086616", + "0x2f1780d8df1d77937e6dc3ec8483d39e3722eee9b102d84cb412b6765e1de74e", + "0x88712075a1174fbe444b715cad257d16547968ac267142ef293897332feac87f", + "0x6287016bcf8d4d4b67412f0b94b080d6b09b35d2a969d333fec03a114f49852e", + "0x7bae2942ac4d0c98a53feae67f5486415b9a59305b6adb3c7fdbf78642004eb7", + "0xe2dcb80caabe834c0897449540154ba5102f7c7a534c40f05dad77d42e26c571", + "0xc1856ba8c970c81104603472986449d9a6ad17f56cf67dd243c707c689e2faf0", + "0x3dc698054a61289b4b39f89c7f09dfdcf72c4a5a54276e508b095374cbbdf69a", + "0x0b27594e85ee0393ee4b16ac44751b9a1d8a9e7d704f42cc7c46bc1cb30dda54", + "0xfd47f64c6b87363b36d1de4950c72a7ae7fc61d941d6d046f89eec5bd63d863d", + "0xa420ed29af2c8a076098250c29704638476fd014558fdc68524d7a1c9b4043cc", + "0x20e516a19060c4f95559484dcff148812ba875407c1e0548714b630439985f65", + "0x779971f5b6aeb2717e6e336f91b3babc6b96621fd93352f0444b96043c34c1f0", + "0xa57891c1f318ee62a989a151b1be70176b8a86466e3f1669a87b3131b3f7190f", + "0xb09340884952e9fce0a543bd8e98617caacc63d4c87485da51cdb906aefd479f", + "0xff2c2dc309fb4c05b90a80a3fc715427f540be0788b33525a5ea00f0376ecf8a", + "0xaff098da407d643f4d60ce864184a0cd2001301833da3f379659ea4462da737d", + "0x0650daa5593e4d835532cb1cc353bd2e93fbae818e1f334491539ef4d363c2c0", + "0x1d6e8666bf720b0cc1fab78d8ea982ecd2b44305dac8edb2f5b9b9881722399a", + "0x673a6337982d71675566e7e6acf703f9c5b18718856bfae59edac11f4cf2ad3a", + "0x6f68da412db64aea7ea33dd930e145f45b36cce9d285ccb878d33594bceafdb7", + "0xbcc221ad6460fb4066d8c630720a519557064183fd3ff3feffce36b0d80b8da3", + "0xe671736f8a72834e5944c296f64a0d35743edaf75becef65203409bd369615d0", + "0xe4b50f9724453eef07bb00e56c32f6e056bddf38fed0cc80d3d9d2f86258810e", + "0xfa0594818b10ecd7be1deba272ee23b3cce007382e6974645a505df7d289ca39", + "0x35cfa0772e326b9325a613ac39ec350241a62d9f51cc0a1b0de4875d2ce48059", + "0xb6575e9d2cdfe08b13fce3badd0a991f5d331cff4444821932973767677ca13a", + "0xd4821ae28196784c066b254b2fb3b6230d5f4a0e769d8b85fc7ba453d3e93f1a", + "0xfd9f762aa42f1eb43e75c3c00d292f9afe393a14e272037d072872f820e710a8", + "0x9f78b0168eddb9acecaeb07fea85080fb638aca8874a9ff15d3bca7e3e4f9e73", + "0x8c2f0986e10039e96cc6695884401991d714adf5c445e9bb0f90a14cb4a12477", + "0xb7059b47417c4a06bcb11c6ab78221835279d130f52f5cfc316e80f87977b87a", + "0x56fcf49a8a7a69d4f8604190d79eae7e2957a1d129cfd813c9447249ace909fa", + "0x9401c3ee1a458253b3da8820c1e9b8945710839a826582f3a86e8a482dbca0f2", + "0xff3f9e5724cfbba1f837a10f3844cd437c0f1b5e31ddf61c4e56ec504fafac55", + "0x8787e48bce6ac94e62c13b82c544c2265b42ec08d959c18722c3f722cc8ff2d4", + "0x18cfd60669f16555f0b0a429a6b98bb64e936863d5524e23c3d263dce8177866", + "0x33a19dfb8f79494cd2b1b5983884992f637099735e67b2197ff48b00fa28ed0a", + "0xcd2d1272d5982579a63f951c3678c5ec440dcbdc2a5fe4ee8c765fd16ff07353", + "0xa7bd53be4ffe9029d5bf0c15051158d4fa1d9857861d9b3fa63dd0d5052ac98f", + "0x6e039f06324bfe8b9604711719bee4c840526f8c3ce9bc5c3c5584315362f0e8", + "0xafd6c666917c47aeae4d44703d891a3498211054535295178903665328d24291", + "0xc0f0dcd1102ae4eb932e3ee71f1417dc852f3f1ba6a8f2b12cfd8b86ceb3c335", + "0x6845dbf33355716e4161cd3e03ad296a4bec741255d91bcdb6e36950c7010c75", + "0x832d9dfedc39989c97066d465f256ceb8922f99e01c730865f62bba3a0aa786b", + "0xdf99981c644b3dd68728aa9801d5ae41579cc499a534d5213797b3fc35bb64d6", + "0x0115b4118eaf40a9f0fc1cdb8f26ed41e88de8c99e572f72d79dffad9a776e20", + "0x8b09da2fa7f9bd66158c3d469cd22d3f8ade9d86d0cfbc49ccb48335eac53df1", + "0x1edaf123ca42fef6c94b334ab5584c2837949abf3b3ad0b05de4e1da16a5fdeb", + "0xa7bf42422c1beb01742120f78b46ac1eae595f442b0f246f53a919343b4b3b37", + "0xcf72cd32a99afad5a5d9db18819131219a92c1404b57f64215a9e9e891c9428c", + "0xb0d4dc75898e16ff0c4b8bb317669eaba1e54f8d1a1cced03e6565ef3063fde2", + "0xde58a7597969ab3d35a4269d0623ba77254fa140ee0dc00f85e1d256f515c26c", + "0xc0c52dbd3d1febd3e5b4a59d9a6c1a4023d612160bccc5733f2006738baeb149", + "0x42759b763eef5c70b4fbb982cd247c29b0570dcfcba9649084622bc93bf0440b", + "0x02b44944241f25120667fd0c83797915239018c4b370378719be93a809d0fe31", + "0x176572271efc8297d8472120996569abdc26e0b2695cc1c69f72d8e27fd927d6", + "0x2c2f7eb653428b3a5329b339094caeeb4924d322b4362546ade060f8ce89ba65", + "0x3b548a06156cb3ce3ee222cd68a95ecd69bce5914a699b020f0890719a5f97fe", + "0xe74cc69a92f69d63c16a4baae5cb692e57f2e2efde17e0c46fc4cb338eadf215", + "0x9b2a05590bcfc56c432ddda8607b7902c1195ac72fae25c7f18e547a20fc1654", + "0x52f4d9509d31fa6100c7fa8d644dbfe2122581e8a277c6fe80b68aec78035ce6", + "0x380c3d4f876907fed243d11a8caf436445ac5ec55bfb3596091791bfd80ab8d3", + "0x386a91979bb6c8e42d282132f6903e517204fb9ce1379fe5f2a90b66b1f708c2", + "0x333d6dcba02dc8418059d95d43e22b9bc33539bda31f424c762c5b62676b04b1", + "0x50b91f399926865ca64ef68dfa540257f660759ced1276da1033bba6c2500da1", + "0x78266d3dde661a3b10f43d31375993ff002a7b49717a075c6367259baaa58fb1", + "0xb5066418dc050952f056082ef0f6d6b47fb423e9e5458176296aaa6edb7e7af0", + "0x3b8320734691ac54f2a231b296b889c9c8511843984a9ad80f3c43b8fdfb2391", + "0xf85d88e47f6b7ec5f5107785f80fd8b51ad6d5488be9b147e03b5697567ec932", + "0xc352f5af398bf837c89b42eeb48c322ac8eafdbf57af5c1c33ab0880623c7599", + "0x450a16022ae364a4f3ffd5e554aa9a324ebf8b9e6e635e753f4872ed6f63051f", + "0x0438e9c7d357912b1527a7fa5d6e30ec428e472a617d30e33946e47a1f648dac", + "0x4cea137040ab131bca9c9cdd41760c181244c736ca1d9d19370012935de0de6f", + "0x757728e69874bcea324af5348e76db22c3eaf8348843f61b82271570a5a96a93", + "0xf45bd1383b1d53e95dd4d0515f20035cecfb0707442c525c0f06b55e7ff52a61", + "0x156d898c3abc5a55d9860d679d97c36b2e48f833c1342bbf455b13874743b1bd", + "0xb3e80e0fe51cd1ab5d8ef201a011bf6a0a5878d070eabfdb4a6d7c77d06dfbe2", + "0xf7302c6bf2d04fff65957a18c8b988bf0e3dd7f3933229a6f1700e6447560d5f", + "0x73ad7c6627035301b9815d82626fe958ec0ddae62060f0c7f431865dc1b9f6b5", + "0xf10b5b53d915c1bb2eb9979dabd2e917dfbcfff17f1d09cb616b2a5179014ce8", + "0x93570e1d259272e6b825a5ed34a103fffcd27f792fb5b09a2442cc83a3bd172a", + "0x8c5538b8ff9ce17625018bc309af258e4f5acbf9c7c2d4e948cee8b30b336f92", + "0xe9a6cf047c81e965dd32c57edb680c2aaffe2e367976eaf49da5dfc957fac2f4", + "0x7b972cd72e31473b463ae197e30b121afdda7878b9bf0e1961d3813734663435", + "0x9690c83cc3a1b1b8649a89a9bb1e1fed606e4c949d46ab8f66f16c8320ff5127", + "0x8326afe249d762313e5e089474f174825821099a5e9136a7783c3eca7a160d05", + "0x240410eba6ddc5b60a0bdc83fca59d615d95c64b0afaed0a7f17b96ea65684b4", + "0xc48969c8f72df638ef2e8b98f0d67dc6d9eae1d5bfba2b02e584ac2dab51f3e9", + "0xc4fa4b201243c20d35df1ba466a4c40139471ec86bb55f872d54f6404d4bb05b", + "0xfd085495f4ebfd30f7ee4ad9f122ff3da3932fb87ee9aeaa7c8103602671b96d", + "0x17ef24bb8c605d6a27b3b44744353bfcd127488be96ac77a3d8c706015889040", + "0xfc2fa0f9a8aabf5fe515cb5b4a4ec6047f08e6140e81bab8624b02dbb3f99d71", + "0x3ea5269fd6cc38f8a2167cb1619d643ec9de3deb9ece6c19542626f7284b7b0d", + "0xd6ae9f4d8afee0374c662a86b489c603b4e16fb82dee3f57ddfa971e68531fbc", + "0xcdc97e7c7aba5cc5939382dc37142c9d59683d3188d642009edb492ccba1ed77", + "0x847886244064d2edd6791561638b63acd09336b4c88eecdb09493e8ee5324dc6", + "0xc3695209de581e3e3ee849b3dfd93d8102c9e047edc1596aa332d8137d0bc3e4", + "0xdf1399b24c2588519cbf19e2e7218d0fdd793cae1eeec52f9fda7c729a0d4e02", + "0x9718b2e289feaf4a2acff80f5d1c61400e917200fe97b5b9b6200d4c48e7a526", + "0x6fbd4948fdbf124fd0a9c958953abf372854bb6e29adfe9190b0101b97a342f9", + "0xb54aabb1fcf4c8b701734624fb68c842b500f5e71c39dd04083f8a3eaf7d7c51", + "0xc3710e6042dce5652464ec6891ec5b9f436208c12afeda5fd3f454edd8b5d79b", + "0xb6e3d629f78477b79bb9368f1611b62d717b3214675c64f1eb737dfa17b03b04", + "0x6fa6a372c4f33ec50d56a4039c0eb7d6652fb934b24ca468c1fa8f034aa043f5", + "0x51ae789b75938201ca463bd4e7c36152aeafc4b63544293e689e15ec80ed94a2", + "0x4fbb4816f1ea23ea83a425969223be5b9cbcd69113ff43e622ba9753a3a25901", + "0xb2df755c413220d7b684b063f81a800072f2f552e37fc057f555b252f70e858d", + "0xb5d01c218c65539914a8b01c40bcf629c83bbb4ef0c6289c127f583b133aa4ca", + "0x1489588ee88b1922296b2ba27abdd0d393a774009941f4779a63d3ccc015c34f", + "0x093c64995cd670084f2a908be6d6a508f490641474bfc722eb8605e0600d246e", + "0x9addbfaec75c7de95a89691ac3c23ac7c557c278155ba6026aa73258870847f4", + "0xedc09711042a5e3e94a1fff57e7d00e0193f1fb292e3625c6c230c66bfadf1e5", + "0x99a935be3a0aeeef44a096fc8b18ed302bf7224b6b7abcf5e897ad7fd44ad9b5", + "0x00d804cff32284e41ec123482da2a86019ad97d8b36c0b743873438e0cc7438d", + "0x669eabe8771c02c109a7d46ec07b346be0901078f5cd4419b05f3f62442f0b1d", + "0xbf26eeacefd0dfe498f7672aab4a5262d75af5a7e8f5a5dbf0a3e9cce3573b1e", + "0x9b43c92edad88c5825f99c8490b627b68602701a8358baa22103d2b11ced2d77", + "0x8e8988d54263d7e2d9692ad884d44575d3fcb7bfc37333a814ad19328df3c690", + "0x208d671c12795da6d89847247d9707cade2dad378a840d281a637e2af57d137e", + "0xfe83e593e005e58c47571fa00075d440286e02674394eb46956a25ac2e2d3622", + "0x41a61f08717bcb479edd0ed1fc9d8bcc13b9ca3ddede35dee6e0d0fc347c4c45", + "0xe9fa1018977dcb1a2dd82ef24105dcd827bf815985fa97afc0d294711997f686", + "0x7deebf65689aefa15a6d15f7b6e4818547f56b01f622f94fbc42ef968762ebf4", + "0xa8fad9841e2c5d7c1131c16145c57829f22b62566b5a7366d6653157dbddbc83", + "0xe0614431ceb7f622aa4f43c03fae28318aa726dc1ce0f95d69aae011eb62a017", + "0xc731b4b0341ff915979233c76f3562e8a28f268b5d3e531d8d4f3c927837f123", + "0xef265f9c899303b2afcf6cf2418cfc8f9c71d4254321aed87827c0c749f51546", + "0x40edf9f2122834fdbfa84483c376a6bd8b67eac8b8bf454258dc7810f8e849e9", + "0x63093778c25926c58ca06014bd1b668b4d89e641acbb94bcb13c9ca0519fdcc6", + "0xd8b930be700bbc53228755ecb5074d16308f8dd3187cd3a0efe0c2414001458e", + "0x75b0cc9e892313d9c1ecfef4bf4b3f5976f1c830a7283a82fc331277a4a97eb8", + "0x4f102fe9ed705a74524f2598ee6f22adfc1d4186e2ebcc7331bb48e900795cdd", + "0x48a257229a0e91207cc31ef82f00532ec12cb605abaeabf1235676dc57306357", + "0x9ed64622acf60a2bc6fdb2bb738517aae8dad9cffa738ed4f95b02d3be04176d", + "0xd23a29871a1fe22d8bb7e7749aadf6d77c0140fd383cab55b099714af617a371", + "0x79c92002b2077df1c7127a4c49575d7caea872ca1175011d47e019ff14ed8535", + "0x9a9434b2d09c181c7d9f8ce3e10fafd8c3b1e27b807243d74075e747570fb391", + "0xd3c946d1ed5a76e6e17a599d06bbae3319dedfa047e8443f9df3c4b09aca3b88", + "0x4f3ef090e35ccddb78598a581800ea6f2709c691e3024c2f5d13635d3fdba27a", + "0xf958691aa9a520e8e399e466e390679ce3781b82f1d0dfc62bb53d0b3f640176", + "0x4a7faaf47a5031e0a798dc00ab8248aae16866cf74935ac0703d3f1730617d79", + "0x6d350d1568d7db6c029f32d7c8fe47cfbe99984d5d24a9470800f4b70207f653", + "0x6553729bf5616496d7d3ff3e120ddf1c4e64857c53303003e4c9c2546f8458c2", + "0x05491ee727fefe4ef46b9922856a5282c4ba27a90150b967a04e62d85cb3dce4", + "0x61e8d5b5143c0c532adc9f466dde430afc1d1755775dd39095a51a5aa2d4422a", + "0x2b5a26a051940c5f804db637ca77a835ab50f6c62648adb5da7ea05b39b04b38", + "0xbc391789c853b9ed06fa0d2533f1f56b55937a49061f1cd1a102fbe88657a764", + "0x4206d3b075128ba118dd06bc273999ab5ec097f1690c2abfdab351efcfddaca8", + "0x78075f3f0420f490386d419fe2b187d8c6a3b0bbb2158e0f9bf04071ad235bb2", + "0x0cf1b70db8922a59f11eb3a40ee22264a231905cabcb270dc3df11d22c8cb780", + "0x093ca9659cfc716634b38ccc97cb8193baabdb6569f4b33e56e3d8ec1157dbbb", + "0xfb17fcc35e7609264b5dde51f3847f98f555808c693fc345e6b4da55dec4fb9e", + "0x7b6ff07aa7bd0decf690c24d510a2d08ec07fa78276311205004b521f15a161f", + "0x2323e4a69094bff2e821a49caf30ccd91717bfd9eef8609331621071d4fcca2d", + "0x9f05738aa053bd67194099d8bf7baf3166c4cc18b76aaf7cc1a197d4af911765", + "0xb46c0513fd784d2ef4029eb3352e4423d627861431c160988bdc901c01957114", + "0xe1b5c3328267a91718980d369530a7ce76c6f7e404030e880c5dd57508abb03e", + "0x66d908a91b10d229bd478a9ae64021757a22edebf9d41e4a58e2168e8445d137", + "0x9de8289dc95f5b61cdea4a32c7064750adaf034123380c68251df2b816790893", + "0xf9de4b4229f1d152bf4d00864d8d5c37e8cf38264b2fe304931392f848fbe8ec", + "0x356654f74408077036e642d6ae98d7d3893190f6169110c682bbeffad006e33c", + "0xe5a731364889cf98c6136de7365fc53b3f8cd622ae7480fc35a9aca8f4e615fc", + "0xecb8b7af4e850d0854aacb48f034d96a74a81e588f900e1acf0f421e8ea2e59a", + "0xd3d25554bfe2217268be1364b9f74ece500ba8e49260218f22bdb86558edeea2", + "0xee9e40ade104510e4d04b9141864d3d14ddf947f7dd8d05ca29fb3b4d4efce7c", + "0x440556c74bba8c2d89d9eae72f713529f0694a72a741951d5144f7f977ba745a", + "0xfb63981c40b30bc7675280cec8063e7f64f44eb60d983b462cbfbd923a18c46f", + "0x666810ed3d8a8cb87b9d3d908285b7428380cbffeaa2ac9f50b9acfe3727a334", + "0xf87e07add78b9ff8c8b8c4e81b1086ae1fc9f97903a0b8d5e30442781abf5747", + "0x7919d5dac99d403b646b4785205c3ec2635023816e534eef9f14aefe01a0c8e5", + "0x99e1935acf142897bcc10ca07285849b08e5d8f0f8ab73bfb5b6f79cc65f4919", + "0x182a38b8286b5a6ecc93b431a20356a178cba89ac025327e28b7bab5e815ae1c", + "0x666d49f7785b6d3db5ad92f1403e2e447743351bfd31f1b3b61665a79037a1ea", + "0x898f91e453cb2349f6a222f23aa848bf01426fb40fc7c00fea3015847da37edd", + "0x6919143735b6f85a9d0e37bc4b81a92d664b5ef75e40be58fd1b269f5627fdc1", + "0xb854a51fa1ac7182b6f92d48cd90d8a576e75f769147916565acfbeeead664e7", + "0x3924e051c439c6a49a7af5d5a07d3b9b193eb1a6c1511ef406aee6f8e94b2f94", + "0xc6a2b425de2dd99bfa1c0970d29df185045a56cfd3b4021a3eaf630d4e87c6b4", + "0xe66104bd368ce9ce40920c6a0a1dace7be55bdd5ec594cb9169e42cf07282168", + "0x876d3a55345136b3079c260cdb312f8c708f9ae8afd3a6a90f8c018ba58be19b", + "0x5c0849ab35f38121bfceec816cdcc2525e88530ad874086bfa4056c8dedb1e77", + "0x3028fba2e7ff0c70acf12e33e744a881b94865d6f373a50d5d5eef23202568f5", + "0x9ac128a61197f07dd4b0fbac847b864a6496f1047a085e9a26f1618e9ae83406", + "0x55c9428bc7a5017957e025f046231005d4199c8e92627074923280cc3f6e3cc1", + "0x474004a4237145fc86484ae385c21523250746c662e791d5c366441c3b9d2189", + "0xa53ff4b977a2417289f9b532a20b758a2b0bbaa84e71c82e783c7ef045f16eec", + "0x0418a7320d961c5dede728027a0be6f4979211ec600b564edd408a1e9377d5b9", + "0xc8ed8d992f2b75be024eafc15ff7d7c5c0b0599cdd6b603437b4e737a60993e8", + "0x3f5e222d8b28b38a8c7b190448286d4a14afd1b0cb2697fd9356158f5215a0e8", + "0xcfc961c5ff3b8615089248635d900fbea9ae9f7b4d86ebee3703453567a67485", + "0xcb88b820997d440812da7192f44c6debd27da3a41f04b595f515e65cf8a80d50", + "0xce6f3fa44aa7a177ea56d97f00ba344852f614951e665e3742429a6aaf698c37", + "0x21bee516e3366f5770dc4f6af36f799a5c967eaf398f2b70c3a8ca694096a9d5", + "0xe5a99d3fddf70f8e732f7f4a14fe81de8cf1ffc945a47d9eaa7a28c5eaf6ef84", + "0x0d9e3847d768c28783981c6313bc9b0e60ef4c2a8693cc25d399e9db50f393da", + "0x728f54d10e7b531b464ec7e86f3320a4e853967c14061e727f58ee3c115cf65b", + "0xe1a0b9237f50b5e47c98190589842f0b72be2acb3b6a57c075b0c9933ee23100", + "0xe42d8bd36eb740ad018367109ad59f8a74ab017eee893be54a4d1b04b7cf37f7", + "0x72bd0949deab66aed968e725b4434158741c70007855105dd17ab9cec2cb1a91", + "0x450177933434050053831a4c162399286a92c18f9899c413d1c579ef95379fad", + "0x8c950374baef552acae9affd2238ce1b0a1c27e463a03e518b99f23f269f805c", + "0x7a09cddc74127b837571d245fc039489cd0be46ef3618460013de17c2bbf7933", + "0x6ad520bcc098e50d371d504a1e4f4e37b63484066606556debb14c1341880f9d", + "0xca0232939f26cf17430ab3299f1970c334f8dc132724c6e6b01a2467f4dbc149", + "0x9edc115c3af74d77a3267df2b87a77d82b825d07993b74fc31668a09915ae070", + "0x0147d798bf772842ca2e33c28b65fc6934e41e8775b5cfd566dd2f60641da26a", + "0xca005d851a4c27070a0706bfb3b95303b7d79008f49a681f052700c1b4275c57", + "0xc365df99690cb05b89c7efc60a7af3bb4e01c22e5f6d51c9631cf737717965c6", + "0x80aac988930e5f1de8d1db964645abb114e145f301db96925bb02cae2f6bbdc2", + "0x7c67c1aa7d047bbb20131ba231a55d0b596394b06b89c574d23b8aee7231b65d", + "0xd2e03510fc847b2890ea18eba3ed90ebdaaed83b55bf9cb5eb37b9fac10517bf", + "0x4047b15bafa722bf1f5ed69691e671a64c54eda20f11d25143ac7e5dd4e9ccad", + "0x746ab5985f0ef9bc18cf60d1216c69d1fd40df2c1bec2262bae7438acdcd42b2", + "0x7fdfec7be4c42f0d16b66818334e49c97d7b06ea6a2befa361a4aba3c511cb7f", + "0xaedb8c3201c978069b5b2b562252cf617e2a0b0cdae62dabef3a04badce1a084", + "0x24dc7b367353aa7ac0c386f4f5768ef1212fa2cb0de8317300ee54b6b8e420fc", + "0x6bf5c551d97c93ed425eefb8f2998b5fb3735f96bd71b1384799a3330347074b", + "0x9d0be98f9e31ad94e6badd0bbaeb85dc69322649b825f8c41dccc8f9a8d0b4a0", + "0x0d1e4ef567e933a591dd361bb254c080f91351b04ded52e022ed296c2c06580f", + "0xb80d22650285ec257007fb6ff1de2c209cc6be02303b3e2bac43c6a57c0d7004", + "0xe2cd2f349288db25e7315e3c8b4257367f082a377ba4384275a506e814940caa", + "0xf56100200b9fee76191568e49bbfa0eba66887f24cbd6cfc0145db6f31da07b9", + "0x13beb775c7a572d1c54631405b45f3e96938af0d5c740c4762d5ebe5f7ceb1b6", + "0xb5b20d1527a14d733fdb3a94f178dcbecfc9f4312e2c3c0dbfe57996e143682b", + "0x5153bf8c2d061de36ebbc21a31c3755f96296936e79584d03ea169d7450700f7", + "0x8d59bf8350b7eb84d5cceecbf735db04270e4d76b66eb9961243af61317a30e3", + "0x90e0af4b3a2806ea91799ee9d973fe9a2a3c7c07574acb7c72665af11a515bc2", + "0x171fc19c2c2e6fa95af7789a01078a34a628f998ed882884e6f514d45642cd6e", + "0x5f73cd024051e26bf239f11b35b757e896dffc144a2cfabb50aee58e2b4c8afd", + "0xdb7401010dd1db0e8af735200f9bfea39f868425afa01bcc404e5136db7cafad", + "0x809dfd2cc6df05328ef813bc5ab86b6ae90bfadf37107dade647e5a49fbda950", + "0xc731c27a9d048ff7ac2f08d1d68d46fa57e61e620e044b929dcd7d076d157eb6", + "0x1d443d7c2a3974ce9d3211aa39efb84d779dde08e132628c77d72cf092ece1ec", + "0x71410564b523d40ccd091e3e19deaad26d74d97963a171cd6e2f739abfacf63e", + "0xab33110fe291f5cc2f469cec31c7d21409345545446ac33c0f49e1e004542f6d", + "0xa775e97c8fb2b70449066c1d33efbc44a10ed6c931b7d4a193e649b853f23794", + "0xf07dd49b627af4aa3253f0403aeef8a3bb452dc2c69a1227325a1c88731ada5b", + "0xfc648f6b75782491734b7d24fde9c7b4bd939d0b338a74a0b36daab26ca3555e", + "0xaa88a296c0cd44bbaaf8148c005f180d7a2757b4ddcc623a43a88a43deeee936", + "0x1ee2fb788d4dc943f726b8455957bc175ebac3e4b8427177a053d7f299a3598b", + "0x13e7c4da8f8982f0ad250a425a24ea8f8b8574abe033e236dfbf596fe2efac0e", + "0x8acdcc6356fc748e03c06ff4878d0fa96f18e4f03272ce01f02ad29d8211f611", + "0x230d99e6323448f1ebcf7e6792e2978a5d74ef654234be97ebaec5c56a684457", + "0xad35598f4bcf7bfa1852a9265a59d0f9914b3b6289a7aa3015e3d808d504aca6", + "0x4d9956ec8c5887e8cce4bab5b6819cc13a8703cb527f14a5e9db99cbfd83b665", + "0x99a277612b78515fd153c88e0060c274b1ab4a60202b575a9b9892420ae657a3", + "0x656acdfdfdf9b76d499176bc3a259aa9722b31c7f3f4ae5c2da8bc3833c12d66", + "0xd06448c98e529a17170aae72cf359a1e2808ff529ca9f37df3360b92790f925e", + "0x9afd24c01afe4856a47db81a6818899d93a5096853b395a24cb9edd693bd24e0", + "0x03b7a5d8eb6ae24ebe158e411df31514229a2f302108984597317196f6226ccf", + "0x6f97a76567724eecec6c55e811085e7a83cd5f6551924f6f8de590b16cd255cc", + "0x5fa0d567d50e49df1d24f243a2ff97feecaacacb6a5d7e34620a9f7e18cb3f84", + "0x727b25a1d44fa0eaea544ac593fd8bbde356a71a48162160feace5596251f1e9", + "0x3d8340ffdc8e124785dcbf85d3b12a65808c49d91a77ed7a1ef54e404acb56cf", + "0x9057ce97cd01e362ac771d04ecdc45b10cfd45d0c3a1070e2c0fbbc81fcdcbd4", + "0x016b166a2ff70c7beec4ecf9a408a8fa4c556e0e4382911057a984454fd9ab45", + "0x9c2a27134a95f9f28d9f313ed2ff1dba33d5a080cd2d00626b8b6efab87d6957", + "0x66f3583ab4095411135af58756f72480d888a24aeda166136e18e25f42d56e39", + "0xf2cbde4bb5fef74ce2342be3f2178a7ec92ec819721456687705025708a2ddcb", + "0x5ce0fddd2a1a63fbe9bb28c01ba7d1c120f2eab2eacb0dc6200fea8c170e5d2d", + "0xeee2051e5b3a37bed40c32e05f141ea33283556a20e42cac05e5efded1b046a4", + "0x0a38951aeda2ad0227d5db28597901dd2f15fb8a53027241941f705f84f3462d", + "0xd532a9afec12700d8a6976dd148621347df54aa5f78fd64581835027a88ef6f1", + "0x2e328120b2bdbe717d673b04c9fe2c66d9320f668798b9fa11c257a5719c12ca", + "0x46a2cc57ba5798731135b891a9cb9af4b1f780a168d91a9d745f5eb39bdf72f8", + "0xe350043ef30f36168e8f68da553667cccd2eaaa4a1ef85c187163b9e5ab243a0", + "0x183ba0d0cdc68e3ac433eae5822bf39e1e351bac9faa4ec279fe9d3304bc6dd7", + "0xdbbfda6ab37d6b32188cbfa975f513f6024e84364bd6c59d513357598c92f80f", + "0xa44361a80cd53311a9e2de8e244013ea6a926cbd5854920ae3e162bd25d8ea21", + "0xd832af8bb66b36e85828711a95a77a2b6f4b42a5865bebbca59209e6585e8c9b", + "0xc7f64dc286ba1f7b6ddb15638662314813113bf058c7a9065597aaa4452c752a", + "0x178b152e9820020d4245e8a997deb02767796841a0220ac22544aa1250f84296", + "0xa182cbcf24b7d477c0efb568a8b120ca341c4b82ff0fd0d6d0b856a65dcf1083", + "0xb1f0f8c06b2743e1f8149ce4dc215f5dfb89f8f1da9718f3f312e500ef06aacb", + "0x5027caa12ed653330800d4de4014e24fe9251ddbcafea58e2c27012dac58c371", + "0x35a7801cd57644a1df91656b0566c62265159106b963368cdaf429472913c189", + "0xe80e4e8f12abcd5a79aeca6efc64bafe1893075bbec001338f625642fc047bee", + "0x994fb4f27b15427028aba87c42b08eb0919e12870a05405e0ef8f2458cc2b279", + "0x67cc00cc4591d984d9c2270fbdadb8c0d4ec9b40c6879aad8176f9cc7131e31b", + "0xd73e02e0c536cabfda569a8da06c99a28f3314d2761e7c0271aa5480dfad3246", + "0x8d709e7a8435b1d5507859d0e4406589b03d1b3ca646f9f26ec3004c6b2d973a", + "0xd5b64c36bc4614f9ee9bdfadab6c095ad183a8cdfa87a9e6858c4b12d9067aac", + "0x9d1d6d5c1eedbffcfcfc2af6aa9a6df958897cd81cac630dcb998f41a6b14638", + "0x39a3945ad321e02ffda18c8072e74f0dae525a57c7197dfeb86453ad208ecd98", + "0x878708a865debc222b72daa2611b7cb8368313c05f7f41e7f8fbbf33f602a582", + "0x305cf1edcfb804a104d777371850939c7c028f50d45f2fc4791524e24b6adfa7", + "0x6f5dac19867a9f14de66769c9a8f0813d7ac7fc4590eb3a862cd14ef63381491", + "0xdd7d64e12a1391437a07fa88b6ea7184676cacfc7cc8db544ab1808dfae8c87e", + "0x1e97a0e1992b75202522362a4edd8004a430f99c024a6503105cc55bcc7b843a", + "0xcc78f11a9f6996cf742875333c8274c68800658fd5a7465bdbf9c13cf2cf72f1", + "0x1fcfc22ea13dc96c9f8f3546f3f1b8f458bf7d1d46445c92deadd848bfee0c09", + "0xaa5d6969d152ebbb075a97c4a051195db68d90a75c37c104321131c073fdd843", + "0xf4f6e0c5bd269c7de9d1473c5074b3bd4d42b207742b918ab1481c633d05a38a", + "0xbba5eb96150613be2e45e1ea8ecad915415cb1e091a85b6858a7d1d5a8a005f4", + "0x1cdd61d797c519d6295196df06cffd0c9819ce0d9315c66e5309f14eacab63ce", + "0xb49771b39eefe9791d25ff5a1c94f0dc7d560a90cd9ca9c997625c05c0299783", + "0x5232fc02627cf406984a2f4f2e3813ad6260c1b07da797c2d1b7218d7eb05ad3", + "0xecc5ee2ea8e3956d964bed681f61323f608bbfe52397b5b28ef26f660e3c214b", + "0x49ce943abece2026b0c51a5ad5bd35613c92f480027bc47954eb9bc7cca5bb0b", + "0x27f731e278a0221daf21ab225b0297276db74ab79edc4806aa6a794e730f615e", + "0x55a9b21ac8387ad6aff87660d889be69d8b506a5de230043fe5937d0bfa53771", + "0xdd2ba4ff24bd512d48b553d031130799e46f3812c4b782c9423235ccebd7e655", + "0xffff9cc54e4484d4e70a6b3770d11fb9e13e583522ab4bc376cd6c7498021d65", + "0xb4bfa3c62b210ad81177faf4f6a170dd801713e5f9e3e4bcb7301c81cf60d083", + "0x5c3f5d4c0836dc02a32d7059c9598bfe46a813684f3576ec24aa8215a5de6270", + "0xd6d8e57c79dc17f19eebdce62de1adc0940d881d61c4a1099d51e6cf0b1009b4", + "0x2d3b6873546a1e6d026249e0cc45ad822fbdbb2ebcbb13832b7862ba9bc09982", + "0xd0d2b37a28cd798dd9d1a1e0892e86d90ebd54e6be912ff122402f6d923becb1", + "0x0345ca4471a47d8d12421bb39b0b0f7e8475d04181abfaa9050b95cde9aa4a8e", + "0x78a603e3f62c47845e657de355bc40d877612062b2f42b63c50645f3c12c4b15", + "0x1e973f2f79722999a5caa72528d1920917d7e7eb6839976ca19165c3a8bd26fb", + "0x3f5242f783e2336e5cf0cfee1427fbb15a833930b22187b3659367563a529039", + "0x181667e480e8017caf91681eb04cfaf0560254028a903b620485cb9771cc26d1", + "0xeaf92b93fcc996d886bca5fec1f6a7dcdb58cd7acd8033637a8fd9d4bda169b0", + "0xe5164f795fac046d3106dd707c4628d731bb73a3fed8d15ecf915de5b2f0a48a", + "0x556f9c42a01e441bf0e74c4a89323bdea6ce402dbbc1f500d5b00146be5439fa", + "0xe59b25cc5415f5b84b41ab7085b854f64f6d839085e85e6b2a30c41e6f689494", + "0x9e2c804effa40cd7a92ac8901798c03a5e66f47496cd89fd3b8314e7973f3d06", + "0xad4eec2bac36a3ea837c95bef538000dbc75374a4c4f8ffa7d2705ba300aebd9", + "0x12212ae8872a77a5d57a4f5fd91797c2fbf64ac2fa5af09aa55742b3950d8e88", + "0xd987ccc0c413e4390b5b5b69370f54b5d35f79c9cf4c1c534598a7e383399ebb", + "0x8d30d2dc8afe7f50e160fb4d3cfc5c54a962f31ae5b4f65c2362ceb7b8cc4733", + "0x617cb9b3cab2b8c43b11bc3412cab6f889197ba608c068dba2eaf1fa051b0f26", + "0x75bf3d53043c8375f1e51194be0942f3ec73ffbd61926d33910fdd00dddf5b87", + "0x72bd67478fa033abe7905125b728485f401aaa31694bf9ae7eb1184adff2db12", + "0x23d7a73706b970688eac1e8affa5524f0f563228aa7601fe7d790f844c186bbf", + "0xea350aacae57df34a533519b3448435879faf637e3f4a7cd3bbc891489d31caa", + "0xbff826ed9cc685de15275d59a299f5272cfab31750d39141e5ceb8f5d3645741", + "0x020ecefd03dde3543cea261d265a265898f6804230e95f044360d4aedfe031a6", + "0x71645432ccbc0826c83dfdf044ad7e3b2df4bc979e68513ca382ff93e24d1d77", + "0xfcd3731fa2259ace8cce5eb1a3fd74c723f997cfd8d4192105c41f2874d22d55", + "0xf13985444c5a6873217da182e9784fa87576829b9e841dc209a2592f0f5522ad", + "0x0e065da66efc90bd88217d6e9a5721280c4037de294d9e6ee8c1207b664217af", + "0xc6f893863ef60cf57991974de8edfa93c28c55c3af96f94cef9360be9a3a05b8", + "0xae2bfbe04bfe046166f0d6871d689a809fe443c9a6cdebdd5b2e32a36d7fa67c", + "0x733fbd82f21056a2e402ab050e32cc83aae96a67dfd3fa9c50732a3fd576e7d5", + "0xf4e29375a5f989dfebdbc9101d411f062c1090a9869058f6b87fe19b3a259489", + "0x95f902f47c21700bb030841890c47d759dbeca59983f1f2d5353674a4f45088f", + "0xb02a6050eaa94106ee9d4577b10f6adbfe7705a3ef9c3019412c4f60ee8d0e1a", + "0x20d64b55c9e4c2eb51e5af544ed068ce9d323c194c5b18bebea4bb0182344ea2", + "0xb6e40dd521e524b30139719580bd7441a35a1bc304c338c426b706673e179320", + "0xc54752027833b57236b5f043fed133b2461f199b75d52da8578c6e98dc2fc5da", + "0xfd3f9c65d1b05ccbf980a35cd433da01443ff8fc7be680892ea3185914d86727", + "0x7175b164364820f36d10f9e079707a40b21004d0687f90bab1b132c9c34ee2a9", + "0xe4c4df954bf0d3d0eff516775d60cfd29d0e780da4f07589ece3f11ba8925b2f", + "0xa927f17776d750c0b6996f1d8d0db22547fffdb006c0cff367d0a0edc41ddb01", + "0x27050f4807ec856a205518e9d13821b2cda0231cd8959f47ee34832181eaf8fa", + "0x4ebe3a5760406a59770cce09a0a44225dd5a2fade1d877b219558029e30ac4e1", + "0x290c328e60c366b0d18e55c5578b9b3bd83bf1b0600faf0822a1f6f1ae85edb5", + "0xd7bab11bbd83da583e3fcceb0f84bb551cda363c33c67f93e02800176c29bcee", + "0x3cdcfb49d11cfa3ba1809271869fdd9071017e5498f8acb01c595dedcd3ff109", + "0xc75582264ee66717ee40ff52a6689d03121ce0f1abb2c354cff6d92e532a81e5", + "0xe7004c5a4d09fc89e8737a5535221b552e67c3a0fb5851021e9f9a0de4672ab1", + "0xd6b8f94deccddb6d4f8b066c0302faa4b562f7a04e3a092b7d87b3a08485d933", + "0x2e726cd7212cdfd26cf0d928932b05ac8258003254e6558c87eca8a82cf6bb02", + "0x6c8786a64069e3f422dc5000e6a614adf14215ebce0aa8ab8e22c5f239a3714d", + "0x2f736729adc62370324b478cacfc6256fa0cb9119219a2a000d2c34c3293f6c8", + "0x8afc8743b959ab340dc86c6ddd9ca1726cf4bbd13054616b3d1d64bf656e0827", + "0x661832363afb109885055ee90663ea7514059a2c6d69144f8892138e89ed037f", + "0x2279ecda37192639297242d97723c6b635456cb2c98266493552e618067fc5ea", + "0xec7b510975a50daf40effbc94c977f508c84a9712cdb28d60c80b30adb3fd24c", + "0xcaea827e123419fe48b7f72dd67eb8c3965a4504f13e4ad7443bc8e87bd7c832", + "0xff012579799171dada6dc819977c222836b9cbb4f521142e74e9ef0762f73131", + "0x70ec4b383c92a8bb37f733825d60e76e75469a71b1d5361a84e37b38e3b8a34b", + "0x4dc584e8bce8efed0a55021d334b87dc5973de45effbc43e84acbfc03592532a", + "0x0fdabd0093aaf388fdc53d49570d3304c8c583415eadabc98635dc472f366b90", + "0x1b29d10d1443bb37e47668c9b6a124a1964a3f12075ab9be1620891579d8db31", + "0x3d350137648ba1e593182918a4ddb6b5983001356d6e406bcb88753449ea55f6", + "0xfc3911c59399e8c329db2dadcb5f7a58855f19401f513b9f6bdeca01e73edbcd", + "0x89a4277d6bf214c50fc0a7219ae59bdb719b71094d6a02c4ef5e07b50501e74e", + "0x7158b6d3debe3b6ef5dc0d40616691c804581d5614714f2284e63df42b5ea578", + "0x46d73cd458ee5a26724a68b2f8186930104aa9674fe4d94ce75215c61d0ede81", + "0x100c71337ae5379ca5d43f2177f2f6e6e57c628bbae4bfb70abdd1f23279787c", + "0x3c9e2e0161341c82207498608091846726ee4dba0fe1fe69c07a92a0ff7675c2", + "0x5c4885fe3f85ee61e50378943a48732843d47184619f40954daf24a165f2ba9b", + "0xce300dbdbc2c8eb91c75f7e0e8e91dc03ba8894478a9e65529241ff462abf713", + "0xebcc160dcb2f38f4607cfd3ae74a15286eb0aae05c8fc4f87abb751ca88a699a", + "0x91aa4f2af47471ac51160d0d1c81137c7c6a22ada295356668427a45d21c6a07", + "0xf30c1a0842faa5df4ef896e192d5902445ed7b01cfc83dc287492b1896126310", + "0x0e069a0772dd736ea68fbbef47302ed6e802868d0847518ea5ea2eb34a79705a", + "0xb49c6e624b584d49ba226f31611a0c4f3ff0033a746b370890533b209da2ac3f", + "0xf2a4cb9c4877795e0ee2964e5aec8828941bef07777ff4db07423b4a2eae5a31", + "0x2e9cee7389233b6b4937f5997be0a6f37a8c347c58886b75e3013060c10c4a82", + "0xd2318412b7dd0eb4f6b3da69c2c3cb7d8a6b7028ea8f0a39bc3bd513ec7c6d3c", + "0x74c00a1f66bbe517e7166993e18a1564d43877110c54be28053321721e619e86", + "0x37de40b83aff733b4792e27dd6211687ad891f8d95e397e3a3e07d481a5c44a7", + "0xb607adc39f83da6b0a7da38893a95cf33582d836c967496ea7636e61c6cb7191", + "0x518708d6d86b3a15dfd50d0003c340998be42ff59d533703be30763aa080c547", + "0xc9cc7282488774cbdb9d6511ebae8f6eb9947cc5360585d75197532e37e9c7ae", + "0x9c73d1c1a937f888d29da748772785d1a8269282003e7cbab2af4140039312ed", + "0xadc5c8b549e56222f6634a308348eda613afa171b5991ede1b127f241d25c570", + "0x0bcab0832ec43772bb1aa95f8ba9eac83b4b47bfa776876276b47722aaf5c3c5", + "0x8b37849d079adedcba7ed2be598a6d84464ccdd807ccdef2d711e5ef7bdc003b", + "0x8e2e677e5f20a78caa0ab3726528209bca791551d0d33346144c5e7b1c8c6bf7", + "0xda0666298d3184c66e54af103e988fa0c9a80a12e32921e5bea0233a8638e23a", + "0x1ffb4873b85e71b067e3ac99bb26e7f5ee5e036bba4835989f1477ac8b03466f", + "0xfc89d4900e3e7a475b8923bad15bf68f4cb967cb50fae648c2efb3d90cde84f9", + "0xb62eb8ea8e54ed6358a752943acd7a2a1fef9553533b56ca17f3cfc0ba719ec8", + "0x795e2eecc65f357e0b7a9c97d2c028b7503524809adc6e783f05eb0423362980", + "0xdb06a90870bce8df7a88118d485eb691a0043c695ceb64af565ed62d37770c98", + "0xa28bb65d12c4875edd64e643da53c1b65a154d9e40a4cd37c6f770940235740f", + "0x136902f6e7104043a9d828a027df5f23c61a7d085e49907042c55d99d72c16d7", + "0x058424a9554f7a52bb6516ee51653aee32ea09d96247fce31dd8b31af52a07aa", + "0xcce2dbdca699f427d620870ae23b96b38da3414c57e71990ba8af36a58e6b936", + "0xd1feadaa1927f77eae9bb7260fe84ada5d524bdf1239a6e688080da9f7b71af0", + "0xebe906165c9808c0b368392dd2cd950b55e1f95394d28255d7cb9848bd4f3839", + "0x639198f58b4712fde6064dc49f73b3db52726e76ab9bdc00f6ef9a0487fd6d5b", + "0xe9e2f1d0afa3d3b0883fc7269618ca1a50ea5aa828ea07f92fae48b2b2fc54fd", + "0x811ee53510a20a012a10ed6a02407dcaf98099823a35e54849b381d4a6e5b5e8", + "0x221c81c3c384717eabd545830b62427d11fc62bd1df260921a8e121456d719e0", + "0xdc62196c03031dfd983ad4a211a514e25c4c97c9cd9ca62ac18b44cc0da4e0ea", + "0x3f60edc7443b2ae2a4ede7f52c2c4de9d58f90d6be2f0fb25772b51c352aee17", + "0xb5cdbf0eda83613a613ea26b14401361a2de1be89412367f39d4ab01449a87f5", + "0x10d0156c9a828e9b8d61e615079beebbaa525a07f32d792e5a67d4f03846bf4c", + "0x4be38f1cac74f26e2e5bed0d2b416482a74aa425564ccfd3e0ef10b5f57a7d59", + "0x814aa2e560adae5e7192ada4ee11567bfebf3ff8a2a93aa8dd432df30c77f44f", + "0x187c004ce45887043188c222842da10e062a9be8a3db326d3ebdf860209e723e", + "0x60036829b2cce1932f2d4198b5207d70a2e0634c929a63df122ea38f620f89eb", + "0xc323959ae94b9d4e5246a35ccb887b8fcdd2b5de43ab581e53fd3090b4dc88b8", + "0x37a114fb8c7c973708d5dba9c37df501db5e0d074c757954e52ef716299239ec", + "0x8cb29fadf7071a43d8208036d986abe64a1974786c4ab573f4dcca88f8db83a9", + "0xfc4485a7b2ddece8cefbc0f45c949920b9412a47b3e21efa9aa381e0cba0ee72", + "0xfdd52d72e5f42cc1cf1bdcbdc97b15f623b78d78425c338fe588e890be995597", + "0x92e26312a466aff28597bf3444b0bd298b12872f099885ab10949c0d263446a5", + "0x420d6f0581dc5c914b0da7339fb69bb5c9094ea8715c778e9dccd922317c36da", + "0xdd8641edece5a0ab2b024b4ceefdc3f524cb0cc9549c200528962eb0fa341310", + "0x740c0963ec5c29ca9fa48445ddc604bec138df538edb18844182556924d09fa6", + "0xe66653af6368613260ba344cc051d6086a2e08331e8bc5ddc2d25ab06ead9eec", + "0x86e1aa0ab7a4e47828216a25073d6c355e2f4ac4773cf1d2d859f62fd8fb8a24", + "0x3be2cdbd947172907f5605beb7863e2edc5f176e0960904550358ed6c2670704", + "0xc7d4869adae5a7593dbea4f802ab068044dab40fe0063d5b7c7727a3bf288525", + "0x620611d92e256bf7cc471c8883801be5d64fc8b77c1f39682bf840031e0dcd3e", + "0xd89f0456b5a3d041d5309ef623e259003383277f7f509096ae5dd02d312543d6", + "0x7d91689ff4e212d6f2c7d62cdef0593686ba04aaf455c576535d097120f1353d", + "0x568a6763698a23b4b2289b851b46907ec5777284741d3a7304d7df297fa4129e", + "0xb9dec1f84c9b71d5939f40982fe5c88d15f868e265d4fd9fa0560c2b64191998", + "0x6620f3e9e7fae45ca0178116a9e478f95bc0a69fab3a8341dca673453741bb6d", + "0xbb418a7f8415e5378cca2ee7056c6c78641b085e30bb9f9da033ea193bbfc77f", + "0x002fe11d761d3135edbb3dcb50533a1b143593145f7b4cd914d84494b1df652e", + "0x5f76ba2c72c3e4d93d98668455def3d335b03f517648c6cfde1d0a37178a0ec1", + "0xda49060ebc8b7963a9ff4095c9777d902075967d75c47ee3e9f86f03031b0a3e", + "0xde325b667d85828b7416d437a91c19a14b0217323650dd5880a8a40ea85f451c", + "0x9c14e5953fe56c60599dea8284b0948603334fc7aa795cae80308eff4cbd67da", + "0xa9e82869a1be8247c665d86f52900784005853c5249393fadabe37d08752ac9b", + "0x3feff38ddc1917cd5cace417b4e86762126997a5420ac2cb32abafa769f91ac5", + "0x01144f9a6fa0b4396560cdee8bc6e873bdf3ec5c3ab3f7409e59884e6d2dbd05", + "0x96778169c9f2b805e67cf18324c292c8b67c57db72aeebfe5369d91aca0983b3", + "0x373f81dd55fb3bdc9de4c42028a5bdc970cfda825723b6f0f7804b50a1754bda", + "0x3af64226f4eb3ea6bd6d0dae027bce6b361b30c50b4a65a4e1661577268953d0", + "0x35b96aa54e1c50049a0c91281c75d3d06c4b609a2d3d92cb22d1328369adcdc6", + "0xb02c9650fc610b3f5a0b547e8bc505b4a840e1dea123b4cb2c8af6232ae1359f", + "0xae53d65eebce31c14b787f1df5b021334312e8d5b8302b84f6a56b6608e25d97", + "0x4901a419abac1937602d98c21e937a03db8a48d088e56895788da845829225cd", + "0xf5636fb8f3a381476267e6713f10763cef51071b6d981a8f661a24ff6d368e71", + "0x059e8319866374d8eb8372e71998cc9277c5f5e5968c126a81d87d0d7a6fe8fa", + "0xd5fbcd3d7a4387000e014e67ef61d4a7ce09a70374ad4fcdb6ca0b6b50b13ea5", + "0xc37ef88d74d307090a0dd49b69d5705c8e65ad606548b0880eef33b8346c2af8", + "0xa316c8a8ac949af5957fc905ba39c247a477224cd9c4cbabccd0671dbc1e17e7", + "0xdb313f10f0dfb56b8684e6ded5e89c4d5a3cd958a99b1773680db8682645b9f4", + "0x0c81ab956b95426f5c327c6ac6db2fbbaa8fd0f41cc9f58971d5089a0f3c52c5", + "0xb09827a7c1bfba1fb7e5c7acee1da5d8fda1c10da19046151f55ef7fefb784b9", + "0x4332b07750799b436dc5b8521feb0927d7e59b25832ac83876da4eb9df333aec", + "0xdf6895278968d74b85e4bb2c53d70772a6176322200f864b004ed914bcc3cf2c", + "0x9a4a6427c038efbb77e255b8e74df6f897590f734328e5be0ab6b16a6ca58e46", + "0xcf683bc5fd50f6c444a84a5524b3e6ba381fe62c39828650f8c70d9b5b6e8d47", + "0x3282bab4eea18b9a8147d6dbf26073882e7f859b498b2d17608cc96548f5ba7f", + "0x04684c3e47911134ccfa142c85d283f26ed315b5818a523a79e9be31c17b4dcc", + "0xa8efff633914b0ed52a2eb3b75d6efbe1efb0f640136807db13d8809289e40a4", + "0x4502554b0b48e3230e24efafc4f8eef7ff50347cea1a27a15ba46187ed0fb2a9", + "0xe0d6508774e4d8772bfed391286d5f13b986518dfe49d6cc9fd55c415e2382f8", + "0xeefb070835b6cacf8237566bfbc77b177ad0e3e6293587d76904f5cf56cfe62d", + "0x06162414a2b278bf48122286cfd04e83ab148c91ff45d5b90bb3a55d374debb1", + "0xf87fcab4bf30f560c5359ee594e263859f1160f3ddd4186918093275e271d520", + "0xf3ea8332782f88dfa789e42eebba3ec9672589d090c557e36e05c7eda9c7372c", + "0xf05f9c5ec95884e6da30f95d56ad58a025dd696215ff57683d6946ebce25d497", + "0x6738c17f58a1e7d41a634984b98a5efa47e910640da0fcd80d2ad0603c0ec9f9", + "0x8c2029217e14a9bd4dd88eefbe6ddf886d30c56df42035464a5acfe567406dcd", + "0x5d0434b926b112a81e7276b96d1dcff0391e782dd68003173a5d11701a8fc190", + "0x4d9a5c9209364544eddbc545822bea83af527fa1f7b24dbedbdda61b69e18250", + "0x3e5800a59c58a56bd2cb7659db0705f45b6b8e827cf06eb0fe98586abfc83368", + "0xbc3f4d3a46d5fe6df5ded66fc47b5b73baa878c9b8fc3798e87a17995614c515", + "0xf715cbf347c5308a4d50c99eeb4882c6244a03ca77349d126337ed3861e454a0", + "0xe831c5b327832f9440cfc795e7f703cae82648704d05f7bd41b2acd4e07b2c1f", + "0x46c6926581d617ac8384583726ec7088f1e0df60bb075a1b43ab51fbdaa108b7", + "0x236eb9d731c98bc8407bcb9954e3297c51ed6a116f90f6d1ccdd8f4c89bf5dd0", + "0x6ea6994bc6b93be59e0e8f48e32f2afbbcc653d4c1b845625b8a5e280db809bd", + "0x3af35cfbcdd184c7579a273a73361271ae9e1a97ef89fb1f0e6dfe89a776c237", + "0x7553093da896b06cda700a41c0233274a089e633dcb5fd8d81ff0393491db2c6", + "0xc555ae61e8f86c775768be4a07045042a8d5898ca6dac14687327b89303d9ad2", + "0x4fc388b57b8d35c704e8c03be70f1c9ba03e638ffac704791c0aeec6d3dd8e2c", + "0xfd0ec61b6a525012d03781c254697a98ac0d4b1e55f46e3aa1ab819e7a90436f", + "0x1d7e68aa18a225ddede2856f421613f88872e89a7024919590930c43326a5bf4", + "0x37865c43f2db20bbfd51a1440e7cf95923c6b980ac6b7e3173d3f867d60d9b32", + "0x44de3419b85216c1d2ab63cf3a002c28835dd084c2e3ee0eb4ba92dc49d5a1b5", + "0xd5fd4d94d504e021eb7865b8aff7ed53c6afa96970fbacd678c2b78fd8c5badf", + "0x479043958f7b84ee3c20a9503fb10b3ecbb895b2b4eb4f69b3ea0b5243f881c8", + "0x683669e82fd55e4162c00a97b2af897395e3a1d3dc51c7f12f4e01e4e3cc3ef6", + "0x9dfc309c9a3382fad72a40825cf621e1dfe095aa77e3b00bd5a0f0c5445d6a34", + "0x63def4af1a927f696cf1abaeba3c172de583cdff6278d8db46e23ac8063ac042", + "0x682e98b0482b1282c896bc2920ce48328246d8d3301b5059988325950f19e0ae", + "0x929abbe6a8ebc0ac32f5ec6a8c1f728d733284e81c02477f606163521d86f642", + "0xd3deb41a543048541beb8b96a1f5b029da6ddb513327d025a5176e95dd4ab1ed", + "0x886432bd185ec9c30a459182ac4467aa9c0f590de8825712c8fe3d9cf7bef9eb", + "0xcc9f64743d0672261a614e9e5c09e9f8416d754f9c536e456a08ef885569a39d", + "0x55bd4b7d2d2ffe8ffd7054d1c8f912119ae793a23dd2d9a10f0ba94ee4b8ac9c", + "0x00a86e2d5dcaec027c9c49853eba467e910f39b4cae50bee85c40b48d34313c6", + "0x89ebc269c4a123f9622e89fd221d22776def13c4a9637a7f69176504ed48ac2e", + "0x808d7a4793aa0afd91d35a6a46eb4f3ed522c77716fbd27765ad2104d2638d75", + "0x5766e58d79181a27639e4e2b1c141de7825e6abe3996d3d06a518bc87044abb0", + "0x53e304b2ae212fac8b059d283f8f97553cb16fb3332e8833305a32db18abb5fa" + ] + }, "nodes": [ "enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303", "enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303", -- GitLab From f135c09b3616a450289002b5f61f5be028b147fc Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Thu, 26 Apr 2018 15:00:42 +0300 Subject: [PATCH 105/263] Update wasmi and pwasm-utils (#8493) * Update wasmi to 0.2 New wasmi supports 32bit platforms and no longer requires a special feature to build for such platforms. * Update pwasm-utils to 0.1.5 --- Cargo.lock | 19 +++++++++++++------ ethcore/wasm/Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb7936297e..4587085dc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1770,6 +1770,11 @@ dependencies = [ "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nan-preserving-float" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "net2" version = "0.2.31" @@ -2586,7 +2591,7 @@ dependencies = [ [[package]] name = "pwasm-utils" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3625,18 +3630,19 @@ dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", - "wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmi" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3888,6 +3894,7 @@ dependencies = [ "checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" "checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3" +"checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "143149743832c6543b60a8ef2a26cd9122dfecec2b767158e852a7beecf6d7a0" @@ -3928,7 +3935,7 @@ dependencies = [ "checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786" "checksum protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40e2484e639dcae0985fc483ad76ce7ad78ee5aa092751d7d538f0b20d76486b" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" -"checksum pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54d440c3b56eee028aa5d4f18cbed8c6e0c9ae23563b93f344beb7e73854ea02" +"checksum pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d51e9954a77aab7b4b606dc315a49cbed187924f163b6750cdf6d5677dbf0839" "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" @@ -4033,7 +4040,7 @@ dependencies = [ "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb" +"checksum wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46df76793c28cd8f590d5667f540a81c1c245440a17b03560e381226e27cf348" "checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2" "checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index a39e6ee529..a0362955d1 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -12,4 +12,4 @@ libc = "0.2" pwasm-utils = "0.1" vm = { path = "../vm" } ethcore-logger = { path = "../../logger" } -wasmi = { version = "0.1.3", features = ["opt-in-32bit"] } +wasmi = { version = "0.2" } -- GitLab From 9376796bdb7c5c9aa8631acca8373a8df60f3ccb Mon Sep 17 00:00:00 2001 From: David Dorgan Date: Fri, 27 Apr 2018 14:01:47 +0100 Subject: [PATCH 106/263] Remove three old warp boot nodes. (#8497) --- ethcore/res/ethereum/foundation.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 4438718711..6658b5e522 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -2873,9 +2873,6 @@ "enode://00526537cb7e1aa6cf49714f0635fd0f608904d8d0693b949eea2dcdfdb0abbe4c794003a5fe57aa662d0a9215e8dfa4d2deb6ef0101c5e185e2617721813d43@40.65.122.44:30303", "enode://4a456b4b6e6ee1f51389763e51b80fe04782c762445d96c32a96ebd34bd9178c1894924d5101123eacfd4f0fc4da25b5e1ee7f18832ac0bf4c6d6ac81442d698@40.71.6.49:3030", "enode://68f85e7403976aa92318eff804cbe9bc988e0f5230d9d07ae4def030cbae16603262638e272d19875b7e5c54e296ba88ab6ec6e98face9e2537346c4dce78882@52.243.47.211:30303", - "enode://dc72806c3aa8fda207c8c018aba8d6cf143728b3628b6ded8d5e8cdeb8aa05cbd53f710ecd014c9a8f0d1e98f2874bff8afb15a229202f510a9c0258d1f6d109@159.203.210.80:30303", - "enode://5a62f19d35c0da8b576c9414568c728d4744e6e9d436c0f9db27456400011414f515871f13a6b8e0468534b5116cfe765d7630f680f1707a38467940a9f62511@45.55.33.62:30303", - "enode://605e04a43b1156966b3a3b66b980c87b7f18522f7f712035f84576016be909a2798a438b2b17b1a8c58db314d88539a77419ca4be36148c086900fba487c9d39@188.166.255.12:30303", "enode://1d1f7bcb159d308eb2f3d5e32dc5f8786d714ec696bb2f7e3d982f9bcd04c938c139432f13aadcaf5128304a8005e8606aebf5eebd9ec192a1471c13b5e31d49@138.201.223.35:30303", "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", -- GitLab From 01d399ad667b54a6fbe912dd04cadf7a3966251a Mon Sep 17 00:00:00 2001 From: Anton Gavrilov Date: Fri, 27 Apr 2018 15:02:45 +0200 Subject: [PATCH 107/263] Return error if RLP size of transaction exceeds the limit (#8473) * Return error if RLP size of transaction exceeds the limit * Review comments fixed * RLP check moved to verifier, corresponding pool test added --- Cargo.lock | 1 + ethcore/src/client/client.rs | 3 +-- ethcore/src/engines/mod.rs | 5 +++++ ethcore/src/machine.rs | 11 +++++++++++ ethcore/src/miner/pool_client.rs | 4 ++++ ethcore/src/spec/spec.rs | 5 +++++ ethcore/sync/src/chain.rs | 5 ----- ethcore/transaction/src/error.rs | 13 +++++++++++++ json/src/spec/params.rs | 3 +++ miner/Cargo.toml | 1 + miner/src/lib.rs | 1 + miner/src/pool/client.rs | 4 ++++ miner/src/pool/res/big_transaction.data | 1 + miner/src/pool/tests/client.rs | 14 ++++++++++++++ miner/src/pool/tests/mod.rs | 10 ++++++++++ miner/src/pool/tests/tx.rs | 13 +++++++++++++ miner/src/pool/verifier.rs | 7 +++++++ rpc/src/v1/helpers/errors.rs | 2 ++ 18 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 miner/src/pool/res/big_transaction.data diff --git a/Cargo.lock b/Cargo.lock index 4587085dc0..48a0ab0d94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -684,6 +684,7 @@ dependencies = [ "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "price-info 1.12.0", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", "transaction-pool 1.12.0", diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 6ec318a03f..ebc8961cd0 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -62,7 +62,6 @@ use ethcore_miner::pool::VerifiedTransaction; use parking_lot::{Mutex, RwLock}; use rand::OsRng; use receipt::{Receipt, LocalizedReceipt}; -use rlp::Rlp; use snapshot::{self, io as snapshot_io}; use spec::Spec; use state_db::StateDB; @@ -995,7 +994,7 @@ impl Client { let txs: Vec = transactions .iter() - .filter_map(|bytes| Rlp::new(bytes).as_val().ok()) + .filter_map(|bytes| self.engine().decode_transaction(bytes).ok()) .collect(); self.notify(|notify| { diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 8556879f95..a17ae356e6 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -426,6 +426,11 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> { fn additional_params(&self) -> HashMap { self.machine().additional_params() } + + /// Performs pre-validation of RLP decoded transaction before other processing + fn decode_transaction(&self, transaction: &[u8]) -> Result { + self.machine().decode_transaction(transaction) + } } // convenience wrappers for existing functions. diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 7d488e0d0c..e3bf7d340c 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -34,6 +34,7 @@ use tx_filter::TransactionFilter; use ethereum_types::{U256, Address}; use bytes::BytesRef; +use rlp::Rlp; use vm::{CallType, ActionParams, ActionValue, ParamsType}; use vm::{EnvInfo, Schedule, CreateContractAddress}; @@ -376,6 +377,16 @@ impl EthereumMachine { "registrar".to_owned() => format!("{:x}", self.params.registrar) ] } + + /// Performs pre-validation of RLP decoded transaction before other processing + pub fn decode_transaction(&self, transaction: &[u8]) -> Result { + let rlp = Rlp::new(&transaction); + if rlp.as_raw().len() > self.params().max_transaction_size { + debug!("Rejected oversized transaction of {} bytes", rlp.as_raw().len()); + return Err(transaction::Error::TooBig) + } + rlp.as_val().map_err(|e| transaction::Error::InvalidRlp(e.to_string())) + } } /// Auxiliary data fetcher for an Ethereum machine. In Ethereum-like machines diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs index 61153be025..dfcdec684f 100644 --- a/ethcore/src/miner/pool_client.rs +++ b/ethcore/src/miner/pool_client.rs @@ -145,6 +145,10 @@ impl<'a, C: 'a> pool::client::Client for PoolClient<'a, C> where } } } + + fn decode_transaction(&self, transaction: &[u8]) -> Result { + self.engine.decode_transaction(transaction) + } } impl<'a, C: 'a> NonceClient for PoolClient<'a, C> where diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 7f6d650dd4..156ab8f15a 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -48,6 +48,8 @@ use trace::{NoopTracer, NoopVMTracer}; pub use ethash::OptimizeFor; +const MAX_TRANSACTION_SIZE: usize = 300 * 1024; + // helper for formatting errors. fn fmt_err(f: F) -> String { format!("Spec json is invalid: {}", f) @@ -123,6 +125,8 @@ pub struct CommonParams { pub max_code_size_transition: BlockNumber, /// Transaction permission managing contract address. pub transaction_permission_contract: Option

, + /// Maximum size of transaction's RLP payload + pub max_transaction_size: usize, } impl CommonParams { @@ -238,6 +242,7 @@ impl From for CommonParams { registrar: p.registrar.map_or_else(Address::new, Into::into), node_permission_contract: p.node_permission_contract.map(Into::into), max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into), + max_transaction_size: p.max_transaction_size.map_or(MAX_TRANSACTION_SIZE, Into::into), max_code_size_transition: p.max_code_size_transition.map_or(0, Into::into), transaction_permission_contract: p.transaction_permission_contract.map(Into::into), wasm_activation_transition: p.wasm_activation_transition.map_or( diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index eaab13b6f4..25d9a09f6b 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -140,7 +140,6 @@ const MAX_PEERS_PROPAGATION: usize = 128; const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20; const MAX_NEW_HASHES: usize = 64; const MAX_NEW_BLOCK_AGE: BlockNumber = 20; -const MAX_TRANSACTION_SIZE: usize = 300*1024; // maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; // Maximal number of transactions in sent in single packet. @@ -1517,10 +1516,6 @@ impl ChainSync { let mut transactions = Vec::with_capacity(item_count); for i in 0 .. item_count { let rlp = r.at(i)?; - if rlp.as_raw().len() > MAX_TRANSACTION_SIZE { - debug!("Skipped oversized transaction of {} bytes", rlp.as_raw().len()); - continue; - } let tx = rlp.as_raw().to_vec(); transactions.push(tx); } diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index e38dc3ac67..eeeba4e53a 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -18,6 +18,7 @@ use std::{fmt, error}; use ethereum_types::U256; use ethkey; +use rlp; use unexpected::OutOfBounds; #[derive(Debug, PartialEq, Clone)] @@ -74,6 +75,10 @@ pub enum Error { NotAllowed, /// Signature error InvalidSignature(String), + /// Transaction too big + TooBig, + /// Invalid RLP encoding + InvalidRlp(String), } impl From for Error { @@ -82,6 +87,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: rlp::DecoderError) -> Self { + Error::InvalidRlp(format!("{}", err)) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; @@ -106,6 +117,8 @@ impl fmt::Display for Error { InvalidChainId => "Transaction of this chain ID is not allowed on this chain.".into(), InvalidSignature(ref err) => format!("Transaction has invalid signature: {}.", err), NotAllowed => "Sender does not have permissions to execute this type of transction".into(), + TooBig => "Transaction too big".into(), + InvalidRlp(ref err) => format!("Transaction has invalid RLP structure: {}.", err), }; f.write_fmt(format_args!("Transaction error ({})", msg)) diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 4a1efe2a7f..ce47086df1 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -113,6 +113,9 @@ pub struct Params { /// See main EthashParams docs. #[serde(rename="maxCodeSize")] pub max_code_size: Option, + /// Maximum size of transaction RLP payload. + #[serde(rename="maxTransactionSize")] + pub max_transaction_size: Option, /// See main EthashParams docs. #[serde(rename="maxCodeSizeTransition")] pub max_code_size_transition: Option, diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 95dd888dc9..707352484e 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -28,6 +28,7 @@ log = "0.3" parking_lot = "0.5" price-info = { path = "../price-info" } rayon = "1.0" +rlp = { path = "../util/rlp" } trace-time = { path = "../util/trace-time" } transaction-pool = { path = "../transaction-pool" } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 197823aec7..08ea7d204f 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -30,6 +30,7 @@ extern crate linked_hash_map; extern crate parking_lot; extern crate price_info; extern crate rayon; +extern crate rlp; extern crate trace_time; extern crate transaction_pool as txpool; diff --git a/miner/src/pool/client.rs b/miner/src/pool/client.rs index 4243e8d26b..622e9a8492 100644 --- a/miner/src/pool/client.rs +++ b/miner/src/pool/client.rs @@ -62,6 +62,10 @@ pub trait Client: fmt::Debug + Sync { /// Classify transaction (check if transaction is filtered by some contracts). fn transaction_type(&self, tx: &transaction::SignedTransaction) -> TransactionType; + + /// Performs pre-validation of RLP decoded transaction + fn decode_transaction(&self, transaction: &[u8]) + -> Result; } /// State nonce client diff --git a/miner/src/pool/res/big_transaction.data b/miner/src/pool/res/big_transaction.data new file mode 100644 index 0000000000..15703f893a --- /dev/null +++ b/miner/src/pool/res/big_transaction.data @@ -0,0 +1 @@ +6060604052341561000f57600080fd5b604051610b0d380380610b0d833981016040528080518201919060200180518201919060200180518201919050508260009080519060200190610053929190610092565b50816002908051906020019061006a92919061011c565b50806001908051906020019061008192919061011c565b506001600381905550505050610204565b82805482825590600052602060002090810192821561010b579160200282015b8281111561010a5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906100b2565b5b509050610118919061019c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061015d57805160ff191683800117855561018b565b8280016001018555821561018b579182015b8281111561018a57825182559160200191906001019061016f565b5b50905061019891906101df565b5090565b6101dc91905b808211156101d857600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016101a2565b5090565b90565b61020191905b808211156101fd5760008160009055506001016101e5565b5090565b90565b6108fa806102136000396000f300606060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806317ac53a21461007d57806324c12bf61461019a57806335aa2e4414610228578063affed0e01461028b578063b7ab4db5146102b4578063c19d93fb1461031e575b600080fd5b341561008857600080fd5b610198600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919050506103ac565b005b34156101a557600080fd5b6101ad610600565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ed5780820151818401526020810190506101d2565b50505050905090810190601f16801561021a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561023357600080fd5b610249600480803590602001909190505061069e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561029657600080fd5b61029e6106dd565b6040518082815260200191505060405180910390f35b34156102bf57600080fd5b6102c76106e3565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561030a5780820151818401526020810190506102ef565b505050509050019250505060405180910390f35b341561032957600080fd5b610331610777565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610371578082015181840152602081019050610356565b50505050905090810190601f16801561039e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000806040805190810160405280876040518082805190602001908083835b6020831015156103f057805182526020820191506020810190506020830392506103cb565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390206000191660001916815260200160035460010260001916600019168152506040518082600260200280838360005b8381101561046657808201518184015260208101905061044b565b5050505090500191505060405180910390209150600090505b6000805490508110156105d55760008181548110151561049b57fe5b906000526020600020900160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660018387848151811015156104ee57fe5b90602001906020020151878581518110151561050657fe5b90602001906020020151878681518110151561051e57fe5b90602001906020020151604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f115156105a057600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff161415156105c857fe5b808060010191505061047f565b85600190805190602001906105eb929190610815565b50600160035401600381905550505050505050565b60028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106965780601f1061066b57610100808354040283529160200191610696565b820191906000526020600020905b81548152906001019060200180831161067957829003601f168201915b505050505081565b6000818154811015156106ad57fe5b90600052602060002090016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b6106eb610895565b600080548060200260200160405190810160405280929190818152602001828054801561076d57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610723575b5050505050905090565b60018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561080d5780601f106107e25761010080835404028352916020019161080d565b820191906000526020600020905b8154815290600101906020018083116107f057829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061085657805160ff1916838001178555610884565b82800160010185558215610884579182015b82811115610883578251825591602001919060010190610868565b5b50905061089191906108a9565b5090565b602060405190810160405280600081525090565b6108cb91905b808211156108c75760008160009055506001016108af565b5090565b905600a165627a7a723058200ae0215fae320b646a22fdd58278b328f46d915bd65ddbfeb5b4a09643d6e0220029000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000007ffbe3512782069be388f41be4d8eb350672d3a500000000000000000000000000000000000000000000000000000000000000e88b98f0e95488c3849ba24320a00a047c39b3ca3af8f066d82d849104eb0218150baf61620b321c8d2db0c8e351fd17826cd2cd13296287fb02cab742db410ba4346b4c13c1f81cc52dd5ee3dd7773e23842fe5d8e29db6da6f8f6f42964f118486b0c8d7971cfb8ed4926622774c92e495ae47dd481eb03090ad09a1fb4a2cd0ad4b108efeb408f160f34fae6f6d9843574f3e37dd11ec54dd69fa7dfa919257e760a78d6cccec92785381f9554b3da1249c4844e259b0f57180034fb63bd6136132f822f6472a31c68b8a60646bcbddfa4ddd3be0fe4457a4f691a6542bf798a4fa6b0990284166000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001056e81f171bcc55a6ff8345e692c0f86e000000000000000000000000000000006060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d833981016060604052341561000f57600080fd5b604051610b0d380380610b0d83398101 diff --git a/miner/src/pool/tests/client.rs b/miner/src/pool/tests/client.rs index 7f7be64cc8..a00cc541eb 100644 --- a/miner/src/pool/tests/client.rs +++ b/miner/src/pool/tests/client.rs @@ -15,17 +15,21 @@ // along with Parity. If not, see . use ethereum_types::{U256, H256, Address}; +use rlp::Rlp; use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; use pool; use pool::client::AccountDetails; +const MAX_TRANSACTION_SIZE: usize = 15 * 1024; + #[derive(Debug, Clone)] pub struct TestClient { account_details: AccountDetails, gas_required: U256, is_service_transaction: bool, local_address: Address, + max_transaction_size: usize, } impl Default for TestClient { @@ -39,6 +43,7 @@ impl Default for TestClient { gas_required: 21_000.into(), is_service_transaction: false, local_address: Default::default(), + max_transaction_size: MAX_TRANSACTION_SIZE, } } } @@ -116,6 +121,15 @@ impl pool::client::Client for TestClient { pool::client::TransactionType::Regular } } + + fn decode_transaction(&self, transaction: &[u8]) -> Result { + let rlp = Rlp::new(&transaction); + if rlp.as_raw().len() > self.max_transaction_size { + return Err(transaction::Error::TooBig) + } + rlp.as_val().map_err(|e| transaction::Error::InvalidRlp(e.to_string())) + } + } impl pool::client::NonceClient for TestClient { diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 340cb75158..0d8e38a6e1 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -755,3 +755,13 @@ fn should_clear_cache_after_timeout_for_local() { // then assert_eq!(txq.pending(TestClient::new(), 0, 1002, None).len(), 2); } + +#[test] +fn should_reject_big_transaction() { + let txq = new_queue(); + let big_tx = Tx::default().big_one(); + let res = txq.import(TestClient::new(), vec![ + verifier::Transaction::Local(PendingTransaction::new(big_tx, transaction::Condition::Timestamp(1000).into())) + ]); + assert_eq!(res, vec![Err(transaction::Error::TooBig)]); +} \ No newline at end of file diff --git a/miner/src/pool/tests/tx.rs b/miner/src/pool/tests/tx.rs index ee0a7390ee..c0f8751ebb 100644 --- a/miner/src/pool/tests/tx.rs +++ b/miner/src/pool/tests/tx.rs @@ -87,6 +87,19 @@ impl Tx { nonce: self.nonce.into() } } + + pub fn big_one(self) -> SignedTransaction { + let keypair = Random.generate().unwrap(); + let tx = Transaction { + action: transaction::Action::Create, + value: U256::from(100), + data: include_str!("../res/big_transaction.data").from_hex().unwrap(), + gas: self.gas.into(), + gas_price: self.gas_price.into(), + nonce: self.nonce.into() + }; + tx.sign(keypair.secret(), None) + } } pub trait TxExt: Sized { type Out; diff --git a/miner/src/pool/verifier.rs b/miner/src/pool/verifier.rs index 92d2eb9c86..0a89a784b1 100644 --- a/miner/src/pool/verifier.rs +++ b/miner/src/pool/verifier.rs @@ -27,6 +27,7 @@ use std::sync::Arc; use std::sync::atomic::{self, AtomicUsize}; use ethereum_types::{U256, H256}; +use rlp::Encodable; use transaction; use txpool; @@ -222,6 +223,12 @@ impl txpool::Verifier for Verifier { Transaction::Local(tx) => tx, }; + // Verify RLP payload + if let Err(err) = self.client.decode_transaction(&transaction.rlp_bytes()) { + debug!(target: "txqueue", "[{:?}] Rejected transaction's rlp payload", err); + bail!(err) + } + let sender = transaction.sender(); let account_details = self.client.account_details(&sender); diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index acff796646..4f3289a116 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -338,6 +338,8 @@ pub fn transaction_message(error: &TransactionError) -> String { RecipientBanned => "Recipient is banned in local queue.".into(), CodeBanned => "Code is banned in local queue.".into(), NotAllowed => "Transaction is not permitted.".into(), + TooBig => "Transaction is too big, see chain specification for the limit.".into(), + InvalidRlp(ref descr) => format!("Invalid RLP data: {}", descr), } } -- GitLab From e36c4ecc9814ee098431c4cb54f5c2c7efb219da Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 27 Apr 2018 15:04:27 +0200 Subject: [PATCH 108/263] `duration_ns: u64 -> duration: Duration` (#8457) * duration_ns: u64 -> duration: Duration * format on millis {:.2} -> {} --- ethcore/private-tx/src/lib.rs | 3 ++- ethcore/src/client/chain_notify.rs | 3 ++- ethcore/src/client/client.rs | 24 +++++++------------ ethcore/src/snapshot/watcher.rs | 9 ++++--- ethcore/sync/src/api.rs | 6 ++--- ethcore/sync/src/tests/helpers.rs | 3 ++- parity/informant.rs | 4 ++-- rpc/src/v1/impls/eth_pubsub.rs | 3 ++- rpc/src/v1/tests/mocked/eth_pubsub.rs | 12 ++++++---- secret_store/src/acl_storage.rs | 3 ++- secret_store/src/key_server_set.rs | 3 ++- .../src/listener/service_contract_listener.rs | 3 ++- updater/src/updater.rs | 2 +- 13 files changed, 43 insertions(+), 35 deletions(-) diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 12028ddf12..26a31fc7ae 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -66,6 +66,7 @@ pub use error::{Error, ErrorKind}; use std::sync::{Arc, Weak}; use std::collections::{HashMap, HashSet}; +use std::time::Duration; use ethereum_types::{H128, H256, U256, Address}; use hash::keccak; use rlp::*; @@ -667,7 +668,7 @@ fn find_account_password(passwords: &Vec, account_provider: &AccountProv } impl ChainNotify for Provider { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !imported.is_empty() { trace!("New blocks imported, try to prune the queue"); if let Err(err) = self.process_queue() { diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index ccfb2558d6..a1f84d2a13 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -17,6 +17,7 @@ use bytes::Bytes; use ethereum_types::H256; use transaction::UnverifiedTransaction; +use std::time::Duration; /// Messages to broadcast via chain pub enum ChainMessageType { @@ -40,7 +41,7 @@ pub trait ChainNotify : Send + Sync { _sealed: Vec, // Block bytes. _proposed: Vec, - _duration: u64, + _duration: Duration, ) { // does nothing by default } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ebc8961cd0..8d305fc057 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -18,7 +18,7 @@ use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; -use std::time::{Instant}; +use std::time::{Instant, Duration}; use itertools::Itertools; // util @@ -32,7 +32,7 @@ use util_error::UtilError; // other use ethereum_types::{H256, Address, U256}; use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; use client::ancient_import::AncientVerifier; use client::Error as ClientError; use client::{ @@ -120,7 +120,7 @@ impl<'a> ::std::ops::Sub<&'a ClientReport> for ClientReport { self.blocks_imported -= other.blocks_imported; self.transactions_applied -= other.transactions_applied; self.gas_processed = self.gas_processed - other.gas_processed; - self.state_db_mem = higher_mem - lower_mem; + self.state_db_mem = higher_mem - lower_mem; self } @@ -331,11 +331,7 @@ impl Importer { self.block_queue.mark_as_bad(&invalid_blocks); } let is_empty = self.block_queue.mark_as_good(&imported_blocks); - let duration_ns = { - let elapsed = start.elapsed(); - elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64 - }; - (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, duration_ns, is_empty) + (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, start.elapsed(), is_empty) }; { @@ -1434,7 +1430,7 @@ impl ImportBlock for Client { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } let status = self.block_status(BlockId::Hash(header.parent_hash())); - if status == BlockStatus::Unknown || status == BlockStatus::Pending { + if status == BlockStatus::Unknown || status == BlockStatus::Pending { bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(header.parent_hash()))); } } @@ -1497,7 +1493,7 @@ impl Call for Client { } fn estimate_gas(&self, t: &SignedTransaction, state: &Self::State, header: &Header) -> Result { - let (mut upper, max_upper, env_info) = { + let (mut upper, max_upper, env_info) = { let init = *header.gas_limit(); let max = init * U256::from(10); @@ -2096,10 +2092,7 @@ impl ImportSealedBlock for Client { retracted.clone(), vec![h.clone()], vec![], - { - let elapsed = start.elapsed(); - elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64 - }, + start.elapsed(), ); }); self.db.read().flush().expect("DB flush failed."); @@ -2109,6 +2102,7 @@ impl ImportSealedBlock for Client { impl BroadcastProposalBlock for Client { fn broadcast_proposal_block(&self, block: SealedBlock) { + const DURATION_ZERO: Duration = Duration::from_millis(0); self.notify(|notify| { notify.new_blocks( vec![], @@ -2117,7 +2111,7 @@ impl BroadcastProposalBlock for Client { vec![], vec![], vec![block.rlp_bytes()], - 0, + DURATION_ZERO, ); }); } diff --git a/ethcore/src/snapshot/watcher.rs b/ethcore/src/snapshot/watcher.rs index 841fa1982a..936feaefba 100644 --- a/ethcore/src/snapshot/watcher.rs +++ b/ethcore/src/snapshot/watcher.rs @@ -24,7 +24,7 @@ use io::IoChannel; use ethereum_types::H256; use bytes::Bytes; -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; // helper trait for transforming hashes to numbers and checking if syncing. trait Oracle: Send + Sync { @@ -107,7 +107,7 @@ impl ChainNotify for Watcher { _: Vec, _: Vec, _: Vec, - _duration: u64) + _duration: Duration) { if self.oracle.is_major_importing() { return } @@ -136,6 +136,7 @@ mod tests { use ethereum_types::{H256, U256}; use std::collections::HashMap; + use std::time::Duration; struct TestOracle(HashMap); @@ -158,6 +159,8 @@ mod tests { // helper harness for tests which expect a notification. fn harness(numbers: Vec, period: u64, history: u64, expected: Option) { + const DURATION_ZERO: Duration = Duration::from_millis(0); + let hashes: Vec<_> = numbers.clone().into_iter().map(|x| H256::from(U256::from(x))).collect(); let map = hashes.clone().into_iter().zip(numbers).collect(); @@ -175,7 +178,7 @@ mod tests { vec![], vec![], vec![], - 0, + DURATION_ZERO, ); } diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index c66a1c6a62..5e96f11cf3 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -413,7 +413,7 @@ impl ChainNotify for EthSync { retracted: Vec, sealed: Vec, proposed: Vec, - _duration: u64) + _duration: Duration) { use light::net::Announcement; @@ -452,7 +452,7 @@ impl ChainNotify for EthSync { fn start(&self) { match self.network.start().map_err(Into::into) { - Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), + Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), Err(err) => warn!("Error starting network: {}", err), _ => {}, } @@ -625,7 +625,7 @@ impl NetworkConfiguration { config_path: self.config_path, net_config_path: self.net_config_path, listen_address: match self.listen_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, - public_address: match self.public_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, + public_address: match self.public_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, udp_port: self.udp_port, nat_enabled: self.nat_enabled, discovery_enabled: self.discovery_enabled, diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 086dc503bb..54467adb77 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -16,6 +16,7 @@ use std::collections::{VecDeque, HashSet, HashMap}; use std::sync::Arc; +use std::time::Duration; use ethereum_types::H256; use parking_lot::{RwLock, Mutex}; use bytes::Bytes; @@ -538,7 +539,7 @@ impl ChainNotify for EthPeer { retracted: Vec, sealed: Vec, proposed: Vec, - _duration: u64) + _duration: Duration) { self.new_blocks_queue.write().push_back(NewBlockMessage { imported, diff --git a/parity/informant.rs b/parity/informant.rs index 896e80ec53..29f732e085 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -351,7 +351,7 @@ impl Informant { } impl ChainNotify for Informant { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, duration: u64) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, duration: Duration) { let mut last_import = self.last_import.lock(); let client = &self.target.client; @@ -373,7 +373,7 @@ impl ChainNotify for Informant { Colour::White.bold().paint(format!("{}", header_view.hash())), Colour::Yellow.bold().paint(format!("{}", block.transactions_count())), Colour::Yellow.bold().paint(format!("{:.2}", header_view.gas_used().low_u64() as f32 / 1000000f32)), - Colour::Purple.bold().paint(format!("{:.2}", duration as f32 / 1000000f32)), + Colour::Purple.bold().paint(format!("{}", duration.as_milliseconds())), Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)), if skipped > 0 { format!(" + another {} block(s) containing {} tx(s)", diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index d7e6112a93..1a872f5600 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -18,6 +18,7 @@ use std::sync::{Arc, Weak}; use std::collections::BTreeMap; +use std::time::Duration; use jsonrpc_core::{BoxFuture, Result, Error}; use jsonrpc_core::futures::{self, Future, IntoFuture}; @@ -227,7 +228,7 @@ impl ChainNotify for ChainNotificationHandler { _sealed: Vec, // Block bytes. _proposed: Vec, - _duration: u64, + _duration: Duration, ) { const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; let headers = enacted diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index 15b178d504..fb28ba3127 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -20,11 +20,15 @@ use jsonrpc_core::MetaIoHandler; use jsonrpc_core::futures::{self, Stream, Future}; use jsonrpc_pubsub::Session; +use std::time::Duration; + use v1::{EthPubSub, EthPubSubClient, Metadata}; use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify}; use parity_reactor::EventLoop; +const DURATION_ZERO: Duration = Duration::from_millis(0); + #[test] fn should_subscribe_to_new_heads() { // given @@ -53,13 +57,13 @@ fn should_subscribe_to_new_heads() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x1","extraData":"0x","gasLimit":"0xf4240","gasUsed":"0x0","hash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","number":"0x1","parentHash":"0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x1c9","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","timestamp":"0x0","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); // Notify about two blocks - handler.new_blocks(vec![], vec![], vec![h2, h3], vec![], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![h2, h3], vec![], vec![], vec![], DURATION_ZERO); // Receive both let (res, receiver) = receiver.into_future().wait().unwrap(); @@ -125,7 +129,7 @@ fn should_subscribe_to_logs() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications (enacted) - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) @@ -133,7 +137,7 @@ fn should_subscribe_to_logs() { assert_eq!(res, Some(response.into())); // Check notifications (retracted) - handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], 0); + handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 58d9bc4775..6399660aff 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -16,6 +16,7 @@ use std::sync::Arc; use std::collections::{HashMap, HashSet}; +use std::time::Duration; use parking_lot::{Mutex, RwLock}; use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; use ethereum_types::{H256, Address}; @@ -75,7 +76,7 @@ impl AclStorage for OnChainAclStorage { } impl ChainNotify for OnChainAclStorage { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !enacted.is_empty() || !retracted.is_empty() { self.contract.lock().update() } diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index 7697408557..cb324dbc9b 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use std::net::SocketAddr; use std::collections::{BTreeMap, HashSet}; +use std::time::Duration; use parking_lot::Mutex; use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, CallContract, RegistryInfo}; use ethcore::filter::Filter; @@ -162,7 +163,7 @@ impl KeyServerSet for OnChainKeyServerSet { } impl ChainNotify for OnChainKeyServerSet { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !enacted.is_empty() || !retracted.is_empty() { self.contract.lock().update(enacted, retracted) } diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 2975eaa134..1e17be8e55 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -17,6 +17,7 @@ use std::collections::HashSet; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::time::Duration; use std::thread; use parking_lot::Mutex; use ethcore::client::ChainNotify; @@ -428,7 +429,7 @@ impl Drop for ServiceContractListener { } impl ChainNotify for ServiceContractListener { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { let enacted_len = enacted.len(); if enacted_len == 0 { return; diff --git a/updater/src/updater.rs b/updater/src/updater.rs index 3b5ce01a93..c5f45c7658 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -660,7 +660,7 @@ impl Updater, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: u64) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { match (self.client.upgrade(), self.sync.as_ref().and_then(Weak::upgrade)) { (Some(ref c), Some(ref s)) if !s.status().is_syncing(c.queue_info()) => self.poll(), _ => {}, -- GitLab From 44c68221a8e45a7e1fab9c3e3326459a92e0c154 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 27 Apr 2018 17:46:17 +0200 Subject: [PATCH 109/263] Remove unused dependency `bigint` (#8505) * remove unused dependency bigint in * remove bigint in rpc_cli --- Cargo.lock | 13 ------------- rpc_cli/Cargo.toml | 1 - util/memorydb/Cargo.toml | 1 - 3 files changed, 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48a0ab0d94..3176c3ab3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,16 +102,6 @@ dependencies = [ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bigint" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bincode" version = "0.8.0" @@ -1634,7 +1624,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "memorydb" version = "0.1.1" dependencies = [ - "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", @@ -2806,7 +2795,6 @@ dependencies = [ name = "rpc-cli" version = "1.4.0" dependencies = [ - "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.12.0", "parity-rpc-client 1.4.0", @@ -3783,7 +3771,6 @@ dependencies = [ "checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4" -"checksum bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5442186ef6560f30f1ee4b9c1e4c87a35a6879d3644550cc248ec2b955eb5fcd" "checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" diff --git a/rpc_cli/Cargo.toml b/rpc_cli/Cargo.toml index 0bda94ab67..7d4652c38c 100644 --- a/rpc_cli/Cargo.toml +++ b/rpc_cli/Cargo.toml @@ -9,6 +9,5 @@ version = "1.4.0" [dependencies] futures = "0.1" rpassword = "1.0" -bigint = "4.0" parity-rpc = { path = "../rpc" } parity-rpc-client = { path = "../rpc_client" } diff --git a/util/memorydb/Cargo.toml b/util/memorydb/Cargo.toml index da83227814..41c41bb628 100644 --- a/util/memorydb/Cargo.toml +++ b/util/memorydb/Cargo.toml @@ -6,7 +6,6 @@ description = "in-memory implementation of hashdb" license = "GPL-3.0" [dependencies] -bigint = "4.0" elastic-array = "0.10" heapsize = "0.4" ethereum-types = "0.3" -- GitLab From 2a829b1f1a68f07ba3b235bb6692fc7799092308 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 1 May 2018 20:16:03 +0800 Subject: [PATCH 110/263] Show imported messages for light client (#8517) --- ethcore/light/src/client/service.rs | 7 ++++++- parity/informant.rs | 29 ++++++++++++++++++++++++++++- parity/run.rs | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/ethcore/light/src/client/service.rs b/ethcore/light/src/client/service.rs index 3d13be16b4..a3ec8a3686 100644 --- a/ethcore/light/src/client/service.rs +++ b/ethcore/light/src/client/service.rs @@ -30,7 +30,7 @@ use kvdb::KeyValueDB; use cache::Cache; use parking_lot::Mutex; -use super::{ChainDataFetcher, Client, Config as ClientConfig}; +use super::{ChainDataFetcher, LightChainNotify, Client, Config as ClientConfig}; /// Errors on service initialization. #[derive(Debug)] @@ -86,6 +86,11 @@ impl Service { }) } + /// Set the actor to be notified on certain chain events + pub fn add_notify(&self, notify: Arc) { + self.client.add_listener(Arc::downgrade(¬ify)); + } + /// Register an I/O handler on the service. pub fn register_handler(&self, handler: Arc + Send>) -> Result<(), IoError> { self.io_service.register_handler(handler) diff --git a/parity/informant.rs b/parity/informant.rs index 29f732e085..5c2e0ab89d 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -33,7 +33,7 @@ use ethcore::snapshot::service::Service as SnapshotService; use sync::{LightSyncProvider, LightSync, SyncProvider, ManageNetwork}; use io::{TimerToken, IoContext, IoHandler}; use light::Cache as LightDataCache; -use light::client::LightChainClient; +use light::client::{LightChainClient, LightChainNotify}; use number_prefix::{binary_prefix, Standalone, Prefixed}; use parity_rpc::{is_major_importing}; use parity_rpc::informant::RpcStats; @@ -395,6 +395,33 @@ impl ChainNotify for Informant { } } +impl LightChainNotify for Informant { + fn new_headers(&self, good: &[H256]) { + let mut last_import = self.last_import.lock(); + let client = &self.target.client; + + let importing = self.target.is_major_importing(); + let ripe = Instant::now() > *last_import + Duration::from_secs(1) && !importing; + + if ripe { + if let Some(header) = good.last().and_then(|h| client.block_header(BlockId::Hash(*h))) { + info!(target: "import", "Imported {} {} ({} Mgas){}", + Colour::White.bold().paint(format!("#{}", header.number())), + Colour::White.bold().paint(format!("{}", header.hash())), + Colour::Yellow.bold().paint(format!("{:.2}", header.gas_used().low_u64() as f32 / 1000000f32)), + if good.len() > 1 { + format!(" + another {} header(s)", + Colour::Red.bold().paint(format!("{}", good.len() - 1))) + } else { + String::new() + } + ); + *last_import = Instant::now(); + } + } + } +} + const INFO_TIMER: TimerToken = 0; impl IoHandler for Informant { diff --git a/parity/run.rs b/parity/run.rs index f07f67caa8..fdb32293b9 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -412,7 +412,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result Date: Tue, 1 May 2018 20:47:04 +0800 Subject: [PATCH 111/263] Directly return None if tracing is disabled (#8504) * Directly return None if tracing is disabled * Address gumbles: release read locks as fast as possible --- ethcore/src/client/client.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8d305fc057..bc20de3dd8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1868,6 +1868,10 @@ impl BlockChainClient for Client { } fn filter_traces(&self, filter: TraceFilter) -> Option> { + if !self.tracedb.read().tracing_enabled() { + return None; + } + let start = self.block_number(filter.range.start)?; let end = self.block_number(filter.range.end)?; @@ -1887,6 +1891,10 @@ impl BlockChainClient for Client { } fn trace(&self, trace: TraceId) -> Option { + if !self.tracedb.read().tracing_enabled() { + return None; + } + let trace_address = trace.address; self.transaction_address(trace.transaction) .and_then(|tx_address| { @@ -1896,6 +1904,10 @@ impl BlockChainClient for Client { } fn transaction_traces(&self, transaction: TransactionId) -> Option> { + if !self.tracedb.read().tracing_enabled() { + return None; + } + self.transaction_address(transaction) .and_then(|tx_address| { self.block_number(BlockId::Hash(tx_address.block_hash)) @@ -1904,6 +1916,10 @@ impl BlockChainClient for Client { } fn block_traces(&self, block: BlockId) -> Option> { + if !self.tracedb.read().tracing_enabled() { + return None; + } + self.block_number(block) .and_then(|number| self.tracedb.read().block_traces(number)) } -- GitLab From 849f5d9a4449ea3631cc49f43f7d8dd04a03831d Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 1 May 2018 15:01:49 +0200 Subject: [PATCH 112/263] Hardware Wallet trait (#8071) * getting started with replacing HardwareWalletManager * trezor and ledger impls the new trait with some drawbacks * Everything move to the new trait * It required lifetime annotations in the trait because [u8] in unsized * Lets now start moving entry point from HardwareWalletManager * rename trait to Wallet * move thread management to the actual wallets * Moved thread management to each respective Wallet * Cleaned up pub items that is needed to be pub * Wallet trait more or less finished * Cleaned up docs * fix tests * omit removed docs * fix spelling, naming och remove old comments * ledger test is broken, add correct logging format * So locally on my machine Linux Ubuntu 17.10 the test doesn't panic but on the CI server libusb::Context::new() fails which I don't understand because it has worked before * Additionally the ledger test is optional so I lean toward ignoring it the CI Server * ignore hardware tests by default * more verbose checking in ledger test --- hw/src/ledger.rs | 397 ++++++++++++++++++++++++++--------------------- hw/src/lib.rs | 132 ++++++++-------- hw/src/trezor.rs | 344 +++++++++++++++++++++------------------- 3 files changed, 473 insertions(+), 400 deletions(-) diff --git a/hw/src/ledger.rs b/hw/src/ledger.rs index e7d616d4f9..e31d49f130 100644 --- a/hw/src/ledger.rs +++ b/hw/src/ledger.rs @@ -20,8 +20,11 @@ use std::cmp::min; use std::fmt; use std::str::FromStr; +use std::sync::atomic; +use std::sync::atomic::AtomicBool; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; +use std::thread; use ethereum_types::{H256, Address}; use ethkey::Signature; @@ -29,12 +32,12 @@ use hidapi; use libusb; use parking_lot::{Mutex, RwLock}; -use super::{WalletInfo, KeyPath}; +use super::{WalletInfo, KeyPath, Device, Wallet, USB_DEVICE_CLASS_DEVICE}; /// Ledger vendor ID -pub const LEDGER_VID: u16 = 0x2c97; -/// Legder product IDs: [Nano S and Blue] -pub const LEDGER_PIDS: [u16; 2] = [0x0000, 0x0001]; +const LEDGER_VID: u16 = 0x2c97; +/// Ledger product IDs: [Nano S and Blue] +const LEDGER_PIDS: [u16; 2] = [0x0000, 0x0001]; const ETH_DERIVATION_PATH_BE: [u8; 17] = [4, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/0'/0 const ETC_DERIVATION_PATH_BE: [u8; 21] = [5, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0x02, 0x73, 0xd0, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/160720'/0'/0 @@ -64,8 +67,10 @@ pub enum Error { KeyNotFound, /// Signing has been cancelled by user. UserCancel, - /// Invalid Device + /// Invalid device InvalidDevice, + /// Impossible error + ImpossibleError, } impl fmt::Display for Error { @@ -77,6 +82,7 @@ impl fmt::Display for Error { Error::KeyNotFound => write!(f, "Key not found"), Error::UserCancel => write!(f, "Operation has been cancelled"), Error::InvalidDevice => write!(f, "Unsupported product was entered"), + Error::ImpossibleError => write!(f, "Placeholder error"), } } } @@ -100,157 +106,43 @@ pub struct Manager { key_path: RwLock, } -#[derive(Debug)] -struct Device { - path: String, - info: WalletInfo, -} - impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>) -> Manager { - Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Manager { usb: hidapi, devices: RwLock::new(Vec::new()), key_path: RwLock::new(KeyPath::Ethereum), - } - } - - /// Re-populate device list. Only those devices that have Ethereum app open will be added. - pub fn update_devices(&self) -> Result { - let mut usb = self.usb.lock(); - usb.refresh_devices(); - let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut num_new_devices = 0; - for device in devices { - trace!("Checking device: {:?}", device); - if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { - continue; - } - match self.read_device_info(&usb, &device) { - Ok(info) => { - debug!("Found device: {:?}", info); - if !self.devices.read().iter().any(|d| d.path == info.path) { - num_new_devices += 1; + }); + + let usb_context = Arc::new(libusb::Context::new()?); + let m = manager.clone(); + + // Subscribe to all Ledger devices + // This means that we need to check that the given productID is supported + // None => LIBUSB_HOTPLUG_MATCH_ANY, in other words that all are subscribed to + // More info can be found: + usb_context.register_callback( + Some(LEDGER_VID), None, Some(USB_DEVICE_CLASS_DEVICE), + Box::new(EventHandler::new(Arc::downgrade(&manager)))).expect("usb_callback"); + + // Ledger event handler thread + thread::Builder::new() + .spawn(move || { + if let Err(e) = m.update_devices() { + debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e); + } + loop { + usb_context.handle_events(Some(Duration::from_millis(500))) + .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); + if exiting.load(atomic::Ordering::Acquire) { + break; } - new_devices.push(info); - } - Err(e) => debug!("Error reading device info: {}", e), - }; - } - *self.devices.write() = new_devices; - Ok(num_new_devices) - } + }) + .ok(); - /// Select key derivation path for a known chain. - pub fn set_key_path(&self, key_path: KeyPath) { - *self.key_path.write() = key_path; - } - - fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { - let mut handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let address = Self::read_wallet_address(&mut handle, *self.key_path.read())?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); - Ok(Device { - path: dev_info.path.clone(), - info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, - address: address, - }, - }) - } - - fn read_wallet_address(handle: &hidapi::HidDevice, key_path: KeyPath) -> Result { - let ver = Self::send_apdu(handle, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; - if ver.len() != 4 { - return Err(Error::Protocol("Version packet size mismatch")); - } - - let (major, minor, patch) = (ver[1], ver[2], ver[3]); - if major < 1 || (major == 1 && minor == 0 && patch < 3) { - return Err(Error::Protocol("App version 1.0.3 is required.")); - } - - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match key_path { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; - let key_and_address = Self::send_apdu(handle, commands::GET_ETH_PUBLIC_ADDRESS, 0, 0, derivation_path)?; - if key_and_address.len() != 107 { // 1 + 65 PK + 1 + 40 Addr (ascii-hex) - return Err(Error::Protocol("Key packet size mismatch")); - } - let address_string = ::std::str::from_utf8(&key_and_address[67..107]) - .map_err(|_| Error::Protocol("Invalid address string"))?; - - let address = Address::from_str(&address_string) - .map_err(|_| Error::Protocol("Invalid address string"))?; - - Ok(address) - } - - /// List connected wallets. This only returns wallets that are ready to be used. - pub fn list_devices(&self) -> Vec { - self.devices.read().iter().map(|d| d.info.clone()).collect() - } - - /// Get wallet info. - pub fn device_info(&self, address: &Address) -> Option { - self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) - } - - /// Sign transaction data with wallet managing `address`. - pub fn sign_transaction(&self, address: &Address, data: &[u8]) -> Result { - let usb = self.usb.lock(); - let devices = self.devices.read(); - let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; - let handle = self.open_path(|| usb.open_path(&device.path))?; - - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match *self.key_path.read() { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; - const MAX_CHUNK_SIZE: usize = 255; - let mut chunk: [u8; MAX_CHUNK_SIZE] = [0; MAX_CHUNK_SIZE]; - &mut chunk[0..derivation_path.len()].copy_from_slice(derivation_path); - let mut dest_offset = derivation_path.len(); - let mut data_pos = 0; - let mut result; - loop { - let p1 = if data_pos == 0 { 0x00 } else { 0x80 }; - let dest_left = MAX_CHUNK_SIZE - dest_offset; - let chunk_data_size = min(dest_left, data.len() - data_pos); - &mut chunk[dest_offset..][0..chunk_data_size].copy_from_slice(&data[data_pos..][0..chunk_data_size]); - result = Self::send_apdu(&handle, commands::SIGN_ETH_TRANSACTION, p1, 0, &chunk[0..(dest_offset + chunk_data_size)])?; - dest_offset = 0; - data_pos += chunk_data_size; - if data_pos == data.len() { - break; - } - } - - if result.len() != 65 { - return Err(Error::Protocol("Signature packet size mismatch")); - } - let v = (result[0] + 1) % 2; - let r = H256::from_slice(&result[1..33]); - let s = H256::from_slice(&result[33..65]); - Ok(Signature::from_rsv(&r, &s, v)) - } - - fn open_path(&self, f: F) -> Result - where F: Fn() -> Result - { - f().map_err(Into::into) + Ok(manager) } fn send_apdu(handle: &hidapi::HidDevice, command: u8, p1: u8, p2: u8, data: &[u8]) -> Result, Error> { @@ -285,7 +177,7 @@ impl Manager { chunk_index += 1; } - // read response + // Read response chunk_index = 0; let mut message_size = 0; let mut message = Vec::new(); @@ -303,7 +195,7 @@ impl Manager { let mut offset = 5; if seq == 0 { - // read message size and status word. + // Read message size and status word. if chunk_size < 7 { return Err(Error::Protocol("Unexpected chunk header")); } @@ -321,7 +213,7 @@ impl Manager { return Err(Error::Protocol("No status word")); } let status = (message[message.len() - 2] as usize) << 8 | (message[message.len() - 1] as usize); - debug!("Read status {:x}", status); + debug!(target: "hw", "Read status {:x}", status); match status { 0x6700 => Err(Error::Protocol("Incorrect length")), 0x6982 => Err(Error::Protocol("Security status not satisfied (Canceled by user)")), @@ -365,18 +257,166 @@ fn try_connect_polling(ledger: Arc, timeout: Duration) -> bool { false } +impl <'a>Wallet<'a> for Manager { + type Error = Error; + type Transaction = &'a [u8]; + + fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result { + let usb = self.usb.lock(); + let devices = self.devices.read(); + let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; + let handle = self.open_path(|| usb.open_path(&device.path))?; + + let eth_path = Ð_DERIVATION_PATH_BE[..]; + let etc_path = &ETC_DERIVATION_PATH_BE[..]; + let derivation_path = match *self.key_path.read() { + KeyPath::Ethereum => eth_path, + KeyPath::EthereumClassic => etc_path, + }; + const MAX_CHUNK_SIZE: usize = 255; + let mut chunk: [u8; MAX_CHUNK_SIZE] = [0; MAX_CHUNK_SIZE]; + &mut chunk[0..derivation_path.len()].copy_from_slice(derivation_path); + let mut dest_offset = derivation_path.len(); + let mut data_pos = 0; + let mut result; + loop { + let p1 = if data_pos == 0 { 0x00 } else { 0x80 }; + let dest_left = MAX_CHUNK_SIZE - dest_offset; + let chunk_data_size = min(dest_left, transaction.len() - data_pos); + &mut chunk[dest_offset..][0..chunk_data_size].copy_from_slice(&transaction[data_pos..][0..chunk_data_size]); + result = Self::send_apdu(&handle, commands::SIGN_ETH_TRANSACTION, p1, 0, &chunk[0..(dest_offset + chunk_data_size)])?; + dest_offset = 0; + data_pos += chunk_data_size; + if data_pos == transaction.len() { + break; + } + } + + if result.len() != 65 { + return Err(Error::Protocol("Signature packet size mismatch")); + } + let v = (result[0] + 1) % 2; + let r = H256::from_slice(&result[1..33]); + let s = H256::from_slice(&result[33..65]); + Ok(Signature::from_rsv(&r, &s, v)) + } + + fn set_key_path(&self, key_path: KeyPath) { + *self.key_path.write() = key_path; + } + + fn update_devices(&self) -> Result { + let mut usb = self.usb.lock(); + usb.refresh_devices(); + let devices = usb.devices(); + let mut new_devices = Vec::new(); + let mut num_new_devices = 0; + for device in devices { + trace!("Checking device: {:?}", device); + if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { + continue; + } + match self.read_device(&usb, &device) { + Ok(info) => { + debug!(target: "hw", "Found device: {:?}", info); + if !self.devices.read().iter().any(|d| d.path == info.path) { + num_new_devices += 1; + } + new_devices.push(info); + + } + Err(e) => debug!(target: "hw", "Error reading device info: {}", e), + }; + } + *self.devices.write() = new_devices; + Ok(num_new_devices) + } + + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { + let handle = self.open_path(|| usb.open_path(&dev_info.path))?; + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + match self.get_address(&handle) { + Ok(Some(addr)) => { + Ok(Device { + path: dev_info.path.clone(), + info: WalletInfo { + name: name, + manufacturer: manufacturer, + serial: serial, + address: addr, + }, + }) + } + // This variant is not possible, but the trait forces this return type + Ok(None) => Err(Error::ImpossibleError), + Err(e) => Err(e), + } + } + + fn list_devices(&self) -> Vec { + self.devices.read().iter().map(|d| d.info.clone()).collect() + } + + // Not used because it is not supported by Ledger + fn list_locked_devices(&self) -> Vec { + vec![] + } + + fn get_wallet(&self, address: &Address) -> Option { + self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) + } + + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Self::Error> { + let ver = Self::send_apdu(device, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; + if ver.len() != 4 { + return Err(Error::Protocol("Version packet size mismatch")); + } + + let (major, minor, patch) = (ver[1], ver[2], ver[3]); + if major < 1 || (major == 1 && minor == 0 && patch < 3) { + return Err(Error::Protocol("App version 1.0.3 is required.")); + } + + let eth_path = Ð_DERIVATION_PATH_BE[..]; + let etc_path = &ETC_DERIVATION_PATH_BE[..]; + let derivation_path = match *self.key_path.read() { + KeyPath::Ethereum => eth_path, + KeyPath::EthereumClassic => etc_path, + }; + let key_and_address = Self::send_apdu(device, commands::GET_ETH_PUBLIC_ADDRESS, 0, 0, derivation_path)?; + if key_and_address.len() != 107 { // 1 + 65 PK + 1 + 40 Addr (ascii-hex) + return Err(Error::Protocol("Key packet size mismatch")); + } + let address_string = ::std::str::from_utf8(&key_and_address[67..107]) + .map_err(|_| Error::Protocol("Invalid address string"))?; + + let address = Address::from_str(&address_string) + .map_err(|_| Error::Protocol("Invalid address string"))?; + + Ok(Some(address)) + } + + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result + { + f().map_err(Into::into) + } +} + /// Ledger event handler -/// A seperate thread is hanedling incoming events +/// A separate thread is handling incoming events /// /// Note, that this run to completion and race-conditions can't occur but this can /// therefore starve other events for being process with a spinlock or similar -pub struct EventHandler { +struct EventHandler { ledger: Weak, } impl EventHandler { /// Ledger event handler constructor - pub fn new(ledger: Weak) -> Self { + fn new(ledger: Weak) -> Self { Self { ledger: ledger } } } @@ -402,27 +442,34 @@ impl libusb::Hotplug for EventHandler { } #[test] +#[ignore] +/// This test can't be run without an actual ledger device connected fn smoke() { use rustc_hex::FromHex; - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap())); - let manager = Manager::new(hidapi.clone()); - manager.update_devices().unwrap(); - for d in &*manager.devices.read() { - println!("Device: {:?}", d); - } - - if let Some(address) = manager.list_devices().first().map(|d| d.address.clone()) { - let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); - let signature = manager.sign_transaction(&address, &tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let large_tx = FromHex::from_hex("f8cb81968504e3b2920083024f279475b02a3c39710d6a3f2870d0d788299d48e790f180b8a4b61d27f6000000000000000000000000e1af840a5a1cb1efdf608a97aa632f4aa39ed199000000000000000000000000000000000000000000000000105ff43f46a9a800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018080").unwrap(); - let signature = manager.sign_transaction(&address, &large_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let huge_tx = FromHex::from_hex("f935e98201048505d21dba00833b82608080b935946103e86003908155620d2f00600455601460055560a060405260608190527f2e2e2e00000000000000000000000000000000000000000000000000000000006080908152600d805460008290527f2e2e2e00000000000000000000000000000000000000000000000000000000068255909260008051602062003474833981519152602060026001851615610100026000190190941693909304601f0192909204820192909190620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b5b50620001009291505b80821115620000fc5760008155600101620000e6565b5090565b5050600e8054600360ff199182168117909255604080518082019091528281527f2e2e2e00000000000000000000000000000000000000000000000000000000006020918201908152600f80546000829052825160069516949094178155937f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80260026101006001871615026000190190951694909404601f019290920483019290620001d7565b82800160010185558215620001d7579182015b82811115620001d7578251825591602001919060010190620001ba565b5b50620001fb9291505b80821115620000fc5760008155600101620000e6565b5090565b50506010805460ff19166001179055346200000057604051620034943803806200349483398101604090815281516020830151918301516060840151919390810191015b5b5b60068054600160a060020a0319166c01000000000000000000000000338102041790558151600d80546000829052909160008051602062003474833981519152602060026101006001861615026000190190941693909304601f908101849004820193870190839010620002c157805160ff1916838001178555620002f1565b82800160010185558215620002f1579182015b82811115620002f1578251825591602001919060010190620002d4565b5b50620003159291505b80821115620000fc5760008155600101620000e6565b5090565b505080600f9080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200036557805160ff191683800117855562000395565b8280016001018555821562000395579182015b828111156200039557825182559160200191906001019062000378565b5b50620003b99291505b80821115620000fc5760008155600101620000e6565b5090565b5050600980546c01000000000000000000000000808602819004600160a060020a0319928316179092556007805487840293909304929091169190911790555b505050505b613066806200040e6000396000f300606060405236156102035760e060020a600035046306fdde03811461034b578063095ea7b3146103c65780630b0b6d5b146103ed5780631b1ccc47146103fc57806320e870931461047757806323b872dd1461049657806325b29d84146104c057806327187991146104df578063277ccde2146104f15780632e1fbfcd14610510578063308b2fdc14610532578063313ce5671461055457806338cc48311461057757806340eddc4e146105a057806341f4793a146105bf578063467ed261146105de578063471ad963146105fd5780634e860ebb1461060f5780634efbe9331461061e57806354786b4e1461064257806354e35ba2146106bd57806358793ad4146106d25780635abedab21461073f5780635af2f8211461074e57806360483a3f1461076d57806360d12fa0146107da578063698f2e84146108035780636a749986146108155780636d5f66391461082a5780636e9c36831461083c57806370a082311461085e5780637a290fe5146108805780637e7541461461088f57806394c41bdb1461090a57806395d89b4114610929578063962a64cd146109a4578063a0b6533214610a09578063a9059cbb14610a2b578063ab62438f14610a52578063b63ca98114610aa9578063b7c54c6f14610abb578063c4e41b2214610ada578063ca7c4dba14610af9578063cb79e31b14610b18578063dd62ed3e14610b3a575b6103495b60006000600c546000141561021b57610000565b600354600c54670de0b6b3a764000091349091020204915060009050816001600030600160a060020a031681526020019081526020016000205410156102c557600160a060020a033016600090815260016020526040902054600c54909250828115610000570466038d7ea4c68000023403905033600160a060020a03166108fc829081150290604051809050600060405180830381858888f1935050505015156102c557610000565b5b600160a060020a03338116600081815260016020908152604080832080548801905530909416825283822080548790039055601380543487900301908190559154600c548551908152918201879052845190949293927f5a0391f2a67f11ed0034b68f8cf14e7e41d6f86e0a7622f2af5ea8f07b488396928290030190a45b5050565b005b3461000057610358610b5f565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103d9600435602435610bed565b604080519115158252519081900360200190f35b3461000057610349610c58565b005b3461000057610358610dbc565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484610e5a565b60408051918252519081900360200190f35b34610000576103d9600435602435604435610ef9565b604080519115158252519081900360200190f35b3461000057610484610ff3565b60408051918252519081900360200190f35b3461000057610349600435611002565b005b346100005761048461105a565b60408051918252519081900360200190f35b3461000057610484600435611061565b60408051918252519081900360200190f35b346100005761048460043561108d565b60408051918252519081900360200190f35b34610000576105616110b9565b6040805160ff9092168252519081900360200190f35b34610000576105846110c2565b60408051600160a060020a039092168252519081900360200190f35b34610000576104846110c7565b60408051918252519081900360200190f35b34610000576104846110ce565b60408051918252519081900360200190f35b34610000576104846110d5565b60408051918252519081900360200190f35b3461000057610349600435611174565b005b34610000576103496113b5565b005b34610000576103d9600435611407565b604080519115158252519081900360200190f35b3461000057610358611549565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103496004356024356115e7565b005b346100005760408051602060046024803582810135601f8101859004850286018501909652858552610726958335959394604494939290920191819084018382808284375094965061167e95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610349611c13565b005b3461000057610484611d46565b60408051918252519081900360200190f35b346100005760408051602060046024803582810135601f81018590048502860185019096528585526107269583359593946044949392909201918190840183828082843750949650611d4d95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610584612303565b60408051600160a060020a039092168252519081900360200190f35b3461000057610349600435612313565b005b3461000057610349600435602435612347565b005b346100005761034960043561252f565b005b3461000057610484600435612941565b60408051918252519081900360200190f35b346100005761048460043561298d565b60408051918252519081900360200190f35b34610000576103496129ac565b005b3461000057610358612a13565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484612ab1565b60408051918252519081900360200190f35b3461000057610358612ab8565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650612b4695505050505050565b60408051918252519081900360200190f35b3461000057610484600435612b63565b60408051918252519081900360200190f35b34610000576103d9600435602435612b8c565b604080519115158252519081900360200190f35b3461000057610349600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350612c3c92505050565b005b3461000057610349600435612f38565b005b3461000057610484612f90565b60408051918252519081900360200190f35b346100005761048461300c565b60408051918252519081900360200190f35b3461000057610484613013565b60408051918252519081900360200190f35b346100005761048460043561301a565b60408051918252519081900360200190f35b3461000057610484600435602435613039565b60408051918252519081900360200190f35b600d805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b601a54600090600160a060020a03161515610c7257610000565b600160a060020a0333166000908152600a60205260409020541515610c9657610000565b600160a060020a0333166000908152601d602052604090205460ff1615610cbc57610000565b601b54426212750090910111610cd157610000565b600160a060020a0333166000818152601d60209081526040808320805460ff19166001179055600a8252918290208054601c805490910190555482519384529083015280517f475c7605c08471fdc551a58d2c318b163628c5852f69323a1b91c34eb0bb09339281900390910190a150601154601c54606490910490604682029010610db857601a5460068054600160a060020a031916606060020a600160a060020a0393841681020417908190556040805191909216815290517f6b8184e23a898262087be50aa3ea5de648451e63f94413e810586c25282d58c2916020908290030190a15b5b50565b604080516020808201835260008252600d8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b600f805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600160a060020a038316600090815260016020526040812054829010801590610f495750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b8015610f555750600082115b15610fe757600160a060020a03808516600081815260016020908152604080832080548890039055878516808452818420805489019055848452600283528184203390961684529482529182902080548790039055815186815291517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610feb56610feb565b5060005b5b9392505050565b600160a060020a033016315b90565b60065433600160a060020a0390811691161461101d57610000565b600c8190556040805182815290517f0bbd501ef336990995d82b5e3fd82a15abe1ff10c982757a1698ac5d1c3e79579181900360200190a15b5b50565b600b545b90565b6000601882815481101561000057906000526020600020906007020160005b506004015490505b919050565b6000601882815481101561000057906000526020600020906007020160005b506001015490505b919050565b600e5460ff1681565b305b90565b6013545b90565b601c545b90565b600d805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600654600090819033600160a060020a0390811691161461119457610000565b60008381526014602052604090205415156111ae57610000565b60008381526014602052604090206005015433600160a060020a039081169116146111d857610000565b60008381526014602052604090206005015460a060020a900460ff16156111fe57610000565b601154600084815260146020526040902060040154606490910460370292508290111561122a57610000565b60008381526014602052604081206005015460a860020a900460ff16600181116100005714156112eb57600954600084815260146020908152604080832060058101546001909101548251840185905282517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810191909152915194169363a9059cbb93604480840194938390030190829087803b156100005760325a03f1156100005750611389915050565b60008381526014602052604080822060058101546001909101549151600160a060020a039091169282156108fc02929190818181858888f160008881526014602090815260409182902060058101546001909101548351600160a060020a0390921682529181019190915281519297507f2648a7e2f9c34700b91370233666e5118fa8be3e0c21fed4f7402b941df8efdd9650829003019350915050a15b6000838152601460205260409020600501805460a060020a60ff02191660a060020a1790555b5b505050565b60065433600160a060020a039081169116146113d057610000565b6010805460ff191690556040517fb48c7f694f0a3b9b22d7e61c60ff8aebbb107314b6b698fc489ff3f017cb57e090600090a15b5b565b600060006000600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f115610000575050604051514210905061147c57610000565b60085433600160a060020a0390811691161461149757610000565b5050600b54600160a060020a03328181166000908152600a6020526040902080549386029384019055601180548401905560128054860190556008549092916114e39130911683610ef9565b506114ee8282612b8c565b50600054601154600b5460408051918252602082018590528051600160a060020a038716927fb4d6befef2def3d17bcb13c2b882ec4fa047f33157446d3e0e6094b2a21609ac92908290030190a4600192505b5b5050919050565b604080516020808201835260008252600f8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b60065433600160a060020a0390811691161461160257610000565b60105460ff16151561161357610000565b600160a060020a0330166000908152600160209081526040808320805485019055600c859055825484019283905580518481529051839286927f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c3929081900390910190a45b5b5b5050565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a039081169116146116ed57610000565b60115460649004935060056016541115801561170c5750836005540288115b1561171657610000565b61171e612f90565b8811156117305761172d612f90565b97505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016000815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061182057805160ff191683800117855561184d565b8280016001018555821561184d579182015b8281111561184d578251825591602001919060010190611832565b5b5061186e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116119c9576007028160070283600052602060002091820191016119c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10611968575061199a565b601f01602090049060005260206000209081019061199a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701611925565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a90810204021790555050505060166000815460010191905081905550426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b60065460009033600160a060020a03908116911614611c3157610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f1156100005750506040515162dd7c00014210159050611ca657610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1600954909550600160a060020a0316935063a9059cbb9250339150611cef9050612f90565b6000604051602001526040518360e060020a0281526004018083600160a060020a0316815260200182815260200192505050602060405180830381600087803b156100005760325a03f115610000575050505b5b50565b6016545b90565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a03908116911614611dbc57610000565b60105460ff1615611dcc57610000565b6000611dd73061298d565b1115611de257610000565b6017546212750001421015611df657610000565b6013546064900493508360055402881115611e1057610000565b30600160a060020a031631881115611e305730600160a060020a03163197505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016001815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f2057805160ff1916838001178555611f4d565b82800160010185558215611f4d579182015b82811115611f4d578251825591602001919060010190611f32565b5b50611f6e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116120c9576007028160070283600052602060002091820191016120c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10612068575061209a565b601f01602090049060005260206000209081019061209a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701612025565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061214a57805160ff1916838001178555612177565b82800160010185558215612177579182015b8281111561217757825182559160200191906001019061215c565b5b506121989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a908102040217905550505050426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b600654600160a060020a03165b90565b600854600160a060020a03161561232957610000565b60088054600160a060020a031916606060020a838102041790555b50565b60065433600160a060020a0390811691161461236257610000565b60105460ff16151561237357610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421090506123e257610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663cdd933326000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421015905061245257610000565b600854600160a060020a0316151561246957610000565b6000805482018155600160a060020a03308116808352600160209081526040808520805487019055600b8790556002825280852060088054861687529083529481902080548701905593548451868152945193169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600054601154600b546040805185815290517f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c39181900360200190a45b5b5b5b5b5050565b604080516101008082018352600080835260208084018290528451808201865282815284860152606084018290526080840182905260a0840182905260c0840182905260e0840182905285825260148152848220855180850187528154815260018083015482850152600280840180548a51600019948216159099029390930190921604601f8101859004850287018501895280875296979496879692959394938601938301828280156126245780601f106125f957610100808354040283529160200191612624565b820191906000526020600020905b81548152906001019060200180831161260757829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154600160a060020a038116606083015260ff60a060020a820481161515608084015260a09092019160a860020a909104166001811161000057905250600085815260146020526040902054909350151561269d57610000565b60008481526014602052604090206005015460a060020a900460ff16156126c357610000565b60008481526014602052604090206003015442106126e057610000565b6000848152601460209081526040808320600160a060020a033316845260060190915290205460ff161561271357610000565b600160a060020a0333166000818152600a6020908152604080832054888452601483528184206004810180548301905594845260069094019091529020805460ff19166001179055915061276684612941565b6000858152601460205260409020601880549293509091839081101561000057906000526020600020906007020160005b50600082015481600001556001820154816001015560028201816002019080546001816001161561010002031660029004828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612801578054855561283d565b8280016001018555821561283d57600052602060002091601f016020900482015b8281111561283d578254825591600101919060010190612822565b5b5061285e9291505b8082111561186a5760008155600101611856565b5090565b5050600382810154908201556004808301549082015560059182018054929091018054600160a060020a031916606060020a600160a060020a0394851681020417808255825460a060020a60ff021990911660f860020a60a060020a9283900460ff908116820282900490930291909117808455935460a860020a60ff021990941660a860020a9485900490921681020490920291909117905560408051868152339092166020830152818101849052517f8f8bbb8c1937f844f6a094cd4c6eeab8ed5e36f83952e6306ffb2c11fffe5bce916060908290030190a15b50505050565b6000805b60185481101561298657601881815481101561000057906000526020600020906007020160005b505483141561297d57809150612986565b5b600101612945565b5b50919050565b600160a060020a0381166000908152600160205260409020545b919050565b60065433600160a060020a039081169116146129c757610000565b600160a060020a03301660009081526001602052604080822080548354038355829055517fe0987873419fe09d3c9a3e0267f4daf163e812d512f867abaf6bf9822f141a8b9190a15b5b565b60408051602080820183526000825260198054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b6011545b90565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b6000602082511115612b5757610000565b5060208101515b919050565b6000601882815481101561000057906000526020600020906007020160005b505490505b919050565b600160a060020a033316600090815260016020526040812054829010801590612bb55750600082115b15612c2d57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610c5256610c52565b506000610c52565b5b92915050565b600160a060020a0333166000908152600a60205260409020541515612c6057610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151626ebe00014210159050612cd557610000565b601b5415801590612cef5750426019600201546212750001115b15612cf957610000565b6040805160808101825283815260208082018490524262127500018284015233600160a060020a03166000908152600a8252928320546060830152815180516019805495819052939484937f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969560026001841615610100026000190190931692909204601f90810182900483019490910190839010612da257805160ff1916838001178555612dcf565b82800160010185558215612dcf579182015b82811115612dcf578251825591602001919060010190612db4565b5b50612df09291505b8082111561186a5760008155600101611856565b5090565b505060208201518160010160006101000a815481600160a060020a030219169083606060020a908102040217905550604082015181600201556060820151816003015590505060016019600401600033600160a060020a0316815260200190815260200160002060006101000a81548160ff021916908360f860020a9081020402179055507f854a9cc4d907d23cd8dcc72af48dc0e6a87e6f76376a309a0ffa3231ce8e13363383426212750001846040518085600160a060020a031681526020018060200184815260200183600160a060020a031681526020018281038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015612f235780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a15b5050565b60065433600160a060020a03908116911614612f5357610000565b600b819055600080546011546040519192909184917f17a7f53ef43da32c3936b4ac2b060caff5c4b03cd24b1c8e96a191eb1ec48d1591a45b5b50565b6000600960009054906101000a9004600160a060020a0316600160a060020a03166370a08231306000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100005760325a03f115610000575050604051519150505b90565b6000545b90565b600c545b90565b600160a060020a0381166000908152600a60205260409020545b919050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b9291505056d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb500000000000000000000000069381683bde924cef65f1c97f7c8fb769a20409300000000000000000000000014f37b574242d366558db61f3335289a5035c506000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000018546573742074657374657220746573746573742063616d700000000000000000000000000000000000000000000000000000000000000000000000000000000354455300000000000000000000000000000000000000000000000000000000001ba033230fce515bea9de982fe85e0ec8fe892984bc3070ad633daab20eb370864d5a05deb41870e2117197b84cb71110fc0508fa7457165cb8cb82cb8d4d801e6e3f1").unwrap(); - let signature = manager.sign_transaction(&address, &huge_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - } + let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().expect("HidApi"))); + let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).expect("Ledger Manager"); + + // Update device list + assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); + + // Fetch the ethereum address of a connected ledger device + let address = manager.list_devices() + .iter() + .filter(|d| d.manufacturer == "Ledger".to_string()) + .nth(0) + .map(|d| d.address.clone()) + .expect("No ledger device detected"); + + let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); + let signature = manager.sign_transaction(&address, &tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + let large_tx = FromHex::from_hex("f8cb81968504e3b2920083024f279475b02a3c39710d6a3f2870d0d788299d48e790f180b8a4b61d27f6000000000000000000000000e1af840a5a1cb1efdf608a97aa632f4aa39ed199000000000000000000000000000000000000000000000000105ff43f46a9a800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018080").unwrap(); + let signature = manager.sign_transaction(&address, &large_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + let huge_tx = FromHex::from_hex("f935e98201048505d21dba00833b82608080b935946103e86003908155620d2f00600455601460055560a060405260608190527f2e2e2e00000000000000000000000000000000000000000000000000000000006080908152600d805460008290527f2e2e2e00000000000000000000000000000000000000000000000000000000068255909260008051602062003474833981519152602060026001851615610100026000190190941693909304601f0192909204820192909190620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b5b50620001009291505b80821115620000fc5760008155600101620000e6565b5090565b5050600e8054600360ff199182168117909255604080518082019091528281527f2e2e2e00000000000000000000000000000000000000000000000000000000006020918201908152600f80546000829052825160069516949094178155937f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80260026101006001871615026000190190951694909404601f019290920483019290620001d7565b82800160010185558215620001d7579182015b82811115620001d7578251825591602001919060010190620001ba565b5b50620001fb9291505b80821115620000fc5760008155600101620000e6565b5090565b50506010805460ff19166001179055346200000057604051620034943803806200349483398101604090815281516020830151918301516060840151919390810191015b5b5b60068054600160a060020a0319166c01000000000000000000000000338102041790558151600d80546000829052909160008051602062003474833981519152602060026101006001861615026000190190941693909304601f908101849004820193870190839010620002c157805160ff1916838001178555620002f1565b82800160010185558215620002f1579182015b82811115620002f1578251825591602001919060010190620002d4565b5b50620003159291505b80821115620000fc5760008155600101620000e6565b5090565b505080600f9080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200036557805160ff191683800117855562000395565b8280016001018555821562000395579182015b828111156200039557825182559160200191906001019062000378565b5b50620003b99291505b80821115620000fc5760008155600101620000e6565b5090565b5050600980546c01000000000000000000000000808602819004600160a060020a0319928316179092556007805487840293909304929091169190911790555b505050505b613066806200040e6000396000f300606060405236156102035760e060020a600035046306fdde03811461034b578063095ea7b3146103c65780630b0b6d5b146103ed5780631b1ccc47146103fc57806320e870931461047757806323b872dd1461049657806325b29d84146104c057806327187991146104df578063277ccde2146104f15780632e1fbfcd14610510578063308b2fdc14610532578063313ce5671461055457806338cc48311461057757806340eddc4e146105a057806341f4793a146105bf578063467ed261146105de578063471ad963146105fd5780634e860ebb1461060f5780634efbe9331461061e57806354786b4e1461064257806354e35ba2146106bd57806358793ad4146106d25780635abedab21461073f5780635af2f8211461074e57806360483a3f1461076d57806360d12fa0146107da578063698f2e84146108035780636a749986146108155780636d5f66391461082a5780636e9c36831461083c57806370a082311461085e5780637a290fe5146108805780637e7541461461088f57806394c41bdb1461090a57806395d89b4114610929578063962a64cd146109a4578063a0b6533214610a09578063a9059cbb14610a2b578063ab62438f14610a52578063b63ca98114610aa9578063b7c54c6f14610abb578063c4e41b2214610ada578063ca7c4dba14610af9578063cb79e31b14610b18578063dd62ed3e14610b3a575b6103495b60006000600c546000141561021b57610000565b600354600c54670de0b6b3a764000091349091020204915060009050816001600030600160a060020a031681526020019081526020016000205410156102c557600160a060020a033016600090815260016020526040902054600c54909250828115610000570466038d7ea4c68000023403905033600160a060020a03166108fc829081150290604051809050600060405180830381858888f1935050505015156102c557610000565b5b600160a060020a03338116600081815260016020908152604080832080548801905530909416825283822080548790039055601380543487900301908190559154600c548551908152918201879052845190949293927f5a0391f2a67f11ed0034b68f8cf14e7e41d6f86e0a7622f2af5ea8f07b488396928290030190a45b5050565b005b3461000057610358610b5f565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103d9600435602435610bed565b604080519115158252519081900360200190f35b3461000057610349610c58565b005b3461000057610358610dbc565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484610e5a565b60408051918252519081900360200190f35b34610000576103d9600435602435604435610ef9565b604080519115158252519081900360200190f35b3461000057610484610ff3565b60408051918252519081900360200190f35b3461000057610349600435611002565b005b346100005761048461105a565b60408051918252519081900360200190f35b3461000057610484600435611061565b60408051918252519081900360200190f35b346100005761048460043561108d565b60408051918252519081900360200190f35b34610000576105616110b9565b6040805160ff9092168252519081900360200190f35b34610000576105846110c2565b60408051600160a060020a039092168252519081900360200190f35b34610000576104846110c7565b60408051918252519081900360200190f35b34610000576104846110ce565b60408051918252519081900360200190f35b34610000576104846110d5565b60408051918252519081900360200190f35b3461000057610349600435611174565b005b34610000576103496113b5565b005b34610000576103d9600435611407565b604080519115158252519081900360200190f35b3461000057610358611549565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103496004356024356115e7565b005b346100005760408051602060046024803582810135601f8101859004850286018501909652858552610726958335959394604494939290920191819084018382808284375094965061167e95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610349611c13565b005b3461000057610484611d46565b60408051918252519081900360200190f35b346100005760408051602060046024803582810135601f81018590048502860185019096528585526107269583359593946044949392909201918190840183828082843750949650611d4d95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610584612303565b60408051600160a060020a039092168252519081900360200190f35b3461000057610349600435612313565b005b3461000057610349600435602435612347565b005b346100005761034960043561252f565b005b3461000057610484600435612941565b60408051918252519081900360200190f35b346100005761048460043561298d565b60408051918252519081900360200190f35b34610000576103496129ac565b005b3461000057610358612a13565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484612ab1565b60408051918252519081900360200190f35b3461000057610358612ab8565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650612b4695505050505050565b60408051918252519081900360200190f35b3461000057610484600435612b63565b60408051918252519081900360200190f35b34610000576103d9600435602435612b8c565b604080519115158252519081900360200190f35b3461000057610349600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350612c3c92505050565b005b3461000057610349600435612f38565b005b3461000057610484612f90565b60408051918252519081900360200190f35b346100005761048461300c565b60408051918252519081900360200190f35b3461000057610484613013565b60408051918252519081900360200190f35b346100005761048460043561301a565b60408051918252519081900360200190f35b3461000057610484600435602435613039565b60408051918252519081900360200190f35b600d805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b601a54600090600160a060020a03161515610c7257610000565b600160a060020a0333166000908152600a60205260409020541515610c9657610000565b600160a060020a0333166000908152601d602052604090205460ff1615610cbc57610000565b601b54426212750090910111610cd157610000565b600160a060020a0333166000818152601d60209081526040808320805460ff19166001179055600a8252918290208054601c805490910190555482519384529083015280517f475c7605c08471fdc551a58d2c318b163628c5852f69323a1b91c34eb0bb09339281900390910190a150601154601c54606490910490604682029010610db857601a5460068054600160a060020a031916606060020a600160a060020a0393841681020417908190556040805191909216815290517f6b8184e23a898262087be50aa3ea5de648451e63f94413e810586c25282d58c2916020908290030190a15b5b50565b604080516020808201835260008252600d8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b600f805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600160a060020a038316600090815260016020526040812054829010801590610f495750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b8015610f555750600082115b15610fe757600160a060020a03808516600081815260016020908152604080832080548890039055878516808452818420805489019055848452600283528184203390961684529482529182902080548790039055815186815291517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610feb56610feb565b5060005b5b9392505050565b600160a060020a033016315b90565b60065433600160a060020a0390811691161461101d57610000565b600c8190556040805182815290517f0bbd501ef336990995d82b5e3fd82a15abe1ff10c982757a1698ac5d1c3e79579181900360200190a15b5b50565b600b545b90565b6000601882815481101561000057906000526020600020906007020160005b506004015490505b919050565b6000601882815481101561000057906000526020600020906007020160005b506001015490505b919050565b600e5460ff1681565b305b90565b6013545b90565b601c545b90565b600d805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600654600090819033600160a060020a0390811691161461119457610000565b60008381526014602052604090205415156111ae57610000565b60008381526014602052604090206005015433600160a060020a039081169116146111d857610000565b60008381526014602052604090206005015460a060020a900460ff16156111fe57610000565b601154600084815260146020526040902060040154606490910460370292508290111561122a57610000565b60008381526014602052604081206005015460a860020a900460ff16600181116100005714156112eb57600954600084815260146020908152604080832060058101546001909101548251840185905282517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810191909152915194169363a9059cbb93604480840194938390030190829087803b156100005760325a03f1156100005750611389915050565b60008381526014602052604080822060058101546001909101549151600160a060020a039091169282156108fc02929190818181858888f160008881526014602090815260409182902060058101546001909101548351600160a060020a0390921682529181019190915281519297507f2648a7e2f9c34700b91370233666e5118fa8be3e0c21fed4f7402b941df8efdd9650829003019350915050a15b6000838152601460205260409020600501805460a060020a60ff02191660a060020a1790555b5b505050565b60065433600160a060020a039081169116146113d057610000565b6010805460ff191690556040517fb48c7f694f0a3b9b22d7e61c60ff8aebbb107314b6b698fc489ff3f017cb57e090600090a15b5b565b600060006000600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f115610000575050604051514210905061147c57610000565b60085433600160a060020a0390811691161461149757610000565b5050600b54600160a060020a03328181166000908152600a6020526040902080549386029384019055601180548401905560128054860190556008549092916114e39130911683610ef9565b506114ee8282612b8c565b50600054601154600b5460408051918252602082018590528051600160a060020a038716927fb4d6befef2def3d17bcb13c2b882ec4fa047f33157446d3e0e6094b2a21609ac92908290030190a4600192505b5b5050919050565b604080516020808201835260008252600f8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b60065433600160a060020a0390811691161461160257610000565b60105460ff16151561161357610000565b600160a060020a0330166000908152600160209081526040808320805485019055600c859055825484019283905580518481529051839286927f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c3929081900390910190a45b5b5b5050565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a039081169116146116ed57610000565b60115460649004935060056016541115801561170c5750836005540288115b1561171657610000565b61171e612f90565b8811156117305761172d612f90565b97505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016000815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061182057805160ff191683800117855561184d565b8280016001018555821561184d579182015b8281111561184d578251825591602001919060010190611832565b5b5061186e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116119c9576007028160070283600052602060002091820191016119c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10611968575061199a565b601f01602090049060005260206000209081019061199a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701611925565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a90810204021790555050505060166000815460010191905081905550426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b60065460009033600160a060020a03908116911614611c3157610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f1156100005750506040515162dd7c00014210159050611ca657610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1600954909550600160a060020a0316935063a9059cbb9250339150611cef9050612f90565b6000604051602001526040518360e060020a0281526004018083600160a060020a0316815260200182815260200192505050602060405180830381600087803b156100005760325a03f115610000575050505b5b50565b6016545b90565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a03908116911614611dbc57610000565b60105460ff1615611dcc57610000565b6000611dd73061298d565b1115611de257610000565b6017546212750001421015611df657610000565b6013546064900493508360055402881115611e1057610000565b30600160a060020a031631881115611e305730600160a060020a03163197505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016001815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f2057805160ff1916838001178555611f4d565b82800160010185558215611f4d579182015b82811115611f4d578251825591602001919060010190611f32565b5b50611f6e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116120c9576007028160070283600052602060002091820191016120c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10612068575061209a565b601f01602090049060005260206000209081019061209a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701612025565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061214a57805160ff1916838001178555612177565b82800160010185558215612177579182015b8281111561217757825182559160200191906001019061215c565b5b506121989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a908102040217905550505050426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b600654600160a060020a03165b90565b600854600160a060020a03161561232957610000565b60088054600160a060020a031916606060020a838102041790555b50565b60065433600160a060020a0390811691161461236257610000565b60105460ff16151561237357610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421090506123e257610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663cdd933326000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421015905061245257610000565b600854600160a060020a0316151561246957610000565b6000805482018155600160a060020a03308116808352600160209081526040808520805487019055600b8790556002825280852060088054861687529083529481902080548701905593548451868152945193169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600054601154600b546040805185815290517f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c39181900360200190a45b5b5b5b5b5050565b604080516101008082018352600080835260208084018290528451808201865282815284860152606084018290526080840182905260a0840182905260c0840182905260e0840182905285825260148152848220855180850187528154815260018083015482850152600280840180548a51600019948216159099029390930190921604601f8101859004850287018501895280875296979496879692959394938601938301828280156126245780601f106125f957610100808354040283529160200191612624565b820191906000526020600020905b81548152906001019060200180831161260757829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154600160a060020a038116606083015260ff60a060020a820481161515608084015260a09092019160a860020a909104166001811161000057905250600085815260146020526040902054909350151561269d57610000565b60008481526014602052604090206005015460a060020a900460ff16156126c357610000565b60008481526014602052604090206003015442106126e057610000565b6000848152601460209081526040808320600160a060020a033316845260060190915290205460ff161561271357610000565b600160a060020a0333166000818152600a6020908152604080832054888452601483528184206004810180548301905594845260069094019091529020805460ff19166001179055915061276684612941565b6000858152601460205260409020601880549293509091839081101561000057906000526020600020906007020160005b50600082015481600001556001820154816001015560028201816002019080546001816001161561010002031660029004828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612801578054855561283d565b8280016001018555821561283d57600052602060002091601f016020900482015b8281111561283d578254825591600101919060010190612822565b5b5061285e9291505b8082111561186a5760008155600101611856565b5090565b5050600382810154908201556004808301549082015560059182018054929091018054600160a060020a031916606060020a600160a060020a0394851681020417808255825460a060020a60ff021990911660f860020a60a060020a9283900460ff908116820282900490930291909117808455935460a860020a60ff021990941660a860020a9485900490921681020490920291909117905560408051868152339092166020830152818101849052517f8f8bbb8c1937f844f6a094cd4c6eeab8ed5e36f83952e6306ffb2c11fffe5bce916060908290030190a15b50505050565b6000805b60185481101561298657601881815481101561000057906000526020600020906007020160005b505483141561297d57809150612986565b5b600101612945565b5b50919050565b600160a060020a0381166000908152600160205260409020545b919050565b60065433600160a060020a039081169116146129c757610000565b600160a060020a03301660009081526001602052604080822080548354038355829055517fe0987873419fe09d3c9a3e0267f4daf163e812d512f867abaf6bf9822f141a8b9190a15b5b565b60408051602080820183526000825260198054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b6011545b90565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b6000602082511115612b5757610000565b5060208101515b919050565b6000601882815481101561000057906000526020600020906007020160005b505490505b919050565b600160a060020a033316600090815260016020526040812054829010801590612bb55750600082115b15612c2d57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610c5256610c52565b506000610c52565b5b92915050565b600160a060020a0333166000908152600a60205260409020541515612c6057610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151626ebe00014210159050612cd557610000565b601b5415801590612cef5750426019600201546212750001115b15612cf957610000565b6040805160808101825283815260208082018490524262127500018284015233600160a060020a03166000908152600a8252928320546060830152815180516019805495819052939484937f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969560026001841615610100026000190190931692909204601f90810182900483019490910190839010612da257805160ff1916838001178555612dcf565b82800160010185558215612dcf579182015b82811115612dcf578251825591602001919060010190612db4565b5b50612df09291505b8082111561186a5760008155600101611856565b5090565b505060208201518160010160006101000a815481600160a060020a030219169083606060020a908102040217905550604082015181600201556060820151816003015590505060016019600401600033600160a060020a0316815260200190815260200160002060006101000a81548160ff021916908360f860020a9081020402179055507f854a9cc4d907d23cd8dcc72af48dc0e6a87e6f76376a309a0ffa3231ce8e13363383426212750001846040518085600160a060020a031681526020018060200184815260200183600160a060020a031681526020018281038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015612f235780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a15b5050565b60065433600160a060020a03908116911614612f5357610000565b600b819055600080546011546040519192909184917f17a7f53ef43da32c3936b4ac2b060caff5c4b03cd24b1c8e96a191eb1ec48d1591a45b5b50565b6000600960009054906101000a9004600160a060020a0316600160a060020a03166370a08231306000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100005760325a03f115610000575050604051519150505b90565b6000545b90565b600c545b90565b600160a060020a0381166000908152600a60205260409020545b919050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b9291505056d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb500000000000000000000000069381683bde924cef65f1c97f7c8fb769a20409300000000000000000000000014f37b574242d366558db61f3335289a5035c506000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000018546573742074657374657220746573746573742063616d700000000000000000000000000000000000000000000000000000000000000000000000000000000354455300000000000000000000000000000000000000000000000000000000001ba033230fce515bea9de982fe85e0ec8fe892984bc3070ad633daab20eb370864d5a05deb41870e2117197b84cb71110fc0508fa7457165cb8cb82cb8d4d801e6e3f1").unwrap(); + let signature = manager.sign_transaction(&address, &huge_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); } diff --git a/hw/src/lib.rs b/hw/src/lib.rs index 9bfec83410..f51be356ae 100644 --- a/hw/src/lib.rs +++ b/hw/src/lib.rs @@ -16,7 +16,8 @@ //! Hardware wallet management. -#![warn(missing_docs)] +#[warn(missing_docs)] +#[warn(warnings)] extern crate ethereum_types; extern crate ethkey; @@ -38,12 +39,60 @@ use std::fmt; use std::sync::Arc; use std::sync::atomic; use std::sync::atomic::AtomicBool; -use std::thread; -use std::time::Duration; use ethereum_types::U256; const USB_DEVICE_CLASS_DEVICE: u8 = 0; +#[derive(Debug)] +pub struct Device { + path: String, + info: WalletInfo, +} + +pub trait Wallet<'a> { + /// Error + type Error; + /// Transaction data format + type Transaction; + + /// Sign transaction data with wallet managing `address`. + fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result; + + /// Set key derivation path for a chain. + fn set_key_path(&self, key_path: KeyPath); + + /// Re-populate device list + /// Note, this assumes all devices are iterated over and updated + fn update_devices(&self) -> Result; + + /// Read device info + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result; + + /// List connected and acknowledged wallets + fn list_devices(&self) -> Vec; + + /// List locked wallets + /// This may be moved if it is the wrong assumption, for example this is not supported by Ledger + /// Then this method return a empty vector + fn list_locked_devices(&self) -> Vec; + + /// Get wallet info. + fn get_wallet(&self, address: &Address) -> Option; + + /// Generate ethereum address for a Wallet + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Self::Error>; + + /// Open a device using `device path` + /// Note, f - is a closure that borrows HidResult + /// HidDevice is in turn a type alias for a `c_void function pointer` + /// For further information see: + /// * + /// * + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result; +} + + /// Hardware wallet error. #[derive(Debug)] pub enum Error { @@ -144,70 +193,13 @@ pub struct HardwareWalletManager { trezor: Arc, } - impl HardwareWalletManager { /// Hardware wallet constructor pub fn new() -> Result { - let usb_context_trezor = Arc::new(libusb::Context::new()?); - let usb_context_ledger = Arc::new(libusb::Context::new()?); - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?)); - let ledger = Arc::new(ledger::Manager::new(hidapi.clone())); - let trezor = Arc::new(trezor::Manager::new(hidapi.clone())); - - // Subscribe to TREZOR V1 - // Note, this support only TREZOR V1 becasue TREZOR V2 has another vendorID for some reason - // Also, we now only support one product as the second argument specifies - usb_context_trezor.register_callback( - Some(trezor::TREZOR_VID), Some(trezor::TREZOR_PIDS[0]), Some(USB_DEVICE_CLASS_DEVICE), - Box::new(trezor::EventHandler::new(Arc::downgrade(&trezor))))?; - - // Subscribe to all Ledger Devices - // This means that we need to check that the given productID is supported - // None => LIBUSB_HOTPLUG_MATCH_ANY, in other words that all are subscribed to - // More info can be found: http://libusb.sourceforge.net/api-1.0/group__hotplug.html#gae6c5f1add6cc754005549c7259dc35ea - usb_context_ledger.register_callback( - Some(ledger::LEDGER_VID), None, Some(USB_DEVICE_CLASS_DEVICE), - Box::new(ledger::EventHandler::new(Arc::downgrade(&ledger))))?; - let exiting = Arc::new(AtomicBool::new(false)); - let thread_exiting_ledger = exiting.clone(); - let thread_exiting_trezor = exiting.clone(); - let l = ledger.clone(); - let t = trezor.clone(); - - // Ledger event thread - thread::Builder::new() - .name("hw_wallet_ledger".to_string()) - .spawn(move || { - if let Err(e) = l.update_devices() { - debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e); - } - loop { - usb_context_ledger.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); - if thread_exiting_ledger.load(atomic::Ordering::Acquire) { - break; - } - } - }) - .ok(); - - // Trezor event thread - thread::Builder::new() - .name("hw_wallet_trezor".to_string()) - .spawn(move || { - if let Err(e) = t.update_devices() { - debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e); - } - loop { - usb_context_trezor.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); - if thread_exiting_trezor.load(atomic::Ordering::Acquire) { - break; - } - } - }) - .ok(); + let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?)); + let ledger = ledger::Manager::new(hidapi.clone(), exiting.clone())?; + let trezor = trezor::Manager::new(hidapi.clone(), exiting.clone())?; Ok(HardwareWalletManager { exiting: exiting, @@ -217,6 +209,8 @@ impl HardwareWalletManager { } /// Select key derivation path for a chain. + /// Currently, only one hard-coded keypath is supported + /// It is managed by `ethcore/account_provider` pub fn set_key_path(&self, key_path: KeyPath) { self.ledger.set_key_path(key_path); self.trezor.set_key_path(key_path); @@ -231,24 +225,26 @@ impl HardwareWalletManager { } /// Return a list of paths to locked hardware wallets + /// This is only applicable to Trezor because Ledger only appears as + /// a device when it is unlocked pub fn list_locked_wallets(&self) -> Result, Error> { Ok(self.trezor.list_locked_devices()) } /// Get connected wallet info. pub fn wallet_info(&self, address: &Address) -> Option { - if let Some(info) = self.ledger.device_info(address) { + if let Some(info) = self.ledger.get_wallet(address) { Some(info) } else { - self.trezor.device_info(address) + self.trezor.get_wallet(address) } } /// Sign transaction data with wallet managing `address`. pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo, encoded_transaction: &[u8]) -> Result { - if self.ledger.device_info(address).is_some() { + if self.ledger.get_wallet(address).is_some() { Ok(self.ledger.sign_transaction(address, encoded_transaction)?) - } else if self.trezor.device_info(address).is_some() { + } else if self.trezor.get_wallet(address).is_some() { Ok(self.trezor.sign_transaction(address, t_info)?) } else { Err(Error::KeyNotFound) @@ -256,6 +252,8 @@ impl HardwareWalletManager { } /// Send a pin to a device at a certain path to unlock it + /// This is only applicable to Trezor because Ledger only appears as + /// a device when it is unlocked pub fn pin_matrix_ack(&self, path: &str, pin: &str) -> Result { self.trezor.pin_matrix_ack(path, pin).map_err(Error::TrezorDevice) } diff --git a/hw/src/trezor.rs b/hw/src/trezor.rs index 7db226718b..044e5487b4 100644 --- a/hw/src/trezor.rs +++ b/hw/src/trezor.rs @@ -19,12 +19,15 @@ //! and https://github.com/trezor/trezor-common/blob/master/protob/protocol.md //! for protocol details. -use super::{WalletInfo, TransactionInfo, KeyPath}; +use super::{WalletInfo, TransactionInfo, KeyPath, Wallet, Device, USB_DEVICE_CLASS_DEVICE}; use std::cmp::{min, max}; use std::fmt; use std::sync::{Arc, Weak}; +use std::sync::atomic; +use std::sync::atomic::AtomicBool; use std::time::{Duration, Instant}; +use std::thread; use ethereum_types::{U256, H256, Address}; use ethkey::Signature; @@ -37,9 +40,9 @@ use protobuf::{Message, ProtobufEnum}; use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumTxRequest, EthereumSignTx, EthereumGetAddress, EthereumTxAck, ButtonAck}; /// Trezor v1 vendor ID -pub const TREZOR_VID: u16 = 0x534c; +const TREZOR_VID: u16 = 0x534c; /// Trezor product IDs -pub const TREZOR_PIDS: [u16; 1] = [0x0001]; +const TREZOR_PIDS: [u16; 1] = [0x0001]; const ETH_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003C, 0x80000000, 0, 0]; // m/44'/60'/0'/0/0 const ETC_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003D, 0x80000000, 0, 0]; // m/44'/61'/0'/0/0 @@ -94,12 +97,6 @@ pub struct Manager { key_path: RwLock, } -#[derive(Debug)] -struct Device { - path: String, - info: WalletInfo, -} - /// HID Version used for the Trezor device enum HidVersion { V1, @@ -108,102 +105,42 @@ enum HidVersion { impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>) -> Manager { - Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Manager { usb: hidapi, devices: RwLock::new(Vec::new()), locked_devices: RwLock::new(Vec::new()), key_path: RwLock::new(KeyPath::Ethereum), - } - } - - /// Re-populate device list - pub fn update_devices(&self) -> Result { - let mut usb = self.usb.lock(); - usb.refresh_devices(); - let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut locked_devices = Vec::new(); - let mut error = None; - for usb_device in devices { - let is_trezor = usb_device.vendor_id == TREZOR_VID; - let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id); - let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0; - - trace!( - "Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}", - usb_device, - is_trezor, - is_supported_product, - is_valid, - ); - if !is_trezor || !is_supported_product || !is_valid { - continue; - } - match self.read_device_info(&usb, &usb_device) { - Ok(device) => new_devices.push(device), - Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()), - Err(e) => { - warn!("Error reading device: {:?}", e); - error = Some(e); + }); + + let usb_context = Arc::new(libusb::Context::new()?); + let m = manager.clone(); + + // Subscribe to TREZOR V1 + // Note, this support only TREZOR V1 because TREZOR V2 has a different vendorID for some reason + // Also, we now only support one product as the second argument specifies + usb_context.register_callback( + Some(TREZOR_VID), Some(TREZOR_PIDS[0]), Some(USB_DEVICE_CLASS_DEVICE), + Box::new(EventHandler::new(Arc::downgrade(&manager))))?; + + // Trezor event thread + thread::Builder::new() + .name("hw_wallet_trezor".to_string()) + .spawn(move || { + if let Err(e) = m.update_devices() { + debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e); } - } - } - let count = new_devices.len(); - trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices); - *self.devices.write() = new_devices; - *self.locked_devices.write() = locked_devices; - match error { - Some(e) => Err(e), - None => Ok(count), - } - } - - fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { - let handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); - match self.get_address(&handle) { - Ok(Some(addr)) => { - Ok(Device { - path: dev_info.path.clone(), - info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, - address: addr, - }, - }) - } - Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())), - Err(e) => Err(e), - } - } - - /// Select key derivation path for a known chain. - pub fn set_key_path(&self, key_path: KeyPath) { - *self.key_path.write() = key_path; - } - - /// List connected wallets. This only returns wallets that are ready to be used. - pub fn list_devices(&self) -> Vec { - self.devices.read().iter().map(|d| d.info.clone()).collect() - } - - pub fn list_locked_devices(&self) -> Vec { - (*self.locked_devices.read()).clone() - } - - /// Get wallet info. - pub fn device_info(&self, address: &Address) -> Option { - self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) - } + loop { + usb_context.handle_events(Some(Duration::from_millis(500))) + .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); + if exiting.load(atomic::Ordering::Acquire) { + break; + } + } + }) + .ok(); - fn open_path(&self, f: F) -> Result - where F: Fn() -> Result - { - f().map_err(Into::into) + Ok(manager) } pub fn pin_matrix_ack(&self, device_path: &str, pin: &str) -> Result { @@ -227,61 +164,6 @@ impl Manager { unlocked } - fn get_address(&self, device: &hidapi::HidDevice) -> Result, Error> { - let typ = MessageType::MessageType_EthereumGetAddress; - let mut message = EthereumGetAddress::new(); - match *self.key_path.read() { - KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), - KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), - } - message.set_show_display(false); - self.send_device_message(&device, &typ, &message)?; - - let (resp_type, bytes) = self.read_device_response(&device)?; - match resp_type { - MessageType::MessageType_EthereumAddress => { - let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?; - Ok(Some(From::from(response.get_address()))) - } - _ => Ok(None), - } - } - - /// Sign transaction data with wallet managing `address`. - pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo) -> Result { - let usb = self.usb.lock(); - let devices = self.devices.read(); - let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; - let handle = self.open_path(|| usb.open_path(&device.path))?; - let msg_type = MessageType::MessageType_EthereumSignTx; - let mut message = EthereumSignTx::new(); - match *self.key_path.read() { - KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), - KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), - } - message.set_nonce(self.u256_to_be_vec(&t_info.nonce)); - message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit)); - message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price)); - message.set_value(self.u256_to_be_vec(&t_info.value)); - - match t_info.to { - Some(addr) => { - message.set_to(addr.to_vec()) - } - None => (), - } - let first_chunk_length = min(t_info.data.len(), 1024); - let chunk = &t_info.data[0..first_chunk_length]; - message.set_data_initial_chunk(chunk.to_vec()); - message.set_data_length(t_info.data.len() as u32); - if let Some(c_id) = t_info.chain_id { - message.set_chain_id(c_id as u32); - } - - self.send_device_message(&handle, &msg_type, &message)?; - - self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..]) - } fn u256_to_be_vec(&self, val: &U256) -> Vec { let mut buf = [0u8; 32]; @@ -400,6 +282,152 @@ impl Manager { } } +impl <'a>Wallet<'a> for Manager { + type Error = Error; + type Transaction = &'a TransactionInfo; + + fn sign_transaction(&self, address: &Address, t_info: Self::Transaction) -> + Result { + let usb = self.usb.lock(); + let devices = self.devices.read(); + let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; + let handle = self.open_path(|| usb.open_path(&device.path))?; + let msg_type = MessageType::MessageType_EthereumSignTx; + let mut message = EthereumSignTx::new(); + match *self.key_path.read() { + KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), + KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), + } + message.set_nonce(self.u256_to_be_vec(&t_info.nonce)); + message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit)); + message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price)); + message.set_value(self.u256_to_be_vec(&t_info.value)); + + match t_info.to { + Some(addr) => { + message.set_to(addr.to_vec()) + } + None => (), + } + let first_chunk_length = min(t_info.data.len(), 1024); + let chunk = &t_info.data[0..first_chunk_length]; + message.set_data_initial_chunk(chunk.to_vec()); + message.set_data_length(t_info.data.len() as u32); + if let Some(c_id) = t_info.chain_id { + message.set_chain_id(c_id as u32); + } + + self.send_device_message(&handle, &msg_type, &message)?; + + self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..]) + } + + fn set_key_path(&self, key_path: KeyPath) { + *self.key_path.write() = key_path; + } + + fn update_devices(&self) -> Result { + let mut usb = self.usb.lock(); + usb.refresh_devices(); + let devices = usb.devices(); + let mut new_devices = Vec::new(); + let mut locked_devices = Vec::new(); + let mut error = None; + for usb_device in devices { + let is_trezor = usb_device.vendor_id == TREZOR_VID; + let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id); + let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0; + + trace!( + "Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}", + usb_device, + is_trezor, + is_supported_product, + is_valid, + ); + if !is_trezor || !is_supported_product || !is_valid { + continue; + } + match self.read_device(&usb, &usb_device) { + Ok(device) => new_devices.push(device), + Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()), + Err(e) => { + warn!("Error reading device: {:?}", e); + error = Some(e); + } + } + } + let count = new_devices.len(); + trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices); + *self.devices.write() = new_devices; + *self.locked_devices.write() = locked_devices; + match error { + Some(e) => Err(e), + None => Ok(count), + } + } + + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { + let handle = self.open_path(|| usb.open_path(&dev_info.path))?; + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + match self.get_address(&handle) { + Ok(Some(addr)) => { + Ok(Device { + path: dev_info.path.clone(), + info: WalletInfo { + name: name, + manufacturer: manufacturer, + serial: serial, + address: addr, + }, + }) + } + Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())), + Err(e) => Err(e), + } + } + + fn list_devices(&self) -> Vec { + self.devices.read().iter().map(|d| d.info.clone()).collect() + } + + fn list_locked_devices(&self) -> Vec { + (*self.locked_devices.read()).clone() + } + + fn get_wallet(&self, address: &Address) -> Option { + self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) + } + + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Error> { + let typ = MessageType::MessageType_EthereumGetAddress; + let mut message = EthereumGetAddress::new(); + match *self.key_path.read() { + KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), + KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), + } + message.set_show_display(false); + self.send_device_message(&device, &typ, &message)?; + + let (resp_type, bytes) = self.read_device_response(&device)?; + match resp_type { + MessageType::MessageType_EthereumAddress => { + let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?; + Ok(Some(From::from(response.get_address()))) + } + _ => Ok(None), + } + } + + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result + { + f().map_err(Into::into) + } +} + // Try to connect to the device using polling in at most the time specified by the `timeout` fn try_connect_polling(trezor: Arc, duration: Duration) -> bool { let start_time = Instant::now(); @@ -412,11 +440,11 @@ fn try_connect_polling(trezor: Arc, duration: Duration) -> bool { } /// Trezor event handler -/// A separate thread is handeling incoming events +/// A separate thread is handling incoming events /// /// Note, that this run to completion and race-conditions can't occur but this can /// therefore starve other events for being process with a spinlock or similar -pub struct EventHandler { +struct EventHandler { trezor: Weak, } @@ -455,10 +483,10 @@ fn test_signature() { use ethereum_types::{H160, H256, U256}; let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap())); - let manager = Manager::new(hidapi.clone()); + let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).unwrap(); let addr: Address = H160::from("some_addr"); - manager.update_devices().unwrap(); + assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); let t_info = TransactionInfo { nonce: U256::from(1), -- GitLab From d1f5284fe665665a98f36ad73606c4a72c25f3d3 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 1 May 2018 16:02:14 +0300 Subject: [PATCH 113/263] SecretStore: merge two types of errors into single one + Error::is_non_fatal (#8357) * SecretStore: error unify initial commit SecretStore: pass real error in error messages SecretStore: is_internal_error -> Error::is_non_fatal warnings SecretStore: ConsensusTemporaryUnreachable fix after merge removed comments removed comments SecretStore: updated HTTP error responses SecretStore: more ConsensusTemporaryUnreachable tests fix after rebase * fixed grumbles * use HashSet in tests --- secret_store/src/acl_storage.rs | 4 +- secret_store/src/key_server.rs | 4 +- .../key_version_negotiation_session.rs | 51 +++-- .../key_server_cluster/admin_sessions/mod.rs | 6 + .../servers_set_change_session.rs | 24 ++- .../admin_sessions/share_add_session.rs | 24 ++- .../client_sessions/decryption_session.rs | 29 ++- .../client_sessions/encryption_session.rs | 5 +- .../client_sessions/generation_session.rs | 63 +----- .../client_sessions/signing_session_ecdsa.rs | 25 ++- .../signing_session_schnorr.rs | 27 ++- .../src/key_server_cluster/cluster.rs | 36 +++- .../key_server_cluster/cluster_sessions.rs | 6 +- .../cluster_sessions_creator.rs | 21 +- .../key_server_cluster/connection_trigger.rs | 2 +- .../connection_trigger_with_migration.rs | 2 +- .../jobs/consensus_session.rs | 62 +++--- .../key_server_cluster/jobs/decryption_job.rs | 2 +- .../key_server_cluster/jobs/job_session.rs | 108 ++++++++-- .../jobs/signing_job_ecdsa.rs | 4 +- .../jobs/signing_job_schnorr.rs | 2 +- .../src/key_server_cluster/message.rs | 20 +- secret_store/src/key_server_cluster/mod.rs | 132 +----------- secret_store/src/key_server_set.rs | 2 +- secret_store/src/key_storage.rs | 4 +- secret_store/src/lib.rs | 2 +- secret_store/src/listener/http_listener.rs | 23 +- secret_store/src/listener/mod.rs | 2 +- .../src/listener/service_contract_listener.rs | 28 +-- secret_store/src/serialization.rs | 2 +- secret_store/src/traits.rs | 2 +- secret_store/src/types/all.rs | 88 +------- secret_store/src/types/error.rs | 199 ++++++++++++++++++ secret_store/src/types/mod.rs | 6 +- 34 files changed, 577 insertions(+), 440 deletions(-) create mode 100644 secret_store/src/types/error.rs diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 6399660aff..50414eff26 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -22,7 +22,7 @@ use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; use ethereum_types::{H256, Address}; use bytes::Bytes; use trusted_client::TrustedClient; -use types::all::{Error, ServerKeyId}; +use types::{Error, ServerKeyId}; use_contract!(acl_storage, "AclStorage", "res/acl_storage.json"); @@ -113,7 +113,7 @@ impl CachedContract { self.contract.functions() .check_permissions() .call(requester, document.clone(), &do_call) - .map_err(|e| Error::Internal(e.to_string())) + .map_err(|e| Error::Internal(format!("ACL checker call error: {}", e.to_string()))) }, None => Err(Error::Internal("ACL checker contract is not configured".to_owned())), } diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs index ea3a3c0a57..f11a157c00 100644 --- a/secret_store/src/key_server.rs +++ b/secret_store/src/key_server.rs @@ -27,7 +27,7 @@ use super::key_storage::KeyStorage; use super::key_server_set::KeyServerSet; use key_server_cluster::{math, ClusterCore}; use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer, NodeKeyPair}; -use types::all::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, +use types::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, ClusterConfiguration, MessageHash, EncryptedMessageSignature, NodeId}; use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration}; @@ -238,7 +238,7 @@ pub mod tests { use key_server_set::tests::MapKeyServerSet; use key_server_cluster::math; use ethereum_types::{H256, H520}; - use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId, + use types::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature, Requester, NodeId}; use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer}; diff --git a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs index 15abdce89d..6c39fd8e7e 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs @@ -143,6 +143,10 @@ pub struct FastestResultComputer { self_node_id: NodeId, /// Threshold (if known). threshold: Option, + /// Count of all configured key server nodes. + configured_nodes_count: usize, + /// Count of all connected key server nodes. + connected_nodes_count: usize, } /// Selects version with most support, waiting for responses from all nodes. @@ -185,7 +189,7 @@ impl SessionImpl where T: SessionTransport { /// Return result computer reference. pub fn version_holders(&self, version: &H256) -> Result, Error> { Ok(self.data.lock().versions.as_ref().ok_or(Error::InvalidStateForRequest)? - .get(version).ok_or(Error::KeyStorage("key version not found".into()))? + .get(version).ok_or(Error::ServerKeyIsNotFound)? .clone()) } @@ -236,7 +240,7 @@ impl SessionImpl where T: SessionTransport { // try to complete session Self::try_complete(&self.core, &mut *data); if no_confirmations_required && data.state != SessionState::Finished { - return Err(Error::MissingKeyShare); + return Err(Error::ServerKeyIsNotFound); } else if data.state == SessionState::Finished { return Ok(()); } @@ -266,7 +270,7 @@ impl SessionImpl where T: SessionTransport { &KeyVersionNegotiationMessage::KeyVersions(ref message) => self.on_key_versions(sender, message), &KeyVersionNegotiationMessage::KeyVersionsError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, } @@ -388,7 +392,7 @@ impl ClusterSession for SessionImpl where T: SessionTransport { if data.state != SessionState::Finished { warn!("{}: key version negotiation session failed with timeout", self.core.meta.self_node_id); - data.result = Some(Err(Error::ConsensusUnreachable)); + data.result = Some(Err(Error::ConsensusTemporaryUnreachable)); self.core.completed.notify_all(); } } @@ -431,11 +435,13 @@ impl SessionTransport for IsolatedSessionTransport { } impl FastestResultComputer { - pub fn new(self_node_id: NodeId, key_share: Option<&DocumentKeyShare>) -> Self { + pub fn new(self_node_id: NodeId, key_share: Option<&DocumentKeyShare>, configured_nodes_count: usize, connected_nodes_count: usize) -> Self { let threshold = key_share.map(|ks| ks.threshold); FastestResultComputer { - self_node_id: self_node_id, - threshold: threshold, + self_node_id, + threshold, + configured_nodes_count, + connected_nodes_count, } }} @@ -443,7 +449,7 @@ impl SessionResultComputer for FastestResultComputer { fn compute_result(&self, threshold: Option, confirmations: &BTreeSet, versions: &BTreeMap>) -> Option> { match self.threshold.or(threshold) { // if there's no versions at all && we're not waiting for confirmations anymore - _ if confirmations.is_empty() && versions.is_empty() => Some(Err(Error::MissingKeyShare)), + _ if confirmations.is_empty() && versions.is_empty() => Some(Err(Error::ServerKeyIsNotFound)), // if we have key share on this node Some(threshold) => { // select version this node have, with enough participants @@ -459,7 +465,17 @@ impl SessionResultComputer for FastestResultComputer { .find(|&(_, ref n)| n.len() >= threshold + 1) .map(|(version, nodes)| Ok((version.clone(), nodes.iter().cloned().nth(0) .expect("version is only inserted when there's at least one owner; qed")))) - .unwrap_or(Err(Error::ConsensusUnreachable))), + // if there's no version consensus among all connected nodes + // AND we're connected to ALL configured nodes + // OR there are less than required nodes for key restore + // => this means that we can't restore key with CURRENT configuration => respond with fatal error + // otherwise we could try later, after all nodes are connected + .unwrap_or_else(|| Err(if self.configured_nodes_count == self.connected_nodes_count + || self.configured_nodes_count < threshold + 1 { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }))), } }, // if we do not have share, then wait for all confirmations @@ -469,7 +485,11 @@ impl SessionResultComputer for FastestResultComputer { .max_by_key(|&(_, ref n)| n.len()) .map(|(version, nodes)| Ok((version.clone(), nodes.iter().cloned().nth(0) .expect("version is only inserted when there's at least one owner; qed")))) - .unwrap_or(Err(Error::ConsensusUnreachable))), + .unwrap_or_else(|| Err(if self.configured_nodes_count == self.connected_nodes_count { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }))), } } } @@ -480,7 +500,7 @@ impl SessionResultComputer for LargestSupportResultComputer { return None; } if versions.is_empty() { - return Some(Err(Error::MissingKeyShare)); + return Some(Err(Error::ServerKeyIsNotFound)); } versions.iter() @@ -552,12 +572,15 @@ mod tests { id: Default::default(), self_node_id: node_id.clone(), master_node_id: master_node_id.clone(), + configured_nodes_count: nodes.len(), + connected_nodes_count: nodes.len(), }, sub_session: sub_sesion.clone(), key_share: key_storage.get(&Default::default()).unwrap(), result_computer: Arc::new(FastestResultComputer::new( node_id.clone(), key_storage.get(&Default::default()).unwrap().as_ref(), + nodes.len(), nodes.len() )), transport: DummyTransport { cluster: cluster, @@ -723,13 +746,15 @@ mod tests { let computer = FastestResultComputer { self_node_id: Default::default(), threshold: None, + configured_nodes_count: 1, + connected_nodes_count: 1, }; - assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::MissingKeyShare))); + assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::ServerKeyIsNotFound))); } #[test] fn largest_computer_returns_missing_share_if_no_versions_returned() { let computer = LargestSupportResultComputer; - assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::MissingKeyShare))); + assert_eq!(computer.compute_result(Some(10), &Default::default(), &Default::default()), Some(Err(Error::ServerKeyIsNotFound))); } } diff --git a/secret_store/src/key_server_cluster/admin_sessions/mod.rs b/secret_store/src/key_server_cluster/admin_sessions/mod.rs index 01655653a2..11c01cac53 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/mod.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/mod.rs @@ -32,6 +32,10 @@ pub struct ShareChangeSessionMeta { pub master_node_id: NodeId, /// Id of node, on which this session is running. pub self_node_id: NodeId, + /// Count of all configured key server nodes. + pub configured_nodes_count: usize, + /// Count of all connected key server nodes. + pub connected_nodes_count: usize, } impl ShareChangeSessionMeta { @@ -42,6 +46,8 @@ impl ShareChangeSessionMeta { master_node_id: self.master_node_id, self_node_id: self.self_node_id, threshold: all_nodes_set_len.checked_sub(1).ok_or(Error::ConsensusUnreachable)?, + configured_nodes_count: self.configured_nodes_count, + connected_nodes_count: self.connected_nodes_count, }) } } diff --git a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs index e9aacdfbb4..698872aadc 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs @@ -282,7 +282,7 @@ impl SessionImpl { &ServersSetChangeMessage::ServersSetChangeShareAddMessage(ref message) => self.on_share_add_message(sender, message), &ServersSetChangeMessage::ServersSetChangeError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, &ServersSetChangeMessage::ServersSetChangeCompleted(ref message) => @@ -416,12 +416,14 @@ impl SessionImpl { match &message.message { &KeyVersionNegotiationMessage::RequestKeyVersions(ref message) if sender == &self.core.meta.master_node_id => { let key_id = message.session.clone().into(); - let key_share = self.core.key_storage.get(&key_id).map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = self.core.key_storage.get(&key_id)?; let negotiation_session = KeyVersionNegotiationSessionImpl::new(KeyVersionNegotiationSessionParams { meta: ShareChangeSessionMeta { id: key_id.clone(), self_node_id: self.core.meta.self_node_id.clone(), master_node_id: sender.clone(), + configured_nodes_count: self.core.meta.configured_nodes_count, + connected_nodes_count: self.core.meta.connected_nodes_count, }, sub_session: message.sub_session.clone().into(), key_share: key_share, @@ -492,7 +494,7 @@ impl SessionImpl { // on nodes, holding selected key share version, we could check if master node plan is correct let master_node_id = message.master_node_id.clone().into(); - if let Some(key_share) = self.core.key_storage.get(&key_id).map_err(|e| Error::KeyStorage(e.into()))? { + if let Some(key_share) = self.core.key_storage.get(&key_id)? { let version = message.version.clone().into(); if let Ok(key_version) = key_share.version(&version) { let key_share_owners = key_version.id_numbers.keys().cloned().collect(); @@ -660,7 +662,7 @@ impl SessionImpl { if !data.new_nodes_set.as_ref() .expect("new_nodes_set is filled during initialization; session is completed after initialization; qed") .contains(&self.core.meta.self_node_id) { - self.core.key_storage.clear().map_err(|e| Error::KeyStorage(e.into()))?; + self.core.key_storage.clear()?; } data.state = SessionState::Finished; @@ -709,6 +711,8 @@ impl SessionImpl { id: key_id, self_node_id: core.meta.self_node_id.clone(), master_node_id: master_node_id, + configured_nodes_count: core.meta.configured_nodes_count, + connected_nodes_count: core.meta.connected_nodes_count, }, cluster: core.cluster.clone(), key_storage: core.key_storage.clone(), @@ -731,12 +735,14 @@ impl SessionImpl { Some(Ok(key_id)) => key_id, }; - let key_share = core.key_storage.get(&key_id).map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = core.key_storage.get(&key_id)?; let negotiation_session = KeyVersionNegotiationSessionImpl::new(KeyVersionNegotiationSessionParams { meta: ShareChangeSessionMeta { id: key_id, self_node_id: core.meta.self_node_id.clone(), master_node_id: core.meta.self_node_id.clone(), + configured_nodes_count: core.meta.configured_nodes_count, + connected_nodes_count: core.meta.connected_nodes_count, }, sub_session: math::generate_random_scalar()?, key_share: key_share, @@ -888,7 +894,7 @@ impl SessionImpl { if !data.new_nodes_set.as_ref() .expect("new_nodes_set is filled during initialization; session is completed after initialization; qed") .contains(&core.meta.self_node_id) { - core.key_storage.clear().map_err(|e| Error::KeyStorage(e.into()))?; + core.key_storage.clear()?; } data.state = SessionState::Finished; @@ -1011,9 +1017,9 @@ impl KeyVersionNegotiationTransport for ServersSetChangeKeyVersionNegotiationTra } fn check_nodes_set(all_nodes_set: &BTreeSet, new_nodes_set: &BTreeSet) -> Result<(), Error> { - // all new nodes must be a part of all nodes set + // all_nodes_set is the set of nodes we're currently connected to (and configured for) match new_nodes_set.iter().any(|n| !all_nodes_set.contains(n)) { - true => Err(Error::InvalidNodesConfiguration), + true => Err(Error::NodeDisconnected), false => Ok(()) } } @@ -1104,6 +1110,8 @@ pub mod tests { self_node_id: master_node_id.clone(), master_node_id: master_node_id.clone(), id: SessionId::default(), + configured_nodes_count: all_nodes_set.len(), + connected_nodes_count: all_nodes_set.len(), }; let old_nodes = gml.nodes.iter().map(|n| create_node(meta.clone(), admin_public.clone(), all_nodes_set.clone(), n.1)); diff --git a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs index 7da73543be..abe34edeab 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs @@ -155,9 +155,7 @@ pub struct IsolatedSessionTransport { impl SessionImpl where T: SessionTransport { /// Create new share addition session. pub fn new(params: SessionParams) -> Result { - let key_share = params.key_storage - .get(¶ms.meta.id) - .map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = params.key_storage.get(¶ms.meta.id)?; Ok(SessionImpl { core: SessionCore { @@ -257,8 +255,8 @@ impl SessionImpl where T: SessionTransport { let admin_public = self.core.admin_public.as_ref().cloned().ok_or(Error::ConsensusUnreachable)?; // key share version is required on ShareAdd master node - let key_share = self.core.key_share.as_ref().ok_or_else(|| Error::KeyStorage("key share is not found on master node".into()))?; - let key_version = key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_share = self.core.key_share.as_ref().ok_or_else(|| Error::ServerKeyIsNotFound)?; + let key_version = key_share.version(&version)?; // old nodes set is all non-isolated owners of version holders let non_isolated_nodes = self.core.transport.nodes(); @@ -326,7 +324,7 @@ impl SessionImpl where T: SessionTransport { &ShareAddMessage::NewKeysDissemination(ref message) => self.on_new_keys_dissemination(sender, message), &ShareAddMessage::ShareAddError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone().into())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, } @@ -714,10 +712,10 @@ impl SessionImpl where T: SessionTransport { // save encrypted data to the key storage data.state = SessionState::Finished; if core.key_share.is_some() { - core.key_storage.update(core.meta.id.clone(), refreshed_key_share.clone()) + core.key_storage.update(core.meta.id.clone(), refreshed_key_share.clone())?; } else { - core.key_storage.insert(core.meta.id.clone(), refreshed_key_share.clone()) - }.map_err(|e| Error::KeyStorage(e.into()))?; + core.key_storage.insert(core.meta.id.clone(), refreshed_key_share.clone())?; + } // signal session completion data.state = SessionState::Finished; @@ -851,7 +849,7 @@ impl SessionTransport for IsolatedSessionTransport { #[cfg(test)] pub mod tests { use std::sync::Arc; - use std::collections::{VecDeque, BTreeMap, BTreeSet}; + use std::collections::{VecDeque, BTreeMap, BTreeSet, HashSet}; use ethkey::{Random, Generator, Public, KeyPair, Signature, sign}; use ethereum_types::H256; use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, DummyKeyStorage}; @@ -952,6 +950,8 @@ pub mod tests { id: SessionId::default(), self_node_id: NodeId::default(), master_node_id: master_node_id, + configured_nodes_count: new_nodes_set.iter().chain(old_nodes_set.iter()).collect::>().len(), + connected_nodes_count: new_nodes_set.iter().chain(old_nodes_set.iter()).collect::>().len(), }; let new_nodes = new_nodes_set.iter() .filter(|n| !old_nodes_set.contains(&n)) @@ -992,6 +992,8 @@ pub mod tests { id: SessionId::default(), self_node_id: NodeId::default(), master_node_id: master_node_id, + configured_nodes_count: new_nodes_set.iter().chain(ml.nodes.keys()).collect::>().len(), + connected_nodes_count: new_nodes_set.iter().chain(ml.nodes.keys()).collect::>().len(), }; let old_nodes_set = ml.nodes.keys().cloned().collect(); let nodes = ml.nodes.iter() @@ -1102,7 +1104,7 @@ pub mod tests { assert_eq!(ml.nodes[&master_node_id].session.initialize(Some(ml.version), Some(new_nodes_set), Some(ml.old_set_signature.clone()), Some(ml.new_set_signature.clone()) - ).unwrap_err(), Error::KeyStorage("key share is not found on master node".into())); + ).unwrap_err(), Error::ServerKeyIsNotFound); } #[test] diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs index c47dd26bad..083acb6480 100644 --- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs @@ -154,7 +154,7 @@ impl SessionImpl { if let Some(key_share) = params.key_share.as_ref() { // encrypted data must be set if key_share.common_point.is_none() || key_share.encrypted_point.is_none() { - return Err(Error::NotStartedSessionId); + return Err(Error::DocumentKeyIsNotFound); } } @@ -290,7 +290,7 @@ impl SessionImpl { // check if version exists let key_version = match self.core.key_share.as_ref() { None => return Err(Error::InvalidMessage), - Some(key_share) => key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?, + Some(key_share) => key_share.version(&version)?, }; let mut data = self.data.lock(); @@ -337,7 +337,7 @@ impl SessionImpl { &DecryptionMessage::PartialDecryption(ref message) => self.on_partial_decryption(sender, message), &DecryptionMessage::DecryptionSessionError(ref message) => - self.process_node_error(Some(&sender), Error::Io(message.error.clone())), + self.process_node_error(Some(&sender), message.error.clone()), &DecryptionMessage::DecryptionSessionCompleted(ref message) => self.on_session_completed(sender, message), &DecryptionMessage::DecryptionSessionDelegation(ref message) => @@ -432,8 +432,7 @@ impl SessionImpl { }; let mut data = self.data.lock(); - let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?) - .map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?)?.hash.clone(); let requester_public = data.consensus_session.consensus_job().executor().requester() .ok_or(Error::InvalidStateForRequest)? .public(&self.core.meta.id) @@ -564,7 +563,7 @@ impl SessionImpl { match { match node { - Some(node) => data.consensus_session.on_node_error(node), + Some(node) => data.consensus_session.on_node_error(node, error.clone()), None => data.consensus_session.on_session_timeout(), } } { @@ -601,7 +600,7 @@ impl SessionImpl { Some(key_share) => key_share, }; - let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(version)?.hash.clone(); let requester = data.consensus_session.consensus_job().executor().requester().ok_or(Error::InvalidStateForRequest)?.clone(); let requester_public = requester.public(&core.meta.id).map_err(Error::InsufficientRequesterData)?; let consensus_group = data.consensus_session.select_consensus_group()?.clone(); @@ -637,6 +636,8 @@ impl SessionImpl { master_node_id: core.meta.self_node_id.clone(), self_node_id: core.meta.self_node_id.clone(), threshold: core.meta.threshold, + configured_nodes_count: core.meta.configured_nodes_count, + connected_nodes_count: core.meta.connected_nodes_count, }, job, transport); job_session.initialize(consensus_group, self_response, core.meta.self_node_id != core.meta.master_node_id)?; data.broadcast_job_session = Some(job_session); @@ -881,6 +882,8 @@ mod tests { self_node_id: id_numbers.iter().nth(i).clone().unwrap().0, master_node_id: id_numbers.iter().nth(0).clone().unwrap().0, threshold: encrypted_datas[i].threshold, + configured_nodes_count: 5, + connected_nodes_count: 5, }, access_key: access_key.clone(), key_share: Some(encrypted_datas[i].clone()), @@ -944,6 +947,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { @@ -976,6 +981,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: None, @@ -998,6 +1005,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 2, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { @@ -1131,7 +1140,7 @@ mod tests { let (_, _, _, sessions) = prepare_decryption_sessions(); assert!(sessions[0].decrypted_secret().is_none()); sessions[0].on_session_timeout(); - assert_eq!(sessions[0].decrypted_secret().unwrap().unwrap_err(), Error::ConsensusUnreachable); + assert_eq!(sessions[0].decrypted_secret().unwrap().unwrap_err(), Error::ConsensusTemporaryUnreachable); } #[test] @@ -1141,7 +1150,7 @@ mod tests { // 1 node disconnects => we still can recover secret sessions[0].on_node_timeout(sessions[1].node()); - assert!(sessions[0].data.lock().consensus_session.consensus_job().rejects().contains(sessions[1].node())); + assert!(sessions[0].data.lock().consensus_session.consensus_job().rejects().contains_key(sessions[1].node())); assert!(sessions[0].state() == ConsensusSessionState::EstablishingConsensus); // 2 node are disconnected => we can not recover secret @@ -1208,7 +1217,7 @@ mod tests { let disconnected = sessions[0].data.lock().consensus_session.computation_job().requests().iter().cloned().nth(0).unwrap(); sessions[0].on_node_timeout(&disconnected); assert_eq!(sessions[0].state(), ConsensusSessionState::EstablishingConsensus); - assert!(sessions[0].data.lock().consensus_session.computation_job().rejects().contains(&disconnected)); + assert!(sessions[0].data.lock().consensus_session.computation_job().rejects().contains_key(&disconnected)); assert!(!sessions[0].data.lock().consensus_session.computation_job().requests().contains(&disconnected)); } diff --git a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs index ca8bac3815..3c863d1cb9 100644 --- a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs @@ -306,7 +306,7 @@ impl ClusterSession for SessionImpl { &EncryptionMessage::ConfirmEncryptionInitialization(ref message) => self.on_confirm_initialization(sender.clone(), message), &EncryptionMessage::EncryptionSessionError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone().into())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, }, @@ -326,7 +326,7 @@ pub fn check_encrypted_data(key_share: Option<&DocumentKeyShare>) -> Result<(), if let Some(key_share) = key_share { // check that common_point and encrypted_point are still not set yet if key_share.common_point.is_some() || key_share.encrypted_point.is_some() { - return Err(Error::CompletedSessionId); + return Err(Error::DocumentKeyAlreadyStored); } } @@ -344,5 +344,4 @@ pub fn update_encrypted_data(key_storage: &Arc, key_id: ServerKeyId, key_share.common_point = Some(common_point); key_share.encrypted_point = Some(encrypted_point); key_storage.update(key_id, key_share) - .map_err(|e| Error::KeyStorage(e.into())) } diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs index 0afe618246..c2effe6c26 100644 --- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs @@ -354,7 +354,7 @@ impl SessionImpl { &GenerationMessage::PublicKeyShare(ref message) => self.on_public_key_share(sender.clone(), message), &GenerationMessage::SessionError(ref message) => { - self.on_session_error(sender, Error::Io(message.error.clone().into())); + self.on_session_error(sender, message.error.clone()); Ok(()) }, &GenerationMessage::SessionCompleted(ref message) => @@ -474,7 +474,7 @@ impl SessionImpl { // simulate failure, if required if data.simulate_faulty_behaviour { - return Err(Error::Io("simulated error".into())); + return Err(Error::Internal("simulated error".into())); } // check state @@ -592,8 +592,7 @@ impl SessionImpl { }; if let Some(ref key_storage) = self.key_storage { - key_storage.insert(self.id.clone(), encrypted_data.clone()) - .map_err(|e| Error::KeyStorage(e.into()))?; + key_storage.insert(self.id.clone(), encrypted_data.clone())?; } // then respond with confirmation @@ -790,8 +789,7 @@ impl SessionImpl { // then save encrypted data to the key storage if let Some(ref key_storage) = self.key_storage { - key_storage.insert(self.id.clone(), encrypted_data.clone()) - .map_err(|e| Error::KeyStorage(e.into()))?; + key_storage.insert(self.id.clone(), encrypted_data.clone())?; } // then distribute encrypted data to every other node @@ -925,23 +923,15 @@ impl Debug for SessionImpl { } } -pub fn check_cluster_nodes(self_node_id: &NodeId, nodes: &BTreeSet) -> Result<(), Error> { - // at least two nodes must be in cluster - if nodes.len() < 1 { - return Err(Error::InvalidNodesCount); - } - // this node must be a part of cluster - if !nodes.contains(self_node_id) { - return Err(Error::InvalidNodesConfiguration); - } - +fn check_cluster_nodes(self_node_id: &NodeId, nodes: &BTreeSet) -> Result<(), Error> { + assert!(nodes.contains(self_node_id)); Ok(()) } -pub fn check_threshold(threshold: usize, nodes: &BTreeSet) -> Result<(), Error> { +fn check_threshold(threshold: usize, nodes: &BTreeSet) -> Result<(), Error> { // at least threshold + 1 nodes are required to collectively decrypt message if threshold >= nodes.len() { - return Err(Error::InvalidThreshold); + return Err(Error::NotEnoughNodesForThreshold); } Ok(()) @@ -1096,25 +1086,10 @@ pub mod tests { assert!(l.master().initialize(Default::default(), Default::default(), false, 0, l.nodes.keys().cloned().collect::>().into()).is_ok()); } - #[test] - fn fails_to_initialize_if_not_a_part_of_cluster() { - let node_id = math::generate_random_point().unwrap(); - let cluster = Arc::new(DummyCluster::new(node_id.clone())); - let session = SessionImpl::new(SessionParams { - id: SessionId::default(), - self_node_id: node_id.clone(), - key_storage: Some(Arc::new(DummyKeyStorage::default())), - cluster: cluster, - nonce: Some(0), - }); - let cluster_nodes: BTreeSet<_> = (0..2).map(|_| math::generate_random_point().unwrap()).collect(); - assert_eq!(session.initialize(Default::default(), Default::default(), false, 0, cluster_nodes.into()).unwrap_err(), Error::InvalidNodesConfiguration); - } - #[test] fn fails_to_initialize_if_threshold_is_wrong() { match make_simple_cluster(2, 2) { - Err(Error::InvalidThreshold) => (), + Err(Error::NotEnoughNodesForThreshold) => (), _ => panic!("unexpected"), } } @@ -1193,24 +1168,6 @@ pub mod tests { assert!(l.master().derived_point().unwrap() != passed_point.into()); } - #[test] - fn fails_to_complete_initialization_if_not_a_part_of_cluster() { - let (sid, m, _, l) = make_simple_cluster(0, 2).unwrap(); - let mut nodes = BTreeMap::new(); - nodes.insert(m, math::generate_random_scalar().unwrap()); - nodes.insert(math::generate_random_point().unwrap(), math::generate_random_scalar().unwrap()); - assert_eq!(l.first_slave().on_initialize_session(m, &message::InitializeSession { - session: sid.into(), - session_nonce: 0, - origin: None, - author: Address::default().into(), - nodes: nodes.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), - is_zero: false, - threshold: 0, - derived_point: math::generate_random_point().unwrap().into(), - }).unwrap_err(), Error::InvalidNodesConfiguration); - } - #[test] fn fails_to_complete_initialization_if_threshold_is_wrong() { let (sid, m, s, l) = make_simple_cluster(0, 2).unwrap(); @@ -1226,7 +1183,7 @@ pub mod tests { is_zero: false, threshold: 2, derived_point: math::generate_random_point().unwrap().into(), - }).unwrap_err(), Error::InvalidThreshold); + }).unwrap_err(), Error::NotEnoughNodesForThreshold); } #[test] diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs index 02c20bc20e..b0d465343b 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs @@ -187,6 +187,8 @@ impl SessionImpl { master_node_id: params.meta.master_node_id, self_node_id: params.meta.self_node_id, threshold: params.meta.threshold * 2, + configured_nodes_count: params.meta.configured_nodes_count, + connected_nodes_count: params.meta.connected_nodes_count, }, consensus_executor: match requester { Some(requester) => KeyAccessJob::new_on_master(params.meta.id.clone(), params.acl_storage.clone(), requester), @@ -259,7 +261,7 @@ impl SessionImpl { // check if version exists let key_version = match self.core.key_share.as_ref() { None => return Err(Error::InvalidMessage), - Some(key_share) => key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?, + Some(key_share) => key_share.version(&version)?, }; // select nodes to participate in consensus etablish session @@ -311,7 +313,7 @@ impl SessionImpl { &EcdsaSigningMessage::EcdsaPartialSignature(ref message) => self.on_partial_signature(sender, message), &EcdsaSigningMessage::EcdsaSigningSessionError(ref message) => - self.process_node_error(Some(&sender), Error::Io(message.error.clone())), + self.process_node_error(Some(&sender), message.error.clone()), &EcdsaSigningMessage::EcdsaSigningSessionCompleted(ref message) => self.on_session_completed(sender, message), &EcdsaSigningMessage::EcdsaSigningSessionDelegation(ref message) => @@ -386,8 +388,7 @@ impl SessionImpl { let key_share = self.core.key_share.as_ref() .expect("this is master node; master node is selected so that it has key version; qed"); let key_version = key_share.version(data.version.as_ref() - .expect("this is master node; master node is selected so that it has key version; qed") - ).map_err(|e| Error::KeyStorage(e.into()))?; + .expect("this is master node; master node is selected so that it has key version; qed"))?; let consensus_group = data.consensus_session.select_consensus_group()?.clone(); let mut other_consensus_group_nodes = consensus_group.clone(); @@ -680,7 +681,7 @@ impl SessionImpl { let inv_nonce_share = data.inv_nonce_generation_session.as_ref().expect(nonce_exists_proof).joint_public_and_secret().expect(nonce_exists_proof)?.2; let version = data.version.as_ref().ok_or(Error::InvalidMessage)?.clone(); - let key_version = key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(&version)?.hash.clone(); let signing_job = EcdsaSigningJob::new_on_slave(key_share.clone(), key_version, sig_nonce_public, inv_nonce_share)?; let signing_transport = self.core.signing_transport(); @@ -744,7 +745,7 @@ impl SessionImpl { match { match node { - Some(node) => data.consensus_session.on_node_error(node), + Some(node) => data.consensus_session.on_node_error(node, error.clone()), None => data.consensus_session.on_session_timeout(), } } { @@ -970,6 +971,14 @@ impl Cluster for NonceGenerationTransport where F: Fn(SessionId, Secret, u fn nodes(&self) -> BTreeSet { self.cluster.nodes() } + + fn configured_nodes_count(&self) -> usize { + self.cluster.configured_nodes_count() + } + + fn connected_nodes_count(&self) -> usize { + self.cluster.connected_nodes_count() + } } impl SessionCore { @@ -988,7 +997,7 @@ impl SessionCore { Some(key_share) => key_share, }; - let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(version)?.hash.clone(); let signing_job = EcdsaSigningJob::new_on_master(key_share.clone(), key_version, nonce_public, inv_nonce_share, inversed_nonce_coeff, message_hash)?; consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false).map(|_| ()) } @@ -1099,6 +1108,8 @@ mod tests { self_node_id: gl_node_id.clone(), master_node_id: master_node_id.clone(), threshold: gl_node.key_storage.get(&session_id).unwrap().unwrap().threshold, + configured_nodes_count: gl.nodes.len(), + connected_nodes_count: gl.nodes.len(), }, access_key: "834cb736f02d9c968dfaf0c37658a1d86ff140554fc8b59c9fdad5a8cf810eec".parse().unwrap(), key_share: Some(gl_node.key_storage.get(&session_id).unwrap().unwrap()), diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs index ed7164ca3a..013748827c 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs @@ -246,7 +246,7 @@ impl SessionImpl { // check if version exists let key_version = match self.core.key_share.as_ref() { None => return Err(Error::InvalidMessage), - Some(key_share) => key_share.version(&version).map_err(|e| Error::KeyStorage(e.into()))?, + Some(key_share) => key_share.version(&version)?, }; let mut data = self.data.lock(); @@ -313,7 +313,7 @@ impl SessionImpl { &SchnorrSigningMessage::SchnorrPartialSignature(ref message) => self.on_partial_signature(sender, message), &SchnorrSigningMessage::SchnorrSigningSessionError(ref message) => - self.process_node_error(Some(&sender), Error::Io(message.error.clone())), + self.process_node_error(Some(&sender), message.error.clone()), &SchnorrSigningMessage::SchnorrSigningSessionCompleted(ref message) => self.on_session_completed(sender, message), &SchnorrSigningMessage::SchnorrSigningSessionDelegation(ref message) => @@ -500,8 +500,7 @@ impl SessionImpl { .expect("session key is generated before signature is computed; we are in SignatureComputing state; qed") .joint_public_and_secret() .expect("session key is generated before signature is computed; we are in SignatureComputing state; qed")?; - let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?) - .map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?)?.hash.clone(); let signing_job = SchnorrSigningJob::new_on_slave(self.core.meta.self_node_id.clone(), key_share.clone(), key_version, joint_public_and_secret.0, joint_public_and_secret.1)?; let signing_transport = self.core.signing_transport(); @@ -564,7 +563,7 @@ impl SessionImpl { match { match node { - Some(node) => data.consensus_session.on_node_error(node), + Some(node) => data.consensus_session.on_node_error(node, error.clone()), None => data.consensus_session.on_session_timeout(), } } { @@ -717,6 +716,14 @@ impl Cluster for SessionKeyGenerationTransport { fn nodes(&self) -> BTreeSet { self.cluster.nodes() } + + fn configured_nodes_count(&self) -> usize { + self.cluster.configured_nodes_count() + } + + fn connected_nodes_count(&self) -> usize { + self.cluster.connected_nodes_count() + } } impl SessionCore { @@ -735,7 +742,7 @@ impl SessionCore { Some(key_share) => key_share, }; - let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone(); + let key_version = key_share.version(version)?.hash.clone(); let signing_job = SchnorrSigningJob::new_on_master(self.meta.self_node_id.clone(), key_share.clone(), key_version, session_public, session_secret_share, message_hash)?; consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false).map(|_| ()) @@ -851,6 +858,8 @@ mod tests { self_node_id: gl_node_id.clone(), master_node_id: master_node_id.clone(), threshold: gl_node.key_storage.get(&session_id).unwrap().unwrap().threshold, + configured_nodes_count: gl.nodes.len(), + connected_nodes_count: gl.nodes.len(), }, access_key: "834cb736f02d9c968dfaf0c37658a1d86ff140554fc8b59c9fdad5a8cf810eec".parse().unwrap(), key_share: Some(gl_node.key_storage.get(&session_id).unwrap().unwrap()), @@ -971,6 +980,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { @@ -1003,6 +1014,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 0, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: None, @@ -1025,6 +1038,8 @@ mod tests { self_node_id: self_node_id.clone(), master_node_id: self_node_id.clone(), threshold: 2, + configured_nodes_count: 1, + connected_nodes_count: 1, }, access_key: Random.generate().unwrap().secret().clone(), key_share: Some(DocumentKeyShare { diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs index 26f0e7ef1f..d782ccd035 100644 --- a/secret_store/src/key_server_cluster/cluster.rs +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -109,6 +109,10 @@ pub trait Cluster: Send + Sync { fn is_connected(&self, node: &NodeId) -> bool; /// Get a set of connected nodes. fn nodes(&self) -> BTreeSet; + /// Get total count of configured key server nodes (valid at the time of ClusterView creation). + fn configured_nodes_count(&self) -> usize; + /// Get total count of connected key server nodes (valid at the time of ClusterView creation). + fn connected_nodes_count(&self) -> usize; } /// Cluster initialization parameters. @@ -160,6 +164,8 @@ pub struct ClusterClientImpl { /// Network cluster view. It is a communication channel, required in single session. pub struct ClusterView { core: Arc>, + configured_nodes_count: usize, + connected_nodes_count: usize, } /// Cross-thread shareable cluster data. @@ -554,7 +560,7 @@ impl ClusterCore { let is_initialization_message = message.is_initialization_message(); let is_delegation_message = message.is_delegation_message(); match is_initialization_message || is_delegation_message { - false => sessions.get(&session_id, true).ok_or(Error::InvalidSessionId), + false => sessions.get(&session_id, true).ok_or(Error::NoActiveSessionWithId), true => { let creation_data = SC::creation_data_from_message(&message)?; let master = if is_initialization_message { sender.clone() } else { data.self_key_pair.public().clone() }; @@ -652,7 +658,7 @@ impl ClusterConnections { let trigger: Box = match config.auto_migrate_enabled { false => Box::new(SimpleConnectionTrigger::new(config.key_server_set.clone(), config.self_key_pair.clone(), config.admin_public.clone())), true if config.admin_public.is_none() => Box::new(ConnectionTriggerWithMigration::new(config.key_server_set.clone(), config.self_key_pair.clone())), - true => return Err(Error::Io("secret store admininstrator public key is specified with auto-migration enabled".into())), // TODO [Refac]: Io -> Internal + true => return Err(Error::Internal("secret store admininstrator public key is specified with auto-migration enabled".into())), }; let connector = trigger.servers_set_change_creator_connector(); @@ -835,8 +841,10 @@ impl Connection { } impl ClusterView { - pub fn new(cluster: Arc, nodes: BTreeSet) -> Self { + pub fn new(cluster: Arc, nodes: BTreeSet, configured_nodes_count: usize) -> Self { ClusterView { + configured_nodes_count: configured_nodes_count, + connected_nodes_count: nodes.len(), core: Arc::new(Mutex::new(ClusterViewCore { cluster: cluster, nodes: nodes, @@ -871,6 +879,14 @@ impl Cluster for ClusterView { fn nodes(&self) -> BTreeSet { self.core.lock().nodes.clone() } + + fn configured_nodes_count(&self) -> usize { + self.configured_nodes_count + } + + fn connected_nodes_count(&self) -> usize { + self.connected_nodes_count + } } impl ClusterClientImpl { @@ -1125,7 +1141,7 @@ pub mod tests { fn cluster_state(&self) -> ClusterState { unimplemented!("test-only") } fn new_generation_session(&self, _session_id: SessionId, _origin: Option
, _author: Address, _threshold: usize) -> Result, Error> { self.generation_requests_count.fetch_add(1, Ordering::Relaxed); - Err(Error::Io("test-errror".into())) + Err(Error::Internal("test-error".into())) } fn new_encryption_session(&self, _session_id: SessionId, _requester: Requester, _common_point: Public, _encrypted_point: Public) -> Result, Error> { unimplemented!("test-only") } fn new_decryption_session(&self, _session_id: SessionId, _origin: Option
, _requester: Requester, _version: Option, _is_shadow_decryption: bool, _is_broadcast_session: bool) -> Result, Error> { unimplemented!("test-only") } @@ -1197,6 +1213,14 @@ pub mod tests { fn nodes(&self) -> BTreeSet { self.data.lock().nodes.iter().cloned().collect() } + + fn configured_nodes_count(&self) -> usize { + self.data.lock().nodes.len() + } + + fn connected_nodes_count(&self) -> usize { + self.data.lock().nodes.len() + } } pub fn loop_until(core: &mut Core, timeout: Duration, predicate: F) where F: Fn() -> bool { @@ -1365,11 +1389,11 @@ pub mod tests { { // try to start generation session => fail in initialization assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 100).map(|_| ()), - Err(Error::InvalidThreshold)); + Err(Error::NotEnoughNodesForThreshold)); // try to start generation session => fails in initialization assert_eq!(clusters[0].client().new_generation_session(SessionId::default(), Default::default(), Default::default(), 100).map(|_| ()), - Err(Error::InvalidThreshold)); + Err(Error::NotEnoughNodesForThreshold)); assert!(clusters[0].data.sessions.generation_sessions.is_empty()); } diff --git a/secret_store/src/key_server_cluster/cluster_sessions.rs b/secret_store/src/key_server_cluster/cluster_sessions.rs index e67458f766..780c947fc3 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions.rs @@ -547,8 +547,9 @@ impl ClusterSession for AdminSession { } } pub fn create_cluster_view(data: &Arc, requires_all_connections: bool) -> Result, Error> { + let disconnected_nodes_count = data.connections.disconnected_nodes().len(); if requires_all_connections { - if !data.connections.disconnected_nodes().is_empty() { + if disconnected_nodes_count != 0 { return Err(Error::NodeDisconnected); } } @@ -556,7 +557,8 @@ pub fn create_cluster_view(data: &Arc, requires_all_connections: bo let mut connected_nodes = data.connections.connected_nodes(); connected_nodes.insert(data.self_key_pair.public().clone()); - Ok(Arc::new(ClusterView::new(data.clone(), connected_nodes))) + let connected_nodes_count = connected_nodes.len(); + Ok(Arc::new(ClusterView::new(data.clone(), connected_nodes, connected_nodes_count + disconnected_nodes_count))) } #[cfg(test)] diff --git a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs index 86e40853e2..a56f51f8fb 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs @@ -115,7 +115,7 @@ impl SessionCreatorCore { /// Read key share && remove disconnected nodes. fn read_key_share(&self, key_id: &SessionId) -> Result, Error> { - self.key_storage.get(key_id).map_err(|e| Error::KeyStorage(e.into())) + self.key_storage.get(key_id) } } @@ -146,7 +146,7 @@ impl ClusterSessionCreator for GenerationSessionCreat fn create(&self, cluster: Arc, master: NodeId, nonce: Option, id: SessionId, _creation_data: Option<()>) -> Result, Error> { // check that there's no finished encryption session with the same id if self.core.key_storage.contains(&id) { - return Err(Error::DuplicateSessionId); + return Err(Error::ServerKeyAlreadyGenerated); } let nonce = self.core.check_session_nonce(&master, nonce)?; @@ -232,6 +232,8 @@ impl ClusterSessionCreator for DecryptionSessi self_node_id: self.core.self_node_id.clone(), master_node_id: master, threshold: encrypted_data.as_ref().map(|ks| ks.threshold).unwrap_or_default(), + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, access_key: id.access_key, key_share: encrypted_data, @@ -278,6 +280,8 @@ impl ClusterSessionCreator for SchnorrSign self_node_id: self.core.self_node_id.clone(), master_node_id: master, threshold: encrypted_data.as_ref().map(|ks| ks.threshold).unwrap_or_default(), + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, access_key: id.access_key, key_share: encrypted_data, @@ -324,6 +328,8 @@ impl ClusterSessionCreator for EcdsaSigningS self_node_id: self.core.self_node_id.clone(), master_node_id: master, threshold: encrypted_data.as_ref().map(|ks| ks.threshold).unwrap_or_default(), + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, access_key: id.access_key, key_share: encrypted_data, @@ -351,14 +357,19 @@ impl ClusterSessionCreator, master: NodeId, nonce: Option, id: SessionIdWithSubSession, _creation_data: Option<()>) -> Result>, Error> { + let configured_nodes_count = cluster.configured_nodes_count(); + let connected_nodes_count = cluster.connected_nodes_count(); let encrypted_data = self.core.read_key_share(&id.id)?; let nonce = self.core.check_session_nonce(&master, nonce)?; - let computer = Arc::new(FastestResultKeyVersionsResultComputer::new(self.core.self_node_id.clone(), encrypted_data.as_ref())); + let computer = Arc::new(FastestResultKeyVersionsResultComputer::new(self.core.self_node_id.clone(), encrypted_data.as_ref(), + configured_nodes_count, configured_nodes_count)); Ok(Arc::new(KeyVersionNegotiationSessionImpl::new(KeyVersionNegotiationSessionParams { meta: ShareChangeSessionMeta { id: id.id.clone(), self_node_id: self.core.self_node_id.clone(), master_node_id: master, + configured_nodes_count: configured_nodes_count, + connected_nodes_count: connected_nodes_count, }, sub_session: id.access_key.clone(), key_share: encrypted_data, @@ -419,6 +430,8 @@ impl ClusterSessionCreator for AdminSess id: id.clone(), self_node_id: self.core.self_node_id.clone(), master_node_id: master, + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, transport: ShareAddTransport::new(id.clone(), Some(version), nonce, cluster), key_storage: self.core.key_storage.clone(), @@ -435,6 +448,8 @@ impl ClusterSessionCreator for AdminSess id: id.clone(), self_node_id: self.core.self_node_id.clone(), master_node_id: master, + configured_nodes_count: cluster.configured_nodes_count(), + connected_nodes_count: cluster.connected_nodes_count(), }, cluster: cluster.clone(), key_storage: self.core.key_storage.clone(), diff --git a/secret_store/src/key_server_cluster/connection_trigger.rs b/secret_store/src/key_server_cluster/connection_trigger.rs index e0172b89ac..66612f044b 100644 --- a/secret_store/src/key_server_cluster/connection_trigger.rs +++ b/secret_store/src/key_server_cluster/connection_trigger.rs @@ -23,7 +23,7 @@ use ethkey::Public; use key_server_cluster::{KeyServerSet, KeyServerSetSnapshot}; use key_server_cluster::cluster::{ClusterClient, ClusterConnectionsData}; use key_server_cluster::cluster_sessions::AdminSession; -use types::all::{Error, NodeId}; +use types::{Error, NodeId}; use {NodeKeyPair}; #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs index 91679928fb..40a4b5028e 100644 --- a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs +++ b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs @@ -26,7 +26,7 @@ use key_server_cluster::cluster_sessions::{AdminSession, ClusterSession}; use key_server_cluster::jobs::servers_set_change_access_job::ordered_nodes_hash; use key_server_cluster::connection_trigger::{Maintain, ConnectionsAction, ConnectionTrigger, ServersSetChangeSessionCreatorConnector, TriggerConnections}; -use types::all::{Error, NodeId}; +use types::{Error, NodeId}; use {NodeKeyPair}; /// Key servers set change trigger with automated migration procedure. diff --git a/secret_store/src/key_server_cluster/jobs/consensus_session.rs b/secret_store/src/key_server_cluster/jobs/consensus_session.rs index cc4ebc6d9f..5d780a48eb 100644 --- a/secret_store/src/key_server_cluster/jobs/consensus_session.rs +++ b/secret_store/src/key_server_cluster/jobs/consensus_session.rs @@ -232,38 +232,42 @@ impl Result { + pub fn on_node_error(&mut self, node: &NodeId, error: Error) -> Result { let is_self_master = self.meta.master_node_id == self.meta.self_node_id; let is_node_master = self.meta.master_node_id == *node; let (is_restart_needed, timeout_result) = match self.state { ConsensusSessionState::WaitingForInitialization if is_self_master => { // it is strange to receive error before session is initialized && slave doesn't know access_key - // => fatal error + // => unreachable self.state = ConsensusSessionState::Failed; (false, Err(Error::ConsensusUnreachable)) } ConsensusSessionState::WaitingForInitialization if is_node_master => { - // can not establish consensus - // => fatal error + // error from master node before establishing consensus + // => unreachable self.state = ConsensusSessionState::Failed; - (false, Err(Error::ConsensusUnreachable)) + (false, Err(if !error.is_non_fatal() { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + })) }, ConsensusSessionState::EstablishingConsensus => { debug_assert!(is_self_master); // consensus still can be established // => try to live without this node - (false, self.consensus_job.on_node_error(node)) + (false, self.consensus_job.on_node_error(node, error)) }, ConsensusSessionState::ConsensusEstablished => { // we could try to continue without this node, if enough nodes left - (false, self.consensus_job.on_node_error(node)) + (false, self.consensus_job.on_node_error(node, error)) }, ConsensusSessionState::WaitingForPartialResults => { // check if *current* computation job can continue without this node let is_computation_node = self.computation_job.as_mut() .expect("WaitingForPartialResults state is only set when computation_job is created; qed") - .on_node_error(node) + .on_node_error(node, error.clone()) .is_err(); if !is_computation_node { // it is not used by current computation job @@ -275,7 +279,7 @@ impl return Ok(false), @@ -312,7 +316,7 @@ impl Result, Error> { - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; if partial_request.other_nodes_ids.len() != self.key_share.threshold || partial_request.other_nodes_ids.contains(&self.self_node_id) || partial_request.other_nodes_ids.iter().any(|n| !key_version.id_numbers.contains_key(n)) { diff --git a/secret_store/src/key_server_cluster/jobs/job_session.rs b/secret_store/src/key_server_cluster/jobs/job_session.rs index 82f387d7b9..d3a765bf5b 100644 --- a/secret_store/src/key_server_cluster/jobs/job_session.rs +++ b/secret_store/src/key_server_cluster/jobs/job_session.rs @@ -101,8 +101,8 @@ struct JobSessionData { struct ActiveJobSessionData { /// Active partial requests. requests: BTreeSet, - /// Rejects to partial requests. - rejects: BTreeSet, + /// Rejects to partial requests (maps to true, if reject is fatal). + rejects: BTreeMap, /// Received partial responses. responses: BTreeMap, } @@ -149,7 +149,7 @@ impl JobSession where Executor: JobExe /// Get rejects. #[cfg(test)] - pub fn rejects(&self) -> &BTreeSet { + pub fn rejects(&self) -> &BTreeMap { debug_assert!(self.meta.self_node_id == self.meta.master_node_id); &self.data.active_data.as_ref() @@ -201,7 +201,11 @@ impl JobSession where Executor: JobExe debug_assert!(self.meta.self_node_id == self.meta.master_node_id); if nodes.len() < self.meta.threshold + 1 { - return Err(Error::ConsensusUnreachable); + return Err(if self.meta.configured_nodes_count < self.meta.threshold + 1 { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }); } if self.data.state != JobSessionState::Inactive { @@ -211,7 +215,7 @@ impl JobSession where Executor: JobExe // result from self let active_data = ActiveJobSessionData { requests: nodes.clone(), - rejects: BTreeSet::new(), + rejects: BTreeMap::new(), responses: BTreeMap::new(), }; let waits_for_self = active_data.requests.contains(&self.meta.self_node_id); @@ -295,13 +299,14 @@ impl JobSession where Executor: JobExe match self.executor.check_partial_response(node, &response)? { JobPartialResponseAction::Ignore => Ok(()), JobPartialResponseAction::Reject => { - active_data.rejects.insert(node.clone()); + // direct reject is always considered as fatal + active_data.rejects.insert(node.clone(), true); if active_data.requests.len() + active_data.responses.len() >= self.meta.threshold + 1 { return Ok(()); } self.data.state = JobSessionState::Failed; - Err(Error::ConsensusUnreachable) + Err(consensus_unreachable(&active_data.rejects)) }, JobPartialResponseAction::Accept => { active_data.responses.insert(node.clone(), response); @@ -316,22 +321,26 @@ impl JobSession where Executor: JobExe } /// When error from node is received. - pub fn on_node_error(&mut self, node: &NodeId) -> Result<(), Error> { + pub fn on_node_error(&mut self, node: &NodeId, error: Error) -> Result<(), Error> { if self.meta.self_node_id != self.meta.master_node_id { if node != &self.meta.master_node_id { return Ok(()); } self.data.state = JobSessionState::Failed; - return Err(Error::ConsensusUnreachable); + return Err(if !error.is_non_fatal() { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + }); } if let Some(active_data) = self.data.active_data.as_mut() { - if active_data.rejects.contains(node) { + if active_data.rejects.contains_key(node) { return Ok(()); } if active_data.requests.remove(node) || active_data.responses.remove(node).is_some() { - active_data.rejects.insert(node.clone()); + active_data.rejects.insert(node.clone(), !error.is_non_fatal()); if self.data.state == JobSessionState::Finished && active_data.responses.len() < self.meta.threshold + 1 { self.data.state = JobSessionState::Active; } @@ -340,7 +349,7 @@ impl JobSession where Executor: JobExe } self.data.state = JobSessionState::Failed; - return Err(Error::ConsensusUnreachable); + return Err(consensus_unreachable(&active_data.rejects)); } } @@ -354,7 +363,8 @@ impl JobSession where Executor: JobExe } self.data.state = JobSessionState::Failed; - Err(Error::ConsensusUnreachable) + // we have started session => consensus is possible in theory, but now it has failed with timeout + Err(Error::ConsensusTemporaryUnreachable) } } @@ -368,6 +378,16 @@ impl JobPartialRequestAction { } } +/// Returns appropriate 'consensus unreachable' error. +fn consensus_unreachable(rejects: &BTreeMap) -> Error { + // when >= 50% of nodes have responded with fatal reject => ConsensusUnreachable + if rejects.values().filter(|r| **r).count() >= rejects.len() / 2 { + Error::ConsensusUnreachable + } else { + Error::ConsensusTemporaryUnreachable + } +} + #[cfg(test)] pub mod tests { use std::collections::{VecDeque, BTreeMap, BTreeSet}; @@ -414,11 +434,27 @@ pub mod tests { } pub fn make_master_session_meta(threshold: usize) -> SessionMeta { - SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(1), threshold: threshold } + SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(1), threshold: threshold, + configured_nodes_count: 5, connected_nodes_count: 5 } } pub fn make_slave_session_meta(threshold: usize) -> SessionMeta { - SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(2), threshold: threshold } + SessionMeta { id: SessionId::default(), master_node_id: NodeId::from(1), self_node_id: NodeId::from(2), threshold: threshold, + configured_nodes_count: 5, connected_nodes_count: 5 } + } + + #[test] + fn job_initialize_fails_if_not_enough_nodes_for_threshold_total() { + let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); + job.meta.configured_nodes_count = 1; + assert_eq!(job.initialize(vec![Public::from(1)].into_iter().collect(), None, false).unwrap_err(), Error::ConsensusUnreachable); + } + + #[test] + fn job_initialize_fails_if_not_enough_nodes_for_threshold_connected() { + let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); + job.meta.connected_nodes_count = 3; + assert_eq!(job.initialize(vec![Public::from(1)].into_iter().collect(), None, false).unwrap_err(), Error::ConsensusTemporaryUnreachable); } #[test] @@ -528,7 +564,7 @@ pub mod tests { fn job_node_error_ignored_when_slave_disconnects_from_slave() { let mut job = JobSession::new(make_slave_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); assert_eq!(job.state(), JobSessionState::Inactive); - job.on_node_error(&NodeId::from(3)).unwrap(); + job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Inactive); } @@ -536,7 +572,7 @@ pub mod tests { fn job_node_error_leads_to_fail_when_slave_disconnects_from_master() { let mut job = JobSession::new(make_slave_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); assert_eq!(job.state(), JobSessionState::Inactive); - assert_eq!(job.on_node_error(&NodeId::from(1)).unwrap_err(), Error::ConsensusUnreachable); + assert_eq!(job.on_node_error(&NodeId::from(1), Error::AccessDenied).unwrap_err(), Error::ConsensusUnreachable); assert_eq!(job.state(), JobSessionState::Failed); } @@ -546,7 +582,7 @@ pub mod tests { job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); job.on_partial_response(&NodeId::from(2), 3).unwrap(); - job.on_node_error(&NodeId::from(2)).unwrap(); + job.on_node_error(&NodeId::from(2), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Active); } @@ -555,7 +591,7 @@ pub mod tests { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); - job.on_node_error(&NodeId::from(3)).unwrap(); + job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Active); } @@ -564,7 +600,7 @@ pub mod tests { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); job.initialize(vec![Public::from(1), Public::from(2), Public::from(3)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); - job.on_node_error(&NodeId::from(3)).unwrap(); + job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap(); assert_eq!(job.state(), JobSessionState::Active); } @@ -573,7 +609,7 @@ pub mod tests { let mut job = JobSession::new(make_master_session_meta(1), SquaredSumJobExecutor, DummyJobTransport::default()); job.initialize(vec![Public::from(1), Public::from(2)].into_iter().collect(), None, false).unwrap(); assert_eq!(job.state(), JobSessionState::Active); - assert_eq!(job.on_node_error(&NodeId::from(2)).unwrap_err(), Error::ConsensusUnreachable); + assert_eq!(job.on_node_error(&NodeId::from(2), Error::AccessDenied).unwrap_err(), Error::ConsensusUnreachable); assert_eq!(job.state(), JobSessionState::Failed); } @@ -592,4 +628,34 @@ pub mod tests { assert_eq!(job.state(), JobSessionState::Active); assert!(job.transport().is_empty_response()); } + + #[test] + fn job_fails_with_temp_error_if_more_than_half_nodes_respond_with_temp_error() { + let mut job = JobSession::new(make_master_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3), Public::from(4)].into_iter().collect(), None, false).unwrap(); + job.on_node_error(&NodeId::from(2), Error::NodeDisconnected).unwrap(); + assert_eq!(job.on_node_error(&NodeId::from(3), Error::NodeDisconnected).unwrap_err(), Error::ConsensusTemporaryUnreachable); + } + + #[test] + fn job_fails_with_temp_error_if_more_than_half_rejects_are_temp() { + let mut job = JobSession::new(make_master_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3), Public::from(4)].into_iter().collect(), None, false).unwrap(); + job.on_node_error(&NodeId::from(2), Error::NodeDisconnected).unwrap(); + assert_eq!(job.on_node_error(&NodeId::from(3), Error::NodeDisconnected).unwrap_err(), Error::ConsensusTemporaryUnreachable); + } + + #[test] + fn job_fails_if_more_than_half_rejects_are_non_temp() { + let mut job = JobSession::new(make_master_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + job.initialize(vec![Public::from(1), Public::from(2), Public::from(3), Public::from(4)].into_iter().collect(), None, false).unwrap(); + job.on_node_error(&NodeId::from(2), Error::AccessDenied).unwrap(); + assert_eq!(job.on_node_error(&NodeId::from(3), Error::AccessDenied).unwrap_err(), Error::ConsensusUnreachable); + } + + #[test] + fn job_fails_with_temp_error_when_temp_error_is_reported_by_master_node() { + let mut job = JobSession::new(make_slave_session_meta(2), SquaredSumJobExecutor, DummyJobTransport::default()); + assert_eq!(job.on_node_error(&NodeId::from(1), Error::NodeDisconnected).unwrap_err(), Error::ConsensusTemporaryUnreachable); + } } diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs index 561a8e0f87..8f4ab1d68e 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs @@ -108,7 +108,7 @@ impl JobExecutor for EcdsaSigningJob { fn process_partial_request(&mut self, partial_request: EcdsaPartialSigningRequest) -> Result, Error> { let inversed_nonce_coeff_mul_nonce = math::compute_secret_mul(&partial_request.inversed_nonce_coeff, &self.inv_nonce_share)?; - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; let signature_r = math::compute_ecdsa_r(&self.nonce_public)?; let inv_nonce_mul_secret = math::compute_secret_mul(&inversed_nonce_coeff_mul_nonce, &key_version.secret_share)?; let partial_signature_s = math::compute_ecdsa_s_share( @@ -134,7 +134,7 @@ impl JobExecutor for EcdsaSigningJob { } fn compute_response(&self, partial_responses: &BTreeMap) -> Result { - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; if partial_responses.keys().any(|n| !key_version.id_numbers.contains_key(n)) { return Err(Error::InvalidMessage); } diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs index 6246a728de..54225a6cf5 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs @@ -107,7 +107,7 @@ impl JobExecutor for SchnorrSigningJob { } fn process_partial_request(&mut self, partial_request: SchnorrPartialSigningRequest) -> Result, Error> { - let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?; + let key_version = self.key_share.version(&self.key_version)?; if partial_request.other_nodes_ids.len() != self.key_share.threshold || partial_request.other_nodes_ids.contains(&self.self_node_id) || partial_request.other_nodes_ids.iter().any(|n| !key_version.id_numbers.contains_key(n)) { diff --git a/secret_store/src/key_server_cluster/message.rs b/secret_store/src/key_server_cluster/message.rs index e08d6761a6..cc49e56fdb 100644 --- a/secret_store/src/key_server_cluster/message.rs +++ b/secret_store/src/key_server_cluster/message.rs @@ -18,8 +18,8 @@ use std::fmt; use std::collections::{BTreeSet, BTreeMap}; use ethkey::Secret; use key_server_cluster::SessionId; -use super::{SerializableH256, SerializablePublic, SerializableSecret, SerializableSignature, - SerializableMessageHash, SerializableRequester, SerializableAddress}; +use super::{Error, SerializableH256, SerializablePublic, SerializableSecret, + SerializableSignature, SerializableMessageHash, SerializableRequester, SerializableAddress}; pub type MessageSessionId = SerializableH256; pub type MessageNodeId = SerializablePublic; @@ -346,7 +346,7 @@ pub struct SessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// When session is completed. @@ -390,7 +390,7 @@ pub struct EncryptionSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// Node is asked to be part of consensus group. @@ -509,7 +509,7 @@ pub struct SchnorrSigningSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// Schnorr signing session completed. @@ -662,7 +662,7 @@ pub struct EcdsaSigningSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// ECDSA signing session completed. @@ -769,7 +769,7 @@ pub struct DecryptionSessionError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// When decryption session is completed. @@ -936,7 +936,7 @@ pub struct ServersSetChangeError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// When servers set change session is completed. @@ -999,7 +999,7 @@ pub struct ShareAddError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } /// Key versions are requested. @@ -1038,7 +1038,7 @@ pub struct KeyVersionsError { /// Session-level nonce. pub session_nonce: u64, /// Error message. - pub error: String, + pub error: Error, } impl Message { diff --git a/secret_store/src/key_server_cluster/mod.rs b/secret_store/src/key_server_cluster/mod.rs index 94386d0510..d5ac85b3de 100644 --- a/secret_store/src/key_server_cluster/mod.rs +++ b/secret_store/src/key_server_cluster/mod.rs @@ -14,14 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; -use std::io::Error as IoError; -use ethkey; -use crypto; -use super::types::all::ServerKeyId; +use super::types::ServerKeyId; pub use super::traits::NodeKeyPair; -pub use super::types::all::{NodeId, Requester, EncryptedDocumentKeyShadow}; +pub use super::types::{Error, NodeId, Requester, EncryptedDocumentKeyShadow}; pub use super::acl_storage::AclStorage; pub use super::key_storage::{KeyStorage, DocumentKeyShare, DocumentKeyShareVersion}; pub use super::key_server_set::{is_migration_required, KeyServerSet, KeyServerSetSnapshot, KeyServerSetMigration}; @@ -53,126 +49,10 @@ pub struct SessionMeta { pub self_node_id: NodeId, /// Session threshold. pub threshold: usize, -} - -/// Errors which can occur during encryption/decryption session -#[derive(Clone, Debug, PartialEq)] -pub enum Error { - /// Invalid node address has been passed. - InvalidNodeAddress, - /// Invalid node id has been passed. - InvalidNodeId, - /// Session with the given id already exists. - DuplicateSessionId, - /// Session with the same id already completed. - CompletedSessionId, - /// Session is not ready to start yet (required data is not ready). - NotStartedSessionId, - /// Session with the given id is unknown. - InvalidSessionId, - /// Invalid number of nodes. - /// There must be at least two nodes participating in encryption. - /// There must be at least one node participating in decryption. - InvalidNodesCount, - /// Node which is required to start encryption/decryption session is not a part of cluster. - InvalidNodesConfiguration, - /// Invalid threshold value has been passed. - /// Threshold value must be in [0; n - 1], where n is a number of nodes participating in the encryption. - InvalidThreshold, - /// Current state of encryption/decryption session does not allow to proceed request. - /// Reschedule this request for later processing. - TooEarlyForRequest, - /// Current state of encryption/decryption session does not allow to proceed request. - /// This means that either there is some comm-failure or node is misbehaving/cheating. - InvalidStateForRequest, - /// Request cannot be sent/received from this node. - InvalidNodeForRequest, - /// Message or some data in the message was recognized as invalid. - /// This means that node is misbehaving/cheating. - InvalidMessage, - /// Message version is not supported. - InvalidMessageVersion, - /// Message is invalid because of replay-attack protection. - ReplayProtection, - /// Connection to node, required for this session is not established. - NodeDisconnected, - /// Node is missing requested key share. - MissingKeyShare, - /// Cryptographic error. - EthKey(String), - /// I/O error has occured. - Io(String), - /// Deserialization error has occured. - Serde(String), - /// Key storage error. - KeyStorage(String), - /// Consensus is unreachable. - ConsensusUnreachable, - /// Acl storage error. - AccessDenied, - /// Can't start session, because exclusive session is active. - ExclusiveSessionActive, - /// Can't start exclusive session, because there are other active sessions. - HasActiveSessions, - /// Insufficient requester data. - InsufficientRequesterData(String), -} - -impl From for Error { - fn from(err: ethkey::Error) -> Self { - Error::EthKey(err.into()) - } -} - -impl From for Error { - fn from(err: crypto::Error) -> Self { - Error::EthKey(err.into()) - } -} - -impl From for Error { - fn from(err: IoError) -> Self { - Error::Io(err.to_string()) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::InvalidNodeAddress => write!(f, "invalid node address has been passed"), - Error::InvalidNodeId => write!(f, "invalid node id has been passed"), - Error::DuplicateSessionId => write!(f, "session with the same id is already registered"), - Error::CompletedSessionId => write!(f, "session with the same id is already completed"), - Error::NotStartedSessionId => write!(f, "not enough data to start session with the given id"), - Error::InvalidSessionId => write!(f, "invalid session id has been passed"), - Error::InvalidNodesCount => write!(f, "invalid nodes count"), - Error::InvalidNodesConfiguration => write!(f, "invalid nodes configuration"), - Error::InvalidThreshold => write!(f, "invalid threshold value has been passed"), - Error::TooEarlyForRequest => write!(f, "session is not yet ready to process this request"), - Error::InvalidStateForRequest => write!(f, "session is in invalid state for processing this request"), - Error::InvalidNodeForRequest => write!(f, "invalid node for this request"), - Error::InvalidMessage => write!(f, "invalid message is received"), - Error::InvalidMessageVersion => write!(f, "unsupported message is received"), - Error::ReplayProtection => write!(f, "replay message is received"), - Error::NodeDisconnected => write!(f, "node required for this operation is currently disconnected"), - Error::MissingKeyShare => write!(f, "requested key share version is not found"), - Error::EthKey(ref e) => write!(f, "cryptographic error {}", e), - Error::Io(ref e) => write!(f, "i/o error {}", e), - Error::Serde(ref e) => write!(f, "serde error {}", e), - Error::KeyStorage(ref e) => write!(f, "key storage error {}", e), - Error::ConsensusUnreachable => write!(f, "Consensus unreachable"), - Error::AccessDenied => write!(f, "Access denied"), - Error::ExclusiveSessionActive => write!(f, "Exclusive session active"), - Error::HasActiveSessions => write!(f, "Unable to start exclusive session"), - Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), - } - } -} - -impl Into for Error { - fn into(self) -> String { - format!("{}", self) - } + /// Count of all configured key server nodes (valid at session start time). + pub configured_nodes_count: usize, + /// Count of all connected key server nodes (valid at session start time). + pub connected_nodes_count: usize, } mod admin_sessions; diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index cb324dbc9b..25651bb4ca 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -25,7 +25,7 @@ use ethkey::public_to_address; use hash::keccak; use ethereum_types::{H256, Address}; use bytes::Bytes; -use types::all::{Error, Public, NodeAddress, NodeId}; +use types::{Error, Public, NodeAddress, NodeId}; use trusted_client::TrustedClient; use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; use {NodeKeyPair}; diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index fee73c2ae1..4f78bc338c 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -21,7 +21,7 @@ use tiny_keccak::Keccak; use ethereum_types::{H256, Address}; use ethkey::{Secret, Public, public_to_address}; use kvdb::KeyValueDB; -use types::all::{Error, ServerKeyId, NodeId}; +use types::{Error, ServerKeyId, NodeId}; use serialization::{SerializablePublic, SerializableSecret, SerializableH256, SerializableAddress}; /// Key of version value. @@ -419,7 +419,7 @@ pub mod tests { use ethereum_types::{Address, H256}; use ethkey::{Random, Generator, Public, Secret, public_to_address}; use kvdb_rocksdb::Database; - use types::all::{Error, ServerKeyId}; + use types::{Error, ServerKeyId}; use super::{DB_META_KEY_VERSION, CURRENT_VERSION, KeyStorage, PersistentKeyStorage, DocumentKeyShare, DocumentKeyShareVersion, CurrentSerializableDocumentKeyShare, upgrade_db, SerializableDocumentKeyShareV0, SerializableDocumentKeyShareV1, SerializableDocumentKeyShareV2, SerializableDocumentKeyShareVersionV2}; diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 8e1278e425..80b15318a9 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -76,7 +76,7 @@ use ethcore::client::Client; use ethcore::miner::Miner; use sync::SyncProvider; -pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, +pub use types::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, Error, NodeAddress, ContractAddress, ServiceConfiguration, ClusterConfiguration}; pub use traits::{NodeKeyPair, KeyServer}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index bf293a44eb..074052fae4 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -29,7 +29,7 @@ use url::percent_encoding::percent_decode; use traits::KeyServer; use serialization::{SerializableEncryptedDocumentKeyShadow, SerializableBytes, SerializablePublic}; -use types::all::{Error, Public, MessageHash, NodeAddress, RequestSignature, ServerKeyId, +use types::{Error, Public, MessageHash, NodeAddress, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId}; /// Key server http-requests listener. Available requests: @@ -271,15 +271,16 @@ fn return_bytes(req_uri: &Uri, result: Result, Error>) - } fn return_error(err: Error) -> HttpResponse { - let mut res = match err { - Error::InsufficientRequesterData(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), - Error::AccessDenied => HttpResponse::new().with_status(HttpStatusCode::Forbidden), - Error::DocumentNotFound => HttpResponse::new().with_status(HttpStatusCode::NotFound), - Error::Hyper(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), - Error::Serde(_) => HttpResponse::new().with_status(HttpStatusCode::BadRequest), - Error::Database(_) => HttpResponse::new().with_status(HttpStatusCode::InternalServerError), - Error::Internal(_) => HttpResponse::new().with_status(HttpStatusCode::InternalServerError), - }; + let mut res = HttpResponse::new().with_status(match err { + Error::AccessDenied | Error::ConsensusUnreachable | Error::ConsensusTemporaryUnreachable => + HttpStatusCode::Forbidden, + Error::ServerKeyIsNotFound | Error::DocumentKeyIsNotFound => + HttpStatusCode::NotFound, + Error::InsufficientRequesterData(_) | Error::Hyper(_) | Error::Serde(_) + | Error::DocumentKeyAlreadyStored | Error::ServerKeyAlreadyGenerated => + HttpStatusCode::BadRequest, + _ => HttpStatusCode::InternalServerError, + }); // return error text. ignore errors when returning error let error_text = format!("\"{}\"", err); @@ -377,7 +378,7 @@ mod tests { use ethkey::Public; use traits::KeyServer; use key_server::tests::DummyKeyServer; - use types::all::NodeAddress; + use types::NodeAddress; use super::{parse_request, Request, KeyServerHttpListener}; #[test] diff --git a/secret_store/src/listener/mod.rs b/secret_store/src/listener/mod.rs index 2c4fbaf4cb..0d1f3f2675 100644 --- a/secret_store/src/listener/mod.rs +++ b/secret_store/src/listener/mod.rs @@ -23,7 +23,7 @@ mod tasks_queue; use std::collections::BTreeSet; use std::sync::Arc; use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, AdminSessionsServer, KeyServer}; -use types::all::{Error, Public, MessageHash, EncryptedMessageSignature, RequestSignature, ServerKeyId, +use types::{Error, Public, MessageHash, EncryptedMessageSignature, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId, Requester}; /// Available API mask. diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 1e17be8e55..0e273b3eee 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -315,7 +315,7 @@ impl ServiceContractListener { Ok(Some(server_key)) => { data.contract.publish_generated_server_key(&origin, server_key_id, server_key) }, - Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_server_key_generation_error(&origin, server_key_id) @@ -335,7 +335,7 @@ impl ServiceContractListener { Ok(None) => { data.contract.publish_server_key_retrieval_error(&origin, server_key_id) } - Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_server_key_retrieval_error(&origin, server_key_id) @@ -349,7 +349,7 @@ impl ServiceContractListener { /// Store document key. fn store_document_key(data: &Arc, origin: Address, server_key_id: &ServerKeyId, author: &Address, common_point: &Public, encrypted_point: &Public) -> Result<(), String> { let store_result = data.key_storage.get(server_key_id) - .and_then(|key_share| key_share.ok_or(Error::DocumentNotFound)) + .and_then(|key_share| key_share.ok_or(Error::ServerKeyIsNotFound)) .and_then(|key_share| check_encrypted_data(Some(&key_share)).map(|_| key_share).map_err(Into::into)) .and_then(|key_share| update_encrypted_data(&data.key_storage, server_key_id.clone(), key_share, author.clone(), common_point.clone(), encrypted_point.clone()).map_err(Into::into)); @@ -357,7 +357,7 @@ impl ServiceContractListener { Ok(()) => { data.contract.publish_stored_document_key(&origin, server_key_id) }, - Err(ref error) if is_internal_error(&error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_document_key_store_error(&origin, server_key_id) @@ -372,17 +372,16 @@ impl ServiceContractListener { fn retrieve_document_key_common(data: &Arc, origin: Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { let retrieval_result = data.acl_storage.check(requester.clone(), server_key_id) .and_then(|is_allowed| if !is_allowed { Err(Error::AccessDenied) } else { Ok(()) }) - .and_then(|_| data.key_storage.get(server_key_id).and_then(|key_share| key_share.ok_or(Error::DocumentNotFound))) + .and_then(|_| data.key_storage.get(server_key_id).and_then(|key_share| key_share.ok_or(Error::ServerKeyIsNotFound))) .and_then(|key_share| key_share.common_point - .ok_or(Error::DocumentNotFound) - .and_then(|common_point| math::make_common_shadow_point(key_share.threshold, common_point) - .map_err(|e| Error::Internal(e.into()))) + .ok_or(Error::DocumentKeyIsNotFound) + .and_then(|common_point| math::make_common_shadow_point(key_share.threshold, common_point)) .map(|common_point| (common_point, key_share.threshold))); match retrieval_result { Ok((common_point, threshold)) => { data.contract.publish_retrieved_document_key_common(&origin, server_key_id, requester, common_point, threshold) }, - Err(ref error) if is_internal_error(&error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_document_key_retrieval_error(&origin, server_key_id, requester) @@ -406,7 +405,7 @@ impl ServiceContractListener { Ok(Some((participants, decrypted_secret, shadow))) => { data.contract.publish_retrieved_document_key_personal(&origin, server_key_id, &requester, &participants, decrypted_secret, shadow) }, - Err(ref error) if is_internal_error(error) => Err(format!("{}", error)), + Err(ref error) if error.is_non_fatal() => Err(format!("{}", error)), Err(ref error) => { // ignore error as we're already processing an error let _ = data.contract.publish_document_key_retrieval_error(&origin, server_key_id, &requester) @@ -511,15 +510,6 @@ impl ::std::fmt::Display for ServiceTask { } } -/// Is internal error? Internal error means that it is SS who's responsible for it, like: connectivity, db failure, ... -/// External error is caused by SS misuse, like: trying to generate duplicated key, access denied, ... -/// When internal error occurs, we just ignore request for now and will retry later. -/// When external error occurs, we reject request. -fn is_internal_error(_error: &Error) -> bool { - // TODO [Reliability]: implement me after proper is passed through network - false -} - /// Log service task result. fn log_service_task_result(task: &ServiceTask, self_id: &Public, result: Result<(), String>) -> Result<(), String> { match result { diff --git a/secret_store/src/serialization.rs b/secret_store/src/serialization.rs index 95f6790967..42209e0de4 100644 --- a/secret_store/src/serialization.rs +++ b/secret_store/src/serialization.rs @@ -22,7 +22,7 @@ use serde::de::{Visitor, Error as SerdeError}; use ethkey::{Public, Secret, Signature}; use ethereum_types::{H160, H256}; use bytes::Bytes; -use types::all::Requester; +use types::Requester; macro_rules! impl_bytes_deserialize { ($name: ident, $value: expr, true) => { diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs index ea09a3d906..04f2fa1294 100644 --- a/secret_store/src/traits.rs +++ b/secret_store/src/traits.rs @@ -17,7 +17,7 @@ use std::collections::BTreeSet; use ethkey::{KeyPair, Signature, Error as EthKeyError}; use ethereum_types::{H256, Address}; -use types::all::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, Requester, +use types::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, Requester, EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId}; /// Node key pair. diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index b994026814..bfc58779a6 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -14,13 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::fmt; -use std::io; -use std::net; use std::collections::BTreeMap; -use serde_json; -use {ethkey, kvdb, bytes, ethereum_types, key_server_cluster}; +use {ethkey, bytes, ethereum_types}; /// Node id. pub type NodeId = ethkey::Public; @@ -37,25 +33,6 @@ pub type RequestSignature = ethkey::Signature; /// Public key type. pub use ethkey::Public; -/// Secret store error -#[derive(Debug, PartialEq)] -pub enum Error { - /// Insufficient requester data - InsufficientRequesterData(String), - /// Access to resource is denied - AccessDenied, - /// Requested document not found - DocumentNotFound, - /// Hyper error - Hyper(String), - /// Serialization/deserialization error - Serde(String), - /// Database-related error - Database(String), - /// Internal error - Internal(String), -} - /// Secret store configuration #[derive(Debug, Clone)] pub struct NodeAddress { @@ -136,69 +113,6 @@ pub enum Requester { Address(ethereum_types::Address), } -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), - Error::AccessDenied => write!(f, "Access dened"), - Error::DocumentNotFound => write!(f, "Document not found"), - Error::Hyper(ref msg) => write!(f, "Hyper error: {}", msg), - Error::Serde(ref msg) => write!(f, "Serialization error: {}", msg), - Error::Database(ref msg) => write!(f, "Database error: {}", msg), - Error::Internal(ref msg) => write!(f, "Internal error: {}", msg), - } - } -} - -impl From for Error { - fn from(err: serde_json::Error) -> Self { - Error::Serde(err.to_string()) - } -} - -impl From for Error { - fn from(err: ethkey::Error) -> Self { - Error::Internal(err.into()) - } -} - -impl From for Error { - fn from(err: io::Error) -> Error { - Error::Internal(err.to_string()) - } -} - -impl From for Error { - fn from(err: net::AddrParseError) -> Error { - Error::Internal(err.to_string()) - } -} - -impl From for Error { - fn from(err: kvdb::Error) -> Self { - Error::Database(err.to_string()) - } -} - -impl From for Error { - fn from(err: key_server_cluster::Error) -> Self { - match err { - key_server_cluster::Error::InsufficientRequesterData(err) - => Error::InsufficientRequesterData(err), - key_server_cluster::Error::ConsensusUnreachable - | key_server_cluster::Error::AccessDenied => Error::AccessDenied, - key_server_cluster::Error::MissingKeyShare => Error::DocumentNotFound, - _ => Error::Internal(err.into()), - } - } -} - -impl Into for Error { - fn into(self) -> String { - format!("{}", self) - } -} - impl Default for Requester { fn default() -> Self { Requester::Signature(Default::default()) diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs new file mode 100644 index 0000000000..6469585fac --- /dev/null +++ b/secret_store/src/types/error.rs @@ -0,0 +1,199 @@ +// 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 . + +use std::fmt; +use std::net; +use std::io::Error as IoError; + +use {ethkey, crypto, kvdb}; + +/// Secret store error. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Error { + /// Invalid node address has been passed. + InvalidNodeAddress, + /// Invalid node id has been passed. + InvalidNodeId, + /// Session with the given id already exists. + DuplicateSessionId, + /// No active session with given id. + NoActiveSessionWithId, + /// Invalid threshold value has been passed. + /// Threshold value must be in [0; n - 1], where n is a number of nodes participating in the encryption. + NotEnoughNodesForThreshold, + /// Current state of encryption/decryption session does not allow to proceed request. + /// Reschedule this request for later processing. + TooEarlyForRequest, + /// Current state of encryption/decryption session does not allow to proceed request. + /// This means that either there is some comm-failure or node is misbehaving/cheating. + InvalidStateForRequest, + /// Request cannot be sent/received from this node. + InvalidNodeForRequest, + /// Message or some data in the message was recognized as invalid. + /// This means that node is misbehaving/cheating. + InvalidMessage, + /// Message version is not supported. + InvalidMessageVersion, + /// Message is invalid because of replay-attack protection. + ReplayProtection, + /// Connection to node, required for this session is not established. + NodeDisconnected, + /// Server key with this ID is already generated. + ServerKeyAlreadyGenerated, + /// Server key with this ID is not yet generated. + ServerKeyIsNotFound, + /// Document key with this ID is already stored. + DocumentKeyAlreadyStored, + /// Document key with this ID is not yet stored. + DocumentKeyIsNotFound, + /// Consensus is temporary unreachable. Means that something is currently blocking us from either forming + /// consensus group (like disconnecting from too many nodes, which are AGREE to partticipate in consensus) + /// or from rejecting request (disconnecting from AccessDenied-nodes). + ConsensusTemporaryUnreachable, + /// Consensus is unreachable. It doesn't mean that it will ALWAYS remain unreachable, but right NOW we have + /// enough nodes confirmed that they do not want to be a part of consensus. Example: we're connected to 10 + /// of 100 nodes. Key threshold is 6 (i.e. 7 nodes are required for consensus). 4 nodes are responding with + /// reject => consensus is considered unreachable, even though another 90 nodes still can respond with OK. + ConsensusUnreachable, + /// Acl storage error. + AccessDenied, + /// Can't start session, because exclusive session is active. + ExclusiveSessionActive, + /// Can't start exclusive session, because there are other active sessions. + HasActiveSessions, + /// Insufficient requester data. + InsufficientRequesterData(String), + /// Cryptographic error. + EthKey(String), + /// I/O error has occured. + Io(String), + /// Deserialization error has occured. + Serde(String), + /// Hyper error. + Hyper(String), + /// Database-related error. + Database(String), + /// Internal error. + Internal(String), +} + +impl Error { + /// Is this a fatal error? Non-fatal means that it is possible to replay the same request with a non-zero + /// chance to success. I.e. the error is not about request itself (or current environment factors that + /// are affecting request processing), but about current SecretStore state. + pub fn is_non_fatal(&self) -> bool { + match *self { + // non-fatal errors: + + // session start errors => restarting session is a solution + Error::DuplicateSessionId | Error::NoActiveSessionWithId | + // unexpected message errors => restarting session/excluding node is a solution + Error::TooEarlyForRequest | Error::InvalidStateForRequest | Error::InvalidNodeForRequest | + // invalid message errors => restarting/updating/excluding node is a solution + Error::InvalidMessage | Error::InvalidMessageVersion | Error::ReplayProtection | + // connectivity problems => waiting for reconnect && restarting session is a solution + Error::NodeDisconnected | + // temporary (?) consensus problems, related to other non-fatal errors => restarting is probably (!) a solution + Error::ConsensusTemporaryUnreachable | + // exclusive session errors => waiting && restarting is a solution + Error::ExclusiveSessionActive | Error::HasActiveSessions => true, + + // fatal errors: + + // config-related errors + Error::InvalidNodeAddress | Error::InvalidNodeId | + // wrong session input params errors + Error::NotEnoughNodesForThreshold | Error::ServerKeyAlreadyGenerated | Error::ServerKeyIsNotFound | + Error::DocumentKeyAlreadyStored | Error::DocumentKeyIsNotFound | Error::InsufficientRequesterData(_) | + // access denied/consensus error + Error::AccessDenied | Error::ConsensusUnreachable | + // indeterminate internal errors, which could be either fatal (db failure, invalid request), or not (network error), + // but we still consider these errors as fatal + Error::EthKey(_) | Error::Serde(_) | Error::Hyper(_) | Error::Database(_) | Error::Internal(_) | Error::Io(_) => false, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::InvalidNodeAddress => write!(f, "invalid node address has been passed"), + Error::InvalidNodeId => write!(f, "invalid node id has been passed"), + Error::DuplicateSessionId => write!(f, "session with the same id is already registered"), + Error::NoActiveSessionWithId => write!(f, "no active session with given id"), + Error::NotEnoughNodesForThreshold => write!(f, "not enough nodes for passed threshold"), + Error::TooEarlyForRequest => write!(f, "session is not yet ready to process this request"), + Error::InvalidStateForRequest => write!(f, "session is in invalid state for processing this request"), + Error::InvalidNodeForRequest => write!(f, "invalid node for this request"), + Error::InvalidMessage => write!(f, "invalid message is received"), + Error::InvalidMessageVersion => write!(f, "unsupported message is received"), + Error::ReplayProtection => write!(f, "replay message is received"), + Error::NodeDisconnected => write!(f, "node required for this operation is currently disconnected"), + Error::ServerKeyAlreadyGenerated => write!(f, "Server key with this ID is already generated"), + Error::ServerKeyIsNotFound => write!(f, "Server key with this ID is not found"), + Error::DocumentKeyAlreadyStored => write!(f, "Document key with this ID is already stored"), + Error::DocumentKeyIsNotFound => write!(f, "Document key with this ID is not found"), + Error::ConsensusUnreachable => write!(f, "Consensus unreachable"), + Error::ConsensusTemporaryUnreachable => write!(f, "Consensus temporary unreachable"), + Error::AccessDenied => write!(f, "Access dened"), + Error::ExclusiveSessionActive => write!(f, "Exclusive session active"), + Error::HasActiveSessions => write!(f, "Unable to start exclusive session"), + Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), + Error::EthKey(ref e) => write!(f, "cryptographic error {}", e), + Error::Hyper(ref msg) => write!(f, "Hyper error: {}", msg), + Error::Serde(ref msg) => write!(f, "Serialization error: {}", msg), + Error::Database(ref msg) => write!(f, "Database error: {}", msg), + Error::Internal(ref msg) => write!(f, "Internal error: {}", msg), + Error::Io(ref msg) => write!(f, "IO error: {}", msg), + } + } +} + +impl From for Error { + fn from(err: ethkey::Error) -> Self { + Error::EthKey(err.into()) + } +} + +impl From for Error { + fn from(err: kvdb::Error) -> Self { + Error::Database(err.to_string()) + } +} + +impl From for Error { + fn from(err: crypto::Error) -> Self { + Error::EthKey(err.into()) + } +} + +impl From for Error { + fn from(err: IoError) -> Self { + Error::Io(err.to_string()) + } +} + +impl Into for Error { + fn into(self) -> String { + format!("{}", self) + } +} + +impl From for Error { + fn from(err: net::AddrParseError) -> Error { + Error::Internal(err.to_string()) + } +} diff --git a/secret_store/src/types/mod.rs b/secret_store/src/types/mod.rs index dc5bd3d8a0..9da7f6ef98 100644 --- a/secret_store/src/types/mod.rs +++ b/secret_store/src/types/mod.rs @@ -16,4 +16,8 @@ //! Types used in the public api -pub mod all; +mod all; +mod error; + +pub use self::all::*; +pub use self::error::*; -- GitLab From 10a346476a4135dd979379cc3c2529e9080ecda4 Mon Sep 17 00:00:00 2001 From: ellaismer <31844524+ellaismer@users.noreply.github.com> Date: Tue, 1 May 2018 14:41:46 -0400 Subject: [PATCH 114/263] Enable WebAssembly and Byzantium for Ellaism (#8520) * Enable WebAssembly and Byzantium for Ellaism * Fix indentation * Remove empty lines --- ethcore/res/ethereum/ellaism.json | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ethcore/res/ethereum/ellaism.json b/ethcore/res/ethereum/ellaism.json index 3650e68df5..96c2016e55 100644 --- a/ethcore/res/ethereum/ellaism.json +++ b/ethcore/res/ethereum/ellaism.json @@ -13,9 +13,9 @@ "eip150Transition": "0x0", "eip160Transition": "0x0", "ecip1017EraRounds": 10000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "eip161dTransition": "0x7fffffffffffffff", + "eip100bTransition": 2000000 } } }, @@ -29,7 +29,12 @@ "chainID": "0x40", "eip155Transition": "0x0", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "wasmActivationTransition": 2000000, + "eip140Transition": 2000000, + "eip211Transition": 2000000, + "eip214Transition": 2000000, + "eip658Transition": 2000000 }, "genesis": { "seal": { @@ -60,6 +65,10 @@ "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } } } } -- GitLab From 629da8f8bf39da2e3a32f178954604a89de898d1 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 2 May 2018 09:20:59 +0200 Subject: [PATCH 115/263] More changes for Android (#8421) --- .gitlab-ci.yml | 17 +++++++++++++++++ Cargo.lock | 22 +++++++++++----------- docker/android/Dockerfile | 2 ++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2c216496f6..347b5a57ba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -180,6 +180,23 @@ windows: paths: - parity.zip name: "x86_64-pc-windows-msvc_parity" +android-armv7: + stage: build + image: parity/parity-android:latest + only: + - beta + - tags + - stable + - triggers + script: + - cargo build --target=armv7-linux-androideabi + # TODO: check that `arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/release/parity | grep c++_shared` is empty + tags: + - rust-arm + artifacts: + paths: + - parity.zip + name: "armv7-linux-androideabi_parity" docker-build: stage: build only: diff --git a/Cargo.lock b/Cargo.lock index 3176c3ab3d..741cc3832c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,7 +70,7 @@ name = "backtrace-sys" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -432,7 +432,7 @@ version = "0.5.7" source = "git+https://github.com/paritytech/rust-secp256k1#db81cfea59014b4d176f10f86ed52e1a130b6822" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1203,7 +1203,7 @@ name = "hidapi" version = "0.3.1" source = "git+https://github.com/paritytech/hidapi-rs#70ec4bd1b755ec5dd32ad2be0c8345864147c8bc" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1436,7 +1436,7 @@ dependencies = [ name = "keccak-hash" version = "0.1.0" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1524,7 +1524,7 @@ name = "libusb-sys" version = "0.2.4" source = "git+https://github.com/paritytech/libusb-sys#14bdb698003731b6344a79e1d814704e44363e7c" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1678,7 +1678,7 @@ name = "miniz_oxide_c_api" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2723,7 +2723,7 @@ name = "ring" version = "0.12.1" source = "git+https://github.com/paritytech/ring#b98d7f586c0467d68e9946a5f47b4a04b9a86b4a" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2774,7 +2774,7 @@ name = "rocksdb-sys" version = "0.3.0" source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", @@ -3010,7 +3010,7 @@ name = "snappy-sys" version = "0.1.0" source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3782,7 +3782,7 @@ dependencies = [ "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" -"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" +"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" diff --git a/docker/android/Dockerfile b/docker/android/Dockerfile index 5769cd13bc..7783781b4c 100644 --- a/docker/android/Dockerfile +++ b/docker/android/Dockerfile @@ -75,3 +75,5 @@ ENV CFLAGS_arm_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID ENV CFLAGS_armv7_linux_androideabi -std=gnu11 -fPIC -D OS_ANDROID ENV CXXFLAGS_arm_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID ENV CXXFLAGS_armv7_linux_androideabi -std=gnu++11 -fPIC -fexceptions -frtti -static-libstdc++ -D OS_ANDROID +ENV CXXSTDLIB_arm_linux_androideabi "" +ENV CXXSTDLIB_armv7_linux_androideabi "" -- GitLab From 8e8679807dbb8df6456172fdfa1396b7f091d267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 2 May 2018 09:31:06 +0200 Subject: [PATCH 116/263] Transaction Pool improvements (#8470) * Don't use ethereum_types in transaction pool. * Hide internal insertion_id. * Fix tests. * Review grumbles. --- miner/src/pool/mod.rs | 13 ++- miner/src/pool/queue.rs | 4 +- miner/src/pool/ready.rs | 12 +-- miner/src/pool/scoring.rs | 11 ++- transaction-pool/Cargo.toml | 2 + transaction-pool/src/error.rs | 16 ++-- transaction-pool/src/lib.rs | 23 +++-- transaction-pool/src/pool.rs | 113 +++++++++++++++-------- transaction-pool/src/ready.rs | 4 +- transaction-pool/src/scoring.rs | 34 ++++--- transaction-pool/src/tests/helpers.rs | 10 +- transaction-pool/src/tests/mod.rs | 13 +-- transaction-pool/src/tests/tx_builder.rs | 10 -- transaction-pool/src/transactions.rs | 46 +++++---- 14 files changed, 173 insertions(+), 138 deletions(-) diff --git a/miner/src/pool/mod.rs b/miner/src/pool/mod.rs index 7950510c6d..45d28f3c12 100644 --- a/miner/src/pool/mod.rs +++ b/miner/src/pool/mod.rs @@ -105,6 +105,11 @@ impl VerifiedTransaction { self.priority } + /// Gets transaction insertion id. + pub(crate) fn insertion_id(&self) -> usize { + self.insertion_id + } + /// Gets wrapped `SignedTransaction` pub fn signed(&self) -> &transaction::SignedTransaction { &self.transaction @@ -114,9 +119,13 @@ impl VerifiedTransaction { pub fn pending(&self) -> &transaction::PendingTransaction { &self.transaction } + } impl txpool::VerifiedTransaction for VerifiedTransaction { + type Hash = H256; + type Sender = Address; + fn hash(&self) -> &H256 { &self.hash } @@ -128,8 +137,4 @@ impl txpool::VerifiedTransaction for VerifiedTransaction { fn sender(&self) -> &Address { &self.sender } - - fn insertion_id(&self) -> u64 { - self.insertion_id as u64 - } } diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index edc092a119..8cf4534b76 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -282,11 +282,11 @@ impl TransactionQueue { // We want to clear stale transactions from the queue as well. // (Transactions that are occuping the queue for a long time without being included) let stale_id = { - let current_id = self.insertion_id.load(atomic::Ordering::Relaxed) as u64; + let current_id = self.insertion_id.load(atomic::Ordering::Relaxed); // wait at least for half of the queue to be replaced let gap = self.pool.read().options().max_count / 2; // but never less than 100 transactions - let gap = cmp::max(100, gap) as u64; + let gap = cmp::max(100, gap); current_id.checked_sub(gap) }; diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs index 54b5aec3a9..c2829b34a9 100644 --- a/miner/src/pool/ready.rs +++ b/miner/src/pool/ready.rs @@ -54,14 +54,14 @@ pub struct State { nonces: HashMap, state: C, max_nonce: Option, - stale_id: Option, + stale_id: Option, } impl State { /// Create new State checker, given client interface. pub fn new( state: C, - stale_id: Option, + stale_id: Option, max_nonce: Option, ) -> Self { State { @@ -91,10 +91,10 @@ impl txpool::Ready for State { match tx.transaction.nonce.cmp(nonce) { // Before marking as future check for stale ids cmp::Ordering::Greater => match self.stale_id { - Some(id) if tx.insertion_id() < id => txpool::Readiness::Stalled, + Some(id) if tx.insertion_id() < id => txpool::Readiness::Stale, _ => txpool::Readiness::Future, }, - cmp::Ordering::Less => txpool::Readiness::Stalled, + cmp::Ordering::Less => txpool::Readiness::Stale, cmp::Ordering::Equal => { *nonce = *nonce + 1.into(); txpool::Readiness::Ready @@ -178,7 +178,7 @@ mod tests { let res = State::new(TestClient::new().with_nonce(125), None, None).is_ready(&tx); // then - assert_eq!(res, txpool::Readiness::Stalled); + assert_eq!(res, txpool::Readiness::Stale); } #[test] @@ -190,7 +190,7 @@ mod tests { let res = State::new(TestClient::new(), Some(1), None).is_ready(&tx); // then - assert_eq!(res, txpool::Readiness::Stalled); + assert_eq!(res, txpool::Readiness::Stale); } #[test] diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs index b9f074ecb0..eaf0698332 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -28,7 +28,6 @@ //! from our local node (own transactions). use std::cmp; -use std::sync::Arc; use ethereum_types::U256; use txpool; @@ -69,7 +68,7 @@ impl txpool::Scoring for NonceAndGasPrice { } } - fn update_scores(&self, txs: &[Arc], scores: &mut [U256], change: txpool::scoring::Change) { + fn update_scores(&self, txs: &[txpool::Transaction], scores: &mut [U256], change: txpool::scoring::Change) { use self::txpool::scoring::Change; match change { @@ -79,7 +78,7 @@ impl txpool::Scoring for NonceAndGasPrice { assert!(i < txs.len()); assert!(i < scores.len()); - scores[i] = txs[i].transaction.gas_price; + scores[i] = txs[i].transaction.transaction.gas_price; let boost = match txs[i].priority() { super::Priority::Local => 15, super::Priority::Retracted => 10, @@ -116,6 +115,7 @@ impl txpool::Scoring for NonceAndGasPrice { mod tests { use super::*; + use std::sync::Arc; use pool::tests::tx::{Tx, TxExt}; use txpool::Scoring; @@ -131,7 +131,10 @@ mod tests { 1 => ::pool::Priority::Retracted, _ => ::pool::Priority::Regular, }; - Arc::new(verified) + txpool::Transaction { + insertion_id: 0, + transaction: Arc::new(verified), + } }).collect::>(); let initial_scores = vec![U256::from(0), 0.into(), 0.into()]; diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index b863078112..342c376f63 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -10,4 +10,6 @@ error-chain = "0.11" log = "0.3" smallvec = "0.4" trace-time = { path = "../util/trace-time" } + +[dev-dependencies] ethereum-types = "0.3" diff --git a/transaction-pool/src/error.rs b/transaction-pool/src/error.rs index 2e8ac73989..4cf221a71e 100644 --- a/transaction-pool/src/error.rs +++ b/transaction-pool/src/error.rs @@ -14,24 +14,26 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; +/// Error chain doesn't let us have generic types. +/// So the hashes are converted to debug strings for easy display. +type Hash = String; error_chain! { errors { /// Transaction is already imported - AlreadyImported(hash: H256) { + AlreadyImported(hash: Hash) { description("transaction is already in the pool"), - display("[{:?}] already imported", hash) + display("[{}] already imported", hash) } /// Transaction is too cheap to enter the queue - TooCheapToEnter(hash: H256, min_score: String) { + TooCheapToEnter(hash: Hash, min_score: String) { description("the pool is full and transaction is too cheap to replace any transaction"), - display("[{:?}] too cheap to enter the pool. Min score: {}", hash, min_score) + display("[{}] too cheap to enter the pool. Min score: {}", hash, min_score) } /// Transaction is too cheap to replace existing transaction that occupies the same slot. - TooCheapToReplace(old_hash: H256, hash: H256) { + TooCheapToReplace(old_hash: Hash, hash: Hash) { description("transaction is too cheap to replace existing transaction in the pool"), - display("[{:?}] too cheap to replace: {:?}", hash, old_hash) + display("[{}] too cheap to replace: {}", hash, old_hash) } } } diff --git a/transaction-pool/src/lib.rs b/transaction-pool/src/lib.rs index 33d17f4b0f..4a1bdcde14 100644 --- a/transaction-pool/src/lib.rs +++ b/transaction-pool/src/lib.rs @@ -69,14 +69,15 @@ #![warn(missing_docs)] extern crate smallvec; -extern crate ethereum_types; +extern crate trace_time; #[macro_use] extern crate error_chain; #[macro_use] extern crate log; -extern crate trace_time; +#[cfg(test)] +extern crate ethereum_types; #[cfg(test)] mod tests; @@ -95,27 +96,29 @@ pub mod scoring; pub use self::error::{Error, ErrorKind}; pub use self::listener::{Listener, NoopListener}; pub use self::options::Options; -pub use self::pool::{Pool, PendingIterator}; +pub use self::pool::{Pool, PendingIterator, Transaction}; pub use self::ready::{Ready, Readiness}; pub use self::scoring::Scoring; pub use self::status::{LightStatus, Status}; pub use self::verifier::Verifier; use std::fmt; - -use ethereum_types::{H256, Address}; +use std::hash::Hash; /// Already verified transaction that can be safely queued. pub trait VerifiedTransaction: fmt::Debug { + /// Transaction hash type. + type Hash: fmt::Debug + fmt::LowerHex + Eq + Clone + Hash; + + /// Transaction sender type. + type Sender: fmt::Debug + Eq + Clone + Hash; + /// Transaction hash - fn hash(&self) -> &H256; + fn hash(&self) -> &Self::Hash; /// Memory usage fn mem_usage(&self) -> usize; /// Transaction sender - fn sender(&self) -> &Address; - - /// Unique index of insertion (lower = older). - fn insertion_id(&self) -> u64; + fn sender(&self) -> &Self::Sender; } diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index fa28cdcdfe..5cb6e479b8 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -17,8 +17,6 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeSet}; -use ethereum_types::{H160, H256}; - use error; use listener::{Listener, NoopListener}; use options::Options; @@ -29,21 +27,51 @@ use transactions::{AddResult, Transactions}; use {VerifiedTransaction}; -type Sender = H160; +/// Internal representation of transaction. +/// +/// Includes unique insertion id that can be used for scoring explictly, +/// but internally is used to resolve conflicts in case of equal scoring +/// (newer transactionsa are preferred). +#[derive(Debug)] +pub struct Transaction { + /// Sequential id of the transaction + pub insertion_id: u64, + /// Shared transaction + pub transaction: Arc, +} + +impl Clone for Transaction { + fn clone(&self) -> Self { + Transaction { + insertion_id: self.insertion_id, + transaction: self.transaction.clone(), + } + } +} + +impl ::std::ops::Deref for Transaction { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.transaction + } +} /// A transaction pool. #[derive(Debug)] -pub struct Pool, L = NoopListener> { +pub struct Pool, L = NoopListener> { listener: L, scoring: S, options: Options, mem_usage: usize, - transactions: HashMap>, - by_hash: HashMap>, + transactions: HashMap>, + by_hash: HashMap>, best_transactions: BTreeSet>, worst_transactions: BTreeSet>, + + insertion_id: u64, } impl + Default> Default for Pool { @@ -89,6 +117,7 @@ impl Pool where by_hash, best_transactions: Default::default(), worst_transactions: Default::default(), + insertion_id: 0, } } @@ -104,10 +133,16 @@ impl Pool where /// If any limit is reached the transaction with the lowest `Score` is evicted to make room. /// /// The `Listener` will be informed on any drops or rejections. - pub fn import(&mut self, mut transaction: T) -> error::Result> { + pub fn import(&mut self, transaction: T) -> error::Result> { let mem_usage = transaction.mem_usage(); - ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(*transaction.hash())); + ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(format!("{:?}", transaction.hash()))); + + self.insertion_id += 1; + let mut transaction = Transaction { + insertion_id: self.insertion_id, + transaction: Arc::new(transaction), + }; // TODO [ToDr] Most likely move this after the transaction is inserted. // Avoid using should_replace, but rather use scoring for that. @@ -115,7 +150,7 @@ impl Pool where let remove_worst = |s: &mut Self, transaction| { match s.remove_worst(&transaction) { Err(err) => { - s.listener.rejected(&Arc::new(transaction), err.kind()); + s.listener.rejected(&transaction, err.kind()); Err(err) }, Ok(removed) => { @@ -138,7 +173,7 @@ impl Pool where } let (result, prev_state, current_state) = { - let transactions = self.transactions.entry(*transaction.sender()).or_insert_with(Transactions::default); + let transactions = self.transactions.entry(transaction.sender().clone()).or_insert_with(Transactions::default); // get worst and best transactions for comparison let prev = transactions.worst_and_best(); let result = transactions.add(transaction, &self.scoring, self.options.max_per_sender); @@ -153,31 +188,31 @@ impl Pool where AddResult::Ok(tx) => { self.listener.added(&tx, None); self.finalize_insert(&tx, None); - Ok(tx) + Ok(tx.transaction) }, AddResult::PushedOut { new, old } | AddResult::Replaced { new, old } => { self.listener.added(&new, Some(&old)); self.finalize_insert(&new, Some(&old)); - Ok(new) + Ok(new.transaction) }, AddResult::TooCheap { new, old } => { - let error = error::ErrorKind::TooCheapToReplace(*old.hash(), *new.hash()); - self.listener.rejected(&Arc::new(new), &error); + let error = error::ErrorKind::TooCheapToReplace(format!("{:x}", old.hash()), format!("{:x}", new.hash())); + self.listener.rejected(&new, &error); bail!(error) }, AddResult::TooCheapToEnter(new, score) => { - let error = error::ErrorKind::TooCheapToEnter(*new.hash(), format!("{:?}", score)); - self.listener.rejected(&Arc::new(new), &error); + let error = error::ErrorKind::TooCheapToEnter(format!("{:x}", new.hash()), format!("{:?}", score)); + self.listener.rejected(&new, &error); bail!(error) } } } /// Updates state of the pool statistics if the transaction was added to a set. - fn finalize_insert(&mut self, new: &Arc, old: Option<&Arc>) { + fn finalize_insert(&mut self, new: &Transaction, old: Option<&Transaction>) { self.mem_usage += new.mem_usage(); - self.by_hash.insert(*new.hash(), new.clone()); + self.by_hash.insert(new.hash().clone(), new.clone()); if let Some(old) = old { self.finalize_remove(old.hash()); @@ -185,23 +220,23 @@ impl Pool where } /// Updates the pool statistics if transaction was removed. - fn finalize_remove(&mut self, hash: &H256) -> Option> { + fn finalize_remove(&mut self, hash: &T::Hash) -> Option> { self.by_hash.remove(hash).map(|old| { - self.mem_usage -= old.mem_usage(); - old + self.mem_usage -= old.transaction.mem_usage(); + old.transaction }) } /// Updates best and worst transactions from a sender. fn update_senders_worst_and_best( &mut self, - previous: Option<((S::Score, Arc), (S::Score, Arc))>, - current: Option<((S::Score, Arc), (S::Score, Arc))>, + previous: Option<((S::Score, Transaction), (S::Score, Transaction))>, + current: Option<((S::Score, Transaction), (S::Score, Transaction))>, ) { let worst_collection = &mut self.worst_transactions; let best_collection = &mut self.best_transactions; - let is_same = |a: &(S::Score, Arc), b: &(S::Score, Arc)| { + let is_same = |a: &(S::Score, Transaction), b: &(S::Score, Transaction)| { a.0 == b.0 && a.1.hash() == b.1.hash() }; @@ -238,19 +273,19 @@ impl Pool where } /// Attempts to remove the worst transaction from the pool if it's worse than the given one. - fn remove_worst(&mut self, transaction: &T) -> error::Result> { + fn remove_worst(&mut self, transaction: &Transaction) -> error::Result> { let to_remove = match self.worst_transactions.iter().next_back() { // No elements to remove? and the pool is still full? None => { warn!("The pool is full but there are no transactions to remove."); - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), "unknown".into()).into()); + return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), "unknown".into()).into()); }, Some(old) => if self.scoring.should_replace(&old.transaction, transaction) { // New transaction is better than the worst one so we can replace it. old.clone() } else { // otherwise fail - return Err(error::ErrorKind::TooCheapToEnter(*transaction.hash(), format!("{:?}", old.score)).into()) + return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), format!("{:?}", old.score)).into()) }, }; @@ -263,7 +298,7 @@ impl Pool where } /// Removes transaction from sender's transaction `HashMap`. - fn remove_from_set, &S) -> R>(&mut self, sender: &Sender, f: F) -> Option { + fn remove_from_set, &S) -> R>(&mut self, sender: &T::Sender, f: F) -> Option { let (prev, next, result) = if let Some(set) = self.transactions.get_mut(sender) { let prev = set.worst_and_best(); let result = f(set, &self.scoring); @@ -286,14 +321,14 @@ impl Pool where self.worst_transactions.clear(); for (_hash, tx) in self.by_hash.drain() { - self.listener.dropped(&tx, None) + self.listener.dropped(&tx.transaction, None) } } /// Removes single transaction from the pool. /// Depending on the `is_invalid` flag the listener /// will either get a `cancelled` or `invalid` notification. - pub fn remove(&mut self, hash: &H256, is_invalid: bool) -> Option> { + pub fn remove(&mut self, hash: &T::Hash, is_invalid: bool) -> Option> { if let Some(tx) = self.finalize_remove(hash) { self.remove_from_set(tx.sender(), |set, scoring| { set.remove(&tx, scoring) @@ -310,7 +345,7 @@ impl Pool where } /// Removes all stalled transactions from given sender. - fn remove_stalled>(&mut self, sender: &Sender, ready: &mut R) -> usize { + fn remove_stalled>(&mut self, sender: &T::Sender, ready: &mut R) -> usize { let removed_from_set = self.remove_from_set(sender, |transactions, scoring| { transactions.cull(ready, scoring) }); @@ -329,7 +364,7 @@ impl Pool where } /// Removes all stalled transactions from given sender list (or from all senders). - pub fn cull>(&mut self, senders: Option<&[Sender]>, mut ready: R) -> usize { + pub fn cull>(&mut self, senders: Option<&[T::Sender]>, mut ready: R) -> usize { let mut removed = 0; match senders { Some(senders) => { @@ -349,13 +384,13 @@ impl Pool where } /// Returns a transaction if it's part of the pool or `None` otherwise. - pub fn find(&self, hash: &H256) -> Option> { - self.by_hash.get(hash).cloned() + pub fn find(&self, hash: &T::Hash) -> Option> { + self.by_hash.get(hash).map(|t| t.transaction.clone()) } /// Returns worst transaction in the queue (if any). pub fn worst_transaction(&self) -> Option> { - self.worst_transactions.iter().next().map(|x| x.transaction.clone()) + self.worst_transactions.iter().next().map(|x| x.transaction.transaction.clone()) } /// Returns an iterator of pending (ready) transactions. @@ -368,7 +403,7 @@ impl Pool where } /// Returns pending (ready) transactions from given sender. - pub fn pending_from_sender>(&self, ready: R, sender: &Sender) -> PendingIterator { + pub fn pending_from_sender>(&self, ready: R, sender: &T::Sender) -> PendingIterator { let best_transactions = self.transactions.get(sender) .and_then(|transactions| transactions.worst_and_best()) .map(|(_, best)| ScoreWithRef::new(best.0, best.1)) @@ -387,7 +422,7 @@ impl Pool where } /// Update score of transactions of a particular sender. - pub fn update_scores(&mut self, sender: &Sender, event: S::Event) { + pub fn update_scores(&mut self, sender: &T::Sender, event: S::Event) { let res = if let Some(set) = self.transactions.get_mut(sender) { let prev = set.worst_and_best(); set.update_scores(&self.scoring, event); @@ -410,7 +445,7 @@ impl Pool where let len = transactions.len(); for (idx, tx) in transactions.iter().enumerate() { match ready.is_ready(tx) { - Readiness::Stalled => status.stalled += 1, + Readiness::Stale => status.stalled += 1, Readiness::Ready => status.pending += 1, Readiness::Future => { status.future += len - idx; @@ -485,7 +520,7 @@ impl<'a, T, R, S, L> Iterator for PendingIterator<'a, T, R, S, L> where self.best_transactions.insert(ScoreWithRef::new(score, tx)); } - return Some(best.transaction) + return Some(best.transaction.transaction) }, state => trace!("[{:?}] Ignoring {:?} transaction.", best.transaction.hash(), state), } diff --git a/transaction-pool/src/ready.rs b/transaction-pool/src/ready.rs index 7352444322..aa913a9eb5 100644 --- a/transaction-pool/src/ready.rs +++ b/transaction-pool/src/ready.rs @@ -17,8 +17,8 @@ /// Transaction readiness. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Readiness { - /// The transaction is stalled (and should/will be removed from the pool). - Stalled, + /// The transaction is stale (and should/will be removed from the pool). + Stale, /// The transaction is ready to be included in pending set. Ready, /// The transaction is not yet ready. diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index 4e7a9833a1..2acfb33748 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -17,9 +17,7 @@ //! A transactions ordering abstraction. use std::{cmp, fmt}; -use std::sync::Arc; - -use {VerifiedTransaction}; +use pool::Transaction; /// Represents a decision what to do with /// a new transaction that tries to enter the pool. @@ -98,7 +96,7 @@ pub trait Scoring: fmt::Debug { /// Updates the transaction scores given a list of transactions and a change to previous scoring. /// NOTE: you can safely assume that both slices have the same length. /// (i.e. score at index `i` represents transaction at the same index) - fn update_scores(&self, txs: &[Arc], scores: &mut [Self::Score], change: Change); + fn update_scores(&self, txs: &[Transaction], scores: &mut [Self::Score], change: Change); /// Decides if `new` should push out `old` transaction from the pool. fn should_replace(&self, old: &T, new: &T) -> bool; @@ -110,7 +108,14 @@ pub struct ScoreWithRef { /// Score pub score: S, /// Shared transaction - pub transaction: Arc, + pub transaction: Transaction, +} + +impl ScoreWithRef { + /// Creates a new `ScoreWithRef` + pub fn new(score: S, transaction: Transaction) -> Self { + ScoreWithRef { score, transaction } + } } impl Clone for ScoreWithRef { @@ -122,30 +127,23 @@ impl Clone for ScoreWithRef { } } -impl ScoreWithRef { - /// Creates a new `ScoreWithRef` - pub fn new(score: S, transaction: Arc) -> Self { - ScoreWithRef { score, transaction } - } -} - -impl Ord for ScoreWithRef { +impl Ord for ScoreWithRef { fn cmp(&self, other: &Self) -> cmp::Ordering { other.score.cmp(&self.score) - .then(other.transaction.insertion_id().cmp(&self.transaction.insertion_id())) + .then(other.transaction.insertion_id.cmp(&self.transaction.insertion_id)) } } -impl PartialOrd for ScoreWithRef { +impl PartialOrd for ScoreWithRef { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl PartialEq for ScoreWithRef { +impl PartialEq for ScoreWithRef { fn eq(&self, other: &Self) -> bool { - self.score == other.score && self.transaction.insertion_id() == other.transaction.insertion_id() + self.score == other.score && self.transaction.insertion_id == other.transaction.insertion_id } } -impl Eq for ScoreWithRef {} +impl Eq for ScoreWithRef {} diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index ab5b2a334b..cfc6641b5e 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -17,9 +17,9 @@ use std::cmp; use std::collections::HashMap; -use ethereum_types::U256; -use {scoring, Scoring, Ready, Readiness, Address as Sender}; -use super::{Transaction, SharedTransaction}; +use ethereum_types::{H160 as Sender, U256}; +use {pool, scoring, Scoring, Ready, Readiness}; +use super::Transaction; #[derive(Debug, Default)] pub struct DummyScoring; @@ -44,7 +44,7 @@ impl Scoring for DummyScoring { } } - fn update_scores(&self, txs: &[SharedTransaction], scores: &mut [Self::Score], change: scoring::Change) { + fn update_scores(&self, txs: &[pool::Transaction], scores: &mut [Self::Score], change: scoring::Change) { if let scoring::Change::Event(_) = change { // In case of event reset all scores to 0 for i in 0..txs.len() { @@ -84,7 +84,7 @@ impl Ready for NonceReady { *nonce = *nonce + 1.into(); Readiness::Ready }, - cmp::Ordering::Less => Readiness::Stalled, + cmp::Ordering::Less => Readiness::Stale, } } } diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index 5113a4663c..b21ea31807 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -32,15 +32,16 @@ pub struct Transaction { pub gas_price: U256, pub gas: U256, pub sender: Address, - pub insertion_id: u64, pub mem_usage: usize, } impl VerifiedTransaction for Transaction { + type Hash = H256; + type Sender = Address; + fn hash(&self) -> &H256 { &self.hash } fn mem_usage(&self) -> usize { self.mem_usage } fn sender(&self) -> &Address { &self.sender } - fn insertion_id(&self) -> u64 { self.insertion_id } } pub type SharedTransaction = Arc; @@ -123,7 +124,7 @@ fn should_reject_if_above_count() { // Reject second let tx1 = b.tx().nonce(0).new(); let tx2 = b.tx().nonce(1).new(); - let hash = *tx2.hash(); + let hash = format!("{:?}", tx2.hash()); txq.import(tx1).unwrap(); assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); @@ -149,7 +150,7 @@ fn should_reject_if_above_mem_usage() { // Reject second let tx1 = b.tx().nonce(1).mem_usage(1).new(); let tx2 = b.tx().nonce(2).mem_usage(2).new(); - let hash = *tx2.hash(); + let hash = format!("{:?}", tx2.hash()); txq.import(tx1).unwrap(); assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); @@ -175,7 +176,7 @@ fn should_reject_if_above_sender_count() { // Reject second let tx1 = b.tx().nonce(1).new(); let tx2 = b.tx().nonce(2).new(); - let hash = *tx2.hash(); + let hash = format!("{:x}", tx2.hash()); txq.import(tx1).unwrap(); assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); assert_eq!(txq.light_status().transaction_count, 1); @@ -185,7 +186,7 @@ fn should_reject_if_above_sender_count() { // Replace first let tx1 = b.tx().nonce(1).new(); let tx2 = b.tx().nonce(2).gas_price(2).new(); - let hash = *tx2.hash(); + let hash = format!("{:x}", tx2.hash()); txq.import(tx1).unwrap(); // This results in error because we also compare nonces assert_eq!(txq.import(tx2).unwrap_err().kind(), &error::ErrorKind::TooCheapToEnter(hash, "0x0".into())); diff --git a/transaction-pool/src/tests/tx_builder.rs b/transaction-pool/src/tests/tx_builder.rs index e9c1c1d5fc..88a881aca8 100644 --- a/transaction-pool/src/tests/tx_builder.rs +++ b/transaction-pool/src/tests/tx_builder.rs @@ -14,9 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::rc::Rc; -use std::cell::Cell; - use super::{Transaction, U256, Address}; #[derive(Debug, Default, Clone)] @@ -26,7 +23,6 @@ pub struct TransactionBuilder { gas: U256, sender: Address, mem_usage: usize, - insertion_id: Rc>, } impl TransactionBuilder { @@ -55,11 +51,6 @@ impl TransactionBuilder { } pub fn new(self) -> Transaction { - let insertion_id = { - let id = self.insertion_id.get() + 1; - self.insertion_id.set(id); - id - }; let hash = self.nonce ^ (U256::from(100) * self.gas_price) ^ (U256::from(100_000) * U256::from(self.sender.low_u64())); Transaction { hash: hash.into(), @@ -67,7 +58,6 @@ impl TransactionBuilder { gas_price: self.gas_price, gas: 21_000.into(), sender: self.sender, - insertion_id, mem_usage: self.mem_usage, } } diff --git a/transaction-pool/src/transactions.rs b/transaction-pool/src/transactions.rs index c839d9e685..f1a91ff4f8 100644 --- a/transaction-pool/src/transactions.rs +++ b/transaction-pool/src/transactions.rs @@ -15,28 +15,28 @@ // along with Parity. If not, see . use std::{fmt, mem}; -use std::sync::Arc; use smallvec::SmallVec; use ready::{Ready, Readiness}; use scoring::{self, Scoring}; +use pool::Transaction; #[derive(Debug)] pub enum AddResult { - Ok(Arc), + Ok(T), TooCheapToEnter(T, S), TooCheap { - old: Arc, + old: T, new: T, }, Replaced { - old: Arc, - new: Arc, + old: T, + new: T, }, PushedOut { - old: Arc, - new: Arc, + old: T, + new: T, }, } @@ -45,7 +45,7 @@ const PER_SENDER: usize = 8; #[derive(Debug)] pub struct Transactions> { // TODO [ToDr] Consider using something that doesn't require shifting all records. - transactions: SmallVec<[Arc; PER_SENDER]>, + transactions: SmallVec<[Transaction; PER_SENDER]>, scores: SmallVec<[S::Score; PER_SENDER]>, } @@ -67,11 +67,11 @@ impl> Transactions { self.transactions.len() } - pub fn iter(&self) -> ::std::slice::Iter> { + pub fn iter(&self) -> ::std::slice::Iter> { self.transactions.iter() } - pub fn worst_and_best(&self) -> Option<((S::Score, Arc), (S::Score, Arc))> { + pub fn worst_and_best(&self) -> Option<((S::Score, Transaction), (S::Score, Transaction))> { let len = self.scores.len(); self.scores.get(0).cloned().map(|best| { let worst = self.scores[len - 1].clone(); @@ -82,7 +82,7 @@ impl> Transactions { }) } - pub fn find_next(&self, tx: &T, scoring: &S) -> Option<(S::Score, Arc)> { + pub fn find_next(&self, tx: &T, scoring: &S) -> Option<(S::Score, Transaction)> { self.transactions.binary_search_by(|old| scoring.compare(old, &tx)).ok().and_then(|index| { let index = index + 1; if index < self.scores.len() { @@ -93,18 +93,17 @@ impl> Transactions { }) } - fn push_cheapest_transaction(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { + fn push_cheapest_transaction(&mut self, tx: Transaction, scoring: &S, max_count: usize) -> AddResult, S::Score> { let index = self.transactions.len(); if index == max_count { let min_score = self.scores[index - 1].clone(); AddResult::TooCheapToEnter(tx, min_score) } else { - let shared = Arc::new(tx); - self.transactions.push(shared.clone()); + self.transactions.push(tx.clone()); self.scores.push(Default::default()); scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::InsertedAt(index)); - AddResult::Ok(shared) + AddResult::Ok(tx) } } @@ -112,28 +111,26 @@ impl> Transactions { scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::Event(event)); } - pub fn add(&mut self, tx: T, scoring: &S, max_count: usize) -> AddResult { - let index = match self.transactions.binary_search_by(|old| scoring.compare(old, &tx)) { + pub fn add(&mut self, new: Transaction, scoring: &S, max_count: usize) -> AddResult, S::Score> { + let index = match self.transactions.binary_search_by(|old| scoring.compare(old, &new)) { Ok(index) => index, Err(index) => index, }; // Insert at the end. if index == self.transactions.len() { - return self.push_cheapest_transaction(tx, scoring, max_count) + return self.push_cheapest_transaction(new, scoring, max_count) } // Decide if the transaction should replace some other. - match scoring.choose(&self.transactions[index], &tx) { + match scoring.choose(&self.transactions[index], &new) { // New transaction should be rejected scoring::Choice::RejectNew => AddResult::TooCheap { old: self.transactions[index].clone(), - new: tx, + new, }, // New transaction should be kept along with old ones. scoring::Choice::InsertNew => { - let new = Arc::new(tx); - self.transactions.insert(index, new.clone()); self.scores.insert(index, Default::default()); scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::InsertedAt(index)); @@ -153,7 +150,6 @@ impl> Transactions { }, // New transaction is replacing some other transaction already in the queue. scoring::Choice::ReplaceOld => { - let new = Arc::new(tx); let old = mem::replace(&mut self.transactions[index], new.clone()); scoring.update_scores(&self.transactions, &mut self.scores, scoring::Change::ReplacedAt(index)); @@ -181,7 +177,7 @@ impl> Transactions { return true; } - pub fn cull>(&mut self, ready: &mut R, scoring: &S) -> SmallVec<[Arc; PER_SENDER]> { + pub fn cull>(&mut self, ready: &mut R, scoring: &S) -> SmallVec<[Transaction; PER_SENDER]> { let mut result = SmallVec::new(); if self.is_empty() { return result; @@ -190,7 +186,7 @@ impl> Transactions { let mut first_non_stalled = 0; for tx in &self.transactions { match ready.is_ready(tx) { - Readiness::Stalled => { + Readiness::Stale => { first_non_stalled += 1; }, Readiness::Ready | Readiness::Future => break, -- GitLab From b10094508f3a149830199ed35ea5ad7850a43603 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 2 May 2018 15:40:27 +0800 Subject: [PATCH 117/263] Fetching logs by hash in blockchain database (#8463) * Fetch logs by hash in blockchain database * Fix tests * Add unit test for branch block logs fetching * Add docs that blocks must already be sorted * Handle branch block cases properly * typo: empty -> is_empty * Remove return_empty_if_none by using a closure * Use BTreeSet to avoid sorting again * Move is_canon to BlockChain * typo: pass value by reference * Use loop and wrap inside blocks to simplify the code Borrowed from https://github.com/paritytech/parity/pull/8463#discussion_r183453326 * typo: missed a comment --- ethcore/src/blockchain/blockchain.rs | 60 ++++++++++++++-- ethcore/src/client/client.rs | 91 +++++++++++++++++++----- ethcore/src/verification/verification.rs | 2 +- 3 files changed, 129 insertions(+), 24 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 6ad8bf8111..57bcdf2bc2 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -57,6 +57,12 @@ pub trait BlockProvider { /// (though not necessarily a part of the canon chain). fn is_known(&self, hash: &H256) -> bool; + /// Returns true if the given block is known and in the canon chain. + fn is_canon(&self, hash: &H256) -> bool { + let is_canon = || Some(hash == &self.block_hash(self.block_number(hash)?)?); + is_canon().unwrap_or(false) + } + /// Get the first block of the best part of the chain. /// Return `None` if there is no gap and the first block is the genesis. /// Any queries of blocks which precede this one are not guaranteed to @@ -148,7 +154,7 @@ pub trait BlockProvider { fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec; /// Returns logs matching given filter. - fn logs(&self, blocks: Vec, matches: F, limit: Option) -> Vec + fn logs(&self, blocks: Vec, matches: F, limit: Option) -> Vec where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized; } @@ -332,16 +338,18 @@ impl BlockProvider for BlockChain { .collect() } - fn logs(&self, mut blocks: Vec, matches: F, limit: Option) -> Vec + /// Returns logs matching given filter. The order of logs returned will be the same as the order of the blocks + /// provided. And it's the callers responsibility to sort blocks provided in advance. + fn logs(&self, mut blocks: Vec, matches: F, limit: Option) -> Vec where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized { // sort in reverse order - blocks.sort_by(|a, b| b.cmp(a)); + blocks.reverse(); let mut logs = blocks .chunks(128) .flat_map(move |blocks_chunk| { blocks_chunk.into_par_iter() - .filter_map(|number| self.block_hash(*number).map(|hash| (*number, hash))) + .filter_map(|hash| self.block_number(&hash).map(|r| (r, hash))) .filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts))) .filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes()))) .flat_map(|(number, hash, mut receipts, mut hashes)| { @@ -368,7 +376,7 @@ impl BlockProvider for BlockChain { .enumerate() .map(move |(i, log)| LocalizedLogEntry { entry: log, - block_hash: hash, + block_hash: *hash, block_number: number, transaction_hash: tx_hash, // iterating in reverse order @@ -1933,17 +1941,33 @@ mod tests { value: 103.into(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), }.sign(&secret(), None); + let t4 = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Create, + value: 104.into(), + data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), + }.sign(&secret(), None); let tx_hash1 = t1.hash(); let tx_hash2 = t2.hash(); let tx_hash3 = t3.hash(); + let tx_hash4 = t4.hash(); let genesis = BlockBuilder::genesis(); let b1 = genesis.add_block_with_transactions(vec![t1, t2]); let b2 = b1.add_block_with_transactions(iter::once(t3)); + let b3 = genesis.add_block_with(|| BlockOptions { + transactions: vec![t4.clone()], + difficulty: U256::from(9), + ..Default::default() + }); // Branch block let b1_hash = b1.last().hash(); let b1_number = b1.last().number(); let b2_hash = b2.last().hash(); let b2_number = b2.last().number(); + let b3_hash = b3.last().hash(); + let b3_number = b3.last().number(); let db = new_db(); let bc = new_chain(&genesis.last().encoded(), db.clone()); @@ -1974,10 +1998,21 @@ mod tests { ], } ]); + insert_block(&db, &bc, &b3.last().encoded(), vec![ + Receipt { + outcome: TransactionOutcome::StateRoot(H256::default()), + gas_used: 10_000.into(), + log_bloom: Default::default(), + logs: vec![ + LogEntry { address: Default::default(), topics: vec![], data: vec![5], }, + ], + } + ]); // when - let logs1 = bc.logs(vec![1, 2], |_| true, None); - let logs2 = bc.logs(vec![1, 2], |_| true, Some(1)); + let logs1 = bc.logs(vec![b1_hash, b2_hash], |_| true, None); + let logs2 = bc.logs(vec![b1_hash, b2_hash], |_| true, Some(1)); + let logs3 = bc.logs(vec![b3_hash], |_| true, None); // then assert_eq!(logs1, vec![ @@ -2029,6 +2064,17 @@ mod tests { log_index: 0, } ]); + assert_eq!(logs3, vec![ + LocalizedLogEntry { + entry: LogEntry { address: Default::default(), topics: vec![], data: vec![5] }, + block_hash: b3_hash, + block_number: b3_number, + transaction_hash: tx_hash4, + transaction_index: 0, + transaction_log_index: 0, + log_index: 0, + } + ]); } #[test] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index bc20de3dd8..5efdef3a4d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; +use std::collections::{HashSet, HashMap, BTreeMap, BTreeSet, VecDeque}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; @@ -1848,23 +1848,82 @@ impl BlockChainClient for Client { } fn logs(&self, filter: Filter) -> Vec { - let (from, to) = match (self.block_number_ref(&filter.from_block), self.block_number_ref(&filter.to_block)) { - (Some(from), Some(to)) => (from, to), - _ => return Vec::new(), - }; + // Wrap the logic inside a closure so that we can take advantage of question mark syntax. + let fetch_logs = || { + let chain = self.chain.read(); - let chain = self.chain.read(); - let blocks = filter.bloom_possibilities().iter() - .map(move |bloom| { - chain.blocks_with_bloom(bloom, from, to) - }) - .flat_map(|m| m) - // remove duplicate elements - .collect::>() - .into_iter() - .collect::>(); + // First, check whether `filter.from_block` and `filter.to_block` is on the canon chain. If so, we can use the + // optimized version. + let is_canon = |id| { + match id { + // If it is referred by number, then it is always on the canon chain. + &BlockId::Earliest | &BlockId::Latest | &BlockId::Number(_) => true, + // If it is referred by hash, we see whether a hash -> number -> hash conversion gives us the same + // result. + &BlockId::Hash(ref hash) => chain.is_canon(hash), + } + }; + + let blocks = if is_canon(&filter.from_block) && is_canon(&filter.to_block) { + // If we are on the canon chain, use bloom filter to fetch required hashes. + let from = self.block_number_ref(&filter.from_block)?; + let to = self.block_number_ref(&filter.to_block)?; + + filter.bloom_possibilities().iter() + .map(|bloom| { + chain.blocks_with_bloom(bloom, from, to) + }) + .flat_map(|m| m) + // remove duplicate elements + .collect::>() + .into_iter() + .filter_map(|n| chain.block_hash(n)) + .collect::>() + + } else { + // Otherwise, we use a slower version that finds a link between from_block and to_block. + let from_hash = Self::block_hash(&chain, filter.from_block)?; + let from_number = chain.block_number(&from_hash)?; + let to_hash = Self::block_hash(&chain, filter.from_block)?; + + let blooms = filter.bloom_possibilities(); + let bloom_match = |header: &encoded::Header| { + blooms.iter().any(|bloom| header.log_bloom().contains_bloom(bloom)) + }; + + let (blocks, last_hash) = { + let mut blocks = Vec::new(); + let mut current_hash = to_hash; + + loop { + let header = chain.block_header_data(¤t_hash)?; + if bloom_match(&header) { + blocks.push(current_hash); + } + + // Stop if `from` block is reached. + if header.number() <= from_number { + break; + } + current_hash = header.parent_hash(); + } + + blocks.reverse(); + (blocks, current_hash) + }; + + // Check if we've actually reached the expected `from` block. + if last_hash != from_hash || blocks.is_empty() { + return None; + } + + blocks + }; + + Some(self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit)) + }; - self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit) + fetch_logs().unwrap_or_default() } fn filter_traces(&self, filter: TraceFilter) -> Option> { diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 814a12aadf..92f3e77f90 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -476,7 +476,7 @@ mod tests { unimplemented!() } - fn logs(&self, _blocks: Vec, _matches: F, _limit: Option) -> Vec + fn logs(&self, _blocks: Vec, _matches: F, _limit: Option) -> Vec where F: Fn(&LogEntry) -> bool, Self: Sized { unimplemented!() } -- GitLab From eec7364760e760c798e744bba7c05f2ae9dd700a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 2 May 2018 22:47:53 +0800 Subject: [PATCH 118/263] Pass on storage keys tracing to handle the case when it is not modified (#8491) * Pass on storage keys even if it is not modified * typo: account and storage query `to_pod_diff` builds both `touched_addresses` merge and storage keys merge. * Fix tests * Use state query directly because of suicided accounts * Fix a RefCell borrow issue * Add tests for unmodified storage trace * Address grumbles * typo: remove unwanted empty line * ensure_cached compiles with the original signature --- ethcore/src/state/mod.rs | 114 +++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 27 deletions(-) diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 9fd3fd8525..255dce5b5d 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -21,7 +21,7 @@ use std::cell::{RefCell, RefMut}; use std::collections::hash_map::Entry; -use std::collections::{HashMap, BTreeMap, HashSet}; +use std::collections::{HashMap, BTreeMap, BTreeSet, HashSet}; use std::fmt; use std::sync::Arc; use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY}; @@ -862,40 +862,65 @@ impl State { })) } - // Return a list of all touched addresses in cache. - fn touched_addresses(&self) -> Vec
{ + /// Populate a PodAccount map from this state, with another state as the account and storage query. + pub fn to_pod_diff(&mut self, query: &State) -> trie::Result { assert!(self.checkpoints.borrow().is_empty()); - self.cache.borrow().iter().map(|(add, _)| *add).collect() - } - fn query_pod(&mut self, query: &PodState, touched_addresses: &[Address]) -> trie::Result<()> { - let pod = query.get(); + // Merge PodAccount::to_pod for cache of self and `query`. + let all_addresses = self.cache.borrow().keys().cloned() + .chain(query.cache.borrow().keys().cloned()) + .collect::>(); + + Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: trie::Result<_>, address| { + let mut m = m?; + + let account = self.ensure_cached(&address, RequireCache::Code, true, |acc| { + acc.map(|acc| { + // Merge all modified storage keys. + let all_keys = { + let self_keys = acc.storage_changes().keys().cloned() + .collect::>(); + + if let Some(ref query_storage) = query.cache.borrow().get(&address) + .and_then(|opt| { + Some(opt.account.as_ref()?.storage_changes().keys().cloned() + .collect::>()) + }) + { + self_keys.union(&query_storage).cloned().collect::>() + } else { + self_keys.into_iter().collect::>() + } + }; - for address in touched_addresses { - if !self.ensure_cached(address, RequireCache::Code, true, |a| a.is_some())? { - continue - } + // Storage must be fetched after ensure_cached to avoid borrow problem. + (*acc.balance(), *acc.nonce(), all_keys, acc.code().map(|x| x.to_vec())) + }) + })?; - if let Some(pod_account) = pod.get(address) { - // needs to be split into two parts for the refcell code here - // to work. - for key in pod_account.storage.keys() { - self.storage_at(address, key)?; - } + if let Some((balance, nonce, storage_keys, code)) = account { + let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: trie::Result<_>, key| { + let mut s = s?; + + s.insert(key, self.storage_at(&address, &key)?); + Ok(s) + })?; + + m.insert(address, PodAccount { + balance, nonce, storage, code + }); } - } - Ok(()) + Ok(m) + })?)) } /// Returns a `StateDiff` describing the difference from `orig` to `self`. /// Consumes self. - pub fn diff_from(&self, orig: State) -> trie::Result { - let addresses_post = self.touched_addresses(); + pub fn diff_from(&self, mut orig: State) -> trie::Result { let pod_state_post = self.to_pod(); - let mut state_pre = orig; - state_pre.query_pod(&pod_state_post, &addresses_post)?; - Ok(pod_state::diff_pod(&state_pre.to_pod(), &pod_state_post)) + let pod_state_pre = orig.to_pod_diff(self)?; + Ok(pod_state::diff_pod(&pod_state_pre, &pod_state_post)) } // load required account data from the databases. @@ -2243,9 +2268,6 @@ mod tests { let original = state.clone(); state.kill_account(&a); - assert_eq!(original.touched_addresses(), vec![]); - assert_eq!(state.touched_addresses(), vec![a]); - let diff = state.diff_from(original).unwrap(); let diff_map = diff.get(); assert_eq!(diff_map.len(), 1); @@ -2258,4 +2280,42 @@ mod tests { storage: Default::default() }), None).as_ref()); } + + #[test] + fn should_trace_diff_unmodified_storage() { + use pod_account; + + let a = 10.into(); + let db = get_temp_state_db(); + + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64))).unwrap(); + state.commit().unwrap(); + state.drop() + }; + + let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + let original = state.clone(); + state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64))).unwrap(); + + let diff = state.diff_from(original).unwrap(); + let diff_map = diff.get(); + assert_eq!(diff_map.len(), 1); + assert!(diff_map.get(&a).is_some()); + assert_eq!(diff_map.get(&a), + pod_account::diff_pod(Some(&PodAccount { + balance: U256::zero(), + nonce: U256::zero(), + code: Some(Default::default()), + storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64)))] + .into_iter().collect(), + }), Some(&PodAccount { + balance: U256::zero(), + nonce: U256::zero(), + code: Some(Default::default()), + storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64)))] + .into_iter().collect(), + })).as_ref()); + } } -- GitLab From 66c0638f3bddd262e4de19eb565413f82fda08fb Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 3 May 2018 08:01:13 +0100 Subject: [PATCH 119/263] Don't panic in import_block if invalid rlp (#8522) * Don't panic in import_block if invalid rlp * Remove redundant type annotation * Replace RLP header view usage with safe decoding Using the view will panic with invalid RLP. Here we use Rlp decoding directly which will return a `Result<_, DecoderError>`. While this path currently should not have any invalid RLP - it makes it safer if ever called with invalid RLP from other code paths. --- ethcore/src/client/client.rs | 14 ++++++-------- ethcore/src/error.rs | 2 ++ ethcore/src/tests/client.rs | 20 ++++++++++++++++++++ ethcore/src/verification/queue/kind.rs | 9 ++++----- ethcore/src/verification/queue/mod.rs | 23 ++++++++++++++--------- 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 5efdef3a4d..a37d62a591 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -447,9 +447,7 @@ impl Importer { /// /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. - fn import_old_block(&self, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { - let block = view!(BlockView, &block_bytes); - let header = block.header(); + fn import_old_block(&self, header: &Header, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { let receipts = ::rlp::decode_list(&receipts_bytes); let hash = header.hash(); let _import_lock = self.import_lock.lock(); @@ -1408,7 +1406,7 @@ impl ImportBlock for Client { use verification::queue::kind::blocks::Unverified; // create unverified block here so the `keccak` calculation can be cached. - let unverified = Unverified::new(bytes); + let unverified = Unverified::from_rlp(bytes)?; { if self.chain.read().is_known(&unverified.hash()) { @@ -1423,19 +1421,19 @@ impl ImportBlock for Client { } fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { + let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; { // check block order - let header = view!(BlockView, &block_bytes).header_view(); if self.chain.read().is_known(&header.hash()) { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } - let status = self.block_status(BlockId::Hash(header.parent_hash())); + let status = self.block_status(BlockId::Hash(*header.parent_hash())); if status == BlockStatus::Unknown || status == BlockStatus::Pending { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(header.parent_hash()))); + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); } } - self.importer.import_old_block(block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into) + self.importer.import_old_block(&header, block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into) } } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index b68bf35534..561701e762 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -190,6 +190,7 @@ error_chain! { foreign_links { Block(BlockError) #[doc = "Block error"]; + Decoder(::rlp::DecoderError) #[doc = "Rlp decoding error"]; } errors { @@ -206,6 +207,7 @@ impl From for BlockImportError { match e { Error(ErrorKind::Block(block_error), _) => BlockImportErrorKind::Block(block_error).into(), Error(ErrorKind::Import(import_error), _) => BlockImportErrorKind::Import(import_error.into()).into(), + Error(ErrorKind::Util(util_error::ErrorKind::Decoder(decoder_err)), _) => BlockImportErrorKind::Decoder(decoder_err).into(), _ => BlockImportErrorKind::Other(format!("other block import error: {:?}", e)).into(), } } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 0b8200e938..6dcad9ba62 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -36,6 +36,7 @@ use views::BlockView; use ethkey::KeyPair; use transaction::{PendingTransaction, Transaction, Action, Condition}; use miner::MinerService; +use rlp::{RlpStream, EMPTY_LIST_RLP}; use tempdir::TempDir; #[test] @@ -111,6 +112,25 @@ fn imports_good_block() { assert!(!block.into_inner().is_empty()); } +#[test] +fn fails_to_import_block_with_invalid_rlp() { + use error::{BlockImportError, BlockImportErrorKind}; + + let client = generate_dummy_client(6); + let mut rlp = RlpStream::new_list(3); + rlp.append_raw(&EMPTY_LIST_RLP, 1); // empty header + rlp.append_raw(&EMPTY_LIST_RLP, 1); + rlp.append_raw(&EMPTY_LIST_RLP, 1); + let invalid_header_block = rlp.out(); + + match client.import_block(invalid_header_block) { + Err(BlockImportError(BlockImportErrorKind::Decoder(_), _)) => (), // all good + Err(_) => panic!("Should fail with a decoder error"), + Ok(_) => panic!("Should not import block with invalid header"), + } +} + + #[test] fn query_none_block() { let tempdir = TempDir::new("").unwrap(); diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index 7007da5be1..ce9bddf4ef 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -119,14 +119,13 @@ pub mod blocks { impl Unverified { /// Create an `Unverified` from raw bytes. - pub fn new(bytes: Bytes) -> Self { - use views::BlockView; + pub fn from_rlp(bytes: Bytes) -> Result { - let header = view!(BlockView, &bytes).header(); - Unverified { + let header = ::rlp::Rlp::new(&bytes).val_at(0)?; + Ok(Unverified { header: header, bytes: bytes, - } + }) } } diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index ca633b0f3d..f7a558f33d 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -734,6 +734,7 @@ mod tests { use test_helpers::{get_good_dummy_block_seq, get_good_dummy_block}; use error::*; use views::BlockView; + use bytes::Bytes; // create a test block queue. // auto_scaling enables verifier adjustment. @@ -746,6 +747,10 @@ mod tests { BlockQueue::new(config, engine, IoChannel::disconnected(), true) } + fn new_unverified(bytes: Bytes) -> Unverified { + Unverified::from_rlp(bytes).expect("Should be valid rlp") + } + #[test] fn can_be_created() { // TODO better test @@ -757,7 +762,7 @@ mod tests { #[test] fn can_import_blocks() { let queue = get_test_queue(false); - if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { + if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) { panic!("error importing block that is valid by definition({:?})", e); } } @@ -765,11 +770,11 @@ mod tests { #[test] fn returns_error_for_duplicates() { let queue = get_test_queue(false); - if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { + if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) { panic!("error importing block that is valid by definition({:?})", e); } - let duplicate_import = queue.import(Unverified::new(get_good_dummy_block())); + let duplicate_import = queue.import(new_unverified(get_good_dummy_block())); match duplicate_import { Err(e) => { match e { @@ -786,7 +791,7 @@ mod tests { let queue = get_test_queue(false); let block = get_good_dummy_block(); let hash = view!(BlockView, &block).header().hash().clone(); - if let Err(e) = queue.import(Unverified::new(block)) { + if let Err(e) = queue.import(new_unverified(block)) { panic!("error importing block that is valid by definition({:?})", e); } queue.flush(); @@ -802,14 +807,14 @@ mod tests { let queue = get_test_queue(false); let block = get_good_dummy_block(); let hash = view!(BlockView, &block).header().hash().clone(); - if let Err(e) = queue.import(Unverified::new(block)) { + if let Err(e) = queue.import(new_unverified(block)) { panic!("error importing block that is valid by definition({:?})", e); } queue.flush(); queue.drain(10); queue.mark_as_good(&[ hash ]); - if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) { + if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) { panic!("error importing block that has already been drained ({:?})", e); } } @@ -817,7 +822,7 @@ mod tests { #[test] fn returns_empty_once_finished() { let queue = get_test_queue(false); - queue.import(Unverified::new(get_good_dummy_block())) + queue.import(new_unverified(get_good_dummy_block())) .expect("error importing block that is valid by definition"); queue.flush(); queue.drain(1); @@ -835,7 +840,7 @@ mod tests { assert!(!queue.queue_info().is_full()); let mut blocks = get_good_dummy_block_seq(50); for b in blocks.drain(..) { - queue.import(Unverified::new(b)).unwrap(); + queue.import(new_unverified(b)).unwrap(); } assert!(queue.queue_info().is_full()); } @@ -863,7 +868,7 @@ mod tests { *queue.state.0.lock() = State::Work(0); for block in get_good_dummy_block_seq(5000) { - queue.import(Unverified::new(block)).expect("Block good by definition; qed"); + queue.import(new_unverified(block)).expect("Block good by definition; qed"); } // almost all unverified == bump verifier count. -- GitLab From f0c6d17ad81636d3ca02e1694d5ffe39941ad425 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 4 May 2018 10:06:54 +0200 Subject: [PATCH 120/263] Remove expect (#8536) * Remove expect and propagate rlp::DecoderErrors as TrieErrors --- util/patricia_trie/src/lib.rs | 8 ++++++++ util/patricia_trie/src/lookup.rs | 2 +- util/patricia_trie/src/triedb.rs | 27 +++++++++++++++++++++++++++ util/rlp/src/error.rs | 2 +- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/util/patricia_trie/src/lib.rs b/util/patricia_trie/src/lib.rs index 3a1d683c26..d1563becff 100644 --- a/util/patricia_trie/src/lib.rs +++ b/util/patricia_trie/src/lib.rs @@ -67,6 +67,8 @@ pub enum TrieError { InvalidStateRoot(H256), /// Trie item not found in the database, IncompleteDatabase(H256), + /// Corrupt Trie item + DecoderError(rlp::DecoderError), } impl fmt::Display for TrieError { @@ -75,6 +77,7 @@ impl fmt::Display for TrieError { TrieError::InvalidStateRoot(ref root) => write!(f, "Invalid state root: {}", root), TrieError::IncompleteDatabase(ref missing) => write!(f, "Database missing expected key: {}", missing), + TrieError::DecoderError(ref err) => write!(f, "Decoding failed with {}", err), } } } @@ -84,10 +87,15 @@ impl error::Error for TrieError { match *self { TrieError::InvalidStateRoot(_) => "Invalid state root", TrieError::IncompleteDatabase(_) => "Incomplete database", + TrieError::DecoderError(ref e) => e.description(), } } } +impl From for Box { + fn from(e: rlp::DecoderError) -> Self { Box::new(TrieError::DecoderError(e)) } +} + /// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries. pub type Result = ::std::result::Result>; diff --git a/util/patricia_trie/src/lookup.rs b/util/patricia_trie/src/lookup.rs index 88d2bc66e0..2d63f7d00e 100644 --- a/util/patricia_trie/src/lookup.rs +++ b/util/patricia_trie/src/lookup.rs @@ -55,7 +55,7 @@ impl<'a, Q: Query> Lookup<'a, Q> { // without incrementing the depth. let mut node_data = &node_data[..]; loop { - match Node::decoded(node_data).expect("rlp read from db; qed") { + match Node::decoded(node_data)? { Node::Leaf(slice, value) => { return Ok(match slice == key { true => Some(self.query.decode(value)), diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index 682f12467d..aed683117d 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -493,3 +493,30 @@ fn get_len() { assert_eq!(t.get_with(b"B", |x: &[u8]| x.len()), Ok(Some(5))); assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None)); } + +// Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking +//#[test] +//fn test_lookup_with_corrupt_data_returns_decoder_error() { +// use memorydb::*; +// use super::TrieMut; +// use super::triedbmut::*; +// use rlp; +// use ethereum_types::H512; +// +// let mut memdb = MemoryDB::new(); +// let mut root = H256::new(); +// { +// let mut t = TrieDBMut::new(&mut memdb, &mut root); +// t.insert(b"A", b"ABC").unwrap(); +// t.insert(b"B", b"ABCBA").unwrap(); +// } +// +// let t = TrieDB::new(&memdb, &root).unwrap(); +// +// // query for an invalid data type to trigger an error +// let q = rlp::decode::; +// let lookup = Lookup{ db: t.db, query: q, hash: root }; +// let query_result = lookup.look_up(NibbleSlice::new(b"A")); +// let expected = Box::new(TrieError::DecoderError(::rlp::DecoderError::RlpIsTooShort)); +// assert_eq!(query_result.unwrap_err(), expected); +//} diff --git a/util/rlp/src/error.rs b/util/rlp/src/error.rs index 5113fdc17d..7aef6cfbf7 100644 --- a/util/rlp/src/error.rs +++ b/util/rlp/src/error.rs @@ -9,7 +9,7 @@ use std::fmt; use std::error::Error as StdError; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone)] /// Error concerning the RLP decoder. pub enum DecoderError { /// Data has additional bytes at the end of the valid RLP fragment. -- GitLab From a4c7843a073cceecf3d2adb8df26e96aa2e6bb6e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 5 May 2018 16:23:50 +0800 Subject: [PATCH 121/263] EIP 145: Bitwise shifting instructions in EVM (#8451) * Add SHL, SHR, SAR opcodes * Add have_bitwise_shifting schedule flag * Add all EIP tests for SHL * Add SHR implementation and tests * Implement SAR and add tests * Add eip145transition config param * Change map_or to map_or_else when possible --- ethcore/evm/src/instructions.rs | 10 +- ethcore/evm/src/interpreter/mod.rs | 55 +++++- ethcore/evm/src/tests.rs | 268 ++++++++++++++++++++++++++++- ethcore/src/spec/spec.rs | 39 +++-- ethcore/vm/src/schedule.rs | 12 +- ethcore/vm/src/tests.rs | 7 + json/src/spec/params.rs | 3 + 7 files changed, 374 insertions(+), 20 deletions(-) diff --git a/ethcore/evm/src/instructions.rs b/ethcore/evm/src/instructions.rs index 3fb9fb9339..6ecfc7f673 100644 --- a/ethcore/evm/src/instructions.rs +++ b/ethcore/evm/src/instructions.rs @@ -187,6 +187,9 @@ lazy_static! { arr[OR as usize] = InstructionInfo::new("OR", 2, 1, GasPriceTier::VeryLow); arr[XOR as usize] = InstructionInfo::new("XOR", 2, 1, GasPriceTier::VeryLow); arr[BYTE as usize] = InstructionInfo::new("BYTE", 2, 1, GasPriceTier::VeryLow); + arr[SHL as usize] = InstructionInfo::new("SHL", 2, 1, GasPriceTier::VeryLow); + arr[SHR as usize] = InstructionInfo::new("SHR", 2, 1, GasPriceTier::VeryLow); + arr[SAR as usize] = InstructionInfo::new("SAR", 2, 1, GasPriceTier::VeryLow); arr[ADDMOD as usize] = InstructionInfo::new("ADDMOD", 3, 1, GasPriceTier::Mid); arr[MULMOD as usize] = InstructionInfo::new("MULMOD", 3, 1, GasPriceTier::Mid); arr[SIGNEXTEND as usize] = InstructionInfo::new("SIGNEXTEND", 2, 1, GasPriceTier::Low); @@ -354,6 +357,12 @@ pub const XOR: Instruction = 0x18; pub const NOT: Instruction = 0x19; /// retrieve single byte from word pub const BYTE: Instruction = 0x1a; +/// shift left operation +pub const SHL: Instruction = 0x1b; +/// logical shift right operation +pub const SHR: Instruction = 0x1c; +/// arithmetic shift right operation +pub const SAR: Instruction = 0x1d; /// compute SHA3-256 hash pub const SHA3: Instruction = 0x20; @@ -589,4 +598,3 @@ pub const REVERT: Instruction = 0xfd; pub const STATICCALL: Instruction = 0xfa; /// halt execution and register account for later deletion pub const SUICIDE: Instruction = 0xff; - diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 05d1fb7885..160a2e5b1d 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -224,7 +224,8 @@ impl Interpreter { (instruction == instructions::CREATE2 && !schedule.have_create2) || (instruction == instructions::STATICCALL && !schedule.have_static_call) || ((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) || - (instruction == instructions::REVERT && !schedule.have_revert) { + (instruction == instructions::REVERT && !schedule.have_revert) || + ((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) { return Err(vm::Error::BadInstruction { instruction: instruction @@ -871,6 +872,58 @@ impl Interpreter { }); } }, + instructions::SHL => { + const CONST_256: U256 = U256([256, 0, 0, 0]); + + let shift = stack.pop_back(); + let value = stack.pop_back(); + + let result = if shift >= CONST_256 { + U256::zero() + } else { + value << (shift.as_u32() as usize) + }; + stack.push(result); + }, + instructions::SHR => { + const CONST_256: U256 = U256([256, 0, 0, 0]); + + let shift = stack.pop_back(); + let value = stack.pop_back(); + + let result = if shift >= CONST_256 { + U256::zero() + } else { + value >> (shift.as_u32() as usize) + }; + stack.push(result); + }, + instructions::SAR => { + // We cannot use get_and_reset_sign/set_sign here, because the rounding looks different. + + const CONST_256: U256 = U256([256, 0, 0, 0]); + const CONST_HIBIT: U256 = U256([0, 0, 0, 0x8000000000000000]); + + let shift = stack.pop_back(); + let value = stack.pop_back(); + let sign = value & CONST_HIBIT != U256::zero(); + + let result = if shift >= CONST_256 { + if sign { + U256::max_value() + } else { + U256::zero() + } + } else { + let shift = shift.as_u32() as usize; + let mut shifted = value >> shift; + if sign { + shifted = shifted | (U256::max_value() << (256 - shift)); + } + shifted + }; + stack.push(result); + }, _ => { return Err(vm::Error::BadInstruction { instruction: instruction diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index 3758156e21..9058d073e8 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -787,6 +787,273 @@ fn test_create_in_staticcall(factory: super::Factory) { assert_eq!(ext.calls.len(), 0); } +evm_test!{test_shl: test_shl_int} +fn test_shl(factory: super::Factory) { + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "00", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "01", + "0000000000000000000000000000000000000000000000000000000000000002"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "ff", + "8000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000001", + "0101", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "8000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "0000000000000000000000000000000000000000000000000000000000000000", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1b, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); +} + +evm_test!{test_shr: test_shr_int} +fn test_shr(factory: super::Factory) { + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "0000000000000000000000000000000000000000000000000000000000000001", + "00", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "0000000000000000000000000000000000000000000000000000000000000001", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "01", + "4000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "ff", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "8000000000000000000000000000000000000000000000000000000000000000", + "0101", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1c, + "0000000000000000000000000000000000000000000000000000000000000000", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); +} + +evm_test!{test_sar: test_sar_int} +fn test_sar(factory: super::Factory) { + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "0000000000000000000000000000000000000000000000000000000000000001", + "00", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "0000000000000000000000000000000000000000000000000000000000000001", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "01", + "c000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "ff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "0100", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "8000000000000000000000000000000000000000000000000000000000000000", + "0101", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "0000000000000000000000000000000000000000000000000000000000000000", + "01", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "4000000000000000000000000000000000000000000000000000000000000000", + "fe", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "f8", + "000000000000000000000000000000000000000000000000000000000000007f"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "fe", + "0000000000000000000000000000000000000000000000000000000000000001"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ff", + "0000000000000000000000000000000000000000000000000000000000000000"); + push_two_pop_one_constantinople_test( + &factory, + 0x1d, + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0100", + "0000000000000000000000000000000000000000000000000000000000000000"); +} + +fn push_two_pop_one_constantinople_test(factory: &super::Factory, opcode: u8, push1: &str, push2: &str, result: &str) { + let mut push1 = push1.from_hex().unwrap(); + let mut push2 = push2.from_hex().unwrap(); + assert!(push1.len() <= 32 && push1.len() != 0); + assert!(push2.len() <= 32 && push2.len() != 0); + + let mut code = Vec::new(); + code.push(0x60 + ((push1.len() - 1) as u8)); + code.append(&mut push1); + code.push(0x60 + ((push2.len() - 1) as u8)); + code.append(&mut push2); + code.push(opcode); + code.append(&mut vec![0x60, 0x00, 0x55]); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + let mut ext = FakeExt::new_constantinople(); + + let _ = { + let mut vm = factory.create(¶ms.gas); + test_finalize(vm.exec(params, &mut ext)).unwrap() + }; + + assert_store(&ext, 0, result); +} + fn assert_set_contains(set: &HashSet, val: &T) { let contains = set.contains(val); if !contains { @@ -799,4 +1066,3 @@ fn assert_set_contains(set: &HashSet, val: fn assert_store(ext: &FakeExt, pos: u64, val: &str) { assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap()); } - diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 156ab8f15a..ef69f4847b 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -105,6 +105,8 @@ pub struct CommonParams { pub eip211_transition: BlockNumber, /// Number of first block where EIP-214 rules begin. pub eip214_transition: BlockNumber, + /// Number of first block where EIP-145 rules begin. + pub eip145_transition: BlockNumber, /// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin. pub dust_protection_transition: BlockNumber, /// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled. @@ -152,6 +154,7 @@ impl CommonParams { schedule.have_revert = block_number >= self.eip140_transition; schedule.have_static_call = block_number >= self.eip214_transition; schedule.have_return_data = block_number >= self.eip211_transition; + schedule.have_bitwise_shifting = block_number >= self.eip145_transition; if block_number >= self.eip210_transition { schedule.blockhash_gas = 800; } @@ -198,16 +201,16 @@ impl From for CommonParams { eip155_transition: p.eip155_transition.map_or(0, Into::into), validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into), validate_chain_id_transition: p.validate_chain_id_transition.map_or(0, Into::into), - eip86_transition: p.eip86_transition.map_or( - BlockNumber::max_value(), + eip86_transition: p.eip86_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip140_transition: p.eip140_transition.map_or( - BlockNumber::max_value(), + eip140_transition: p.eip140_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip210_transition: p.eip210_transition.map_or( - BlockNumber::max_value(), + eip210_transition: p.eip210_transition.map_or_else( + BlockNumber::max_value, Into::into, ), eip210_contract_address: p.eip210_contract_address.map_or(0xf0.into(), Into::into), @@ -220,20 +223,24 @@ impl From for CommonParams { Into::into, ), eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into), - eip211_transition: p.eip211_transition.map_or( - BlockNumber::max_value(), + eip211_transition: p.eip211_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip214_transition: p.eip214_transition.map_or( - BlockNumber::max_value(), + eip145_transition: p.eip145_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - eip658_transition: p.eip658_transition.map_or( - BlockNumber::max_value(), + eip214_transition: p.eip214_transition.map_or_else( + BlockNumber::max_value, Into::into, ), - dust_protection_transition: p.dust_protection_transition.map_or( - BlockNumber::max_value(), + eip658_transition: p.eip658_transition.map_or_else( + BlockNumber::max_value, + Into::into, + ), + dust_protection_transition: p.dust_protection_transition.map_or_else( + BlockNumber::max_value, Into::into, ), nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into), @@ -245,8 +252,8 @@ impl From for CommonParams { max_transaction_size: p.max_transaction_size.map_or(MAX_TRANSACTION_SIZE, Into::into), max_code_size_transition: p.max_code_size_transition.map_or(0, Into::into), transaction_permission_contract: p.transaction_permission_contract.map(Into::into), - wasm_activation_transition: p.wasm_activation_transition.map_or( - BlockNumber::max_value(), + wasm_activation_transition: p.wasm_activation_transition.map_or_else( + BlockNumber::max_value, Into::into ), } diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index 6cfabed0df..a0085ef1ec 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -109,6 +109,8 @@ pub struct Schedule { pub have_static_call: bool, /// RETURNDATA and RETURNDATASIZE opcodes enabled. pub have_return_data: bool, + /// SHL, SHR, SAR opcodes enabled. + pub have_bitwise_shifting: bool, /// Kill basic accounts below this balance if touched. pub kill_dust: CleanDustMode, /// Enable EIP-86 rules @@ -194,6 +196,7 @@ impl Schedule { have_create2: false, have_revert: false, have_return_data: false, + have_bitwise_shifting: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -250,6 +253,13 @@ impl Schedule { schedule } + /// Schedule for the Constantinople fork of the Ethereum main net. + pub fn new_constantinople() -> Schedule { + let mut schedule = Self::new_byzantium(); + schedule.have_bitwise_shifting = true; + schedule + } + fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { Schedule { exceptional_failed_code_deposit: efcd, @@ -257,6 +267,7 @@ impl Schedule { have_create2: false, have_revert: false, have_return_data: false, + have_bitwise_shifting: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -328,4 +339,3 @@ fn schedule_evm_assumptions() { assert_eq!(s1.quad_coeff_div, 512); assert_eq!(s2.quad_coeff_div, 512); } - diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index ce47121458..daf46be0f0 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -88,6 +88,13 @@ impl FakeExt { ext } + /// New fake externalities with constantinople schedule rules + pub fn new_constantinople() -> Self { + let mut ext = FakeExt::default(); + ext.schedule = Schedule::new_constantinople(); + ext + } + /// Alter fake externalities to allow wasm pub fn with_wasm(mut self) -> Self { self.schedule.wasm = Some(Default::default()); diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index ce47086df1..0addf52e4a 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -85,6 +85,9 @@ pub struct Params { #[serde(rename="eip211Transition")] pub eip211_transition: Option, /// See `CommonParams` docs. + #[serde(rename="eip145Transition")] + pub eip145_transition: Option, + /// See `CommonParams` docs. #[serde(rename="eip214Transition")] pub eip214_transition: Option, /// See `CommonParams` docs. -- GitLab From e30839e85ff74cd5eb087ef19a48d70afd1fd285 Mon Sep 17 00:00:00 2001 From: Toralf Wittner Date: Sat, 5 May 2018 11:02:33 +0200 Subject: [PATCH 122/263] Consolidate crypto functionality in `ethcore-crypto`. (#8432) * Consolidate crypto functionality in `ethcore-crypto`. - Move `ecdh`/`ecies` modules to `ethkey`. - Refactor `ethcore-crypto` to use file per module. - Replace `subtle` with `ethcore_crypto::is_equal`. - Add `aes_gcm` module to `ethcore-crypto`. * Rename `aes::{encrypt,decrypt,decrypt_cbc}` ... ... to `aes::{encrypt_128_ctr,decrypt_128_ctr,decrypt_128_cbc}`. --- Cargo.lock | 26 +- ethcore/Cargo.toml | 2 +- ethcore/benches/evm.rs | 9 +- ethcore/crypto/Cargo.toml | 10 +- ethcore/crypto/src/aes.rs | 54 ++++ ethcore/crypto/src/aes_gcm.rs | 199 ++++++++++++ ethcore/crypto/src/digest.rs | 109 +++++++ ethcore/crypto/src/error.rs | 83 +++++ ethcore/crypto/src/hmac.rs | 89 ++++++ ethcore/crypto/src/lib.rs | 299 +----------------- ethcore/crypto/src/pbkdf2.rs | 29 ++ ethcore/crypto/src/scrypt.rs | 39 +++ ethcore/private-tx/src/encryptor.rs | 7 +- ethcore/src/builtin.rs | 25 +- ethcore/src/lib.rs | 2 +- ethkey/Cargo.toml | 3 +- ethkey/src/crypto.rs | 189 +++++++++++ ethkey/src/extended.rs | 22 +- ethkey/src/lib.rs | 5 +- ethstore/Cargo.toml | 2 - ethstore/src/account/crypto.rs | 29 +- ethstore/src/account/safe_account.rs | 25 +- ethstore/src/accounts_dir/disk.rs | 6 +- ethstore/src/accounts_dir/vault.rs | 2 +- ethstore/src/error.rs | 25 +- ethstore/src/ethstore.rs | 2 +- ethstore/src/lib.rs | 2 - ethstore/src/presale.rs | 15 +- rpc/Cargo.toml | 1 - rpc/src/lib.rs | 1 - rpc/src/v1/helpers/ipfs.rs | 12 +- rpc/src/v1/helpers/secretstore.rs | 8 +- rpc/src/v1/impls/light/parity.rs | 4 +- rpc/src/v1/impls/parity.rs | 4 +- secret_store/src/key_server.rs | 35 +- .../client_sessions/decryption_session.rs | 4 +- .../src/key_server_cluster/io/handshake.rs | 2 +- .../src/key_server_cluster/io/message.rs | 4 +- .../key_server_cluster/jobs/decryption_job.rs | 2 +- secret_store/src/node_key_pair.rs | 5 +- secret_store/src/types/error.rs | 8 +- util/network-devp2p/src/connection.rs | 2 +- util/network-devp2p/src/handshake.rs | 2 +- util/network/src/error.rs | 16 +- whisper/Cargo.toml | 1 - whisper/src/lib.rs | 1 - whisper/src/rpc/crypto.rs | 109 ++----- whisper/src/rpc/filter.rs | 2 +- whisper/src/rpc/key_store.rs | 9 +- whisper/src/rpc/mod.rs | 4 +- 50 files changed, 1003 insertions(+), 542 deletions(-) create mode 100644 ethcore/crypto/src/aes.rs create mode 100644 ethcore/crypto/src/aes_gcm.rs create mode 100644 ethcore/crypto/src/digest.rs create mode 100644 ethcore/crypto/src/error.rs create mode 100644 ethcore/crypto/src/hmac.rs create mode 100644 ethcore/crypto/src/pbkdf2.rs create mode 100644 ethcore/crypto/src/scrypt.rs create mode 100644 ethkey/src/crypto.rs diff --git a/Cargo.lock b/Cargo.lock index 741cc3832c..ceb14ff277 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -509,6 +509,7 @@ dependencies = [ "ethash 1.12.0", "ethcore-bloom-journal 0.1.0", "ethcore-bytes 0.1.0", + "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", "ethcore-logger 1.12.0", "ethcore-miner 1.12.0", @@ -545,7 +546,6 @@ dependencies = [ "rlp 0.2.1", "rlp_compress 0.1.0", "rlp_derive 0.1.0", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", "stats 0.1.0", @@ -576,11 +576,10 @@ version = "0.1.0" name = "ethcore-crypto" version = "0.1.0" dependencies = [ - "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethkey 0.3.0", + "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -925,13 +924,14 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", + "ethcore-crypto 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -966,13 +966,11 @@ dependencies = [ "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2197,7 +2195,6 @@ dependencies = [ "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2362,7 +2359,6 @@ dependencies = [ "ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rlp 0.2.1", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2621,6 +2617,11 @@ dependencies = [ "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quick-error" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quote" version = "0.5.1" @@ -3035,11 +3036,6 @@ name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "subtle" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "syn" version = "0.13.1" @@ -3927,6 +3923,7 @@ dependencies = [ "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" +"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" @@ -3973,7 +3970,6 @@ dependencies = [ "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" "checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e" "checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 147d9484c7..71c84a293f 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -20,6 +20,7 @@ fetch = { path = "../util/fetch" } hashdb = { path = "../util/hashdb" } memorydb = { path = "../util/memorydb" } patricia-trie = { path = "../util/patricia_trie" } +ethcore-crypto = { path = "crypto" } error-chain = { version = "0.11", default-features = false } ethcore-io = { path = "../util/io" } ethcore-logger = { path = "../logger" } @@ -56,7 +57,6 @@ util-error = { path = "../util/error" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } macros = { path = "../util/macros" } -rust-crypto = "0.2.34" rustc-hex = "1.0" stats = { path = "../util/stats" } trace-time = { path = "../util/trace-time" } diff --git a/ethcore/benches/evm.rs b/ethcore/benches/evm.rs index 324e3382e5..9fe2657d61 100644 --- a/ethcore/benches/evm.rs +++ b/ethcore/benches/evm.rs @@ -20,7 +20,7 @@ extern crate test; extern crate ethcore_util as util; extern crate rand; extern crate bn; -extern crate crypto; +extern crate ethcore_crypto; extern crate ethkey; extern crate rustc_hex; extern crate ethcore_bigint; @@ -61,16 +61,13 @@ fn bn_128_mul(b: &mut Bencher) { #[bench] fn sha256(b: &mut Bencher) { - use crypto::sha2::Sha256; - use crypto::digest::Digest; + use ethcore_crypto::digest::sha256; let mut input: [u8; 256] = [0; 256]; let mut out = [0; 32]; b.iter(|| { - let mut sha = Sha256::new(); - sha.input(&input); - sha.result(&mut input[0..32]); + sha256(&input); }); } diff --git a/ethcore/crypto/Cargo.toml b/ethcore/crypto/Cargo.toml index c3a2191b55..4fe023f25c 100644 --- a/ethcore/crypto/Cargo.toml +++ b/ethcore/crypto/Cargo.toml @@ -4,13 +4,9 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] +ethereum-types = "0.3" +quick-error = "1.2" +ring = "0.12" rust-crypto = "0.2.36" tiny-keccak = "1.3" -eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true } -ethkey = { path = "../../ethkey", optional = true } -ethereum-types = "0.3" -subtle = "0.5" -[features] -default = ["secp256k1"] -secp256k1 = ["eth-secp256k1", "ethkey"] diff --git a/ethcore/crypto/src/aes.rs b/ethcore/crypto/src/aes.rs new file mode 100644 index 0000000000..79a8dcc86d --- /dev/null +++ b/ethcore/crypto/src/aes.rs @@ -0,0 +1,54 @@ +// 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 . + +use error::SymmError; +use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; +use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; +use rcrypto::symmetriccipher::{Encryptor, Decryptor}; +use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer}; + +/// Encrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); + encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true)?; + Ok(()) +} + +/// Decrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); + encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)?; + Ok(()) +} + +/// Decrypt a message (CBC mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result { + let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); + let len = dest.len(); + let mut buffer = RefWriteBuffer::new(dest); + encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; + Ok(len - buffer.remaining()) +} + diff --git a/ethcore/crypto/src/aes_gcm.rs b/ethcore/crypto/src/aes_gcm.rs new file mode 100644 index 0000000000..178b5d1e12 --- /dev/null +++ b/ethcore/crypto/src/aes_gcm.rs @@ -0,0 +1,199 @@ +// 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 . + +use error::SymmError; +use ring; + +enum Mode { Aes128Gcm, Aes256Gcm } + +/// AES GCM encryptor. +pub struct Encryptor<'a> { + mode: Mode, + key: ring::aead::SealingKey, + ad: &'a [u8], + offset: usize, +} + +impl<'a> Encryptor<'a> { + pub fn aes_128_gcm(key: &[u8; 16]) -> Result, SymmError> { + let sk = ring::aead::SealingKey::new(&ring::aead::AES_128_GCM, key)?; + Ok(Encryptor { + mode: Mode::Aes128Gcm, + key: sk, + ad: &[], + offset: 0, + }) + } + + pub fn aes_256_gcm(key: &[u8; 32]) -> Result, SymmError> { + let sk = ring::aead::SealingKey::new(&ring::aead::AES_256_GCM, key)?; + Ok(Encryptor { + mode: Mode::Aes256Gcm, + key: sk, + ad: &[], + offset: 0, + }) + } + + /// Optional associated data which is not encrypted but authenticated. + pub fn associate(&mut self, data: &'a [u8]) -> &mut Self { + self.ad = data; + self + } + + /// Optional offset value. Only the slice `[offset..]` will be encrypted. + pub fn offset(&mut self, off: usize) -> &mut Self { + self.offset = off; + self + } + + /// Please note that the pair (key, nonce) must never be reused. Using random nonces + /// limits the number of messages encrypted with the same key to 2^32 (cf. [[1]]) + /// + /// [1]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf + pub fn encrypt(&self, nonce: &[u8; 12], mut data: Vec) -> Result, SymmError> { + if self.offset > data.len() { + return Err(SymmError::offset_error(self.offset)) + } + let tag_len = match self.mode { + Mode::Aes128Gcm => ring::aead::AES_128_GCM.tag_len(), + Mode::Aes256Gcm => ring::aead::AES_256_GCM.tag_len(), + }; + data.extend(::std::iter::repeat(0).take(tag_len)); + let len = ring::aead::seal_in_place(&self.key, nonce, self.ad, &mut data[self.offset ..], tag_len)?; + data.truncate(self.offset + len); + Ok(data) + } +} + +/// AES GCM decryptor. +pub struct Decryptor<'a> { + key: ring::aead::OpeningKey, + ad: &'a [u8], + offset: usize, +} + +impl<'a> Decryptor<'a> { + pub fn aes_128_gcm(key: &[u8; 16]) -> Result, SymmError> { + let ok = ring::aead::OpeningKey::new(&ring::aead::AES_128_GCM, key)?; + Ok(Decryptor { + key: ok, + ad: &[], + offset: 0, + }) + } + + pub fn aes_256_gcm(key: &[u8; 32]) -> Result, SymmError> { + let ok = ring::aead::OpeningKey::new(&ring::aead::AES_256_GCM, key)?; + Ok(Decryptor { + key: ok, + ad: &[], + offset: 0, + }) + } + + /// Optional associated data which is not encrypted but authenticated. + pub fn associate(&mut self, data: &'a [u8]) -> &mut Self { + self.ad = data; + self + } + + /// Optional offset value. Only the slice `[offset..]` will be decrypted. + pub fn offset(&mut self, off: usize) -> &mut Self { + self.offset = off; + self + } + + pub fn decrypt(&self, nonce: &[u8; 12], mut data: Vec) -> Result, SymmError> { + if self.offset > data.len() { + return Err(SymmError::offset_error(self.offset)) + } + let len = ring::aead::open_in_place(&self.key, nonce, self.ad, 0, &mut data[self.offset ..])?.len(); + data.truncate(self.offset + len); + Ok(data) + } +} + +#[cfg(test)] +mod tests { + use super::{Encryptor, Decryptor}; + + #[test] + fn aes_gcm_128() { + let secret = b"1234567890123456"; + let nonce = b"123456789012"; + let message = b"So many books, so little time"; + + let ciphertext = Encryptor::aes_128_gcm(secret) + .unwrap() + .encrypt(nonce, message.to_vec()) + .unwrap(); + + assert!(ciphertext != message); + + let plaintext = Decryptor::aes_128_gcm(secret) + .unwrap() + .decrypt(nonce, ciphertext) + .unwrap(); + + assert_eq!(plaintext, message) + } + + #[test] + fn aes_gcm_256() { + let secret = b"12345678901234567890123456789012"; + let nonce = b"123456789012"; + let message = b"So many books, so little time"; + + let ciphertext = Encryptor::aes_256_gcm(secret) + .unwrap() + .encrypt(nonce, message.to_vec()) + .unwrap(); + + assert!(ciphertext != message); + + let plaintext = Decryptor::aes_256_gcm(secret) + .unwrap() + .decrypt(nonce, ciphertext) + .unwrap(); + + assert_eq!(plaintext, message) + } + + #[test] + fn aes_gcm_256_offset() { + let secret = b"12345678901234567890123456789012"; + let nonce = b"123456789012"; + let message = b"prefix data; So many books, so little time"; + + let ciphertext = Encryptor::aes_256_gcm(secret) + .unwrap() + .offset(13) // length of "prefix data; " + .encrypt(nonce, message.to_vec()) + .unwrap(); + + assert!(ciphertext != &message[..]); + + let plaintext = Decryptor::aes_256_gcm(secret) + .unwrap() + .offset(13) // length of "prefix data; " + .decrypt(nonce, ciphertext) + .unwrap(); + + assert_eq!(plaintext, &message[..]) + } +} + diff --git a/ethcore/crypto/src/digest.rs b/ethcore/crypto/src/digest.rs new file mode 100644 index 0000000000..095a8ca262 --- /dev/null +++ b/ethcore/crypto/src/digest.rs @@ -0,0 +1,109 @@ +// Copyright 2018 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 . + +use rcrypto::ripemd160; +use ring::digest::{self, Context, SHA256, SHA512}; +use std::marker::PhantomData; +use std::ops::Deref; + +/// The message digest. +pub struct Digest(InnerDigest, PhantomData); + +enum InnerDigest { + Ring(digest::Digest), + Ripemd160([u8; 20]), +} + +impl Deref for Digest { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + match self.0 { + InnerDigest::Ring(ref d) => d.as_ref(), + InnerDigest::Ripemd160(ref d) => &d[..] + } + } +} + +/// Single-step sha256 digest computation. +pub fn sha256(data: &[u8]) -> Digest { + Digest(InnerDigest::Ring(digest::digest(&SHA256, data)), PhantomData) +} + +/// Single-step sha512 digest computation. +pub fn sha512(data: &[u8]) -> Digest { + Digest(InnerDigest::Ring(digest::digest(&SHA512, data)), PhantomData) +} + +/// Single-step ripemd160 digest computation. +pub fn ripemd160(data: &[u8]) -> Digest { + let mut hasher = Hasher::ripemd160(); + hasher.update(data); + hasher.finish() +} + +pub enum Sha256 {} +pub enum Sha512 {} +pub enum Ripemd160 {} + +/// Stateful digest computation. +pub struct Hasher(Inner, PhantomData); + +enum Inner { + Ring(Context), + Ripemd160(ripemd160::Ripemd160) +} + +impl Hasher { + pub fn sha256() -> Hasher { + Hasher(Inner::Ring(Context::new(&SHA256)), PhantomData) + } +} + +impl Hasher { + pub fn sha512() -> Hasher { + Hasher(Inner::Ring(Context::new(&SHA512)), PhantomData) + } +} + +impl Hasher { + pub fn ripemd160() -> Hasher { + Hasher(Inner::Ripemd160(ripemd160::Ripemd160::new()), PhantomData) + } +} + +impl Hasher { + pub fn update(&mut self, data: &[u8]) { + match self.0 { + Inner::Ring(ref mut ctx) => ctx.update(data), + Inner::Ripemd160(ref mut ctx) => { + use rcrypto::digest::Digest; + ctx.input(data) + } + } + } + + pub fn finish(self) -> Digest { + match self.0 { + Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData), + Inner::Ripemd160(mut ctx) => { + use rcrypto::digest::Digest; + let mut d = [0; 20]; + ctx.result(&mut d); + Digest(InnerDigest::Ripemd160(d), PhantomData) + } + } + } +} diff --git a/ethcore/crypto/src/error.rs b/ethcore/crypto/src/error.rs new file mode 100644 index 0000000000..4de3b80036 --- /dev/null +++ b/ethcore/crypto/src/error.rs @@ -0,0 +1,83 @@ +// 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 . + +use rcrypto; +use ring; + +quick_error! { + #[derive(Debug)] + pub enum Error { + Scrypt(e: ScryptError) { + cause(e) + from() + } + Symm(e: SymmError) { + cause(e) + from() + } + } +} + +quick_error! { + #[derive(Debug)] + pub enum ScryptError { + // log(N) < r / 16 + InvalidN { + display("Invalid N argument of the scrypt encryption") + } + // p <= (2^31-1 * 32)/(128 * r) + InvalidP { + display("Invalid p argument of the scrypt encryption") + } + } +} + +quick_error! { + #[derive(Debug)] + pub enum SymmError wraps PrivSymmErr { + RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) { + display("symmetric crypto error") + from() + } + Ring(e: ring::error::Unspecified) { + display("symmetric crypto error") + cause(e) + from() + } + Offset(x: usize) { + display("offset {} greater than slice length", x) + } + } +} + +impl SymmError { + pub(crate) fn offset_error(x: usize) -> SymmError { + SymmError(PrivSymmErr::Offset(x)) + } +} + +impl From for SymmError { + fn from(e: ring::error::Unspecified) -> SymmError { + SymmError(PrivSymmErr::Ring(e)) + } +} + +impl From for SymmError { + fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError { + SymmError(PrivSymmErr::RustCrypto(e)) + } +} + diff --git a/ethcore/crypto/src/hmac.rs b/ethcore/crypto/src/hmac.rs new file mode 100644 index 0000000000..7327250442 --- /dev/null +++ b/ethcore/crypto/src/hmac.rs @@ -0,0 +1,89 @@ +// Copyright 2018 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 . + +use digest; +use ring::digest::{SHA256, SHA512}; +use ring::hmac::{self, SigningContext}; +use std::marker::PhantomData; +use std::ops::Deref; + +/// HMAC signature. +pub struct Signature(hmac::Signature, PhantomData); + +impl Deref for Signature { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + self.0.as_ref() + } +} + +/// HMAC signing key. +pub struct SigKey(hmac::SigningKey, PhantomData); + +impl SigKey { + pub fn sha256(key: &[u8]) -> SigKey { + SigKey(hmac::SigningKey::new(&SHA256, key), PhantomData) + } +} + +impl SigKey { + pub fn sha512(key: &[u8]) -> SigKey { + SigKey(hmac::SigningKey::new(&SHA512, key), PhantomData) + } +} + +/// Compute HMAC signature of `data`. +pub fn sign(k: &SigKey, data: &[u8]) -> Signature { + Signature(hmac::sign(&k.0, data), PhantomData) +} + +/// Stateful HMAC computation. +pub struct Signer(SigningContext, PhantomData); + +impl Signer { + pub fn with(key: &SigKey) -> Signer { + Signer(hmac::SigningContext::with_key(&key.0), PhantomData) + } + + pub fn update(&mut self, data: &[u8]) { + self.0.update(data) + } + + pub fn sign(self) -> Signature { + Signature(self.0.sign(), PhantomData) + } +} + +/// HMAC signature verification key. +pub struct VerifyKey(hmac::VerificationKey, PhantomData); + +impl VerifyKey { + pub fn sha256(key: &[u8]) -> VerifyKey { + VerifyKey(hmac::VerificationKey::new(&SHA256, key), PhantomData) + } +} + +impl VerifyKey { + pub fn sha512(key: &[u8]) -> VerifyKey { + VerifyKey(hmac::VerificationKey::new(&SHA512, key), PhantomData) + } +} + +/// Verify HMAC signature of `data`. +pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { + hmac::verify(&k.0, data, sig).is_ok() +} + diff --git a/ethcore/crypto/src/lib.rs b/ethcore/crypto/src/lib.rs index caa4cf77c4..0ee42e3599 100644 --- a/ethcore/crypto/src/lib.rs +++ b/ethcore/crypto/src/lib.rs @@ -18,23 +18,22 @@ extern crate crypto as rcrypto; extern crate ethereum_types; -extern crate subtle; +#[macro_use] +extern crate quick_error; +extern crate ring; extern crate tiny_keccak; -#[cfg(feature = "secp256k1")] -extern crate secp256k1; -#[cfg(feature = "secp256k1")] -extern crate ethkey; +pub mod aes; +pub mod aes_gcm; +pub mod error; +pub mod scrypt; +pub mod digest; +pub mod hmac; +pub mod pbkdf2; -use std::fmt; -use tiny_keccak::Keccak; -use rcrypto::pbkdf2::pbkdf2; -use rcrypto::scrypt::{scrypt, ScryptParams}; -use rcrypto::sha2::Sha256; -use rcrypto::hmac::Hmac; +pub use error::Error; -#[cfg(feature = "secp256k1")] -use secp256k1::Error as SecpError; +use tiny_keccak::Keccak; pub const KEY_LENGTH: usize = 32; pub const KEY_ITERATIONS: usize = 10240; @@ -43,65 +42,6 @@ pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2; /// Default authenticated data to use (in RPC). pub const DEFAULT_MAC: [u8; 2] = [0, 0]; -#[derive(PartialEq, Debug)] -pub enum ScryptError { - // log(N) < r / 16 - InvalidN, - // p <= (2^31-1 * 32)/(128 * r) - InvalidP, -} - -impl fmt::Display for ScryptError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let s = match *self { - ScryptError::InvalidN => "Invalid N argument of the scrypt encryption" , - ScryptError::InvalidP => "Invalid p argument of the scrypt encryption", - }; - - write!(f, "{}", s) - } -} - -#[derive(PartialEq, Debug)] -pub enum Error { - #[cfg(feature = "secp256k1")] - Secp(SecpError), - Scrypt(ScryptError), - InvalidMessage, -} - -impl From for Error { - fn from(err: ScryptError) -> Self { - Error::Scrypt(err) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let s = match *self { - #[cfg(feature = "secp256k1")] - Error::Secp(ref err) => err.to_string(), - Error::Scrypt(ref err) => err.to_string(), - Error::InvalidMessage => "Invalid message".into(), - }; - - write!(f, "{}", s) - } -} - -impl Into for Error { - fn into(self) -> String { - format!("{}", self) - } -} - -#[cfg(feature = "secp256k1")] -impl From for Error { - fn from(e: SecpError) -> Self { - Error::Secp(e) - } -} - pub trait Keccak256 { fn keccak256(&self) -> T where T: Sized; } @@ -117,33 +57,13 @@ impl Keccak256<[u8; 32]> for T where T: AsRef<[u8]> { } pub fn derive_key_iterations(password: &str, salt: &[u8; 32], c: u32) -> (Vec, Vec) { - let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes()); - let mut derived_key = vec![0u8; KEY_LENGTH]; - pbkdf2(&mut h_mac, salt, c, &mut derived_key); + let mut derived_key = [0u8; KEY_LENGTH]; + pbkdf2::sha256(c, pbkdf2::Salt(salt), pbkdf2::Secret(password.as_bytes()), &mut derived_key); let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; (derived_right_bits.to_vec(), derived_left_bits.to_vec()) } -pub fn derive_key_scrypt(password: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), Error> { - // sanity checks - let log_n = (32 - n.leading_zeros() - 1) as u8; - if log_n as u32 >= r * 16 { - return Err(Error::Scrypt(ScryptError::InvalidN)); - } - - if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) { - return Err(Error::Scrypt(ScryptError::InvalidP)); - } - - let mut derived_key = vec![0u8; KEY_LENGTH]; - let scrypt_params = ScryptParams::new(log_n, r, p); - scrypt(password.as_bytes(), salt, &scrypt_params, &mut derived_key); - let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; - let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; - Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) -} - pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { let mut mac = vec![0u8; KEY_LENGTH_AES + cipher_text.len()]; mac[0..KEY_LENGTH_AES].copy_from_slice(derived_left_bits); @@ -151,194 +71,7 @@ pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { mac } -/// AES encryption -pub mod aes { - use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; - use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; - use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError}; - use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer}; - - /// Encrypt a message (CTR mode) - pub fn encrypt(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); - } - - /// Decrypt a message (CTR mode) - pub fn decrypt(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); - } - - - /// Decrypt a message using cbc mode - pub fn decrypt_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result { - let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); - let len = dest.len(); - let mut buffer = RefWriteBuffer::new(dest); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; - Ok(len - buffer.remaining()) - } -} - -/// ECDH functions -#[cfg(feature = "secp256k1")] -pub mod ecdh { - use secp256k1::{ecdh, key, Error as SecpError}; - use ethkey::{Secret, Public, SECP256K1}; - use Error; - - /// Agree on a shared secret - pub fn agree(secret: &Secret, public: &Public) -> Result { - let context = &SECP256K1; - let pdata = { - let mut temp = [4u8; 65]; - (&mut temp[1..65]).copy_from_slice(&public[0..64]); - temp - }; - - let publ = key::PublicKey::from_slice(context, &pdata)?; - let sec = key::SecretKey::from_slice(context, &secret)?; - let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); - - Secret::from_unsafe_slice(&shared[0..32]) - .map_err(|_| Error::Secp(SecpError::InvalidSecretKey)) - } -} - -/// ECIES function -#[cfg(feature = "secp256k1")] -pub mod ecies { - use rcrypto::digest::Digest; - use rcrypto::sha2::Sha256; - use rcrypto::hmac::Hmac; - use rcrypto::mac::Mac; - use ethereum_types::H128; - use ethkey::{Random, Generator, Public, Secret}; - use {Error, ecdh, aes}; - - /// Encrypt a message with a public key, writing an HMAC covering both - /// the plaintext and authenticated data. - /// - /// Authenticated data may be empty. - pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result, Error> { - let r = Random.generate() - .expect("context known to have key-generation capabilities; qed"); - - let z = ecdh::agree(r.secret(), public)?; - let mut key = [0u8; 32]; - let mut mkey = [0u8; 32]; - kdf(&z, &[0u8; 0], &mut key); - let mut hasher = Sha256::new(); - let mkey_material = &key[16..32]; - hasher.input(mkey_material); - hasher.result(&mut mkey); - let ekey = &key[0..16]; - - let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32]; - msg[0] = 0x04u8; - { - let msgd = &mut msg[1..]; - msgd[0..64].copy_from_slice(r.public()); - let iv = H128::random(); - msgd[64..80].copy_from_slice(&iv); - { - let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())]; - aes::encrypt(ekey, &iv, plain, cipher); - } - let mut hmac = Hmac::new(Sha256::new(), &mkey); - { - let cipher_iv = &msgd[64..(64 + 16 + plain.len())]; - hmac.input(cipher_iv); - } - hmac.input(auth_data); - hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]); - } - Ok(msg) - } - - /// Decrypt a message with a secret key, checking HMAC for ciphertext - /// and authenticated data validity. - pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result, Error> { - let meta_len = 1 + 64 + 16 + 32; - if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 { - return Err(Error::InvalidMessage); //invalid message: publickey - } - - let e = &encrypted[1..]; - let p = Public::from_slice(&e[0..64]); - let z = ecdh::agree(secret, &p)?; - let mut key = [0u8; 32]; - kdf(&z, &[0u8; 0], &mut key); - let ekey = &key[0..16]; - let mkey_material = &key[16..32]; - let mut hasher = Sha256::new(); - let mut mkey = [0u8; 32]; - hasher.input(mkey_material); - hasher.result(&mut mkey); - - let clen = encrypted.len() - meta_len; - let cipher_with_iv = &e[64..(64+16+clen)]; - let cipher_iv = &cipher_with_iv[0..16]; - let cipher_no_iv = &cipher_with_iv[16..]; - let msg_mac = &e[(64+16+clen)..]; - - // Verify tag - let mut hmac = Hmac::new(Sha256::new(), &mkey); - hmac.input(cipher_with_iv); - hmac.input(auth_data); - let mut mac = [0u8; 32]; - hmac.raw_result(&mut mac); - - // constant time compare to avoid timing attack. - if ::subtle::slices_equal(&mac[..], msg_mac) != 1 { - return Err(Error::InvalidMessage); - } - - let mut msg = vec![0u8; clen]; - aes::decrypt(ekey, cipher_iv, cipher_no_iv, &mut msg[..]); - Ok(msg) - } - - fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) { - let mut hasher = Sha256::new(); - // SEC/ISO/Shoup specify counter size SHOULD be equivalent - // to size of hash output, however, it also notes that - // the 4 bytes is okay. NIST specifies 4 bytes. - let mut ctr = 1u32; - let mut written = 0usize; - while written < dest.len() { - let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8]; - hasher.input(&ctrs); - hasher.input(secret); - hasher.input(s1); - hasher.result(&mut dest[written..(written + 32)]); - hasher.reset(); - written += 32; - ctr += 1; - } - } -} - -#[cfg(test)] -mod tests { - use ethkey::{Random, Generator}; - use ecies; - - #[test] - fn ecies_shared() { - let kp = Random.generate().unwrap(); - let message = b"So many books, so little time"; - - let shared = b"shared"; - let wrong_shared = b"incorrect"; - let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap(); - assert!(encrypted[..] != message[..]); - assert_eq!(encrypted[0], 0x04); - - assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err()); - let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap(); - assert_eq!(decrypted[..message.len()], message[..]); - } +pub fn is_equal(a: &[u8], b: &[u8]) -> bool { + ring::constant_time::verify_slices_are_equal(a, b).is_ok() } diff --git a/ethcore/crypto/src/pbkdf2.rs b/ethcore/crypto/src/pbkdf2.rs new file mode 100644 index 0000000000..b4c993c513 --- /dev/null +++ b/ethcore/crypto/src/pbkdf2.rs @@ -0,0 +1,29 @@ +// Copyright 2018 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 . + +use ring; + +pub struct Salt<'a>(pub &'a [u8]); +pub struct Secret<'a>(pub &'a [u8]); + +pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { + ring::pbkdf2::derive(&ring::digest::SHA256, iter, salt.0, sec.0, &mut out[..]) +} + +pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { + ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..]) +} + diff --git a/ethcore/crypto/src/scrypt.rs b/ethcore/crypto/src/scrypt.rs new file mode 100644 index 0000000000..684ab2c572 --- /dev/null +++ b/ethcore/crypto/src/scrypt.rs @@ -0,0 +1,39 @@ +// 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 . + +use error::ScryptError; +use rcrypto::scrypt::{scrypt, ScryptParams}; +use super::{KEY_LENGTH_AES, KEY_LENGTH}; + +pub fn derive_key(pass: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), ScryptError> { + // sanity checks + let log_n = (32 - n.leading_zeros() - 1) as u8; + if log_n as u32 >= r * 16 { + return Err(ScryptError::InvalidN); + } + + if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) { + return Err(ScryptError::InvalidP); + } + + let mut derived_key = vec![0u8; KEY_LENGTH]; + let scrypt_params = ScryptParams::new(log_n, r, p); + scrypt(pass.as_bytes(), salt, &scrypt_params, &mut derived_key); + let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; + let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; + Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) +} + diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs index 5d592de603..b15acbee71 100644 --- a/ethcore/private-tx/src/encryptor.rs +++ b/ethcore/private-tx/src/encryptor.rs @@ -217,7 +217,8 @@ impl Encryptor for SecretStoreEncryptor { // encrypt data let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len()); cypher.extend(repeat(0).take(plain_data.len())); - crypto::aes::encrypt(&key, initialisation_vector, plain_data, &mut cypher); + crypto::aes::encrypt_128_ctr(&key, initialisation_vector, plain_data, &mut cypher) + .map_err(|e| ErrorKind::Encrypt(e.to_string()))?; cypher.extend_from_slice(&initialisation_vector); Ok(cypher) @@ -243,8 +244,8 @@ impl Encryptor for SecretStoreEncryptor { let (cypher, iv) = cypher.split_at(cypher_len - INIT_VEC_LEN); let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN); plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN)); - crypto::aes::decrypt(&key, &iv, cypher, &mut plain_data); - + crypto::aes::decrypt_128_ctr(&key, &iv, cypher, &mut plain_data) + .map_err(|e| ErrorKind::Decrypt(e.to_string()))?; Ok(plain_data) } } diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index c18e1f3cd3..a0833cfb5e 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -18,9 +18,7 @@ use std::cmp::{max, min}; use std::io::{self, Read}; use byteorder::{ByteOrder, BigEndian}; -use crypto::sha2::Sha256 as Sha256Digest; -use crypto::ripemd160::Ripemd160 as Ripemd160Digest; -use crypto::digest::Digest; +use ethcore_crypto::digest; use num::{BigUint, Zero, One}; use hash::keccak; @@ -295,28 +293,17 @@ impl Impl for EcRecover { impl Impl for Sha256 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - let mut sha = Sha256Digest::new(); - sha.input(input); - - let mut out = [0; 32]; - sha.result(&mut out); - - output.write(0, &out); - + let d = digest::sha256(input); + output.write(0, &*d); Ok(()) } } impl Impl for Ripemd160 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> { - let mut sha = Ripemd160Digest::new(); - sha.input(input); - - let mut out = [0; 32]; - sha.result(&mut out[12..32]); - - output.write(0, &out); - + let hash = digest::ripemd160(input); + output.write(0, &[0; 12][..]); + output.write(12, &hash); Ok(()) } } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 9bb2e94c1c..b1782cb1d6 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -63,9 +63,9 @@ extern crate bn; extern crate byteorder; extern crate crossbeam; extern crate common_types as types; -extern crate crypto; extern crate ethash; extern crate ethcore_bloom_journal as bloom_journal; +extern crate ethcore_crypto; extern crate ethcore_io as io; extern crate ethcore_bytes as bytes; extern crate ethcore_logger; diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index 335f92fe15..d6698f86d9 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -6,13 +6,14 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.0" edit-distance = "2.0" +ethcore-crypto = { path = "../ethcore/crypto" } eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } ethereum-types = "0.3" lazy_static = "1.0" log = "0.3" mem = { path = "../util/mem" } parity-wordlist = "1.2" +quick-error = "1.2" rand = "0.4" -rust-crypto = "0.2" rustc-hex = "1.0" tiny-keccak = "1.3" diff --git a/ethkey/src/crypto.rs b/ethkey/src/crypto.rs new file mode 100644 index 0000000000..739a463c07 --- /dev/null +++ b/ethkey/src/crypto.rs @@ -0,0 +1,189 @@ +// 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 . + +use secp256k1; +use std::io; +use ethcore_crypto::error::SymmError; + +quick_error! { + #[derive(Debug)] + pub enum Error { + Secp(e: secp256k1::Error) { + display("secp256k1 error: {}", e) + cause(e) + from() + } + Io(e: io::Error) { + display("i/o error: {}", e) + cause(e) + from() + } + InvalidMessage { + display("invalid message") + } + Symm(e: SymmError) { + cause(e) + from() + } + } +} + +/// ECDH functions +pub mod ecdh { + use secp256k1::{self, ecdh, key}; + use super::Error; + use {Secret, Public, SECP256K1}; + + /// Agree on a shared secret + pub fn agree(secret: &Secret, public: &Public) -> Result { + let context = &SECP256K1; + let pdata = { + let mut temp = [4u8; 65]; + (&mut temp[1..65]).copy_from_slice(&public[0..64]); + temp + }; + + let publ = key::PublicKey::from_slice(context, &pdata)?; + let sec = key::SecretKey::from_slice(context, &secret)?; + let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); + + Secret::from_unsafe_slice(&shared[0..32]) + .map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey)) + } +} + +/// ECIES function +pub mod ecies { + use ethcore_crypto::{aes, digest, hmac, is_equal}; + use ethereum_types::H128; + use super::{ecdh, Error}; + use {Random, Generator, Public, Secret}; + + /// Encrypt a message with a public key, writing an HMAC covering both + /// the plaintext and authenticated data. + /// + /// Authenticated data may be empty. + pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result, Error> { + let r = Random.generate()?; + let z = ecdh::agree(r.secret(), public)?; + let mut key = [0u8; 32]; + kdf(&z, &[0u8; 0], &mut key); + + let ekey = &key[0..16]; + let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32])); + + let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32]; + msg[0] = 0x04u8; + { + let msgd = &mut msg[1..]; + msgd[0..64].copy_from_slice(r.public()); + let iv = H128::random(); + msgd[64..80].copy_from_slice(&iv); + { + let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())]; + aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?; + } + let mut hmac = hmac::Signer::with(&mkey); + { + let cipher_iv = &msgd[64..(64 + 16 + plain.len())]; + hmac.update(cipher_iv); + } + hmac.update(auth_data); + let sig = hmac.sign(); + msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig); + } + Ok(msg) + } + + /// Decrypt a message with a secret key, checking HMAC for ciphertext + /// and authenticated data validity. + pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result, Error> { + let meta_len = 1 + 64 + 16 + 32; + if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 { + return Err(Error::InvalidMessage); //invalid message: publickey + } + + let e = &encrypted[1..]; + let p = Public::from_slice(&e[0..64]); + let z = ecdh::agree(secret, &p)?; + let mut key = [0u8; 32]; + kdf(&z, &[0u8; 0], &mut key); + + let ekey = &key[0..16]; + let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32])); + + let clen = encrypted.len() - meta_len; + let cipher_with_iv = &e[64..(64+16+clen)]; + let cipher_iv = &cipher_with_iv[0..16]; + let cipher_no_iv = &cipher_with_iv[16..]; + let msg_mac = &e[(64+16+clen)..]; + + // Verify tag + let mut hmac = hmac::Signer::with(&mkey); + hmac.update(cipher_with_iv); + hmac.update(auth_data); + let mac = hmac.sign(); + + if !is_equal(&mac.as_ref()[..], msg_mac) { + return Err(Error::InvalidMessage); + } + + let mut msg = vec![0u8; clen]; + aes::decrypt_128_ctr(ekey, cipher_iv, cipher_no_iv, &mut msg[..])?; + Ok(msg) + } + + fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) { + // SEC/ISO/Shoup specify counter size SHOULD be equivalent + // to size of hash output, however, it also notes that + // the 4 bytes is okay. NIST specifies 4 bytes. + let mut ctr = 1u32; + let mut written = 0usize; + while written < dest.len() { + let mut hasher = digest::Hasher::sha256(); + let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8]; + hasher.update(&ctrs); + hasher.update(secret); + hasher.update(s1); + let d = hasher.finish(); + &mut dest[written..(written + 32)].copy_from_slice(&d); + written += 32; + ctr += 1; + } + } +} + +#[cfg(test)] +mod tests { + use super::ecies; + use {Random, Generator}; + + #[test] + fn ecies_shared() { + let kp = Random.generate().unwrap(); + let message = b"So many books, so little time"; + + let shared = b"shared"; + let wrong_shared = b"incorrect"; + let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap(); + assert!(encrypted[..] != message[..]); + assert_eq!(encrypted[0], 0x04); + + assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err()); + let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap(); + assert_eq!(decrypted[..message.len()], message[..]); + } +} diff --git a/ethkey/src/extended.rs b/ethkey/src/extended.rs index 55bae62754..d41ae54c53 100644 --- a/ethkey/src/extended.rs +++ b/ethkey/src/extended.rs @@ -207,9 +207,7 @@ impl ExtendedKeyPair { // Work is based on BIP0032 // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki mod derivation { - use rcrypto::hmac::Hmac; - use rcrypto::mac::Mac; - use rcrypto::sha2::Sha512; + use ethcore_crypto::hmac; use ethereum_types::{U256, U512, H512, H256}; use secp256k1::key::{SecretKey, PublicKey}; use SECP256K1; @@ -242,10 +240,8 @@ mod derivation { let private: U256 = private_key.into(); // produces 512-bit derived hmac (I) - let mut hmac = Hmac::new(Sha512::new(), &*chain_code); - let mut i_512 = [0u8; 64]; - hmac.input(&data[..]); - hmac.raw_result(&mut i_512); + let skey = hmac::SigKey::sha512(&*chain_code); + let i_512 = hmac::sign(&skey, &data[..]); // left most 256 bits are later added to original private key let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into(); @@ -321,10 +317,8 @@ mod derivation { index.store(&mut data[33..(33 + T::len())]); // HMAC512SHA produces [derived private(256); new chain code(256)] - let mut hmac = Hmac::new(Sha512::new(), &*chain_code); - let mut i_512 = [0u8; 64]; - hmac.input(&data[..]); - hmac.raw_result(&mut i_512); + let skey = hmac::SigKey::sha512(&*chain_code); + let i_512 = hmac::sign(&skey, &data[..]); let new_private = H256::from(&i_512[0..32]); let new_chain_code = H256::from(&i_512[32..64]); @@ -369,10 +363,8 @@ mod derivation { } pub fn seed_pair(seed: &[u8]) -> (H256, H256) { - let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed"); - let mut i_512 = [0u8; 64]; - hmac.input(seed); - hmac.raw_result(&mut i_512); + let skey = hmac::SigKey::sha512(b"Bitcoin seed"); + let i_512 = hmac::sign(&skey, seed); let master_key = H256::from_slice(&i_512[0..32]); let chain_code = H256::from_slice(&i_512[32..64]); diff --git a/ethkey/src/lib.rs b/ethkey/src/lib.rs index 951179771b..b5cf984530 100644 --- a/ethkey/src/lib.rs +++ b/ethkey/src/lib.rs @@ -17,11 +17,13 @@ // #![warn(missing_docs)] extern crate byteorder; -extern crate crypto as rcrypto; extern crate edit_distance; +extern crate ethcore_crypto; extern crate ethereum_types; extern crate mem; extern crate parity_wordlist; +#[macro_use] +extern crate quick_error; extern crate rand; extern crate rustc_hex; extern crate secp256k1; @@ -44,6 +46,7 @@ mod secret; mod extended; pub mod brain_recover; +pub mod crypto; pub mod math; pub use self::parity_wordlist::Error as WordlistError; diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index d0524baeaf..6330ce97ce 100644 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -12,7 +12,6 @@ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" rustc-hex = "1.0" -rust-crypto = "0.2.36" tiny-keccak = "1.3" time = "0.1.34" itertools = "0.5" @@ -22,7 +21,6 @@ ethereum-types = "0.3" dir = { path = "../util/dir" } smallvec = "0.4" parity-wordlist = "1.0" -subtle = "0.5" tempdir = "0.3" [dev-dependencies] diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs index 967c92306a..bd65bc927b 100644 --- a/ethstore/src/account/crypto.rs +++ b/ethstore/src/account/crypto.rs @@ -21,7 +21,6 @@ use crypto::Keccak256; use random::Random; use smallvec::SmallVec; use account::{Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf}; -use subtle; /// Encrypted data #[derive(Debug, PartialEq, Clone)] @@ -74,12 +73,12 @@ impl From for String { impl Crypto { /// Encrypt account secret - pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self { + pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Result { Crypto::with_plain(&*secret, password, iterations) } /// Encrypt custom plain data - pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Self { + pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Result { let salt: [u8; 32] = Random::random(); let iv: [u8; 16] = Random::random(); @@ -93,12 +92,12 @@ impl Crypto { let mut ciphertext: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; plain_len]); // aes-128-ctr with initial vector of iv - crypto::aes::encrypt(&derived_left_bits, &iv, plain, &mut *ciphertext); + crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext)?; // KECCAK(DK[16..31] ++ ), where DK[16..31] - derived_right_bits let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256(); - Crypto { + Ok(Crypto { cipher: Cipher::Aes128Ctr(Aes128Ctr { iv: iv, }), @@ -110,7 +109,7 @@ impl Crypto { prf: Prf::HmacSha256, }), mac: mac, - } + }) } /// Try to decrypt and convert result to account secret @@ -132,13 +131,13 @@ impl Crypto { fn do_decrypt(&self, password: &str, expected_len: usize) -> Result, Error> { let (derived_left_bits, derived_right_bits) = match self.kdf { Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c), - Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r)?, + Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(password, ¶ms.salt, params.n, params.p, params.r)?, }; let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256(); - if subtle::slices_equal(&mac, &self.mac) == 0 { - return Err(Error::InvalidPassword); + if !crypto::is_equal(&mac, &self.mac) { + return Err(Error::InvalidPassword) } let mut plain: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; expected_len]); @@ -149,7 +148,7 @@ impl Crypto { debug_assert!(expected_len >= self.ciphertext.len()); let from = expected_len - self.ciphertext.len(); - crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..]); + crypto::aes::decrypt_128_ctr(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..])?; Ok(plain.into_iter().collect()) }, } @@ -164,7 +163,7 @@ mod tests { #[test] fn crypto_with_secret_create() { let keypair = Random.generate().unwrap(); - let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240); + let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap(); let secret = crypto.secret("this is sparta").unwrap(); assert_eq!(keypair.secret(), &secret); } @@ -172,14 +171,14 @@ mod tests { #[test] fn crypto_with_secret_invalid_password() { let keypair = Random.generate().unwrap(); - let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240); + let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap(); assert_matches!(crypto.secret("this is sparta!"), Err(Error::InvalidPassword)) } #[test] fn crypto_with_null_plain_data() { let original_data = b""; - let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240); + let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap(); let decrypted_data = crypto.decrypt("this is sparta").unwrap(); assert_eq!(original_data[..], *decrypted_data); } @@ -187,7 +186,7 @@ mod tests { #[test] fn crypto_with_tiny_plain_data() { let original_data = b"{}"; - let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240); + let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap(); let decrypted_data = crypto.decrypt("this is sparta").unwrap(); assert_eq!(original_data[..], *decrypted_data); } @@ -195,7 +194,7 @@ mod tests { #[test] fn crypto_with_huge_plain_data() { let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect(); - let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240); + let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240).unwrap(); let decrypted_data = crypto.decrypt("this is sparta").unwrap(); assert_eq!(&original_data, &decrypted_data); } diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 478b796e64..069c997e10 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -14,10 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::{KeyPair, sign, Address, Signature, Message, Public, Secret}; -use crypto::ecdh::agree; -use {json, Error, crypto}; +use ethkey::{self, KeyPair, sign, Address, Signature, Message, Public, Secret}; +use ethkey::crypto::ecdh::agree; +use {json, Error}; use account::Version; +use crypto; use super::crypto::Crypto; /// Account representation. @@ -61,16 +62,16 @@ impl SafeAccount { iterations: u32, name: String, meta: String - ) -> Self { - SafeAccount { + ) -> Result { + Ok(SafeAccount { id: id, version: Version::V3, - crypto: Crypto::with_secret(keypair.secret(), password, iterations), + crypto: Crypto::with_secret(keypair.secret(), password, iterations)?, address: keypair.address(), filename: None, name: name, meta: meta, - } + }) } /// Create a new `SafeAccount` from the given `json`; if it was read from a @@ -114,7 +115,7 @@ impl SafeAccount { meta: Some(self.meta), }; let meta_plain = meta_plain.write().map_err(|e| Error::Custom(format!("{:?}", e)))?; - let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations); + let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations)?; Ok(json::VaultKeyFile { id: self.id.into(), @@ -133,7 +134,7 @@ impl SafeAccount { /// Decrypt a message. pub fn decrypt(&self, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { let secret = self.crypto.secret(password)?; - crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) + ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) } /// Agree on shared key. @@ -154,7 +155,7 @@ impl SafeAccount { let result = SafeAccount { id: self.id.clone(), version: self.version.clone(), - crypto: Crypto::with_secret(&secret, new_password, iterations), + crypto: Crypto::with_secret(&secret, new_password, iterations)?, address: self.address.clone(), filename: self.filename.clone(), name: self.name.clone(), @@ -180,7 +181,7 @@ mod tests { let password = "hello world"; let message = Message::default(); let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240, "Test".to_owned(), "{}".to_owned()); - let signature = account.sign(password, &message).unwrap(); + let signature = account.unwrap().sign(password, &message).unwrap(); assert!(verify_public(keypair.public(), &signature, &message).unwrap()); } @@ -191,7 +192,7 @@ mod tests { let sec_password = "this is sparta"; let i = 10240; let message = Message::default(); - let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned()); + let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned()).unwrap(); let new_account = account.change_password(first_password, sec_password, i).unwrap(); assert!(account.sign(first_password, &message).is_ok()); assert!(account.sign(sec_password, &message).is_err()); diff --git a/ethstore/src/accounts_dir/disk.rs b/ethstore/src/accounts_dir/disk.rs index 1446118440..29b7e52466 100644 --- a/ethstore/src/accounts_dir/disk.rs +++ b/ethstore/src/accounts_dir/disk.rs @@ -319,7 +319,7 @@ mod test { // when let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); - let res = directory.insert(account); + let res = directory.insert(account.unwrap()); // then assert!(res.is_ok(), "Should save account succesfuly."); @@ -339,7 +339,7 @@ mod test { let directory = RootDiskDirectory::create(dir.clone()).unwrap(); // when - let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); + let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()).unwrap(); let filename = "test".to_string(); let dedup = true; @@ -424,7 +424,7 @@ mod test { let keypair = Random.generate().unwrap(); let password = "test pass"; let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); - directory.insert(account).expect("Account should be inserted ok"); + directory.insert(account.unwrap()).expect("Account should be inserted ok"); let new_hash = directory.files_hash().expect("New files hash should be calculated ok"); diff --git a/ethstore/src/accounts_dir/vault.rs b/ethstore/src/accounts_dir/vault.rs index 1ef85402a7..2705262666 100644 --- a/ethstore/src/accounts_dir/vault.rs +++ b/ethstore/src/accounts_dir/vault.rs @@ -235,7 +235,7 @@ fn check_vault_name(name: &str) -> bool { /// Vault can be empty, but still must be pluggable => we store vault password in separate file fn create_vault_file

(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef { let password_hash = key.password.keccak256(); - let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations); + let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?; let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into(); vault_file_path.push(VAULT_FILE_NAME); diff --git a/ethstore/src/error.rs b/ethstore/src/error.rs index f7e0b0bfad..7c89473280 100644 --- a/ethstore/src/error.rs +++ b/ethstore/src/error.rs @@ -16,8 +16,8 @@ use std::fmt; use std::io::Error as IoError; -use ethkey::Error as EthKeyError; -use crypto::Error as EthCryptoError; +use ethkey::{self, Error as EthKeyError}; +use crypto::{self, Error as EthCryptoError}; use ethkey::DerivationError; /// Account-related errors. @@ -49,6 +49,8 @@ pub enum Error { CreationFailed, /// `EthKey` error EthKey(EthKeyError), + /// `ethkey::crypto::Error` + EthKeyCrypto(ethkey::crypto::Error), /// `EthCrypto` error EthCrypto(EthCryptoError), /// Derivation error @@ -73,6 +75,7 @@ impl fmt::Display for Error { Error::VaultNotFound => "Vault not found".into(), Error::CreationFailed => "Account creation failed".into(), Error::EthKey(ref err) => err.to_string(), + Error::EthKeyCrypto(ref err) => err.to_string(), Error::EthCrypto(ref err) => err.to_string(), Error::Derivation(ref err) => format!("Derivation error: {:?}", err), Error::Custom(ref s) => s.clone(), @@ -94,12 +97,30 @@ impl From for Error { } } +impl From for Error { + fn from(err: ethkey::crypto::Error) -> Self { + Error::EthKeyCrypto(err) + } +} + impl From for Error { fn from(err: EthCryptoError) -> Self { Error::EthCrypto(err) } } +impl From for Error { + fn from(err: crypto::error::ScryptError) -> Self { + Error::EthCrypto(err.into()) + } +} + +impl From for Error { + fn from(err: crypto::error::SymmError) -> Self { + Error::EthCrypto(err.into()) + } +} + impl From for Error { fn from(err: DerivationError) -> Self { Error::Derivation(err) diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 40a687fc98..46c81153c7 100644 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -458,7 +458,7 @@ impl SimpleSecretStore for EthMultiStore { fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result { let keypair = KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?; let id: [u8; 16] = Random::random(); - let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned()); + let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned())?; self.import(vault, account) } diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index 75df0953ce..b558126ada 100644 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -18,7 +18,6 @@ #![warn(missing_docs)] -extern crate crypto as rcrypto; extern crate dir; extern crate itertools; extern crate libc; @@ -28,7 +27,6 @@ extern crate rustc_hex; extern crate serde; extern crate serde_json; extern crate smallvec; -extern crate subtle; extern crate time; extern crate tiny_keccak; extern crate tempdir; diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index 0c3e72e31b..555d00c1e9 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -1,11 +1,8 @@ use std::fs; use std::path::Path; -use rcrypto::pbkdf2::pbkdf2; -use rcrypto::sha2::Sha256; -use rcrypto::hmac::Hmac; use json; use ethkey::{Address, Secret, KeyPair}; -use crypto::Keccak256; +use crypto::{Keccak256, pbkdf2}; use {crypto, Error}; /// Pre-sale wallet. @@ -42,12 +39,14 @@ impl PresaleWallet { /// Decrypt the wallet. pub fn decrypt(&self, password: &str) -> Result { - let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes()); - let mut derived_key = vec![0u8; 16]; - pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key); + let mut derived_key = [0u8; 32]; + let salt = pbkdf2::Salt(password.as_bytes()); + let sec = pbkdf2::Secret(password.as_bytes()); + pbkdf2::sha256(2000, salt, sec, &mut derived_key); let mut key = vec![0; self.ciphertext.len()]; - let len = crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)?; + let len = crypto::aes::decrypt_128_cbc(&derived_key[0..16], &self.iv, &self.ciphertext, &mut key) + .map_err(|_| Error::InvalidPassword)?; let unpadded = &key[..len]; let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b8eb525462..731544a55f 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -17,7 +17,6 @@ multihash ="0.7" order-stat = "0.1" parking_lot = "0.5" rand = "0.4" -rust-crypto = "0.2" rustc-hex = "1.0" semver = "0.9" serde = "1.0" diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 7b5cc36447..1fc3d0e242 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -23,7 +23,6 @@ extern crate futures; extern crate ansi_term; extern crate cid; -extern crate crypto as rust_crypto; extern crate futures_cpupool; extern crate itertools; extern crate multihash; diff --git a/rpc/src/v1/helpers/ipfs.rs b/rpc/src/v1/helpers/ipfs.rs index 80ad1c207b..da51f1fd54 100644 --- a/rpc/src/v1/helpers/ipfs.rs +++ b/rpc/src/v1/helpers/ipfs.rs @@ -18,21 +18,15 @@ use multihash; use cid::{Cid, Codec, Version}; -use rust_crypto::sha2::Sha256; -use rust_crypto::digest::Digest; +use crypto::digest; use jsonrpc_core::Error; use v1::types::Bytes; use super::errors; /// Compute CIDv0 from protobuf encoded bytes. pub fn cid(content: Bytes) -> Result { - let mut hasher = Sha256::new(); - hasher.input(&content.0); - let len = hasher.output_bytes(); - let mut buf = Vec::with_capacity(len); - buf.resize(len, 0); - hasher.result(&mut buf); - let mh = multihash::encode(multihash::Hash::SHA2256, &buf).map_err(errors::encoding)?; + let hash = digest::sha256(&content.0); + let mh = multihash::encode(multihash::Hash::SHA2256, &*hash).map_err(errors::encoding)?; let cid = Cid::new(Codec::DagProtobuf, Version::V0, &mh); Ok(cid.to_string().into()) } diff --git a/rpc/src/v1/helpers/secretstore.rs b/rpc/src/v1/helpers/secretstore.rs index fbcc167e23..019d2b1051 100644 --- a/rpc/src/v1/helpers/secretstore.rs +++ b/rpc/src/v1/helpers/secretstore.rs @@ -16,7 +16,7 @@ use std::collections::BTreeSet; use rand::{Rng, OsRng}; -use ethkey::{Public, Secret, Random, Generator, math}; +use ethkey::{self, Public, Secret, Random, Generator, math}; use crypto; use bytes::Bytes; use jsonrpc_core::Error; @@ -36,7 +36,7 @@ pub fn generate_document_key(account_public: Public, server_key_public: Public) let (common_point, encrypted_point) = encrypt_secret(document_key.public(), &server_key_public)?; // ..and now encrypt document key with account public - let encrypted_key = crypto::ecies::encrypt(&account_public, &crypto::DEFAULT_MAC, document_key.public()) + let encrypted_key = ethkey::crypto::ecies::encrypt(&account_public, &crypto::DEFAULT_MAC, document_key.public()) .map_err(errors::encryption)?; Ok(EncryptedDocumentKey { @@ -57,7 +57,7 @@ pub fn encrypt_document(key: Bytes, document: Bytes) -> Result { { let (mut encryption_buffer, iv_buffer) = encrypted_document.split_at_mut(document.len()); - crypto::aes::encrypt(&key, &iv, &document, &mut encryption_buffer); + crypto::aes::encrypt_128_ctr(&key, &iv, &document, &mut encryption_buffer).map_err(errors::encryption)?; iv_buffer.copy_from_slice(&iv); } @@ -78,7 +78,7 @@ pub fn decrypt_document(key: Bytes, mut encrypted_document: Bytes) -> Result = decrypted_secret.decrypt_shadows.unwrap().into_iter() .map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap()) .collect(); @@ -1423,7 +1423,7 @@ mod tests { // 4 nodes must be able to recover original secret use crypto::DEFAULT_MAC; - use crypto::ecies::decrypt; + use ethkey::crypto::ecies::decrypt; let result = sessions[0].decrypted_secret().unwrap().unwrap(); assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == Some(Ok(result.clone()))).count()); let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter() diff --git a/secret_store/src/key_server_cluster/io/handshake.rs b/secret_store/src/key_server_cluster/io/handshake.rs index 838e48e1f7..af64295632 100644 --- a/secret_store/src/key_server_cluster/io/handshake.rs +++ b/secret_store/src/key_server_cluster/io/handshake.rs @@ -37,7 +37,7 @@ use std::sync::Arc; use std::collections::BTreeSet; use futures::{Future, Poll, Async}; use tokio_io::{AsyncRead, AsyncWrite}; -use crypto::ecdh::agree; +use ethkey::crypto::ecdh::agree; use ethkey::{Random, Generator, KeyPair, Public, Signature, verify_public, sign, recover}; use ethereum_types::H256; use key_server_cluster::{NodeId, Error, NodeKeyPair}; diff --git a/secret_store/src/key_server_cluster/io/message.rs b/secret_store/src/key_server_cluster/io/message.rs index 784b0b2b6a..9925b789d2 100644 --- a/secret_store/src/key_server_cluster/io/message.rs +++ b/secret_store/src/key_server_cluster/io/message.rs @@ -19,7 +19,7 @@ use std::u16; use std::ops::Deref; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use serde_json; -use crypto::ecies; +use ethkey::crypto::ecies; use ethkey::{Secret, KeyPair}; use ethkey::math::curve_order; use ethereum_types::{H256, U256}; @@ -306,7 +306,7 @@ pub mod tests { use futures::Poll; use tokio_io::{AsyncRead, AsyncWrite}; use ethkey::{Random, Generator, KeyPair}; - use crypto::ecdh::agree; + use ethkey::crypto::ecdh::agree; use key_server_cluster::Error; use key_server_cluster::message::Message; use super::{MESSAGE_HEADER_SIZE, CURRENT_HEADER_VERSION, MessageHeader, fix_shared_key, encrypt_message, diff --git a/secret_store/src/key_server_cluster/jobs/decryption_job.rs b/secret_store/src/key_server_cluster/jobs/decryption_job.rs index 1f14a484da..2c11fe0ab3 100644 --- a/secret_store/src/key_server_cluster/jobs/decryption_job.rs +++ b/secret_store/src/key_server_cluster/jobs/decryption_job.rs @@ -17,8 +17,8 @@ use std::collections::{BTreeSet, BTreeMap}; use ethereum_types::H256; use ethkey::{Public, Secret}; -use crypto::ecies::encrypt; use crypto::DEFAULT_MAC; +use ethkey::crypto::ecies::encrypt; use key_server_cluster::{Error, NodeId, DocumentKeyShare, EncryptedDocumentKeyShadow}; use key_server_cluster::math; use key_server_cluster::jobs::job_session::{JobPartialRequestAction, JobPartialResponseAction, JobExecutor}; diff --git a/secret_store/src/node_key_pair.rs b/secret_store/src/node_key_pair.rs index 55c2a8a28a..428dba6c1a 100644 --- a/secret_store/src/node_key_pair.rs +++ b/secret_store/src/node_key_pair.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::sync::Arc; -use crypto::ecdh::agree; +use ethkey::crypto::ecdh::agree; use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_address}; use ethcore::account_provider::AccountProvider; use ethereum_types::{H256, Address}; @@ -54,7 +54,8 @@ impl NodeKeyPair for PlainNodeKeyPair { } fn compute_shared_key(&self, peer_public: &Public) -> Result { - agree(self.key_pair.secret(), peer_public).map_err(|e| EthKeyError::Custom(e.into())) + agree(self.key_pair.secret(), peer_public) + .map_err(|e| EthKeyError::Custom(e.to_string())) .and_then(KeyPair::from_secret) } } diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs index 6469585fac..1fceb120e8 100644 --- a/secret_store/src/types/error.rs +++ b/secret_store/src/types/error.rs @@ -168,6 +168,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: ethkey::crypto::Error) -> Self { + Error::EthKey(err.to_string()) + } +} + impl From for Error { fn from(err: kvdb::Error) -> Self { Error::Database(err.to_string()) @@ -176,7 +182,7 @@ impl From for Error { impl From for Error { fn from(err: crypto::Error) -> Self { - Error::EthKey(err.into()) + Error::EthKey(err.to_string()) } } diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 2b390baf75..5dbf71fa01 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -34,7 +34,7 @@ use rcrypto::symmetriccipher::*; use rcrypto::buffer::*; use tiny_keccak::Keccak; use bytes::{Buf, BufMut}; -use crypto; +use ethkey::crypto; use network::{Error, ErrorKind}; const ENCRYPTED_HEADER_LEN: usize = 32; diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 37c39eb618..a203af5b4b 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -25,7 +25,7 @@ use connection::{Connection}; use node_table::NodeId; use io::{IoContext, StreamToken}; use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; -use crypto::{ecdh, ecies}; +use ethkey::crypto::{ecdh, ecies}; use network::{Error, ErrorKind, HostInfo}; #[derive(PartialEq, Eq, Debug)] diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 48bcf75965..6342bfe4ad 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -151,8 +151,14 @@ impl From for Error { } } -impl From for Error { - fn from(_err: crypto::Error) -> Self { +impl From for Error { + fn from(_err: ethkey::crypto::Error) -> Self { + ErrorKind::Auth.into() + } +} + +impl From for Error { + fn from(_err: crypto::error::SymmError) -> Self { ErrorKind::Auth.into() } } @@ -168,11 +174,11 @@ fn test_errors() { match *>::from(rlp::DecoderError::RlpIsTooBig).kind() { ErrorKind::Auth => {}, - _ => panic!("Unexpeceted error"), + _ => panic!("Unexpected error"), } - match *>::from(crypto::Error::InvalidMessage).kind() { + match *>::from(ethkey::crypto::Error::InvalidMessage).kind() { ErrorKind::Auth => {}, - _ => panic!("Unexpeceted error"), + _ => panic!("Unexpected error"), } } diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index bd1fc2dbb0..ed370e38a2 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -17,7 +17,6 @@ mem = { path = "../util/mem" } ordered-float = "0.5" parking_lot = "0.5" rand = "0.4" -ring = "0.12" rlp = { path = "../util/rlp" } serde = "1.0" serde_derive = "1.0" diff --git a/whisper/src/lib.rs b/whisper/src/lib.rs index 4aa1a99b9e..85ab55e0f4 100644 --- a/whisper/src/lib.rs +++ b/whisper/src/lib.rs @@ -28,7 +28,6 @@ extern crate ordered_float; extern crate parking_lot; extern crate rand; extern crate rlp; -extern crate ring; extern crate serde; extern crate slab; extern crate smallvec; diff --git a/whisper/src/rpc/crypto.rs b/whisper/src/rpc/crypto.rs index 8780045b47..667656d6bf 100644 --- a/whisper/src/rpc/crypto.rs +++ b/whisper/src/rpc/crypto.rs @@ -16,11 +16,11 @@ //! Encryption schemes supported by RPC layer. -use crypto; +use crypto::aes_gcm::{Encryptor, Decryptor}; +use ethkey::crypto::ecies; use ethereum_types::H256; use ethkey::{self, Public, Secret}; use mem::Memzero; -use ring::aead::{self, AES_256_GCM, SealingKey, OpeningKey}; /// Length of AES key pub const AES_KEY_LEN: usize = 32; @@ -72,38 +72,15 @@ impl EncryptionInstance { } /// Encrypt the supplied plaintext - pub fn encrypt(self, plain: &[u8]) -> Vec { + pub fn encrypt(self, plain: &[u8]) -> Option> { match self.0 { EncryptionInner::AES(key, nonce, encode) => { - let sealing_key = SealingKey::new(&AES_256_GCM, &*key) - .expect("key is of correct len; qed"); - - let encrypt_plain = move |buf: &mut Vec| { - let out_suffix_capacity = AES_256_GCM.tag_len(); - - let prepend_len = buf.len(); - buf.extend(plain); - - buf.resize(prepend_len + plain.len() + out_suffix_capacity, 0); - - let out_size = aead::seal_in_place( - &sealing_key, - &nonce, - &[], // no authenticated data. - &mut buf[prepend_len..], - out_suffix_capacity, - ).expect("key, nonce, buf are valid and out suffix large enough; qed"); - - // truncate to the output size and return. - buf.truncate(prepend_len + out_size); - }; - match encode { AesEncode::AppendedNonce => { - let mut buf = Vec::new(); - encrypt_plain(&mut buf); + let mut enc = Encryptor::aes_256_gcm(&*key).ok()?; + let mut buf = enc.encrypt(&nonce, plain.to_vec()).ok()?; buf.extend(&nonce[..]); - buf + Some(buf) } AesEncode::OnTopics(topics) => { let mut buf = Vec::new(); @@ -111,14 +88,16 @@ impl EncryptionInstance { xor(&mut t.0, &key); buf.extend(&t.0); } - encrypt_plain(&mut buf); - buf + let mut enc = Encryptor::aes_256_gcm(&*key).ok()?; + enc.offset(buf.len()); + buf.extend(plain); + let ciphertext = enc.encrypt(&nonce, buf).ok()?; + Some(ciphertext) } } } EncryptionInner::ECIES(valid_public) => { - crypto::ecies::encrypt(&valid_public, &[], plain) - .expect("validity of public key an invariant of the type; qed") + ecies::encrypt(&valid_public, &[], plain).ok() } } } @@ -169,58 +148,36 @@ impl DecryptionInstance { pub fn decrypt(self, ciphertext: &[u8]) -> Option> { match self.0 { DecryptionInner::AES(extract) => { - let decrypt = | - key: Memzero<[u8; AES_KEY_LEN]>, - nonce: [u8; AES_NONCE_LEN], - ciphertext: &[u8] - | { - if ciphertext.len() < AES_256_GCM.tag_len() { return None } - - let opening_key = OpeningKey::new(&AES_256_GCM, &*key) - .expect("key length is valid for mode; qed"); - - let mut buf = ciphertext.to_vec(); - - // decrypted plaintext always ends up at the - // front of the buffer. - let maybe_decrypted = aead::open_in_place( - &opening_key, - &nonce, - &[], // no authenticated data - 0, // no header. - &mut buf, - ).ok().map(|plain_slice| plain_slice.len()); - - maybe_decrypted.map(move |len| { buf.truncate(len); buf }) - }; - match extract { AesExtract::AppendedNonce(key) => { - if ciphertext.len() < AES_NONCE_LEN { return None } - + if ciphertext.len() < AES_NONCE_LEN { + return None + } // nonce is the suffix of ciphertext. let mut nonce = [0; AES_NONCE_LEN]; let nonce_offset = ciphertext.len() - AES_NONCE_LEN; - nonce.copy_from_slice(&ciphertext[nonce_offset..]); - decrypt(key, nonce, &ciphertext[..nonce_offset]) + Decryptor::aes_256_gcm(&*key).ok()? + .decrypt(&nonce, Vec::from(&ciphertext[..nonce_offset])) + .ok() } AesExtract::OnTopics(num_topics, known_index, known_topic) => { - if ciphertext.len() < num_topics * 32 { return None } - + if ciphertext.len() < num_topics * 32 { + return None + } let mut salted_topic = H256::new(); salted_topic.copy_from_slice(&ciphertext[(known_index * 32)..][..32]); - let key = Memzero::from((salted_topic ^ known_topic).0); - let offset = num_topics * 32; - decrypt(key, BROADCAST_IV, &ciphertext[offset..]) + Decryptor::aes_256_gcm(&*key).ok()? + .decrypt(&BROADCAST_IV, Vec::from(&ciphertext[offset..])) + .ok() } } } DecryptionInner::ECIES(secret) => { // secret is checked for validity, so only fails on invalid message. - crypto::ecies::decrypt(&secret, &[], ciphertext).ok() + ecies::decrypt(&secret, &[], ciphertext).ok() } } } @@ -230,16 +187,6 @@ impl DecryptionInstance { mod tests { use super::*; - #[test] - fn aes_key_len_should_be_equal_to_constant() { - assert_eq!(::ring::aead::AES_256_GCM.key_len(), AES_KEY_LEN); - } - - #[test] - fn aes_nonce_len_should_be_equal_to_constant() { - assert_eq!(::ring::aead::AES_256_GCM.nonce_len(), AES_NONCE_LEN); - } - #[test] fn encrypt_asymmetric() { use ethkey::{Generator, Random}; @@ -247,7 +194,7 @@ mod tests { let key_pair = Random.generate().unwrap(); let test_message = move |message: &[u8]| { let instance = EncryptionInstance::ecies(key_pair.public().clone()).unwrap(); - let ciphertext = instance.encrypt(&message); + let ciphertext = instance.encrypt(&message).unwrap(); if !message.is_empty() { assert!(&ciphertext[..message.len()] != message) @@ -273,7 +220,7 @@ mod tests { let key = Memzero::from(rng.gen::<[u8; 32]>()); let instance = EncryptionInstance::aes(key.clone(), rng.gen()); - let ciphertext = instance.encrypt(message); + let ciphertext = instance.encrypt(message).unwrap(); if !message.is_empty() { assert!(&ciphertext[..message.len()] != message) @@ -303,7 +250,7 @@ mod tests { let key = Memzero::from(rng.gen::<[u8; 32]>()); let instance = EncryptionInstance::broadcast(key, all_topics); - let ciphertext = instance.encrypt(message); + let ciphertext = instance.encrypt(message).unwrap(); if !message.is_empty() { assert!(&ciphertext[..message.len()] != message) diff --git a/whisper/src/rpc/filter.rs b/whisper/src/rpc/filter.rs index 5a192ac04c..8d125174ed 100644 --- a/whisper/src/rpc/filter.rs +++ b/whisper/src/rpc/filter.rs @@ -402,7 +402,7 @@ mod tests { sign_with: Some(signing_pair.secret().unwrap()) }).unwrap(); - let encrypted = encryption_instance.encrypt(&payload); + let encrypted = encryption_instance.encrypt(&payload).unwrap(); let message = Message::create(CreateParams { ttl: 100, diff --git a/whisper/src/rpc/key_store.rs b/whisper/src/rpc/key_store.rs index 02781e20ad..1fb4e264ac 100644 --- a/whisper/src/rpc/key_store.rs +++ b/whisper/src/rpc/key_store.rs @@ -25,7 +25,6 @@ use ethereum_types::H256; use ethkey::{KeyPair, Public, Secret}; use mem::Memzero; use rand::{Rng, OsRng}; -use ring::error::Unspecified; use rpc::crypto::{AES_KEY_LEN, EncryptionInstance, DecryptionInstance}; @@ -54,10 +53,8 @@ impl Key { } /// From secret asymmetric key. Fails if secret is invalid. - pub fn from_secret(secret: Secret) -> Result { - KeyPair::from_secret(secret) - .map(Key::Asymmetric) - .map_err(|_| Unspecified) + pub fn from_secret(secret: Secret) -> Option { + KeyPair::from_secret(secret).map(Key::Asymmetric).ok() } /// From raw symmetric key. @@ -179,7 +176,7 @@ mod tests { #[test] fn rejects_invalid_secret() { let bad_secret = ::ethkey::Secret::from([0xff; 32]); - assert!(Key::from_secret(bad_secret).is_err()); + assert!(Key::from_secret(bad_secret).is_none()); } #[test] diff --git a/whisper/src/rpc/mod.rs b/whisper/src/rpc/mod.rs index e9e6577085..7daa3f4559 100644 --- a/whisper/src/rpc/mod.rs +++ b/whisper/src/rpc/mod.rs @@ -226,7 +226,7 @@ impl Whisper for WhisperClien fn add_private_key(&self, private: types::Private) -> Result { let key_pair = Key::from_secret(private.into_inner().into()) - .map_err(|_| whisper_error("Invalid private key"))?; + .ok_or_else(|| whisper_error("Invalid private key"))?; Ok(HexEncode(self.store.write().insert(key_pair))) } @@ -317,7 +317,7 @@ impl Whisper for WhisperClien sign_with: sign_with.as_ref(), }).map_err(whisper_error)?; - encryption.encrypt(&payload) + encryption.encrypt(&payload).ok_or(whisper_error("encryption error"))? }; // mining the packet is the heaviest item of work by far. -- GitLab From 32c32ecfdac7787ab8d4271b5245661bf253d471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 7 May 2018 11:57:03 +0100 Subject: [PATCH 123/263] ethcore, rpc, machine: refactor block reward application and tracing (#8490) --- ethcore/src/engines/authority_round/mod.rs | 9 ++++-- ethcore/src/engines/block_reward.rs | 34 +++++++++++++++++----- ethcore/src/engines/mod.rs | 2 +- ethcore/src/engines/null_engine.rs | 20 +++++-------- ethcore/src/engines/tendermint/mod.rs | 10 +++++-- ethcore/src/ethereum/ethash.rs | 25 ++++++++-------- ethcore/src/machine.rs | 24 ++++++++++----- ethcore/src/trace/types/trace.rs | 8 +++++ machine/src/lib.rs | 8 ----- rpc/src/v1/types/trace.rs | 8 +++++ 10 files changed, 93 insertions(+), 55 deletions(-) diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 4807d6c3fb..c2aee7c6ef 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1015,8 +1015,10 @@ impl Engine for AuthorityRound { let author = *block.header().author(); benefactors.push((author, RewardKind::Author)); - let rewards = match self.block_reward_contract { + let rewards: Vec<_> = match self.block_reward_contract { Some(ref c) if block.header().number() >= self.block_reward_contract_transition => { + // NOTE: this logic should be moved to a function when another + // engine needs support for block reward contract. let mut call = |to, data| { let result = self.machine.execute_as_system( block, @@ -1027,10 +1029,11 @@ impl Engine for AuthorityRound { result.map_err(|e| format!("{}", e)) }; - c.reward(&benefactors, &mut call)? + let rewards = c.reward(&benefactors, &mut call)?; + rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect() }, _ => { - benefactors.into_iter().map(|(author, _)| (author, self.block_reward)).collect() + benefactors.into_iter().map(|(author, reward_kind)| (author, reward_kind, self.block_reward)).collect() }, }; diff --git a/ethcore/src/engines/block_reward.rs b/ethcore/src/engines/block_reward.rs index 510a5255f5..9a9d54e4af 100644 --- a/ethcore/src/engines/block_reward.rs +++ b/ethcore/src/engines/block_reward.rs @@ -14,13 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! A module with types for declaring block rewards and a client interface for interacting with a +//! block reward contract. + use ethabi; use ethabi::ParamType; use ethereum_types::{H160, Address, U256}; -use block::ExecutedBlock; use error::Error; -use machine::EthereumMachine; +use machine::WithRewards; +use parity_machine::{Machine, WithBalances}; +use trace; use super::SystemCall; use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json"); @@ -37,6 +41,8 @@ pub enum RewardKind { Uncle = 1, /// Reward attributed to the author(s) of empty step(s) included in the block (AuthorityRound engine). EmptyStep = 2, + /// Reward attributed by an external protocol (e.g. block reward contract). + External = 3, } impl From for u16 { @@ -45,6 +51,17 @@ impl From for u16 { } } +impl Into for RewardKind { + fn into(self) -> trace::RewardType { + match self { + RewardKind::Author => trace::RewardType::Block, + RewardKind::Uncle => trace::RewardType::Uncle, + RewardKind::EmptyStep => trace::RewardType::EmptyStep, + RewardKind::External => trace::RewardType::External, + } + } +} + /// A client for the block reward contract. pub struct BlockRewardContract { /// Address of the contract. @@ -112,14 +129,17 @@ impl BlockRewardContract { /// Applies the given block rewards, i.e. adds the given balance to each benefactors' address. /// If tracing is enabled the operations are recorded. -pub fn apply_block_rewards(rewards: &[(Address, U256)], block: &mut ExecutedBlock, machine: &EthereumMachine) -> Result<(), Error> { - use parity_machine::WithBalances; - - for &(ref author, ref block_reward) in rewards { +pub fn apply_block_rewards( + rewards: &[(Address, RewardKind, U256)], + block: &mut M::LiveBlock, + machine: &M, +) -> Result<(), M::Error> { + for &(ref author, _, ref block_reward) in rewards { machine.add_balance(block, author, block_reward)?; } - machine.note_rewards(block, &rewards, &[]) + let rewards: Vec<_> = rewards.into_iter().map(|&(a, k, r)| (a, k.into(), r)).collect(); + machine.note_rewards(block, &rewards) } #[cfg(test)] diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index a17ae356e6..e019636f53 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -18,7 +18,6 @@ mod authority_round; mod basic_authority; -mod block_reward; mod instant_seal; mod null_engine; mod signer; @@ -27,6 +26,7 @@ mod transition; mod validator_set; mod vote_collector; +pub mod block_reward; pub mod epoch; pub use self::authority_round::AuthorityRound; diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index f20a9cdfd9..278eb037c0 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -16,7 +16,9 @@ use ethereum_types::U256; use engines::Engine; +use engines::block_reward::{self, RewardKind}; use header::BlockNumber; +use machine::WithRewards; use parity_machine::{Header, LiveBlock, WithBalances}; /// Params for a null engine. @@ -56,7 +58,7 @@ impl Default for NullEngine { } } -impl Engine for NullEngine { +impl Engine for NullEngine { fn name(&self) -> &str { "NullEngine" } @@ -74,26 +76,20 @@ impl Engine for NullEngine { let n_uncles = LiveBlock::uncles(&*block).len(); + let mut rewards = Vec::new(); + // Bestow block reward let result_block_reward = reward + reward.shr(5) * U256::from(n_uncles); - let mut uncle_rewards = Vec::with_capacity(n_uncles); - - self.machine.add_balance(block, &author, &result_block_reward)?; + rewards.push((author, RewardKind::Author, result_block_reward)); // bestow uncle rewards. for u in LiveBlock::uncles(&*block) { let uncle_author = u.author(); let result_uncle_reward = (reward * U256::from(8 + u.number() - number)).shr(3); - - uncle_rewards.push((*uncle_author, result_uncle_reward)); - } - - for &(ref a, ref reward) in &uncle_rewards { - self.machine.add_balance(block, a, reward)?; + rewards.push((*uncle_author, RewardKind::Uncle, result_uncle_reward)); } - // note and trace. - self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards) + block_reward::apply_block_rewards(&rewards, block, &self.machine) } fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 289beaad0c..d80a5e182f 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -41,6 +41,7 @@ use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; use block::*; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; +use engines::block_reward::{self, RewardKind}; use io::IoService; use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, SimpleList}; @@ -550,10 +551,13 @@ impl Engine for Tendermint { /// Apply the block reward on finalisation of the block. fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error>{ - use parity_machine::WithBalances; let author = *block.header().author(); - self.machine.add_balance(block, &author, &self.block_reward)?; - self.machine.note_rewards(block, &[(author, self.block_reward)], &[]) + + block_reward::apply_block_rewards( + &[(author, RewardKind::Author, self.block_reward)], + block, + &self.machine, + ) } fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> { diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 09e9caf727..09151415c8 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -19,6 +19,7 @@ use std::cmp; use std::collections::BTreeMap; use std::sync::Arc; use hash::{KECCAK_EMPTY_LIST_RLP}; +use engines::block_reward::{self, RewardKind}; use ethash::{quick_get_difficulty, slow_hash_block_number, EthashManager, OptimizeFor}; use ethereum_types::{H256, H64, U256, Address}; use unexpected::{OutOfBounds, Mismatch}; @@ -233,11 +234,13 @@ impl Engine for Arc { /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { use std::ops::Shr; - use parity_machine::{LiveBlock, WithBalances}; + use parity_machine::LiveBlock; let author = *LiveBlock::header(&*block).author(); let number = LiveBlock::header(&*block).number(); + let mut rewards = Vec::new(); + // Applies EIP-649 reward. let reward = if number >= self.ethash_params.eip649_transition { self.ethash_params.eip649_reward.unwrap_or(self.ethash_params.block_reward) @@ -253,20 +256,21 @@ impl Engine for Arc { // Bestow block rewards. let mut result_block_reward = reward + reward.shr(5) * U256::from(n_uncles); - let mut uncle_rewards = Vec::with_capacity(n_uncles); if number >= self.ethash_params.mcip3_transition { result_block_reward = self.ethash_params.mcip3_miner_reward; + let ubi_contract = self.ethash_params.mcip3_ubi_contract; let ubi_reward = self.ethash_params.mcip3_ubi_reward; let dev_contract = self.ethash_params.mcip3_dev_contract; let dev_reward = self.ethash_params.mcip3_dev_reward; - self.machine.add_balance(block, &author, &result_block_reward)?; - self.machine.add_balance(block, &ubi_contract, &ubi_reward)?; - self.machine.add_balance(block, &dev_contract, &dev_reward)?; + rewards.push((author, RewardKind::Author, result_block_reward)); + rewards.push((ubi_contract, RewardKind::External, ubi_reward)); + rewards.push((dev_contract, RewardKind::External, dev_reward)); + } else { - self.machine.add_balance(block, &author, &result_block_reward)?; + rewards.push((author, RewardKind::Author, result_block_reward)); } // Bestow uncle rewards. @@ -278,15 +282,10 @@ impl Engine for Arc { reward.shr(5) }; - uncle_rewards.push((*uncle_author, result_uncle_reward)); - } - - for &(ref a, ref reward) in &uncle_rewards { - self.machine.add_balance(block, a, reward)?; + rewards.push((*uncle_author, RewardKind::Uncle, result_uncle_reward)); } - // Note and trace. - self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards) + block_reward::apply_block_rewards(&rewards, block, &self.machine) } fn verify_local_seal(&self, header: &Header) -> Result<(), Error> { diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index e3bf7d340c..4aa72b50d9 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -437,22 +437,30 @@ impl ::parity_machine::WithBalances for EthereumMachine { fn add_balance(&self, live: &mut ExecutedBlock, address: &Address, amount: &U256) -> Result<(), Error> { live.state_mut().add_balance(address, amount, CleanupMode::NoEmpty).map_err(Into::into) } +} + +/// A state machine that uses block rewards. +pub trait WithRewards: ::parity_machine::Machine { + /// Note block rewards, traces each reward storing information about benefactor, amount and type + /// of reward. + fn note_rewards( + &self, + live: &mut Self::LiveBlock, + rewards: &[(Address, RewardType, U256)], + ) -> Result<(), Self::Error>; +} +impl WithRewards for EthereumMachine { fn note_rewards( &self, live: &mut Self::LiveBlock, - direct: &[(Address, U256)], - indirect: &[(Address, U256)], + rewards: &[(Address, RewardType, U256)], ) -> Result<(), Self::Error> { if let Tracing::Enabled(ref mut traces) = *live.traces_mut() { let mut tracer = ExecutiveTracer::default(); - for &(address, amount) in direct { - tracer.trace_reward(address, amount, RewardType::Block); - } - - for &(address, amount) in indirect { - tracer.trace_reward(address, amount, RewardType::Uncle); + for &(address, ref reward_type, amount) in rewards { + tracer.trace_reward(address, amount, reward_type.clone()); } traces.push(tracer.drain().into()); diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index 06f24efac3..cdb00a5229 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -141,6 +141,10 @@ pub enum RewardType { Block, /// Uncle Uncle, + /// Empty step (AuthorityRound) + EmptyStep, + /// A reward directly attributed by an external protocol (e.g. block reward contract) + External, } impl Encodable for RewardType { @@ -148,6 +152,8 @@ impl Encodable for RewardType { let v = match *self { RewardType::Block => 0u32, RewardType::Uncle => 1, + RewardType::EmptyStep => 2, + RewardType::External => 3, }; Encodable::rlp_append(&v, s); } @@ -158,6 +164,8 @@ impl Decodable for RewardType { rlp.as_val().and_then(|v| Ok(match v { 0u32 => RewardType::Block, 1 => RewardType::Uncle, + 2 => RewardType::EmptyStep, + 3 => RewardType::External, _ => return Err(DecoderError::Custom("Invalid value of RewardType item")), })) } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 3a45c38d2e..54ee403d95 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -106,12 +106,4 @@ pub trait WithBalances: Machine { /// Increment the balance of an account in the state of the live block. fn add_balance(&self, live: &mut Self::LiveBlock, address: &Address, amount: &U256) -> Result<(), Self::Error>; - - /// Note block rewards. "direct" rewards are for authors, "indirect" are for e.g. uncles. - fn note_rewards( - &self, - _live: &mut Self::LiveBlock, - _direct: &[(Address, U256)], - _indirect: &[(Address, U256)], - ) -> Result<(), Self::Error> { Ok(()) } } diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index a984c64ba8..6eb222f5e6 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -308,6 +308,12 @@ pub enum RewardType { /// Uncle #[serde(rename="uncle")] Uncle, + /// EmptyStep (AuthorityRound) + #[serde(rename="emptyStep")] + EmptyStep, + /// External (attributed as part of an external protocol) + #[serde(rename="external")] + External, } impl From for RewardType { @@ -315,6 +321,8 @@ impl From for RewardType { match c { trace::RewardType::Block => RewardType::Block, trace::RewardType::Uncle => RewardType::Uncle, + trace::RewardType::EmptyStep => RewardType::EmptyStep, + trace::RewardType::External => RewardType::External, } } } -- GitLab From 528497b86a93c64f317dd869da47010c2675e4ed Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 7 May 2018 18:58:25 +0800 Subject: [PATCH 124/263] Keep all enacted blocks notify in order (#8524) * Keep all enacted blocks notify in order * Collect is unnecessary * Update ChainNotify to use ChainRouteType * Fix all ethcore fn defs * Wrap the type within ChainRoute * Fix private-tx and sync api * Fix secret_store API * Fix updater API * Fix rpc api * Fix informant api * Eagerly cache enacted/retracted and remove contain_enacted/retracted * Fix indent * tests: should use full expr form for struct constructor * Use into_enacted_retracted to further avoid copy * typo: not a function * rpc/tests: ChainRoute -> ChainRoute::new --- ethcore/private-tx/src/lib.rs | 4 +- ethcore/src/blockchain/import_route.rs | 2 +- ethcore/src/client/chain_notify.rs | 88 ++++++++++++++++++- ethcore/src/client/client.rs | 49 +++-------- ethcore/src/client/mod.rs | 2 +- ethcore/src/snapshot/watcher.rs | 10 +-- ethcore/sync/src/api.rs | 9 +- ethcore/sync/src/tests/helpers.rs | 7 +- parity/informant.rs | 4 +- rpc/src/v1/impls/eth_pubsub.rs | 49 ++++++----- rpc/src/v1/tests/mocked/eth_pubsub.rs | 10 +-- secret_store/src/acl_storage.rs | 6 +- secret_store/src/key_server_set.rs | 6 +- .../src/listener/service_contract_listener.rs | 6 +- updater/src/updater.rs | 4 +- 15 files changed, 158 insertions(+), 98 deletions(-) diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 26a31fc7ae..723d491829 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -79,7 +79,7 @@ use ethcore::executed::{Executed}; use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction}; use ethcore::{contract_address as ethcore_contract_address}; use ethcore::client::{ - Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, CallContract + Client, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage, BlockId, CallContract }; use ethcore::account_provider::AccountProvider; use ethcore::miner::{self, Miner, MinerService}; @@ -668,7 +668,7 @@ fn find_account_password(passwords: &Vec, account_provider: &AccountProv } impl ChainNotify for Provider { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { if !imported.is_empty() { trace!("New blocks imported, try to prune the queue"); if let Err(err) = self.process_queue() { diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs index cf5d3ca1e7..080d3b0682 100644 --- a/ethcore/src/blockchain/import_route.rs +++ b/ethcore/src/blockchain/import_route.rs @@ -20,7 +20,7 @@ use ethereum_types::H256; use blockchain::block_info::{BlockInfo, BlockLocation}; /// Import route for newly inserted block. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub struct ImportRoute { /// Blocks that were invalidated by new block. pub retracted: Vec, diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index a1f84d2a13..8330fb40d9 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -17,7 +17,9 @@ use bytes::Bytes; use ethereum_types::H256; use transaction::UnverifiedTransaction; +use blockchain::ImportRoute; use std::time::Duration; +use std::collections::HashMap; /// Messages to broadcast via chain pub enum ChainMessageType { @@ -29,6 +31,89 @@ pub enum ChainMessageType { SignedPrivateTransaction(Vec), } +/// Route type to indicate whether it is enacted or retracted. +#[derive(Clone)] +pub enum ChainRouteType { + /// Enacted block + Enacted, + /// Retracted block + Retracted +} + +/// A complete chain enacted retracted route. +#[derive(Default, Clone)] +pub struct ChainRoute { + route: Vec<(H256, ChainRouteType)>, + enacted: Vec, + retracted: Vec, +} + +impl<'a> From<&'a [ImportRoute]> for ChainRoute { + fn from(import_results: &'a [ImportRoute]) -> ChainRoute { + ChainRoute::new(import_results.iter().flat_map(|route| { + route.retracted.iter().map(|h| (*h, ChainRouteType::Retracted)) + .chain(route.enacted.iter().map(|h| (*h, ChainRouteType::Enacted))) + }).collect()) + } +} + +impl ChainRoute { + /// Create a new ChainRoute based on block hash and route type pairs. + pub fn new(route: Vec<(H256, ChainRouteType)>) -> Self { + let (enacted, retracted) = Self::to_enacted_retracted(&route); + + Self { route, enacted, retracted } + } + + /// Gather all non-duplicate enacted and retracted blocks. + fn to_enacted_retracted(route: &[(H256, ChainRouteType)]) -> (Vec, Vec) { + fn map_to_vec(map: Vec<(H256, bool)>) -> Vec { + map.into_iter().map(|(k, _v)| k).collect() + } + + // Because we are doing multiple inserts some of the blocks that were enacted in import `k` + // could be retracted in import `k+1`. This is why to understand if after all inserts + // the block is enacted or retracted we iterate over all routes and at the end final state + // will be in the hashmap + let map = route.iter().fold(HashMap::new(), |mut map, route| { + match &route.1 { + &ChainRouteType::Enacted => { + map.insert(route.0, true); + }, + &ChainRouteType::Retracted => { + map.insert(route.0, false); + }, + } + map + }); + + // Split to enacted retracted (using hashmap value) + let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v); + // And convert tuples to keys + (map_to_vec(enacted), map_to_vec(retracted)) + } + + /// Consume route and return the enacted retracted form. + pub fn into_enacted_retracted(self) -> (Vec, Vec) { + (self.enacted, self.retracted) + } + + /// All non-duplicate enacted blocks. + pub fn enacted(&self) -> &[H256] { + &self.enacted + } + + /// All non-duplicate retracted blocks. + pub fn retracted(&self) -> &[H256] { + &self.retracted + } + + /// All blocks in the route. + pub fn route(&self) -> &[(H256, ChainRouteType)] { + &self.route + } +} + /// Represents what has to be handled by actor listening to chain events pub trait ChainNotify : Send + Sync { /// fires when chain has new blocks. @@ -36,8 +121,7 @@ pub trait ChainNotify : Send + Sync { &self, _imported: Vec, _invalid: Vec, - _enacted: Vec, - _retracted: Vec, + _route: ChainRoute, _sealed: Vec, // Block bytes. _proposed: Vec, diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a37d62a591..8119ebd35f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::{HashSet, HashMap, BTreeMap, BTreeSet, VecDeque}; +use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; @@ -45,7 +45,7 @@ use client::{ use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, - ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType + ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType }; use encoded; use engines::{EthEngine, EpochTransition}; @@ -245,32 +245,6 @@ impl Importer { }) } - fn calculate_enacted_retracted(&self, import_results: &[ImportRoute]) -> (Vec, Vec) { - fn map_to_vec(map: Vec<(H256, bool)>) -> Vec { - map.into_iter().map(|(k, _v)| k).collect() - } - - // In ImportRoute we get all the blocks that have been enacted and retracted by single insert. - // Because we are doing multiple inserts some of the blocks that were enacted in import `k` - // could be retracted in import `k+1`. This is why to understand if after all inserts - // the block is enacted or retracted we iterate over all routes and at the end final state - // will be in the hashmap - let map = import_results.iter().fold(HashMap::new(), |mut map, route| { - for hash in &route.enacted { - map.insert(hash.clone(), true); - } - for hash in &route.retracted { - map.insert(hash.clone(), false); - } - map - }); - - // Split to enacted retracted (using hashmap value) - let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v); - // And convert tuples to keys - (map_to_vec(enacted), map_to_vec(retracted)) - } - /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self, client: &Client) -> usize { @@ -336,18 +310,17 @@ impl Importer { { if !imported_blocks.is_empty() && is_empty { - let (enacted, retracted) = self.calculate_enacted_retracted(&import_results); + let route = ChainRoute::from(import_results.as_ref()); if is_empty { - self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, &enacted, &retracted, false); + self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, route.enacted(), route.retracted(), false); } client.notify(|notify| { notify.new_blocks( imported_blocks.clone(), invalid_blocks.clone(), - enacted.clone(), - retracted.clone(), + route.clone(), Vec::new(), proposed_blocks.clone(), duration, @@ -1421,7 +1394,7 @@ impl ImportBlock for Client { } fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { - let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; + let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; { // check block order if self.chain.read().is_known(&header.hash()) { @@ -2155,14 +2128,13 @@ impl ImportSealedBlock for Client { self.state_db.write().sync_cache(&route.enacted, &route.retracted, false); route }; - let (enacted, retracted) = self.importer.calculate_enacted_retracted(&[route]); - self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted, true); + let route = ChainRoute::from([route].as_ref()); + self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), true); self.notify(|notify| { notify.new_blocks( vec![h.clone()], vec![], - enacted.clone(), - retracted.clone(), + route.clone(), vec![h.clone()], vec![], start.elapsed(), @@ -2180,8 +2152,7 @@ impl BroadcastProposalBlock for Client { notify.new_blocks( vec![], vec![], - vec![], - vec![], + ChainRoute::default(), vec![], vec![block.rlp_bytes()], DURATION_ZERO, diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 1e4ccba585..05e2018258 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -31,7 +31,7 @@ pub use self::error::Error; pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; pub use self::io_message::ClientIoMessage; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; -pub use self::chain_notify::{ChainNotify, ChainMessageType}; +pub use self::chain_notify::{ChainNotify, ChainRoute, ChainRouteType, ChainMessageType}; pub use self::traits::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter diff --git a/ethcore/src/snapshot/watcher.rs b/ethcore/src/snapshot/watcher.rs index 936feaefba..6e04fe6d16 100644 --- a/ethcore/src/snapshot/watcher.rs +++ b/ethcore/src/snapshot/watcher.rs @@ -17,7 +17,7 @@ //! Watcher for snapshot-related chain events. use parking_lot::Mutex; -use client::{BlockInfo, Client, ChainNotify, ClientIoMessage}; +use client::{BlockInfo, Client, ChainNotify, ChainRoute, ClientIoMessage}; use ids::BlockId; use io::IoChannel; @@ -103,8 +103,7 @@ impl ChainNotify for Watcher { &self, imported: Vec, _: Vec, - _: Vec, - _: Vec, + _: ChainRoute, _: Vec, _: Vec, _duration: Duration) @@ -131,7 +130,7 @@ impl ChainNotify for Watcher { mod tests { use super::{Broadcast, Oracle, Watcher}; - use client::ChainNotify; + use client::{ChainNotify, ChainRoute}; use ethereum_types::{H256, U256}; @@ -174,8 +173,7 @@ mod tests { watcher.new_blocks( hashes, vec![], - vec![], - vec![], + ChainRoute::default(), vec![], vec![], DURATION_ZERO, diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 5e96f11cf3..7690eeb864 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -25,7 +25,7 @@ use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, Protocol use ethereum_types::{H256, H512, U256}; use io::{TimerToken}; use ethcore::ethstore::ethkey::Secret; -use ethcore::client::{BlockChainClient, ChainNotify, ChainMessageType}; +use ethcore::client::{BlockChainClient, ChainNotify, ChainRoute, ChainMessageType}; use ethcore::snapshot::SnapshotService; use ethcore::header::BlockNumber; use sync_io::NetSyncIo; @@ -409,8 +409,7 @@ impl ChainNotify for EthSync { fn new_blocks(&self, imported: Vec, invalid: Vec, - enacted: Vec, - retracted: Vec, + route: ChainRoute, sealed: Vec, proposed: Vec, _duration: Duration) @@ -424,8 +423,8 @@ impl ChainNotify for EthSync { &mut sync_io, &imported, &invalid, - &enacted, - &retracted, + route.enacted(), + route.retracted(), &sealed, &proposed); }); diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 54467adb77..dc52fdd8b8 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -23,7 +23,7 @@ use bytes::Bytes; use network::{self, PeerId, ProtocolId, PacketId, SessionInfo}; use tests::snapshot::*; use ethcore::client::{TestBlockChainClient, BlockChainClient, Client as EthcoreClient, - ClientConfig, ChainNotify, ChainMessageType, ClientIoMessage}; + ClientConfig, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage}; use ethcore::header::BlockNumber; use ethcore::snapshot::SnapshotService; use ethcore::spec::Spec; @@ -535,12 +535,13 @@ impl ChainNotify for EthPeer { fn new_blocks(&self, imported: Vec, invalid: Vec, - enacted: Vec, - retracted: Vec, + route: ChainRoute, sealed: Vec, proposed: Vec, _duration: Duration) { + let (enacted, retracted) = route.into_enacted_retracted(); + self.new_blocks_queue.write().push_back(NewBlockMessage { imported, invalid, diff --git a/parity/informant.rs b/parity/informant.rs index 5c2e0ab89d..beeb258b52 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -25,7 +25,7 @@ use std::time::{Instant, Duration}; use atty; use ethcore::client::{ BlockId, BlockChainClient, ChainInfo, BlockInfo, BlockChainInfo, - BlockQueueInfo, ChainNotify, ClientReport, Client, ClientIoMessage + BlockQueueInfo, ChainNotify, ChainRoute, ClientReport, Client, ClientIoMessage }; use ethcore::header::BlockNumber; use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; @@ -351,7 +351,7 @@ impl Informant { } impl ChainNotify for Informant { - fn new_blocks(&self, imported: Vec, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, duration: Duration) { + fn new_blocks(&self, imported: Vec, _invalid: Vec, _route: ChainRoute, _sealed: Vec, _proposed: Vec, duration: Duration) { let mut last_import = self.last_import.lock(); let client = &self.target.client; diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index 1a872f5600..3045959446 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -34,7 +34,7 @@ use v1::types::{pubsub, RichHeader, Log}; use ethcore::encoded; use ethcore::filter::Filter as EthFilter; -use ethcore::client::{BlockChainClient, ChainNotify, BlockId}; +use ethcore::client::{BlockChainClient, ChainNotify, ChainRoute, ChainRouteType, BlockId}; use sync::LightSync; use light::cache::Cache; use light::on_demand::OnDemand; @@ -141,19 +141,20 @@ impl ChainNotificationHandler { } } - fn notify_logs(&self, enacted: &[H256], logs: F) where - F: Fn(EthFilter) -> T, + fn notify_logs(&self, enacted: &[(H256, Ex)], logs: F) where + F: Fn(EthFilter, &Ex) -> T, + Ex: Send, T: IntoFuture, Error = Error>, T::Future: Send + 'static, { for &(ref subscriber, ref filter) in self.logs_subscribers.read().values() { let logs = futures::future::join_all(enacted .iter() - .map(|hash| { + .map(|&(hash, ref ex)| { let mut filter = filter.clone(); - filter.from_block = BlockId::Hash(*hash); + filter.from_block = BlockId::Hash(hash); filter.to_block = filter.from_block.clone(); - logs(filter).into_future() + logs(filter, ex).into_future() }) .collect::>() ); @@ -214,7 +215,7 @@ impl LightChainNotify for ChainNotificationHandler { .collect::>(); self.notify_heads(&headers); - self.notify_logs(&enacted, |filter| self.client.logs(filter)) + self.notify_logs(&enacted.iter().map(|h| (*h, ())).collect::>(), |filter, _| self.client.logs(filter)) } } @@ -223,17 +224,21 @@ impl ChainNotify for ChainNotificationHandler { &self, _imported: Vec, _invalid: Vec, - enacted: Vec, - retracted: Vec, + route: ChainRoute, _sealed: Vec, // Block bytes. _proposed: Vec, _duration: Duration, ) { const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; - let headers = enacted + let headers = route.route() .iter() - .filter_map(|hash| self.client.block_header(BlockId::Hash(*hash))) + .filter_map(|&(hash, ref typ)| { + match typ { + &ChainRouteType::Retracted => None, + &ChainRouteType::Enacted => self.client.block_header(BlockId::Hash(hash)) + } + }) .map(|header| { let hash = header.hash(); (header, self.client.block_extra_info(BlockId::Hash(hash)).expect(EXTRA_INFO_PROOF)) @@ -243,17 +248,17 @@ impl ChainNotify for ChainNotificationHandler { // Headers self.notify_heads(&headers); - // Enacted logs - self.notify_logs(&enacted, |filter| { - Ok(self.client.logs(filter).into_iter().map(Into::into).collect()) - }); - - // Retracted logs - self.notify_logs(&retracted, |filter| { - Ok(self.client.logs(filter).into_iter().map(Into::into).map(|mut log: Log| { - log.log_type = "removed".into(); - log - }).collect()) + // We notify logs enacting and retracting as the order in route. + self.notify_logs(route.route(), |filter, ex| { + match ex { + &ChainRouteType::Enacted => + Ok(self.client.logs(filter).into_iter().map(Into::into).collect()), + &ChainRouteType::Retracted => + Ok(self.client.logs(filter).into_iter().map(Into::into).map(|mut log: Log| { + log.log_type = "removed".into(); + log + }).collect()), + } }); } } diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index fb28ba3127..936695a9a1 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -24,7 +24,7 @@ use std::time::Duration; use v1::{EthPubSub, EthPubSubClient, Metadata}; -use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify}; +use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify, ChainRoute, ChainRouteType}; use parity_reactor::EventLoop; const DURATION_ZERO: Duration = Duration::from_millis(0); @@ -57,13 +57,13 @@ fn should_subscribe_to_new_heads() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x1","extraData":"0x","gasLimit":"0xf4240","gasUsed":"0x0","hash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","number":"0x1","parentHash":"0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x1c9","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","timestamp":"0x0","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); // Notify about two blocks - handler.new_blocks(vec![], vec![], vec![h2, h3], vec![], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h2, ChainRouteType::Enacted), (h3, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO); // Receive both let (res, receiver) = receiver.into_future().wait().unwrap(); @@ -129,7 +129,7 @@ fn should_subscribe_to_logs() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Check notifications (enacted) - handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) @@ -137,7 +137,7 @@ fn should_subscribe_to_logs() { assert_eq!(res, Some(response.into())); // Check notifications (retracted) - handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], DURATION_ZERO); + handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Retracted)]), vec![], vec![], DURATION_ZERO); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() + &format!("0x{:x}", tx_hash) diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 50414eff26..b3427fa1b2 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use std::collections::{HashMap, HashSet}; use std::time::Duration; use parking_lot::{Mutex, RwLock}; -use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; +use ethcore::client::{BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo}; use ethereum_types::{H256, Address}; use bytes::Bytes; use trusted_client::TrustedClient; @@ -76,8 +76,8 @@ impl AclStorage for OnChainAclStorage { } impl ChainNotify for OnChainAclStorage { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { - if !enacted.is_empty() || !retracted.is_empty() { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { + if !route.enacted().is_empty() || !route.retracted().is_empty() { self.contract.lock().update() } } diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index 25651bb4ca..d13017261c 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -19,7 +19,7 @@ use std::net::SocketAddr; use std::collections::{BTreeMap, HashSet}; use std::time::Duration; use parking_lot::Mutex; -use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, CallContract, RegistryInfo}; +use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo}; use ethcore::filter::Filter; use ethkey::public_to_address; use hash::keccak; @@ -163,7 +163,9 @@ impl KeyServerSet for OnChainKeyServerSet { } impl ChainNotify for OnChainKeyServerSet { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { + let (enacted, retracted) = route.into_enacted_retracted(); + if !enacted.is_empty() || !retracted.is_empty() { self.contract.lock().update(enacted, retracted) } diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 0e273b3eee..214235210f 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -20,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; use std::thread; use parking_lot::Mutex; -use ethcore::client::ChainNotify; +use ethcore::client::{ChainNotify, ChainRoute}; use ethkey::{Public, public_to_address}; use bytes::Bytes; use ethereum_types::{H256, U256, Address}; @@ -428,8 +428,8 @@ impl Drop for ServiceContractListener { } impl ChainNotify for ServiceContractListener { - fn new_blocks(&self, _imported: Vec, _invalid: Vec, enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { - let enacted_len = enacted.len(); + fn new_blocks(&self, _imported: Vec, _invalid: Vec, route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { + let enacted_len = route.enacted().len(); if enacted_len == 0 { return; } diff --git a/updater/src/updater.rs b/updater/src/updater.rs index c5f45c7658..f8a98f3b0f 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -28,7 +28,7 @@ use target_info::Target; use bytes::Bytes; use ethcore::BlockNumber; use ethcore::filter::Filter; -use ethcore::client::{BlockId, BlockChainClient, ChainNotify}; +use ethcore::client::{BlockId, BlockChainClient, ChainNotify, ChainRoute}; use ethereum_types::H256; use sync::{SyncProvider}; use hash_fetch::{self as fetch, HashFetch}; @@ -660,7 +660,7 @@ impl Updater, _invalid: Vec, _enacted: Vec, _retracted: Vec, _sealed: Vec, _proposed: Vec, _duration: Duration) { + fn new_blocks(&self, _imported: Vec, _invalid: Vec, _route: ChainRoute, _sealed: Vec, _proposed: Vec, _duration: Duration) { match (self.client.upgrade(), self.sync.as_ref().and_then(Weak::upgrade)) { (Some(ref c), Some(ref s)) if !s.status().is_syncing(c.queue_info()) => self.poll(), _ => {}, -- GitLab From a7a46f425369fd662042cb4a1c9ffc301b3b5b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 7 May 2018 12:11:12 +0100 Subject: [PATCH 125/263] Node table sorting according to last contact data (#8541) * network-devp2p: sort nodes in node table using last contact data * network-devp2p: rename node contact types in node table json output * network-devp2p: fix node table tests * network-devp2p: note node failure when failed to establish connection * network-devp2p: handle UselessPeer error * network-devp2p: note failure when marking node as useless --- util/network-devp2p/src/host.rs | 28 +++- util/network-devp2p/src/node_table.rs | 230 +++++++++++++++++++------- 2 files changed, 188 insertions(+), 70 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 73ca2aca4b..2de9a1884c 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -105,10 +105,13 @@ pub struct NetworkContext<'s> { impl<'s> NetworkContext<'s> { /// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler. - fn new(io: &'s IoContext, + fn new( + io: &'s IoContext, protocol: ProtocolId, - session: Option, sessions: Arc>>, - reserved_peers: &'s HashSet) -> NetworkContext<'s> { + session: Option, + sessions: Arc>>, + reserved_peers: &'s HashSet, + ) -> NetworkContext<'s> { let id = session.as_ref().map(|s| s.lock().token()); NetworkContext { io: io, @@ -585,10 +588,8 @@ impl Host { let address = { let mut nodes = self.nodes.write(); if let Some(node) = nodes.get_mut(id) { - node.attempts += 1; node.endpoint.address - } - else { + } else { debug!(target: "network", "Connection to expired node aborted"); return; } @@ -600,6 +601,7 @@ impl Host { }, Err(e) => { debug!(target: "network", "{}: Can't connect to address {:?}: {:?}", id, address, e); + self.nodes.write().note_failure(&id); return; } } @@ -685,10 +687,12 @@ impl Host { Err(e) => { let s = session.lock(); trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); - if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() { + if let ErrorKind::Disconnect(DisconnectReason::UselessPeer) = *e.kind() { if let Some(id) = s.id() { if !self.reserved_nodes.read().contains(id) { - self.nodes.write().mark_as_useless(id); + let mut nodes = self.nodes.write(); + nodes.note_failure(&id); + nodes.mark_as_useless(id); } } } @@ -754,6 +758,10 @@ impl Host { } } } + + // Note connection success + self.nodes.write().note_success(&id); + for (p, _) in self.handlers.read().iter() { if s.have_capability(*p) { ready_data.push(*p); @@ -1024,7 +1032,9 @@ impl IoHandler for Host { if let Some(session) = session { session.lock().disconnect(io, DisconnectReason::DisconnectRequested); if let Some(id) = session.lock().id() { - self.nodes.write().mark_as_useless(id) + let mut nodes = self.nodes.write(); + nodes.note_failure(&id); + nodes.mark_as_useless(id); } } trace!(target: "network", "Disabling peer {}", peer); diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index fd18c10a12..5079455866 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -21,6 +21,8 @@ use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, use std::path::PathBuf; use std::str::FromStr; use std::{fs, mem, slice}; +use std::time::{self, Duration, SystemTime}; +use rand::{self, Rng}; use ethereum_types::H512; use rlp::{Rlp, RlpStream, DecoderError}; use network::{Error, ErrorKind, AllowIP, IpFilter}; @@ -128,40 +130,64 @@ impl FromStr for NodeEndpoint { } } -#[derive(PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum PeerType { _Required, Optional } +/// A type for representing an interaction (contact) with a node at a given time +/// that was either a success or a failure. +#[derive(Clone, Copy, Debug)] +pub enum NodeContact { + Success(SystemTime), + Failure(SystemTime), +} + +impl NodeContact { + fn success() -> NodeContact { + NodeContact::Success(SystemTime::now()) + } + + fn failure() -> NodeContact { + NodeContact::Failure(SystemTime::now()) + } + + fn time(&self) -> SystemTime { + match *self { + NodeContact::Success(t) | NodeContact::Failure(t) => t + } + } + + /// Filters and old contact, returning `None` if it happened longer than a + /// week ago. + fn recent(&self) -> Option<&NodeContact> { + let t = self.time(); + if let Ok(d) = t.elapsed() { + if d < Duration::from_secs(60 * 60 * 24 * 7) { + return Some(self); + } + } + + None + } +} + +#[derive(Debug)] pub struct Node { pub id: NodeId, pub endpoint: NodeEndpoint, pub peer_type: PeerType, - pub attempts: u32, - pub failures: u32, + pub last_contact: Option, } -const DEFAULT_FAILURE_PERCENTAGE: usize = 50; - impl Node { pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { Node { id: id, endpoint: endpoint, peer_type: PeerType::Optional, - attempts: 0, - failures: 0, - } - } - - /// Returns the node's failure percentage (0..100) in buckets of 5%. If there are 0 connection attempts for this - /// node the default failure percentage is returned (50%). - pub fn failure_percentage(&self) -> usize { - if self.attempts == 0 { - DEFAULT_FAILURE_PERCENTAGE - } else { - (self.failures * 100 / self.attempts / 5 * 5) as usize + last_contact: None, } } } @@ -191,8 +217,7 @@ impl FromStr for Node { id: id, endpoint: endpoint, peer_type: PeerType::Optional, - attempts: 0, - failures: 0, + last_contact: None, }) } } @@ -231,28 +256,61 @@ impl NodeTable { /// Add a node to table pub fn add_node(&mut self, mut node: Node) { - // preserve attempts and failure counter - let (attempts, failures) = - self.nodes.get(&node.id).map_or((0, 0), |n| (n.attempts, n.failures)); - - node.attempts = attempts; - node.failures = failures; - + // preserve node last_contact + node.last_contact = self.nodes.get(&node.id).and_then(|n| n.last_contact); self.nodes.insert(node.id.clone(), node); } + /// Returns a list of ordered nodes according to their most recent contact + /// and filtering useless nodes. The algorithm for creating the sorted nodes + /// is: + /// - Contacts that aren't recent (older than 1 week) are discarded + /// - (1) Nodes with a successful contact are ordered (most recent success first) + /// - (2) Nodes with unknown contact (older than 1 week or new nodes) are randomly shuffled + /// - (3) Nodes with a failed contact are ordered (oldest failure first) + /// - The final result is the concatenation of (1), (2) and (3) fn ordered_entries(&self) -> Vec<&Node> { - let mut refs: Vec<&Node> = self.nodes.values() - .filter(|n| !self.useless_nodes.contains(&n.id)) - .collect(); + let mut success = Vec::new(); + let mut failures = Vec::new(); + let mut unknown = Vec::new(); + + let nodes = self.nodes.values() + .filter(|n| !self.useless_nodes.contains(&n.id)); + + for node in nodes { + // discard contact points older that aren't recent + match node.last_contact.as_ref().and_then(|c| c.recent()) { + Some(&NodeContact::Success(_)) => { + success.push(node); + }, + Some(&NodeContact::Failure(_)) => { + failures.push(node); + }, + None => { + unknown.push(node); + }, + } + } - refs.sort_by(|a, b| { - a.failure_percentage().cmp(&b.failure_percentage()) - .then_with(|| a.failures.cmp(&b.failures)) - .then_with(|| b.attempts.cmp(&a.attempts)) // we use reverse ordering for number of attempts + success.sort_by(|a, b| { + let a = a.last_contact.expect("vector only contains values with defined last_contact; qed"); + let b = b.last_contact.expect("vector only contains values with defined last_contact; qed"); + // inverse ordering, most recent successes come first + b.time().cmp(&a.time()) }); - refs + failures.sort_by(|a, b| { + let a = a.last_contact.expect("vector only contains values with defined last_contact; qed"); + let b = b.last_contact.expect("vector only contains values with defined last_contact; qed"); + // normal ordering, most distant failures come first + a.time().cmp(&b.time()) + }); + + rand::thread_rng().shuffle(&mut unknown); + + success.append(&mut unknown); + success.append(&mut failures); + success } /// Returns node ids sorted by failure percentage, for nodes with the same failure percentage the absolute number of @@ -296,10 +354,17 @@ impl NodeTable { } } - /// Increase failure counte for a node + /// Set last contact as failure for a node pub fn note_failure(&mut self, id: &NodeId) { if let Some(node) = self.nodes.get_mut(id) { - node.failures += 1; + node.last_contact = Some(NodeContact::failure()); + } + } + + /// Set last contact as success for a node + pub fn note_success(&mut self, id: &NodeId) { + if let Some(node) = self.nodes.get_mut(id) { + node.last_contact = Some(NodeContact::success()); } } @@ -396,19 +461,38 @@ mod json { pub nodes: Vec, } + #[derive(Serialize, Deserialize)] + pub enum NodeContact { + #[serde(rename = "success")] + Success(u64), + #[serde(rename = "failure")] + Failure(u64), + } + + impl NodeContact { + pub fn into_node_contact(self) -> super::NodeContact { + match self { + NodeContact::Success(s) => super::NodeContact::Success( + time::UNIX_EPOCH + Duration::from_secs(s) + ), + NodeContact::Failure(s) => super::NodeContact::Failure( + time::UNIX_EPOCH + Duration::from_secs(s) + ), + } + } + } + #[derive(Serialize, Deserialize)] pub struct Node { pub url: String, - pub attempts: u32, - pub failures: u32, + pub last_contact: Option, } impl Node { pub fn into_node(self) -> Option { match super::Node::from_str(&self.url) { Ok(mut node) => { - node.attempts = self.attempts; - node.failures = self.failures; + node.last_contact = self.last_contact.map(|c| c.into_node_contact()); Some(node) }, _ => None, @@ -418,10 +502,18 @@ mod json { impl<'a> From<&'a super::Node> for Node { fn from(node: &'a super::Node) -> Self { + let last_contact = node.last_contact.and_then(|c| { + match c { + super::NodeContact::Success(t) => + t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Success(d.as_secs())), + super::NodeContact::Failure(t) => + t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Failure(d.as_secs())), + } + }); + Node { url: format!("{}", node), - attempts: node.attempts, - failures: node.failures, + last_contact } } } @@ -464,42 +556,54 @@ mod tests { } #[test] - fn table_failure_percentage_order() { + fn table_last_contact_order() { let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node4 = Node::from_str("enode://d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node5 = Node::from_str("enode://e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node6 = Node::from_str("enode://f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id4 = H512::from_str("d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id5 = H512::from_str("e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id6 = H512::from_str("f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let mut table = NodeTable::new(None); table.add_node(node1); table.add_node(node2); table.add_node(node3); table.add_node(node4); + table.add_node(node5); + table.add_node(node6); - // node 1 - failure percentage 100% - table.get_mut(&id1).unwrap().attempts = 2; - table.note_failure(&id1); + // failures - nodes 1 & 2 table.note_failure(&id1); - - // node2 - failure percentage 33% - table.get_mut(&id2).unwrap().attempts = 3; table.note_failure(&id2); - // node3 - failure percentage 0% - table.get_mut(&id3).unwrap().attempts = 1; + // success - nodes 3 & 4 + table.note_success(&id3); + table.note_success(&id4); - // node4 - failure percentage 50% (default when no attempts) + // success - node 5 (old contact) + table.get_mut(&id5).unwrap().last_contact = Some(NodeContact::Success(time::UNIX_EPOCH)); + + // unknown - node 6 let r = table.nodes(IpFilter::default()); - assert_eq!(r[0][..], id3[..]); - assert_eq!(r[1][..], id2[..]); - assert_eq!(r[2][..], id4[..]); - assert_eq!(r[3][..], id1[..]); + assert_eq!(r[0][..], id4[..]); // most recent success + assert_eq!(r[1][..], id3[..]); + + // unknown (old contacts and new nodes), randomly shuffled + assert!( + r[2][..] == id5[..] && r[3][..] == id6[..] || + r[2][..] == id6[..] && r[3][..] == id5[..] + ); + + assert_eq!(r[4][..], id1[..]); // oldest failure + assert_eq!(r[5][..], id2[..]); } #[test] @@ -507,23 +611,27 @@ mod tests { let tempdir = TempDir::new("").unwrap(); let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + { let mut table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned())); table.add_node(node1); table.add_node(node2); + table.add_node(node3); - table.get_mut(&id1).unwrap().attempts = 1; - table.get_mut(&id2).unwrap().attempts = 1; - table.note_failure(&id2); + table.note_success(&id2); + table.note_failure(&id3); } { let table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned())); let r = table.nodes(IpFilter::default()); - assert_eq!(r[0][..], id1[..]); - assert_eq!(r[1][..], id2[..]); + assert_eq!(r[0][..], id2[..]); // latest success + assert_eq!(r[1][..], id1[..]); // unknown + assert_eq!(r[2][..], id3[..]); // oldest failure } } -- GitLab From 28c731881f2da0ceca4752dbcc1a8f9ad041f988 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 8 May 2018 11:22:12 +0200 Subject: [PATCH 126/263] Rlp decode returns Result (#8527) rlp::decode returns Result Make a best effort to handle decoding errors gracefully throughout the code, using `expect` where the value is guaranteed to be valid (and in other places where it makes sense). --- ethcore/light/src/client/header_chain.rs | 27 +++++++++++++----------- ethcore/light/src/net/request_credits.rs | 2 +- ethcore/light/src/types/request/mod.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 4 ++-- ethcore/src/db.rs | 13 +++++------- ethcore/src/encoded.rs | 11 +++++----- ethcore/src/engines/tendermint/mod.rs | 6 ++++-- ethcore/src/header.rs | 4 ++-- ethcore/src/snapshot/account.rs | 6 +++--- ethcore/src/snapshot/mod.rs | 6 +++--- ethcore/src/snapshot/tests/helpers.rs | 2 +- ethcore/src/snapshot/tests/state.rs | 2 +- ethcore/src/state/account.rs | 23 +++++++++++--------- ethcore/src/state/mod.rs | 17 ++++++++++----- ethcore/src/trace/types/flat.rs | 2 +- ethcore/transaction/src/transaction.rs | 5 +++-- ethcore/types/src/receipt.rs | 4 ++-- ethcore/vm/src/call_type.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 3 ++- util/journaldb/src/archivedb.rs | 13 ++++++------ util/journaldb/src/earlymergedb.rs | 2 +- util/journaldb/src/overlaydb.rs | 2 +- util/journaldb/src/overlayrecentdb.rs | 4 ++-- util/journaldb/src/refcounteddb.rs | 15 +++++++------ util/rlp/src/lib.rs | 6 +++--- util/rlp/tests/tests.rs | 6 ++++-- util/rlp_derive/tests/rlp.rs | 4 ++-- whisper/src/message.rs | 4 ++-- 28 files changed, 107 insertions(+), 90 deletions(-) diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index abcb04c366..02a18a60df 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -228,7 +228,7 @@ impl HeaderChain { let decoded_header = spec.genesis_header(); let chain = if let Some(current) = db.get(col, CURRENT_KEY)? { - let curr : BestAndLatest = ::rlp::decode(¤t); + let curr : BestAndLatest = ::rlp::decode(¤t).expect("decoding db value failed"); let mut cur_number = curr.latest_num; let mut candidates = BTreeMap::new(); @@ -236,7 +236,7 @@ impl HeaderChain { // load all era entries, referenced headers within them, // and live epoch proofs. 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).expect("decoding db value failed"); trace!(target: "chain", "loaded header chain entry for era {} with {} candidates", cur_number, entry.candidates.len()); @@ -524,7 +524,10 @@ impl HeaderChain { None } Ok(None) => panic!("stored candidates always have corresponding headers; qed"), - Ok(Some(header)) => Some((epoch_transition, ::rlp::decode(&header))), + Ok(Some(header)) => Some(( + epoch_transition, + ::rlp::decode(&header).expect("decoding value from db failed") + )), }; } } @@ -591,7 +594,7 @@ impl HeaderChain { in an inconsistent state", h_num); ErrorKind::Database(msg.into()) })?; - ::rlp::decode(&bytes) + ::rlp::decode(&bytes).expect("decoding db value failed") }; let total_difficulty = entry.candidates.iter() @@ -604,9 +607,9 @@ impl HeaderChain { .total_difficulty; break Ok(Some(SpecHardcodedSync { - header: header, - total_difficulty: total_difficulty, - chts: chts, + header, + total_difficulty, + chts, })); }, None => { @@ -742,7 +745,7 @@ impl HeaderChain { /// so including it within a CHT would be redundant. pub fn cht_root(&self, n: usize) -> Option { match self.db.get(self.col, cht_key(n as u64).as_bytes()) { - Ok(val) => val.map(|x| ::rlp::decode(&x)), + Ok(db_fetch) => db_fetch.map(|bytes| ::rlp::decode(&bytes).expect("decoding value from db failed")), Err(e) => { warn!(target: "chain", "Error reading from database: {}", e); None @@ -793,7 +796,7 @@ impl HeaderChain { pub fn pending_transition(&self, hash: H256) -> Option { let key = pending_transition_key(hash); match self.db.get(self.col, &*key) { - Ok(val) => val.map(|x| ::rlp::decode(&x)), + Ok(db_fetch) => db_fetch.map(|bytes| ::rlp::decode(&bytes).expect("decoding value from db failed")), Err(e) => { warn!(target: "chain", "Error reading from database: {}", e); None @@ -1192,7 +1195,7 @@ mod tests { let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600)))); - let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).unwrap(); + let chain = HeaderChain::new(db.clone(), None, &spec, cache, HardcodedSync::Allow).expect("failed to instantiate a new HeaderChain"); let mut parent_hash = genesis_header.hash(); let mut rolling_timestamp = genesis_header.timestamp(); @@ -1211,14 +1214,14 @@ mod tests { parent_hash = header.hash(); let mut tx = db.transaction(); - let pending = chain.insert(&mut tx, header, None).unwrap(); + let pending = chain.insert(&mut tx, header, None).expect("failed inserting a transaction"); db.write(tx).unwrap(); chain.apply_pending(pending); rolling_timestamp += 10; } - let hardcoded_sync = chain.read_hardcoded_sync().unwrap().unwrap(); + let hardcoded_sync = chain.read_hardcoded_sync().expect("failed reading hardcoded sync").expect("failed unwrapping hardcoded sync"); assert_eq!(hardcoded_sync.chts.len(), 3); assert_eq!(hardcoded_sync.total_difficulty, total_difficulty); let decoded: Header = hardcoded_sync.header.decode(); diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index abe609dabb..29570b613c 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -407,7 +407,7 @@ mod tests { let costs = CostTable::default(); let serialized = ::rlp::encode(&costs); - let new_costs: CostTable = ::rlp::decode(&*serialized); + let new_costs: CostTable = ::rlp::decode(&*serialized).unwrap(); assert_eq!(costs, new_costs); } diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index 8d911d3f55..bda992df97 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -1642,7 +1642,7 @@ mod tests { { // check as single value. let bytes = ::rlp::encode(&val); - let new_val: T = ::rlp::decode(&bytes); + let new_val: T = ::rlp::decode(&bytes).unwrap(); assert_eq!(val, new_val); // check as list containing single value. diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 57bcdf2bc2..0e18c5f889 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -438,7 +438,7 @@ impl<'a> Iterator for EpochTransitionIter<'a> { return None } - let transitions: EpochTransitions = ::rlp::decode(&val[..]); + let transitions: EpochTransitions = ::rlp::decode(&val[..]).expect("decode error: the db is corrupted or the data structure has changed"); // if there are multiple candidates, at most one will be on the // canon chain. @@ -462,7 +462,7 @@ impl<'a> Iterator for EpochTransitionIter<'a> { impl BlockChain { /// Create new instance of blockchain from given Genesis. pub fn new(config: Config, genesis: &[u8], db: Arc) -> BlockChain { - // 400 is the avarage size of the key + // 400 is the average size of the key let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400); let mut bc = BlockChain { diff --git a/ethcore/src/db.rs b/ethcore/src/db.rs index d11adc7710..a1c7d6b0f5 100644 --- a/ethcore/src/db.rs +++ b/ethcore/src/db.rs @@ -218,15 +218,12 @@ impl Writable for DBTransaction { } impl Readable for KVDB { - fn read(&self, col: Option, key: &Key) -> Option where T: rlp::Decodable, R: Deref { - let result = self.get(col, &key.key()); + fn read(&self, col: Option, key: &Key) -> Option + where T: rlp::Decodable, R: Deref { + self.get(col, &key.key()) + .expect(&format!("db get failed, key: {:?}", &key.key() as &[u8])) + .map(|v| rlp::decode(&v).expect("decode db value failed") ) - match result { - Ok(option) => option.map(|v| rlp::decode(&v)), - Err(err) => { - panic!("db get failed, key: {:?}, err: {:?}", &key.key() as &[u8], err); - } - } } fn exists(&self, col: Option, key: &Key) -> bool where R: Deref { diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 1f627666a9..01df386cc2 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -24,13 +24,12 @@ //! decoded object where parts like the hash can be saved. use block::Block as FullBlock; -use header::{BlockNumber, Header as FullHeader}; -use transaction::UnverifiedTransaction; - +use ethereum_types::{H256, Bloom, U256, Address}; use hash::keccak; +use header::{BlockNumber, Header as FullHeader}; use heapsize::HeapSizeOf; -use ethereum_types::{H256, Bloom, U256, Address}; use rlp::{Rlp, RlpStream}; +use transaction::UnverifiedTransaction; use views::{self, BlockView, HeaderView, BodyView}; /// Owning header view. @@ -48,7 +47,7 @@ impl Header { pub fn new(encoded: Vec) -> Self { Header(encoded) } /// Upgrade this encoded view to a fully owned `Header` object. - pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0) } + pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0).expect("decoding failure") } /// Get a borrowed header view onto the data. #[inline] @@ -205,7 +204,7 @@ impl Block { pub fn header_view(&self) -> HeaderView { self.view().header_view() } /// Decode to a full block. - pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0) } + pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0).expect("decoding failure") } /// Decode the header. pub fn decode_header(&self) -> FullHeader { self.view().rlp().val_at(0) } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index d80a5e182f..93fc347e94 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -143,8 +143,10 @@ impl super::EpochVerifier for EpochVerifier } fn check_finality_proof(&self, proof: &[u8]) -> Option> { - let header: Header = ::rlp::decode(proof); - self.verify_light(&header).ok().map(|_| vec![header.hash()]) + match ::rlp::decode(proof) { + Ok(header) => self.verify_light(&header).ok().map(|_| vec![header.hash()]), + Err(_) => None // REVIEW: log perhaps? Not sure what the policy is. + } } } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index a31aa029b3..ba71eb3049 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -398,7 +398,7 @@ mod tests { let nonce = "88ab4e252a7e8c2a23".from_hex().unwrap(); let nonce_decoded = "ab4e252a7e8c2a23".from_hex().unwrap(); - let header: Header = rlp::decode(&header_rlp); + let header: Header = rlp::decode(&header_rlp).expect("error decoding header"); let seal_fields = header.seal.clone(); assert_eq!(seal_fields.len(), 2); assert_eq!(seal_fields[0], mix_hash); @@ -415,7 +415,7 @@ mod tests { // that's rlp of block header created with ethash engine. let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap(); - let header: Header = rlp::decode(&header_rlp); + let header: Header = rlp::decode(&header_rlp).expect("error decoding header"); let encoded_header = rlp::encode(&header).into_vec(); assert_eq!(header_rlp, encoded_header); diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 6c9e0f3d6e..49f45136e9 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -236,7 +236,7 @@ mod tests { }; let thin_rlp = ::rlp::encode(&account); - assert_eq!(::rlp::decode::(&thin_rlp), account); + assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); let fat_rlp = Rlp::new(&fat_rlps[0]).at(1).unwrap(); @@ -261,7 +261,7 @@ mod tests { }; let thin_rlp = ::rlp::encode(&account); - assert_eq!(::rlp::decode::(&thin_rlp), account); + assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); let fat_rlp = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap(); let fat_rlp = Rlp::new(&fat_rlp[0]).at(1).unwrap(); @@ -286,7 +286,7 @@ mod tests { }; let thin_rlp = ::rlp::encode(&account); - assert_eq!(::rlp::decode::(&thin_rlp), account); + assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); let fat_rlps = to_fat_rlps(&keccak(addr), &account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), 500, 1000).unwrap(); let mut root = KECCAK_NULL_RLP; diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index fbf0c5ca5e..94236e9e95 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -281,7 +281,7 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex(rlp).storage_root); + known_storage_roots.insert(*hash, ::rlp::decode::(rlp)?.storage_root); } if let Some(&(ref hash, ref rlp)) = out_chunk.iter().next() { - known_storage_roots.insert(*hash, ::rlp::decode::(rlp).storage_root); + known_storage_roots.insert(*hash, ::rlp::decode::(rlp)?.storage_root); } Ok(status) } diff --git a/ethcore/src/snapshot/tests/helpers.rs b/ethcore/src/snapshot/tests/helpers.rs index 51f417149b..067a3abab0 100644 --- a/ethcore/src/snapshot/tests/helpers.rs +++ b/ethcore/src/snapshot/tests/helpers.rs @@ -75,7 +75,7 @@ impl StateProducer { // sweep once to alter storage tries. for &mut (ref mut address_hash, ref mut account_data) in &mut accounts_to_modify { - let mut account: BasicAccount = ::rlp::decode(&*account_data); + let mut account: BasicAccount = ::rlp::decode(&*account_data).expect("error decoding basic account"); let acct_db = AccountDBMut::from_hash(db, *address_hash); fill_storage(acct_db, &mut account.storage_root, &mut self.storage_seed); *account_data = DBValue::from_vec(::rlp::encode(&account).into_vec()); diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index f17fa7dde5..05926a7e66 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -114,7 +114,7 @@ fn get_code_from_prev_chunk() { // first one will have code inlined, // second will just have its hash. let thin_rlp = acc_stream.out(); - let acc: BasicAccount = ::rlp::decode(&thin_rlp); + let acc: BasicAccount = ::rlp::decode(&thin_rlp).expect("error decoding basic account"); let mut make_chunk = |acc, hash| { let mut db = MemoryDB::new(); diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index f9c8f258e6..ff7d70bd3a 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -21,6 +21,7 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeMap}; use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP, keccak}; use ethereum_types::{H256, U256, Address}; +use error::Error; use hashdb::HashDB; use kvdb::DBValue; use bytes::{Bytes, ToPretty}; @@ -144,9 +145,10 @@ impl Account { } /// Create a new account from RLP. - pub fn from_rlp(rlp: &[u8]) -> Account { - let basic: BasicAccount = ::rlp::decode(rlp); - basic.into() + pub fn from_rlp(rlp: &[u8]) -> Result { + ::rlp::decode::(rlp) + .map(|ba| ba.into()) + .map_err(|e| e.into()) } /// Create a new contract account. @@ -202,8 +204,8 @@ impl Account { return Ok(value); } let db = SecTrieDB::new(db, &self.storage_root)?; - - let item: U256 = db.get_with(key, ::rlp::decode)?.unwrap_or_else(U256::zero); + let panicky_decoder = |bytes:&[u8]| ::rlp::decode(&bytes).expect("decoding db value failed"); + let item: U256 = db.get_with(key, panicky_decoder)?.unwrap_or_else(U256::zero); let value: H256 = item.into(); self.storage_cache.borrow_mut().insert(key.clone(), value.clone()); Ok(value) @@ -478,7 +480,8 @@ impl Account { let trie = TrieDB::new(db, &self.storage_root)?; let item: U256 = { - let query = (&mut recorder, ::rlp::decode); + let panicky_decoder = |bytes:&[u8]| ::rlp::decode(bytes).expect("decoding db value failed"); + let query = (&mut recorder, panicky_decoder); trie.get_with(&storage_key, query)?.unwrap_or_else(U256::zero) }; @@ -528,7 +531,7 @@ mod tests { a.rlp() }; - let a = Account::from_rlp(&rlp); + let a = Account::from_rlp(&rlp).expect("decoding db value failed"); assert_eq!(*a.storage_root().unwrap(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2".into()); assert_eq!(a.storage_at(&db.immutable(), &0x00u64.into()).unwrap(), 0x1234u64.into()); assert_eq!(a.storage_at(&db.immutable(), &0x01u64.into()).unwrap(), H256::default()); @@ -546,10 +549,10 @@ mod tests { a.rlp() }; - let mut a = Account::from_rlp(&rlp); + let mut a = Account::from_rlp(&rlp).expect("decoding db value failed"); assert!(a.cache_code(&db.immutable()).is_some()); - let mut a = Account::from_rlp(&rlp); + let mut a = Account::from_rlp(&rlp).expect("decoding db value failed"); assert_eq!(a.note_code(vec![0x55, 0x44, 0xffu8]), Ok(())); } @@ -609,7 +612,7 @@ mod tests { #[test] fn rlpio() { let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new()); - let b = Account::from_rlp(&a.rlp()); + let b = Account::from_rlp(&a.rlp()).unwrap(); assert_eq!(a.balance(), b.balance()); assert_eq!(a.nonce(), b.nonce()); assert_eq!(a.code_hash(), b.code_hash()); diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 255dce5b5d..20d564588c 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -605,7 +605,8 @@ impl State { // account is not found in the global cache, get from the DB and insert into local let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); - let maybe_acc = db.get_with(address, Account::from_rlp)?; + let from_rlp = |b: &[u8]| Account::from_rlp(b).expect("decoding db value failed"); + let maybe_acc = db.get_with(address, from_rlp)?; let r = maybe_acc.as_ref().map_or(Ok(H256::new()), |a| { let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), a.address_hash(address)); a.storage_at(account_db.as_hashdb(), key) @@ -983,7 +984,8 @@ impl State { // not found in the global cache, get from the DB and insert into local let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root)?; - let mut maybe_acc = db.get_with(a, Account::from_rlp)?; + let from_rlp = |b: &[u8]| Account::from_rlp(b).expect("decoding db value failed"); + let mut maybe_acc = db.get_with(a, from_rlp)?; if let Some(ref mut account) = maybe_acc.as_mut() { let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), account.address_hash(a)); Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); @@ -1012,7 +1014,8 @@ impl State { None => { let maybe_acc = if !self.db.is_known_null(a) { let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root)?; - AccountEntry::new_clean(db.get_with(a, Account::from_rlp)?) + let from_rlp = |b:&[u8]| { Account::from_rlp(b).expect("decoding db value failed") }; + AccountEntry::new_clean(db.get_with(a, from_rlp)?) } else { AccountEntry::new_clean(None) }; @@ -1064,7 +1067,10 @@ impl State { let mut recorder = Recorder::new(); let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?; let maybe_account: Option = { - let query = (&mut recorder, ::rlp::decode); + let panicky_decoder = |bytes: &[u8]| { + ::rlp::decode(bytes).expect(&format!("prove_account, could not query trie for account key={}", &account_key)) + }; + let query = (&mut recorder, panicky_decoder); trie.get_with(&account_key, query)? }; let account = maybe_account.unwrap_or_else(|| BasicAccount { @@ -1086,7 +1092,8 @@ impl State { // TODO: probably could look into cache somehow but it's keyed by // address, not keccak(address). let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?; - let acc = match trie.get_with(&account_key, Account::from_rlp)? { + let from_rlp = |b: &[u8]| Account::from_rlp(b).expect("decoding db value failed"); + let acc = match trie.get_with(&account_key, from_rlp)? { Some(acc) => acc, None => return Ok((Vec::new(), H256::new())), }; diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index e2746ca7f7..00cf517df8 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -244,7 +244,7 @@ mod tests { ]); let encoded = ::rlp::encode(&block_traces); - let decoded = ::rlp::decode(&encoded); + let decoded = ::rlp::decode(&encoded).expect("error decoding block traces"); assert_eq!(block_traces, decoded); } } diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 571dec3fae..6152e61acb 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -576,7 +576,8 @@ mod tests { #[test] fn sender_test() { - let t: UnverifiedTransaction = rlp::decode(&::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); + let bytes = ::rustc_hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap(); + let t: UnverifiedTransaction = rlp::decode(&bytes).expect("decoding UnverifiedTransaction failed"); assert_eq!(t.data, b""); assert_eq!(t.gas, U256::from(0x5208u64)); assert_eq!(t.gas_price, U256::from(0x01u64)); @@ -645,7 +646,7 @@ mod tests { use rustc_hex::FromHex; let test_vector = |tx_data: &str, address: &'static str| { - let signed = rlp::decode(&FromHex::from_hex(tx_data).unwrap()); + let signed = rlp::decode(&FromHex::from_hex(tx_data).unwrap()).expect("decoding tx data failed"); let signed = SignedTransaction::new(signed).unwrap(); assert_eq!(signed.sender(), address.into()); println!("chainid: {:?}", signed.chain_id()); diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index c1defbc151..8846d27c02 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -193,7 +193,7 @@ mod tests { ); let encoded = ::rlp::encode(&r); assert_eq!(&encoded[..], &expected[..]); - let decoded: Receipt = ::rlp::decode(&encoded); + let decoded: Receipt = ::rlp::decode(&encoded).expect("decoding receipt failed"); assert_eq!(decoded, r); } @@ -211,7 +211,7 @@ mod tests { ); let encoded = ::rlp::encode(&r); assert_eq!(&encoded[..], &expected[..]); - let decoded: Receipt = ::rlp::decode(&encoded); + let decoded: Receipt = ::rlp::decode(&encoded).expect("decoding receipt failed"); assert_eq!(decoded, r); } } diff --git a/ethcore/vm/src/call_type.rs b/ethcore/vm/src/call_type.rs index 83260825f3..dc00b2b839 100644 --- a/ethcore/vm/src/call_type.rs +++ b/ethcore/vm/src/call_type.rs @@ -64,7 +64,7 @@ mod tests { fn should_encode_and_decode_call_type() { let original = CallType::Call; let encoded = encode(&original); - let decoded = decode(&encoded); + let decoded = decode(&encoded).expect("failure decoding CallType"); assert_eq!(original, decoded); } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index badf5bff72..39a2e842db 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -566,7 +566,8 @@ fn rpc_eth_pending_transaction_by_hash() { let tester = EthTester::default(); { - let tx = rlp::decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); + let bytes = FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap(); + let tx = rlp::decode(&bytes).expect("decoding failure"); let tx = SignedTransaction::new(tx).unwrap(); tester.miner.pending_transactions.lock().insert(H256::zero(), tx); } diff --git a/util/journaldb/src/archivedb.rs b/util/journaldb/src/archivedb.rs index e00b37d3c4..b58558a332 100644 --- a/util/journaldb/src/archivedb.rs +++ b/util/journaldb/src/archivedb.rs @@ -45,14 +45,15 @@ pub struct ArchiveDB { impl ArchiveDB { /// Create a new instance from a key-value db. - pub fn new(backing: Arc, col: Option) -> ArchiveDB { - let latest_era = backing.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") - .map(|val| decode::(&val)); + pub fn new(backing: Arc, column: Option) -> ArchiveDB { + let latest_era = backing.get(column, &LATEST_ERA_KEY) + .expect("Low-level database error.") + .map(|val| decode::(&val).expect("decoding db value failed")); ArchiveDB { overlay: MemoryDB::new(), - backing: backing, - latest_era: latest_era, - column: col, + backing, + latest_era, + column, } } diff --git a/util/journaldb/src/earlymergedb.rs b/util/journaldb/src/earlymergedb.rs index bb8e49d41e..e76cdcd313 100644 --- a/util/journaldb/src/earlymergedb.rs +++ b/util/journaldb/src/earlymergedb.rs @@ -263,7 +263,7 @@ impl EarlyMergeDB { let mut refs = HashMap::new(); let mut latest_era = None; if let Some(val) = db.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); + let mut era = decode::(&val).expect("decoding db value failed"); latest_era = Some(era); loop { let mut db_key = DatabaseKey { diff --git a/util/journaldb/src/overlaydb.rs b/util/journaldb/src/overlaydb.rs index fa7ff04596..54d0bb12d7 100644 --- a/util/journaldb/src/overlaydb.rs +++ b/util/journaldb/src/overlaydb.rs @@ -137,7 +137,7 @@ impl OverlayDB { fn payload(&self, key: &H256) -> Option { self.backing.get(self.column, key) .expect("Low-level database error. Some issue with your hard disk?") - .map(|d| decode(&d)) + .map(|d| decode(&d).expect("decoding db value failed")) } /// Put the refs and value of the given key, possibly deleting it from the db. diff --git a/util/journaldb/src/overlayrecentdb.rs b/util/journaldb/src/overlayrecentdb.rs index fdc178350e..2c9ce5cb1d 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -186,7 +186,7 @@ impl OverlayRecentDB { let mut earliest_era = None; let mut cumulative_size = 0; if let Some(val) = db.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); + let mut era = decode::(&val).expect("decoding db value failed"); latest_era = Some(era); loop { let mut db_key = DatabaseKey { @@ -195,7 +195,7 @@ impl OverlayRecentDB { }; while let Some(rlp_data) = db.get(col, &encode(&db_key)).expect("Low-level database error.") { trace!("read_overlay: era={}, index={}", era, db_key.index); - let value = decode::(&rlp_data); + let value = decode::(&rlp_data).expect(&format!("read_overlay: Error decoding DatabaseValue era={}, index{}", era, db_key.index)); count += value.inserts.len(); let mut inserted_keys = Vec::new(); for (k, v) in value.inserts { diff --git a/util/journaldb/src/refcounteddb.rs b/util/journaldb/src/refcounteddb.rs index bf366faf75..944d81d373 100644 --- a/util/journaldb/src/refcounteddb.rs +++ b/util/journaldb/src/refcounteddb.rs @@ -62,17 +62,18 @@ pub struct RefCountedDB { impl RefCountedDB { /// Create a new instance given a `backing` database. - pub fn new(backing: Arc, col: Option) -> RefCountedDB { - let latest_era = backing.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") - .map(|val| decode::(&val)); + pub fn new(backing: Arc, column: Option) -> RefCountedDB { + let latest_era = backing.get(column, &LATEST_ERA_KEY) + .expect("Low-level database error.") + .map(|v| decode::(&v).expect("decoding db value failed")); RefCountedDB { - forward: OverlayDB::new(backing.clone(), col), - backing: backing, + forward: OverlayDB::new(backing.clone(), column), + backing, inserts: vec![], removes: vec![], - latest_era: latest_era, - column: col, + latest_era, + column, } } } diff --git a/util/rlp/src/lib.rs b/util/rlp/src/lib.rs index a6754e22de..b416b1c25b 100644 --- a/util/rlp/src/lib.rs +++ b/util/rlp/src/lib.rs @@ -63,13 +63,13 @@ pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; /// /// fn main () { /// let data = vec![0x83, b'c', b'a', b't']; -/// let animal: String = rlp::decode(&data); +/// let animal: String = rlp::decode(&data).expect("could not decode"); /// assert_eq!(animal, "cat".to_owned()); /// } /// ``` -pub fn decode(bytes: &[u8]) -> T where T: Decodable { +pub fn decode(bytes: &[u8]) -> Result where T: Decodable { let rlp = Rlp::new(bytes); - rlp.as_val().expect("trusted rlp should be valid") + rlp.as_val() } pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable { diff --git a/util/rlp/tests/tests.rs b/util/rlp/tests/tests.rs index 6ff426a773..041c267667 100644 --- a/util/rlp/tests/tests.rs +++ b/util/rlp/tests/tests.rs @@ -209,8 +209,10 @@ struct VDTestPair(Vec, Vec) where T: Decodable + fmt::Debug + cmp::Eq; fn run_decode_tests(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq { for t in &tests { - let res: T = rlp::decode(&t.1); - assert_eq!(res, t.0); + let res : Result = rlp::decode(&t.1); + assert!(res.is_ok()); + let res = res.unwrap(); + assert_eq!(&res, &t.0); } } diff --git a/util/rlp_derive/tests/rlp.rs b/util/rlp_derive/tests/rlp.rs index c873805247..ba51309146 100644 --- a/util/rlp_derive/tests/rlp.rs +++ b/util/rlp_derive/tests/rlp.rs @@ -24,7 +24,7 @@ fn test_encode_foo() { let out = encode(&foo).into_vec(); assert_eq!(out, expected); - let decoded = decode(&expected); + let decoded = decode(&expected).expect("decode failure"); assert_eq!(foo, decoded); } @@ -38,7 +38,7 @@ fn test_encode_foo_wrapper() { let out = encode(&foo).into_vec(); assert_eq!(out, expected); - let decoded = decode(&expected); + let decoded = decode(&expected).expect("decode failure"); assert_eq!(foo, decoded); } diff --git a/whisper/src/message.rs b/whisper/src/message.rs index fbf2faf3fd..d0de9af4b5 100644 --- a/whisper/src/message.rs +++ b/whisper/src/message.rs @@ -446,7 +446,7 @@ mod tests { }; let encoded = ::rlp::encode(&envelope); - let decoded = ::rlp::decode(&encoded); + let decoded = ::rlp::decode(&encoded).expect("failure decoding Envelope"); assert_eq!(envelope, decoded) } @@ -462,7 +462,7 @@ mod tests { }; let encoded = ::rlp::encode(&envelope); - let decoded = ::rlp::decode(&encoded); + let decoded = ::rlp::decode(&encoded).expect("failure decoding Envelope"); assert_eq!(envelope, decoded) } -- GitLab From ac3de4c5fca0c0b469aa2198c42e92f04be18626 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 9 May 2018 08:47:21 +0200 Subject: [PATCH 127/263] Parity as a library (#8412) * Parity as a library * Fix concerns * Allow using a null on_client_restart_cb * Fix more concerns * Test the C library in test.sh * Reduce CMake version to 3.5 * Move the clib test before cargo test * Add println in test --- Cargo.lock | 8 +- Cargo.toml | 5 +- parity-clib-example/CMakeLists.txt | 19 ++ parity-clib-example/main.cpp | 28 +++ parity-clib/Cargo.toml | 17 ++ parity-clib/parity.h | 93 ++++++++++ parity-clib/src/lib.rs | 133 ++++++++++++++ parity/blockchain.rs | 7 - parity/cli/usage.rs | 1 + parity/configuration.rs | 41 +++-- parity/lib.rs | 249 ++++++++++++++++++++++++++ parity/main.rs | 275 +++++++---------------------- parity/run.rs | 138 +++++---------- parity/snapshot.rs | 3 - parity/url.rs | 3 +- test.sh | 16 +- 16 files changed, 702 insertions(+), 334 deletions(-) create mode 100644 parity-clib-example/CMakeLists.txt create mode 100644 parity-clib-example/main.cpp create mode 100644 parity-clib/Cargo.toml create mode 100644 parity-clib/parity.h create mode 100644 parity-clib/src/lib.rs create mode 100644 parity/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ceb14ff277..64e468e670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1954,7 +1954,6 @@ dependencies = [ "ethcore-private-tx 1.0.0", "ethcore-secretstore 1.0.0", "ethcore-service 0.1.0", - "ethcore-stratum 1.12.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2008,6 +2007,13 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parity-clib" +version = "1.12.0" +dependencies = [ + "parity 1.12.0", +] + [[package]] name = "parity-dapps" version = "1.12.0" diff --git a/Cargo.toml b/Cargo.toml index a611458e65..de1a78bf4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ ethcore-miner = { path = "miner" } ethcore-network = { path = "util/network" } ethcore-private-tx = { path = "ethcore/private-tx" } ethcore-service = { path = "ethcore/service" } -ethcore-stratum = { path = "ethcore/stratum" } ethcore-sync = { path = "ethcore/sync" } ethcore-transaction = { path = "ethcore/transaction" } ethereum-types = "0.3" @@ -108,6 +107,9 @@ slow-blocks = ["ethcore/slow-blocks"] secretstore = ["ethcore-secretstore"] final = ["parity-version/final"] +[lib] +path = "parity/lib.rs" + [[bin]] path = "parity/main.rs" name = "parity" @@ -130,6 +132,7 @@ members = [ "ethstore/cli", "evmbin", "miner", + "parity-clib", "transaction-pool", "whisper", "whisper/cli", diff --git a/parity-clib-example/CMakeLists.txt b/parity-clib-example/CMakeLists.txt new file mode 100644 index 0000000000..143d014e32 --- /dev/null +++ b/parity-clib-example/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.5) +include(ExternalProject) + +include_directories("${CMAKE_SOURCE_DIR}/../parity-clib") + +add_executable(parity-example main.cpp) + +ExternalProject_Add( + libparity + DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + COMMAND cargo build -p parity-clib # Note: use --release in a real project + BINARY_DIR "${CMAKE_SOURCE_DIR}/../target" + INSTALL_COMMAND "" + LOG_BUILD ON) + +add_dependencies(parity-example libparity) +target_link_libraries(parity-example "${CMAKE_SOURCE_DIR}/../target/debug/libparity.so") diff --git a/parity-clib-example/main.cpp b/parity-clib-example/main.cpp new file mode 100644 index 0000000000..1fadf1b5b5 --- /dev/null +++ b/parity-clib-example/main.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +void on_restart(void*, const char*, size_t) {} + +int main() { + ParityParams cfg = { 0 }; + cfg.on_client_restart_cb = on_restart; + + const char* args[] = {"--light"}; + size_t str_lens[] = {7}; + if (parity_config_from_cli(args, str_lens, 1, &cfg.configuration) != 0) { + return 1; + } + + void* parity; + if (parity_start(&cfg, &parity) != 0) { + return 1; + } + + sleep(5); + if (parity != NULL) { + parity_destroy(parity); + } + + return 0; +} diff --git a/parity-clib/Cargo.toml b/parity-clib/Cargo.toml new file mode 100644 index 0000000000..001f954c21 --- /dev/null +++ b/parity-clib/Cargo.toml @@ -0,0 +1,17 @@ +[package] +description = "C bindings for the Parity Ethereum client" +name = "parity-clib" +version = "1.12.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[lib] +name = "parity" +crate-type = ["cdylib", "staticlib"] + +[dependencies] +parity = { path = "../", default-features = false } + +[features] +default = [] +final = ["parity/final"] diff --git a/parity-clib/parity.h b/parity-clib/parity.h new file mode 100644 index 0000000000..b61da8e458 --- /dev/null +++ b/parity-clib/parity.h @@ -0,0 +1,93 @@ +// Copyright 2018 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 . + +#ifndef _PARITY_H_INCLUDED_ +#define _PARITY_H_INCLUDED_ + +#include + +/// Parameters to pass to `parity_start`. +struct ParityParams { + /// Configuration object, as handled by the `parity_config_*` functions. + /// Note that calling `parity_start` will destroy the configuration object (even on failure). + void *configuration; + + /// Callback function to call when the client receives an RPC request to change its chain spec. + /// + /// Will only be called if you enable the `--can-restart` flag. + /// + /// The first parameter of the callback is the value of `on_client_restart_cb_custom`. + /// The second and third parameters of the callback are the string pointer and length. + void (*on_client_restart_cb)(void* custom, const char* new_chain, size_t new_chain_len); + + /// Custom parameter passed to the `on_client_restart_cb` callback as first parameter. + void *on_client_restart_cb_custom; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/// Builds a new configuration object by parsing a list of CLI arguments. +/// +/// The first two parameters are string pointers and string lengths. They must have a length equal +/// to `len`. The strings don't need to be zero-terminated. +/// +/// On success, the produced object will be written to the `void*` pointed by `out`. +/// +/// Returns 0 on success, and non-zero on error. +/// +/// # Example +/// +/// ```no_run +/// void* cfg; +/// const char *args[] = {"--light", "--can-restart"}; +/// size_t str_lens[] = {7, 13}; +/// if (parity_config_from_cli(args, str_lens, 2, &cfg) != 0) { +/// return 1; +/// } +/// ``` +/// +int parity_config_from_cli(char const* const* args, size_t const* arg_lens, size_t len, void** out); + +/// Destroys a configuration object created earlier. +/// +/// **Important**: You probably don't need to call this function. Calling `parity_start` destroys +/// the configuration object as well (even on failure). +void parity_config_destroy(void* cfg); + +/// Starts the parity client in background threads. Returns a pointer to a struct that represents +/// the running client. Can also return NULL if the execution completes instantly. +/// +/// **Important**: The configuration object passed inside `cfg` is destroyed when you +/// call `parity_start` (even on failure). +/// +/// On success, the produced object will be written to the `void*` pointed by `out`. +/// +/// Returns 0 on success, and non-zero on error. +int parity_start(const ParityParams* params, void** out); + +/// Destroys the parity client created with `parity_start`. +/// +/// **Warning**: `parity_start` can return NULL if execution finished instantly, in which case you +/// must not call this function. +void parity_destroy(void* parity); + +#ifdef __cplusplus +} +#endif + +#endif // include guard diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs new file mode 100644 index 0000000000..b08d6487d1 --- /dev/null +++ b/parity-clib/src/lib.rs @@ -0,0 +1,133 @@ +// Copyright 2018 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 . + +//! Note that all the structs and functions here are documented in `parity.h`, to avoid +//! duplicating documentation. + +extern crate parity; + +use std::os::raw::{c_char, c_void, c_int}; +use std::panic; +use std::ptr; +use std::slice; + +#[repr(C)] +pub struct ParityParams { + pub configuration: *mut c_void, + pub on_client_restart_cb: Option, + pub on_client_restart_cb_custom: *mut c_void, +} + +#[no_mangle] +pub extern fn parity_config_from_cli(args: *const *const c_char, args_lens: *const usize, len: usize, output: *mut *mut c_void) -> c_int { + unsafe { + panic::catch_unwind(|| { + *output = ptr::null_mut(); + + let args = { + let arg_ptrs = slice::from_raw_parts(args, len); + let arg_lens = slice::from_raw_parts(args_lens, len); + + let mut args = Vec::with_capacity(len + 1); + args.push("parity".to_owned()); + + for (&arg, &len) in arg_ptrs.iter().zip(arg_lens.iter()) { + let string = slice::from_raw_parts(arg as *const u8, len); + match String::from_utf8(string.to_owned()) { + Ok(a) => args.push(a), + Err(_) => return 1, + }; + } + + args + }; + + match parity::Configuration::parse_cli(&args) { + Ok(mut cfg) => { + // Always disable the auto-updater when used as a library. + cfg.args.arg_auto_update = "none".to_owned(); + + let cfg = Box::into_raw(Box::new(cfg)); + *output = cfg as *mut _; + 0 + }, + Err(_) => { + 1 + }, + } + }).unwrap_or(1) + } +} + +#[no_mangle] +pub extern fn parity_config_destroy(cfg: *mut c_void) { + unsafe { + let _ = panic::catch_unwind(|| { + let _cfg = Box::from_raw(cfg as *mut parity::Configuration); + }); + } +} + +#[no_mangle] +pub extern fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) -> c_int { + unsafe { + panic::catch_unwind(|| { + *output = ptr::null_mut(); + let cfg: &ParityParams = &*cfg; + + let config = Box::from_raw(cfg.configuration as *mut parity::Configuration); + + let on_client_restart_cb = { + struct Cb(Option, *mut c_void); + unsafe impl Send for Cb {} + unsafe impl Sync for Cb {} + impl Cb { + fn call(&self, new_chain: String) { + if let Some(ref cb) = self.0 { + cb(self.1, new_chain.as_bytes().as_ptr() as *const _, new_chain.len()) + } + } + } + let cb = Cb(cfg.on_client_restart_cb, cfg.on_client_restart_cb_custom); + move |new_chain: String| { cb.call(new_chain); } + }; + + let action = match parity::start(*config, on_client_restart_cb, || {}) { + Ok(action) => action, + Err(_) => return 1, + }; + + match action { + parity::ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 }, + parity::ExecutionAction::Instant(None) => 0, + parity::ExecutionAction::Running(client) => { + *output = Box::into_raw(Box::::new(client)) as *mut c_void; + 0 + } + } + }).unwrap_or(1) + } +} + +#[no_mangle] +pub extern fn parity_destroy(client: *mut c_void) { + unsafe { + let _ = panic::catch_unwind(|| { + let client = Box::from_raw(client as *mut parity::RunningClient); + client.shutdown(); + }); + } +} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index f9c2f8ba37..027814f245 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -37,7 +37,6 @@ use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_ use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; -use fdlimit; use ethcore_private_tx; use db; @@ -178,8 +177,6 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { // load user defaults let user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = cmd.pruning.to_algorithm(&user_defaults); @@ -327,8 +324,6 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { // load user defaults let mut user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = cmd.pruning.to_algorithm(&user_defaults); @@ -518,8 +513,6 @@ fn start_client( // load user defaults let user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = pruning.to_algorithm(&user_defaults); diff --git a/parity/cli/usage.rs b/parity/cli/usage.rs index 2bdeaaed1a..ce138fdff3 100644 --- a/parity/cli/usage.rs +++ b/parity/cli/usage.rs @@ -198,6 +198,7 @@ macro_rules! usage { } } + /// Parsed command line arguments. #[derive(Debug, PartialEq)] pub struct Args { $( diff --git a/parity/configuration.rs b/parity/configuration.rs index 93cc9a4dd6..3151621801 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -92,23 +92,30 @@ pub struct Execute { pub cmd: Cmd, } +/// Configuration for the Parity client. #[derive(Debug, PartialEq)] pub struct Configuration { + /// Arguments to be interpreted. pub args: Args, } impl Configuration { - pub fn parse>(command: &[S]) -> Result { - let args = Args::parse(command)?; - + /// Parses a configuration from a list of command line arguments. + /// + /// # Example + /// + /// ``` + /// let _cfg = parity::Configuration::parse_cli(&["--light", "--chain", "koven"]).unwrap(); + /// ``` + pub fn parse_cli>(command: &[S]) -> Result { let config = Configuration { - args: args, + args: Args::parse(command)?, }; Ok(config) } - pub fn into_command(self) -> Result { + pub(crate) fn into_command(self) -> Result { let dirs = self.directories(); let pruning = self.args.arg_pruning.parse()?; let pruning_history = self.args.arg_pruning_history; @@ -1843,7 +1850,7 @@ mod tests { let filename = tempdir.path().join("peers"); File::create(&filename).unwrap().write_all(b" \n\t\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); assert!(conf.init_reserved_nodes().is_ok()); } @@ -1853,7 +1860,7 @@ mod tests { let filename = tempdir.path().join("peers_comments"); File::create(&filename).unwrap().write_all(b"# Sample comment\nenode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@172.0.0.1:30303\n").unwrap(); let args = vec!["parity", "--reserved-peers", filename.to_str().unwrap()]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); let reserved_nodes = conf.init_reserved_nodes(); assert!(reserved_nodes.is_ok()); assert_eq!(reserved_nodes.unwrap().len(), 1); @@ -1862,7 +1869,7 @@ mod tests { #[test] fn test_dev_preset() { let args = vec!["parity", "--config", "dev"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1876,7 +1883,7 @@ mod tests { #[test] fn test_mining_preset() { let args = vec!["parity", "--config", "mining"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 50); @@ -1898,7 +1905,7 @@ mod tests { #[test] fn test_non_standard_ports_preset() { let args = vec!["parity", "--config", "non-standard-ports"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.network_port, 30305); @@ -1911,7 +1918,7 @@ mod tests { #[test] fn test_insecure_preset() { let args = vec!["parity", "--config", "insecure"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.update_policy.require_consensus, false); @@ -1931,7 +1938,7 @@ mod tests { #[test] fn test_dev_insecure_preset() { let args = vec!["parity", "--config", "dev-insecure"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_settings.chain, "dev"); @@ -1954,7 +1961,7 @@ mod tests { #[test] fn test_override_preset() { let args = vec!["parity", "--config", "mining", "--min-peers=99"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 99); @@ -2077,7 +2084,7 @@ mod tests { #[test] fn should_respect_only_max_peers_and_default() { let args = vec!["parity", "--max-peers=50"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 25); @@ -2090,7 +2097,7 @@ mod tests { #[test] fn should_respect_only_max_peers_less_than_default() { let args = vec!["parity", "--max-peers=5"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2103,7 +2110,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_default() { let args = vec!["parity", "--min-peers=5"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 5); @@ -2116,7 +2123,7 @@ mod tests { #[test] fn should_respect_only_min_peers_and_greater_than_default() { let args = vec!["parity", "--min-peers=500"]; - let conf = Configuration::parse(&args).unwrap(); + let conf = Configuration::parse_cli(&args).unwrap(); match conf.into_command().unwrap().cmd { Cmd::Run(c) => { assert_eq!(c.net_conf.min_peers, 500); diff --git a/parity/lib.rs b/parity/lib.rs new file mode 100644 index 0000000000..4d9d1a2c95 --- /dev/null +++ b/parity/lib.rs @@ -0,0 +1,249 @@ +// Copyright 2015-2018 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 . + +//! Ethcore client application. + +#![warn(missing_docs)] + +extern crate ansi_term; +extern crate docopt; +#[macro_use] +extern crate clap; +extern crate dir; +extern crate env_logger; +extern crate futures; +extern crate futures_cpupool; +extern crate atty; +extern crate jsonrpc_core; +extern crate num_cpus; +extern crate number_prefix; +extern crate parking_lot; +extern crate regex; +extern crate rlp; +extern crate rpassword; +extern crate rustc_hex; +extern crate semver; +extern crate serde; +extern crate serde_json; +#[macro_use] +extern crate serde_derive; +extern crate toml; + +extern crate ethcore; +extern crate ethcore_bytes as bytes; +extern crate ethcore_io as io; +extern crate ethcore_light as light; +extern crate ethcore_logger; +extern crate ethcore_miner as miner; +extern crate ethcore_network as network; +extern crate ethcore_private_tx; +extern crate ethcore_service; +extern crate ethcore_sync as sync; +extern crate ethcore_transaction as transaction; +extern crate ethereum_types; +extern crate ethkey; +extern crate kvdb; +extern crate node_health; +extern crate panic_hook; +extern crate parity_hash_fetch as hash_fetch; +extern crate parity_ipfs_api; +extern crate parity_local_store as local_store; +extern crate parity_reactor; +extern crate parity_rpc; +extern crate parity_updater as updater; +extern crate parity_version; +extern crate parity_whisper; +extern crate path; +extern crate rpc_cli; +extern crate node_filter; +extern crate keccak_hash as hash; +extern crate journaldb; +extern crate registrar; + +#[macro_use] +extern crate log as rlog; + +#[cfg(feature="secretstore")] +extern crate ethcore_secretstore; + +#[cfg(feature = "dapps")] +extern crate parity_dapps; + +#[cfg(test)] +#[macro_use] +extern crate pretty_assertions; + +#[cfg(windows)] extern crate winapi; + +#[cfg(test)] +extern crate tempdir; + +mod account; +mod blockchain; +mod cache; +mod cli; +mod configuration; +mod dapps; +mod export_hardcoded_sync; +mod ipfs; +mod deprecated; +mod helpers; +mod informant; +mod light_helpers; +mod modules; +mod params; +mod presale; +mod rpc; +mod rpc_apis; +mod run; +mod secretstore; +mod signer; +mod snapshot; +mod upgrade; +mod url; +mod user_defaults; +mod whisper; +mod db; + +use std::net::{TcpListener}; +use std::io::BufReader; +use std::fs::File; +use ansi_term::Style; +use hash::keccak_buffer; +use cli::Args; +use configuration::{Cmd, Execute}; +use deprecated::find_deprecated; +use ethcore_logger::{Config as LogConfig, setup_log}; + +pub use self::configuration::Configuration; +pub use self::run::RunningClient; + +fn print_hash_of(maybe_file: Option) -> Result { + if let Some(file) = maybe_file { + let mut f = BufReader::new(File::open(&file).map_err(|_| "Unable to open file".to_owned())?); + let hash = keccak_buffer(&mut f).map_err(|_| "Unable to read from file".to_owned())?; + Ok(format!("{:x}", hash)) + } else { + Err("Streaming from standard input not yet supported. Specify a file.".to_owned()) + } +} + +/// Action that Parity performed when running `start`. +pub enum ExecutionAction { + /// The execution didn't require starting a node, and thus has finished. + /// Contains the string to print on stdout, if any. + Instant(Option), + + /// The client has started running and must be shut down manually by calling `shutdown`. + /// + /// If you don't call `shutdown()`, execution will continue in the background. + Running(RunningClient), +} + +fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Result + where Cr: Fn(String) + 'static + Send, + Rr: Fn() + 'static + Send +{ + // TODO: move this to `main()` and expose in the C API so that users can setup logging the way + // they want + let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed"); + + match command.cmd { + Cmd::Run(run_cmd) => { + if run_cmd.ui_conf.enabled && !run_cmd.ui_conf.info_page_only { + warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead.")); + warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases")); + } + + if run_cmd.ui && run_cmd.dapps_conf.enabled { + // Check if Parity is already running + let addr = format!("{}:{}", run_cmd.ui_conf.interface, run_cmd.ui_conf.port); + if !TcpListener::bind(&addr as &str).is_ok() { + return open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config).map(|_| ExecutionAction::Instant(None)); + } + } + + // start ui + if run_cmd.ui { + open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config)?; + } + + if let Some(ref dapp) = run_cmd.dapp { + open_dapp(&run_cmd.dapps_conf, &run_cmd.http_conf, dapp)?; + } + + let outcome = run::execute(run_cmd, logger, on_client_rq, on_updater_rq)?; + Ok(ExecutionAction::Running(outcome)) + }, + Cmd::Version => Ok(ExecutionAction::Instant(Some(Args::print_version()))), + Cmd::Hash(maybe_file) => print_hash_of(maybe_file).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| ExecutionAction::Instant(None)), + Cmd::SignerToken(ws_conf, ui_conf, logger_config) => signer::execute(ws_conf, ui_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::ExportHardcodedSync(export_hs_cmd) => export_hardcoded_sync::execute(export_hs_cmd).map(|s| ExecutionAction::Instant(Some(s))), + } +} + +/// Starts the parity client. +/// +/// `on_client_rq` is the action to perform when the client receives an RPC request to be restarted +/// with a different chain. +/// +/// `on_updater_rq` is the action to perform when the updater has a new binary to execute. +/// +/// The first parameter is the command line arguments that you would pass when running the parity +/// binary. +/// +/// On error, returns what to print on stderr. +pub fn start(conf: Configuration, on_client_rq: Cr, on_updater_rq: Rr) -> Result + where Cr: Fn(String) + 'static + Send, + Rr: Fn() + 'static + Send +{ + let deprecated = find_deprecated(&conf.args); + for d in deprecated { + println!("{}", d); + } + + execute(conf.into_command()?, on_client_rq, on_updater_rq) +} + +fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { + if !ui_conf.enabled { + return Err("Cannot use UI command with UI turned off.".into()) + } + + let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; + // Open a browser + url::open(&token.url).map_err(|e| format!("{}", e))?; + // Print a message + println!("{}", token.message); + Ok(()) +} + +fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { + if !dapps_conf.enabled { + return Err("Cannot use DAPP command with Dapps turned off.".into()) + } + + let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); + url::open(&url).map_err(|e| format!("{}", e))?; + Ok(()) +} diff --git a/parity/main.rs b/parity/main.rs index 6774a83864..e489ad865e 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,187 +18,28 @@ #![warn(missing_docs)] -extern crate ansi_term; +extern crate parity; + extern crate ctrlc; -extern crate docopt; -#[macro_use] -extern crate clap; extern crate dir; -extern crate env_logger; extern crate fdlimit; -extern crate futures; -extern crate futures_cpupool; -extern crate atty; -extern crate jsonrpc_core; -extern crate num_cpus; -extern crate number_prefix; -extern crate parking_lot; -extern crate regex; -extern crate rlp; -extern crate rpassword; -extern crate rustc_hex; -extern crate semver; -extern crate serde; -extern crate serde_json; #[macro_use] -extern crate serde_derive; -extern crate toml; - -extern crate ethcore; -extern crate ethcore_bytes as bytes; -extern crate ethcore_io as io; -extern crate ethcore_light as light; -extern crate ethcore_logger; -extern crate ethcore_miner as miner; -extern crate ethcore_network as network; -extern crate ethcore_private_tx; -extern crate ethcore_service; -extern crate ethcore_sync as sync; -extern crate ethcore_transaction as transaction; -extern crate ethereum_types; -extern crate ethkey; -extern crate kvdb; -extern crate node_health; +extern crate log; extern crate panic_hook; -extern crate parity_hash_fetch as hash_fetch; -extern crate parity_ipfs_api; -extern crate parity_local_store as local_store; -extern crate parity_reactor; -extern crate parity_rpc; -extern crate parity_updater as updater; -extern crate parity_version; -extern crate parity_whisper; -extern crate path; -extern crate rpc_cli; -extern crate node_filter; -extern crate keccak_hash as hash; -extern crate journaldb; -extern crate registrar; - -#[macro_use] -extern crate log as rlog; - -#[cfg(feature="stratum")] -extern crate ethcore_stratum; - -#[cfg(feature="secretstore")] -extern crate ethcore_secretstore; - -#[cfg(feature = "dapps")] -extern crate parity_dapps; - -#[cfg(test)] -#[macro_use] -extern crate pretty_assertions; +extern crate parking_lot; #[cfg(windows)] extern crate winapi; -#[cfg(test)] -extern crate tempdir; - -mod account; -mod blockchain; -mod cache; -mod cli; -mod configuration; -mod dapps; -mod export_hardcoded_sync; -mod ipfs; -mod deprecated; -mod helpers; -mod informant; -mod light_helpers; -mod modules; -mod params; -mod presale; -mod rpc; -mod rpc_apis; -mod run; -mod secretstore; -mod signer; -mod snapshot; -mod upgrade; -mod url; -mod user_defaults; -mod whisper; -mod db; - -#[cfg(feature="stratum")] -mod stratum; - use std::{process, env}; -use std::collections::HashMap; -use std::io::{self as stdio, BufReader, Read, Write}; +use std::io::{self as stdio, Read, Write}; use std::fs::{remove_file, metadata, File, create_dir_all}; use std::path::PathBuf; -use hash::keccak_buffer; -use cli::Args; -use configuration::{Cmd, Execute, Configuration}; -use deprecated::find_deprecated; -use ethcore_logger::setup_log; +use std::sync::Arc; +use ctrlc::CtrlC; use dir::default_hypervisor_path; - -fn print_hash_of(maybe_file: Option) -> Result { - if let Some(file) = maybe_file { - let mut f = BufReader::new(File::open(&file).map_err(|_| "Unable to open file".to_owned())?); - let hash = keccak_buffer(&mut f).map_err(|_| "Unable to read from file".to_owned())?; - Ok(format!("{:x}", hash)) - } else { - Err("Streaming from standard input not yet supported. Specify a file.".to_owned()) - } -} - -enum PostExecutionAction { - Print(String), - Restart(Option), - Quit, -} - -fn execute(command: Execute, can_restart: bool) -> Result { - let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed"); - - match command.cmd { - Cmd::Run(run_cmd) => { - let (restart, spec_name) = run::execute(run_cmd, can_restart, logger)?; - Ok(if restart { PostExecutionAction::Restart(spec_name) } else { PostExecutionAction::Quit }) - }, - Cmd::Version => Ok(PostExecutionAction::Print(Args::print_version())), - Cmd::Hash(maybe_file) => print_hash_of(maybe_file).map(|s| PostExecutionAction::Print(s)), - Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| PostExecutionAction::Print(s)), - Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| PostExecutionAction::Print(s)), - Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| PostExecutionAction::Quit), - Cmd::SignerToken(ws_conf, ui_conf, logger_config) => signer::execute(ws_conf, ui_conf, logger_config).map(|s| PostExecutionAction::Print(s)), - Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| PostExecutionAction::Print(s)), - Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| PostExecutionAction::Print(s)), - Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| PostExecutionAction::Print(s)), - Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd).map(|s| PostExecutionAction::Print(s)), - Cmd::ExportHardcodedSync(export_hs_cmd) => export_hardcoded_sync::execute(export_hs_cmd).map(|s| PostExecutionAction::Print(s)), - } -} - -fn start(mut args: Vec) -> Result { - args.insert(0, "parity".to_owned()); - let conf = Configuration::parse(&args).unwrap_or_else(|e| e.exit()); - let can_restart = conf.args.flag_can_restart; - - let deprecated = find_deprecated(&conf.args); - for d in deprecated { - println!("{}", d); - } - - let cmd = conf.into_command()?; - execute(cmd, can_restart) -} - -#[cfg(not(feature="stratum"))] -fn stratum_main(_: &mut HashMap) {} - -#[cfg(feature="stratum")] -fn stratum_main(alt_mains: &mut HashMap) { - alt_mains.insert("stratum".to_owned(), stratum::main); -} - -fn sync_main(_: &mut HashMap) {} +use fdlimit::raise_fd_limit; +use parity::{start, ExecutionAction}; +use parking_lot::{Condvar, Mutex}; fn updates_path(name: &str) -> PathBuf { let mut dest = PathBuf::from(default_hypervisor_path()); @@ -275,48 +116,68 @@ const PLEASE_RESTART_EXIT_CODE: i32 = 69; // Returns the exit error code. fn main_direct(force_can_restart: bool) -> i32 { global_init(); - let mut alt_mains = HashMap::new(); - sync_main(&mut alt_mains); - stratum_main(&mut alt_mains); - let res = if let Some(f) = std::env::args().nth(1).and_then(|arg| alt_mains.get(&arg.to_string())) { - f(); - 0 + + let mut conf = { + let args = std::env::args().collect::>(); + parity::Configuration::parse_cli(&args).unwrap_or_else(|e| e.exit()) + }; + + if let Some(spec_override) = take_spec_name_override() { + conf.args.flag_testnet = false; + conf.args.arg_chain = spec_override; + } + + let can_restart = force_can_restart || conf.args.flag_can_restart; + + // increase max number of open files + raise_fd_limit(); + + let exit = Arc::new((Mutex::new((false, None)), Condvar::new())); + + let exec = if can_restart { + let e1 = exit.clone(); + let e2 = exit.clone(); + start(conf, + move |new_chain: String| { *e1.0.lock() = (true, Some(new_chain)); e1.1.notify_all(); }, + move || { *e2.0.lock() = (true, None); e2.1.notify_all(); }) } else { - let mut args = std::env::args().skip(1).collect::>(); - if force_can_restart && !args.iter().any(|arg| arg == "--can-restart") { - args.push("--can-restart".to_owned()); - } + trace!(target: "mode", "Not hypervised: not setting exit handlers."); + start(conf, move |_| {}, move || {}) + }; - if let Some(spec_override) = take_spec_name_override() { - args.retain(|f| f != "--testnet"); - args.retain(|f| !f.starts_with("--chain=")); - while let Some(pos) = args.iter().position(|a| a == "--chain") { - if args.len() > pos + 1 { - args.remove(pos + 1); + let res = match exec { + Ok(result) => match result { + ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 }, + ExecutionAction::Instant(None) => 0, + ExecutionAction::Running(client) => { + CtrlC::set_handler({ + let e = exit.clone(); + move || { e.1.notify_all(); } + }); + + // Wait for signal + let mut lock = exit.0.lock(); + let _ = exit.1.wait(&mut lock); + + client.shutdown(); + + match &*lock { + &(true, ref spec_name_override) => { + if let &Some(ref spec_name) = spec_name_override { + set_spec_name_override(spec_name.clone()); + } + PLEASE_RESTART_EXIT_CODE + }, + _ => 0, } - args.remove(pos); - } - args.push("--chain".to_owned()); - args.push(spec_override); - } - - match start(args) { - Ok(result) => match result { - PostExecutionAction::Print(s) => { println!("{}", s); 0 }, - PostExecutionAction::Restart(spec_name_override) => { - if let Some(spec_name) = spec_name_override { - set_spec_name_override(spec_name); - } - PLEASE_RESTART_EXIT_CODE - }, - PostExecutionAction::Quit => 0, - }, - Err(err) => { - writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed"); - 1 }, - } + }, + Err(err) => { + writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed"); + 1 + }, }; + global_cleanup(); res } diff --git a/parity/run.rs b/parity/run.rs index fdb32293b9..73113055bb 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -19,10 +19,8 @@ use std::fmt; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; use std::thread; -use std::net::{TcpListener}; -use ansi_term::{Colour, Style}; -use ctrlc::CtrlC; +use ansi_term::Colour; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; use ethcore::ethstore::ethkey; @@ -34,7 +32,6 @@ use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_service::ClientService; use sync::{self, SyncConfig}; use miner::work_notify::WorkPoster; -use fdlimit::raise_fd_limit; use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; @@ -45,7 +42,6 @@ use node_filter::NodeFilter; use node_health; use parity_reactor::EventLoop; use parity_rpc::{NetworkSettings, informant, is_major_importing}; -use parking_lot::{Condvar, Mutex}; use updater::{UpdatePolicy, Updater}; use parity_version::version; use ethcore_private_tx::{ProviderConfig, EncryptorConfig, SecretStoreEncryptor}; @@ -65,7 +61,6 @@ use rpc; use rpc_apis; use secretstore; use signer; -use url; use db; // how often to take periodic snapshots. @@ -138,28 +133,6 @@ pub struct RunCmd { pub no_hardcoded_sync: bool, } -pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { - if !ui_conf.enabled { - return Err("Cannot use UI command with UI turned off.".into()) - } - - let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; - // Open a browser - url::open(&token.url).map_err(|e| format!("{}", e))?; - // Print a message - println!("{}", token.message); - Ok(()) -} - -pub fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { - if !dapps_conf.enabled { - return Err("Cannot use DAPP command with Dapps turned off.".into()) - } - - let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); - url::open(&url).map_err(|e| format!("{}", e))?; - Ok(()) -} // node info fetcher for the local store. struct FullNodeInfo { miner: Option>, // TODO: only TXQ needed, just use that after decoupling. @@ -415,10 +388,12 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: }, }; - // start ui - if cmd.ui { - open_ui(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config)?; - } - - if let Some(dapp) = cmd.dapp { - open_dapp(&cmd.dapps_conf, &cmd.http_conf, &dapp)?; - } - client.set_exit_handler(on_client_rq); updater.set_exit_handler(on_updater_rq); - Ok(RunningClient::Full { - informant, - client, - keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + Ok(RunningClient { + inner: RunningClientInner::Full { + informant, + client, + keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + } }) } -enum RunningClient { +/// Parity client currently executing in background threads. +/// +/// Should be destroyed by calling `shutdown()`, otherwise execution will continue in the +/// background. +pub struct RunningClient { + inner: RunningClientInner +} + +enum RunningClientInner { Light { informant: Arc>, client: Arc, @@ -931,9 +907,10 @@ enum RunningClient { } impl RunningClient { - fn shutdown(self) { - match self { - RunningClient::Light { informant, client, keep_alive } => { + /// Shuts down the client. + pub fn shutdown(self) { + match self.inner { + RunningClientInner::Light { informant, client, keep_alive } => { // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); @@ -943,7 +920,7 @@ impl RunningClient { drop(client); wait_for_drop(weak_client); }, - RunningClient::Full { informant, client, keep_alive } => { + RunningClientInner::Full { informant, client, keep_alive } => { info!("Finishing work, please wait..."); // Create a weak reference to the client so that we can wait on shutdown // until it is dropped @@ -961,51 +938,24 @@ impl RunningClient { } } -pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<(bool, Option), String> { - if cmd.ui_conf.enabled && !cmd.ui_conf.info_page_only { - warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead.")); - warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases")); - } - - if cmd.ui && cmd.dapps_conf.enabled { - // Check if Parity is already running - let addr = format!("{}:{}", cmd.ui_conf.interface, cmd.ui_conf.port); - if !TcpListener::bind(&addr as &str).is_ok() { - return open_ui(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config).map(|_| (false, None)); - } - } - - // increase max number of open files - raise_fd_limit(); - - let exit = Arc::new((Mutex::new((false, None)), Condvar::new())); - - let running_client = if cmd.light { - execute_light_impl(cmd, logger)? - } else if can_restart { - let e1 = exit.clone(); - let e2 = exit.clone(); - execute_impl(cmd, logger, - move |new_chain: String| { *e1.0.lock() = (true, Some(new_chain)); e1.1.notify_all(); }, - move || { *e2.0.lock() = (true, None); e2.1.notify_all(); })? +/// Executes the given run command. +/// +/// `on_client_rq` is the action to perform when the client receives an RPC request to be restarted +/// with a different chain. +/// +/// `on_updater_rq` is the action to perform when the updater has a new binary to execute. +/// +/// On error, returns what to print on stderr. +pub fn execute(cmd: RunCmd, logger: Arc, + on_client_rq: Cr, on_updater_rq: Rr) -> Result + where Cr: Fn(String) + 'static + Send, + Rr: Fn() + 'static + Send +{ + if cmd.light { + execute_light_impl(cmd, logger) } else { - trace!(target: "mode", "Not hypervised: not setting exit handlers."); - execute_impl(cmd, logger, move |_| {}, move || {})? - }; - - // Handle possible exits - CtrlC::set_handler({ - let e = exit.clone(); - move || { e.1.notify_all(); } - }); - - // Wait for signal - let mut l = exit.0.lock(); - let _ = exit.1.wait(&mut l); - - running_client.shutdown(); - - Ok(l.clone()) + execute_impl(cmd, logger, on_client_rq, on_updater_rq) + } } #[cfg(not(windows))] diff --git a/parity/snapshot.rs b/parity/snapshot.rs index ad93801c0b..423864679a 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -35,7 +35,6 @@ use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_ use helpers::{to_client_config, execute_upgrades}; use dir::Directories; use user_defaults::UserDefaults; -use fdlimit; use ethcore_private_tx; use db; @@ -149,8 +148,6 @@ impl SnapshotCommand { // load user defaults let user_defaults = UserDefaults::load(&user_defaults_path)?; - fdlimit::raise_fd_limit(); - // select pruning algorithm let algorithm = self.pruning.to_algorithm(&user_defaults); diff --git a/parity/url.rs b/parity/url.rs index 41c4e54583..4f547c28f0 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -80,8 +80,9 @@ pub fn open(url: &str) -> Result<(), Error> { } #[cfg(target_os="android")] -pub fn open(_url: &str) { +pub fn open(_url: &str) -> Result<(), Error> { // TODO: While it is generally always bad to leave a function implemented, there is not much // more we can do here. This function will eventually be removed when we compile Parity // as a library and not as a full binary. + Ok(()) } diff --git a/test.sh b/test.sh index 84940a6aca..6dcd258ea3 100755 --- a/test.sh +++ b/test.sh @@ -40,8 +40,18 @@ echo "________Validate chainspecs________" fi -# Running test's +# Running the C example +echo "________Running the C example________" +cd parity-clib-example && \ + mkdir -p build && \ + cd build && \ + cmake .. && \ + make && \ + ./parity-example && \ + cd .. && \ + rm -rf build && \ + cd .. + +# Running tests echo "________Running Parity Full Test Suite________" - cargo test -j 8 $OPTIONS --features "$FEATURES" --all $1 - -- GitLab From 7a00d97977f387e66793e6b31e0d739d3f5ff8c8 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 9 May 2018 14:48:55 +0800 Subject: [PATCH 128/263] Trace precompiled contracts when the transfer value is not zero (#8486) * Trace precompiled contracts when the transfer value is not zero * Add tests for precompiled CALL tracing * Use byzantium test machine for the new test * Add notes in comments on why we don't trace all precompileds * Use is_transferred instead of transferred --- ethcore/src/executive.rs | 86 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index cded6358e8..e29da093c7 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -428,8 +428,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { self.state.discard_checkpoint(); output.write(0, &builtin_out_buffer); - // trace only top level calls to builtins to avoid DDoS attacks - if self.depth == 0 { + // Trace only top level calls and calls with balance transfer to builtins. The reason why we don't + // trace all internal calls to builtin contracts is that memcpy (IDENTITY) is a heavily used + // function. + let is_transferred = match params.value { + ActionValue::Transfer(value) => value != U256::zero(), + ActionValue::Apparent(_) => false, + }; + if self.depth == 0 || is_transferred { let mut trace_output = tracer.prepare_trace_output(); if let Some(out) = trace_output.as_mut() { *out = output.to_owned(); @@ -722,6 +728,12 @@ mod tests { machine } + fn make_byzantium_machine(max_depth: usize) -> EthereumMachine { + let mut machine = ::ethereum::new_byzantium_test_machine(); + machine.set_schedule_creation_rules(Box::new(move |s, _| s.max_depth = max_depth)); + machine + } + #[test] fn test_contract_address() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); @@ -813,6 +825,76 @@ mod tests { assert_eq!(substate.contracts_created.len(), 0); } + #[test] + fn test_call_to_precompiled_tracing() { + // code: + // + // 60 00 - push 00 out size + // 60 00 - push 00 out offset + // 60 00 - push 00 in size + // 60 00 - push 00 in offset + // 60 01 - push 01 value + // 60 03 - push 03 to + // 61 ffff - push fff gas + // f1 - CALL + + let code = "60006000600060006001600361fffff1".from_hex().unwrap(); + let sender = Address::from_str("4444444444444444444444444444444444444444").unwrap(); + let address = Address::from_str("5555555555555555555555555555555555555555").unwrap(); + + let mut params = ActionParams::default(); + params.address = address.clone(); + params.code_address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + params.value = ActionValue::Transfer(U256::from(100)); + params.call_type = CallType::Call; + let mut state = get_temp_state(); + state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); + let info = EnvInfo::default(); + let machine = make_byzantium_machine(5); + let mut substate = Substate::new(); + let mut tracer = ExecutiveTracer::default(); + let mut vm_tracer = ExecutiveVMTracer::toplevel(); + + let mut ex = Executive::new(&mut state, &info, &machine); + let output = BytesRef::Fixed(&mut[0u8;0]); + ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap(); + + assert_eq!(tracer.drain(), vec![FlatTrace { + action: trace::Action::Call(trace::Call { + from: "4444444444444444444444444444444444444444".into(), + to: "5555555555555555555555555555555555555555".into(), + value: 100.into(), + gas: 100_000.into(), + input: vec![], + call_type: CallType::Call + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 33021.into(), + output: vec![] + }), + subtraces: 1, + trace_address: Default::default() + }, FlatTrace { + action: trace::Action::Call(trace::Call { + from: "5555555555555555555555555555555555555555".into(), + to: "0000000000000000000000000000000000000003".into(), + value: 1.into(), + gas: 66560.into(), + input: vec![], + call_type: CallType::Call + }), result: trace::Res::Call(trace::CallResult { + gas_used: 600.into(), + output: vec![] + }), + subtraces: 0, + trace_address: vec![0].into_iter().collect(), + }]); + } + #[test] // Tracing is not suported in JIT fn test_call_to_create() { -- GitLab From 24838bbcd3aa3eccde8bb0c24909172c06fdf58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 May 2018 08:49:34 +0200 Subject: [PATCH 129/263] Don't block sync when importing old blocks (#8530) * Alter IO queueing. * Don't require IoMessages to be Clone * Ancient blocks imported via IoChannel. * Get rid of private transactions io message. * Get rid of deadlock and fix disconnected handler. * Revert to old disconnect condition. * Fix tests. * Fix deadlock. --- Cargo.lock | 2 + ethcore/private-tx/src/lib.rs | 250 +++++++++--------- ethcore/private-tx/tests/private_contract.rs | 2 +- ethcore/service/Cargo.toml | 1 + ethcore/service/src/lib.rs | 3 + ethcore/service/src/service.rs | 32 +-- ethcore/src/client/ancient_import.rs | 50 +++- ethcore/src/client/client.rs | 254 +++++++++++-------- ethcore/src/client/io_message.rs | 30 ++- ethcore/src/client/mod.rs | 3 +- ethcore/src/client/test_client.rs | 32 +-- ethcore/src/client/traits.rs | 24 +- ethcore/src/views/block.rs | 5 +- ethcore/sync/Cargo.toml | 1 + ethcore/sync/src/api.rs | 4 + ethcore/sync/src/block_sync.rs | 2 +- ethcore/sync/src/chain.rs | 5 +- ethcore/sync/src/lib.rs | 2 + ethcore/sync/src/tests/helpers.rs | 6 +- ethcore/sync/src/tests/private.rs | 9 +- util/io/src/lib.rs | 4 +- util/io/src/service.rs | 50 ++-- util/io/src/worker.rs | 10 +- 23 files changed, 452 insertions(+), 329 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64e468e670..b02fcbd24e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -818,6 +818,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "stop-guard 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", ] [[package]] @@ -866,6 +867,7 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "trace-time 0.1.0", "triehash 0.1.0", ] diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 723d491829..7aca4c85dc 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -149,8 +149,8 @@ impl Provider where { encryptor: Box, config: ProviderConfig, channel: IoChannel, - ) -> Result { - Ok(Provider { + ) -> Self { + Provider { encryptor, validator_accounts: config.validator_accounts.into_iter().collect(), signer_account: config.signer_account, @@ -162,7 +162,7 @@ impl Provider where { miner, accounts, channel, - }) + } } // TODO [ToDr] Don't use `ChainNotify` here! @@ -243,50 +243,6 @@ impl Provider where { Ok(original_transaction) } - /// Process received private transaction - pub fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { - trace!("Private transaction received"); - let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?; - let contract = private_tx.contract; - let contract_validators = self.get_validators(BlockId::Latest, &contract)?; - - let validation_account = contract_validators - .iter() - .find(|address| self.validator_accounts.contains(address)); - - match validation_account { - None => { - // TODO [ToDr] This still seems a bit invalid, imho we should still import the transaction to the pool. - // Importing to pool verifies correctness and nonce; here we are just blindly forwarding. - // - // Not for verification, broadcast further to peers - self.broadcast_private_transaction(rlp.into()); - return Ok(()); - }, - Some(&validation_account) => { - let hash = private_tx.hash(); - trace!("Private transaction taken for verification"); - let original_tx = self.extract_original_transaction(private_tx, &contract)?; - trace!("Validating transaction: {:?}", original_tx); - // Verify with the first account available - trace!("The following account will be used for verification: {:?}", validation_account); - let nonce_cache = Default::default(); - self.transactions_for_verification.lock().add_transaction( - original_tx, - contract, - validation_account, - hash, - self.pool_client(&nonce_cache), - )?; - // NOTE This will just fire `on_private_transaction_queued` but from a client thread. - // It seems that a lot of heavy work (verification) is done in this thread anyway - // it might actually make sense to decouple it from clientService and just use dedicated thread - // for both verification and execution. - self.channel.send(ClientIoMessage::NewPrivateTransaction).map_err(|_| ErrorKind::ClientIsMalformed.into()) - } - } - } - fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { let engine = self.client.engine(); let refuse_service_transactions = true; @@ -299,11 +255,6 @@ impl Provider where { ) } - /// Private transaction for validation added into queue - pub fn on_private_transaction_queued(&self) -> Result<(), Error> { - self.process_queue() - } - /// Retrieve and verify the first available private transaction for every sender /// /// TODO [ToDr] It seems that: @@ -347,73 +298,6 @@ impl Provider where { Ok(()) } - /// Add signed private transaction into the store - /// Creates corresponding public transaction if last required singature collected and sends it to the chain - pub fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { - let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?; - trace!("Signature for private transaction received: {:?}", tx); - let private_hash = tx.private_transaction_hash(); - let desc = match self.transactions_for_signing.lock().get(&private_hash) { - None => { - // TODO [ToDr] Verification (we can't just blindly forward every transaction) - - // Not our transaction, broadcast further to peers - self.broadcast_signed_private_transaction(rlp.into()); - return Ok(()); - }, - Some(desc) => desc, - }; - - let last = self.last_required_signature(&desc, tx.signature())?; - - if last { - let mut signatures = desc.received_signatures.clone(); - signatures.push(tx.signature()); - let rsv: Vec = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect(); - //Create public transaction - let public_tx = self.public_transaction( - desc.state.clone(), - &desc.original_transaction, - &rsv, - desc.original_transaction.nonce, - desc.original_transaction.gas_price - )?; - trace!("Last required signature received, public transaction created: {:?}", public_tx); - //Sign and add it to the queue - let chain_id = desc.original_transaction.chain_id(); - let hash = public_tx.hash(chain_id); - let signer_account = self.signer_account.ok_or_else(|| ErrorKind::SignerAccountNotSet)?; - let password = find_account_password(&self.passwords, &*self.accounts, &signer_account); - let signature = self.accounts.sign(signer_account, password, hash)?; - let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?; - match self.miner.import_own_transaction(&*self.client, signed.into()) { - Ok(_) => trace!("Public transaction added to queue"), - Err(err) => { - trace!("Failed to add transaction to queue, error: {:?}", err); - bail!(err); - } - } - //Remove from store for signing - match self.transactions_for_signing.lock().remove(&private_hash) { - Ok(_) => {} - Err(err) => { - trace!("Failed to remove transaction from signing store, error: {:?}", err); - bail!(err); - } - } - } else { - //Add signature to the store - match self.transactions_for_signing.lock().add_signature(&private_hash, tx.signature()) { - Ok(_) => trace!("Signature stored for private transaction"), - Err(err) => { - trace!("Failed to add signature to signing store, error: {:?}", err); - bail!(err); - } - } - } - Ok(()) - } - fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result { if desc.received_signatures.contains(&sign) { return Ok(false); @@ -657,6 +541,134 @@ impl Provider where { } } +pub trait Importer { + /// Process received private transaction + fn import_private_transaction(&self, _rlp: &[u8]) -> Result<(), Error>; + + /// Add signed private transaction into the store + /// + /// Creates corresponding public transaction if last required signature collected and sends it to the chain + fn import_signed_private_transaction(&self, _rlp: &[u8]) -> Result<(), Error>; +} + +// TODO [ToDr] Offload more heavy stuff to the IoService thread. +// It seems that a lot of heavy work (verification) is done in this thread anyway +// it might actually make sense to decouple it from clientService and just use dedicated thread +// for both verification and execution. + +impl Importer for Arc { + fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { + trace!("Private transaction received"); + let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?; + let contract = private_tx.contract; + let contract_validators = self.get_validators(BlockId::Latest, &contract)?; + + let validation_account = contract_validators + .iter() + .find(|address| self.validator_accounts.contains(address)); + + match validation_account { + None => { + // TODO [ToDr] This still seems a bit invalid, imho we should still import the transaction to the pool. + // Importing to pool verifies correctness and nonce; here we are just blindly forwarding. + // + // Not for verification, broadcast further to peers + self.broadcast_private_transaction(rlp.into()); + return Ok(()); + }, + Some(&validation_account) => { + let hash = private_tx.hash(); + trace!("Private transaction taken for verification"); + let original_tx = self.extract_original_transaction(private_tx, &contract)?; + trace!("Validating transaction: {:?}", original_tx); + // Verify with the first account available + trace!("The following account will be used for verification: {:?}", validation_account); + let nonce_cache = Default::default(); + self.transactions_for_verification.lock().add_transaction( + original_tx, + contract, + validation_account, + hash, + self.pool_client(&nonce_cache), + )?; + let provider = Arc::downgrade(self); + self.channel.send(ClientIoMessage::execute(move |_| { + if let Some(provider) = provider.upgrade() { + if let Err(e) = provider.process_queue() { + debug!("Unable to process the queue: {}", e); + } + } + })).map_err(|_| ErrorKind::ClientIsMalformed.into()) + } + } + } + + fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), Error> { + let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?; + trace!("Signature for private transaction received: {:?}", tx); + let private_hash = tx.private_transaction_hash(); + let desc = match self.transactions_for_signing.lock().get(&private_hash) { + None => { + // TODO [ToDr] Verification (we can't just blindly forward every transaction) + + // Not our transaction, broadcast further to peers + self.broadcast_signed_private_transaction(rlp.into()); + return Ok(()); + }, + Some(desc) => desc, + }; + + let last = self.last_required_signature(&desc, tx.signature())?; + + if last { + let mut signatures = desc.received_signatures.clone(); + signatures.push(tx.signature()); + let rsv: Vec = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect(); + //Create public transaction + let public_tx = self.public_transaction( + desc.state.clone(), + &desc.original_transaction, + &rsv, + desc.original_transaction.nonce, + desc.original_transaction.gas_price + )?; + trace!("Last required signature received, public transaction created: {:?}", public_tx); + //Sign and add it to the queue + let chain_id = desc.original_transaction.chain_id(); + let hash = public_tx.hash(chain_id); + let signer_account = self.signer_account.ok_or_else(|| ErrorKind::SignerAccountNotSet)?; + let password = find_account_password(&self.passwords, &*self.accounts, &signer_account); + let signature = self.accounts.sign(signer_account, password, hash)?; + let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?; + match self.miner.import_own_transaction(&*self.client, signed.into()) { + Ok(_) => trace!("Public transaction added to queue"), + Err(err) => { + trace!("Failed to add transaction to queue, error: {:?}", err); + bail!(err); + } + } + //Remove from store for signing + match self.transactions_for_signing.lock().remove(&private_hash) { + Ok(_) => {} + Err(err) => { + trace!("Failed to remove transaction from signing store, error: {:?}", err); + bail!(err); + } + } + } else { + //Add signature to the store + match self.transactions_for_signing.lock().add_signature(&private_hash, tx.signature()) { + Ok(_) => trace!("Signature stored for private transaction"), + Err(err) => { + trace!("Failed to add signature to signing store, error: {:?}", err); + bail!(err); + } + } + } + Ok(()) + } +} + /// Try to unlock account using stored password, return found password if any fn find_account_password(passwords: &Vec, account_provider: &AccountProvider, account: &Address) -> Option { for password in passwords { diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs index e53ad5e5f6..e7e608c2b6 100644 --- a/ethcore/private-tx/tests/private_contract.rs +++ b/ethcore/private-tx/tests/private_contract.rs @@ -74,7 +74,7 @@ fn private_contract() { Box::new(NoopEncryptor::default()), config, io, - ).unwrap()); + )); let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]); diff --git a/ethcore/service/Cargo.toml b/ethcore/service/Cargo.toml index b612baf566..3a10849b61 100644 --- a/ethcore/service/Cargo.toml +++ b/ethcore/service/Cargo.toml @@ -13,6 +13,7 @@ ethcore-sync = { path = "../sync" } kvdb = { path = "../../util/kvdb" } log = "0.3" stop-guard = { path = "../../util/stop-guard" } +trace-time = { path = "../../util/trace-time" } [dev-dependencies] tempdir = "0.3" diff --git a/ethcore/service/src/lib.rs b/ethcore/service/src/lib.rs index 1604e84b10..d85a377cde 100644 --- a/ethcore/service/src/lib.rs +++ b/ethcore/service/src/lib.rs @@ -28,6 +28,9 @@ extern crate error_chain; #[macro_use] extern crate log; +#[macro_use] +extern crate trace_time; + #[cfg(test)] extern crate tempdir; diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index b60d4194c9..5f46799796 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -33,7 +33,7 @@ use ethcore::snapshot::{RestorationStatus}; use ethcore::spec::Spec; use ethcore::account_provider::AccountProvider; -use ethcore_private_tx; +use ethcore_private_tx::{self, Importer}; use Error; pub struct PrivateTxService { @@ -112,14 +112,13 @@ impl ClientService { account_provider, encryptor, private_tx_conf, - io_service.channel())?, - ); + io_service.channel(), + )); let private_tx = Arc::new(PrivateTxService::new(provider)); let client_io = Arc::new(ClientIoHandler { client: client.clone(), snapshot: snapshot.clone(), - private_tx: private_tx.clone(), }); io_service.register_handler(client_io)?; @@ -175,7 +174,6 @@ impl ClientService { struct ClientIoHandler { client: Arc, snapshot: Arc, - private_tx: Arc, } const CLIENT_TICK_TIMER: TimerToken = 0; @@ -191,6 +189,7 @@ impl IoHandler for ClientIoHandler { } fn timeout(&self, _io: &IoContext, timer: TimerToken) { + trace_time!("service::read"); match timer { CLIENT_TICK_TIMER => { use ethcore::snapshot::SnapshotService; @@ -203,20 +202,24 @@ impl IoHandler for ClientIoHandler { } fn message(&self, _io: &IoContext, net_message: &ClientIoMessage) { + trace_time!("service::message"); use std::thread; match *net_message { - ClientIoMessage::BlockVerified => { self.client.import_verified_blocks(); } - ClientIoMessage::NewTransactions(ref transactions, peer_id) => { - self.client.import_queued_transactions(transactions, peer_id); + ClientIoMessage::BlockVerified => { + self.client.import_verified_blocks(); } ClientIoMessage::BeginRestoration(ref manifest) => { if let Err(e) = self.snapshot.init_restore(manifest.clone(), true) { warn!("Failed to initialize snapshot restoration: {}", e); } } - ClientIoMessage::FeedStateChunk(ref hash, ref chunk) => self.snapshot.feed_state_chunk(*hash, chunk), - ClientIoMessage::FeedBlockChunk(ref hash, ref chunk) => self.snapshot.feed_block_chunk(*hash, chunk), + ClientIoMessage::FeedStateChunk(ref hash, ref chunk) => { + self.snapshot.feed_state_chunk(*hash, chunk) + } + ClientIoMessage::FeedBlockChunk(ref hash, ref chunk) => { + self.snapshot.feed_block_chunk(*hash, chunk) + } ClientIoMessage::TakeSnapshot(num) => { let client = self.client.clone(); let snapshot = self.snapshot.clone(); @@ -231,12 +234,9 @@ impl IoHandler for ClientIoHandler { debug!(target: "snapshot", "Failed to initialize periodic snapshot thread: {:?}", e); } }, - ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) { - trace!(target: "poa", "Invalid message received: {}", e); - }, - ClientIoMessage::NewPrivateTransaction => if let Err(e) = self.private_tx.provider.on_private_transaction_queued() { - warn!("Failed to handle private transaction {:?}", e); - }, + ClientIoMessage::Execute(ref exec) => { + (*exec.0)(&self.client); + } _ => {} // ignore other messages } } diff --git a/ethcore/src/client/ancient_import.rs b/ethcore/src/client/ancient_import.rs index 13699ea5a0..c2523a13a5 100644 --- a/ethcore/src/client/ancient_import.rs +++ b/ethcore/src/client/ancient_import.rs @@ -32,16 +32,16 @@ const HEAVY_VERIFY_RATE: f32 = 0.02; /// Ancient block verifier: import an ancient sequence of blocks in order from a starting /// epoch. pub struct AncientVerifier { - cur_verifier: RwLock>>, + cur_verifier: RwLock>>>, engine: Arc, } impl AncientVerifier { - /// Create a new ancient block verifier with the given engine and initial verifier. - pub fn new(engine: Arc, start_verifier: Box>) -> Self { + /// Create a new ancient block verifier with the given engine. + pub fn new(engine: Arc) -> Self { AncientVerifier { - cur_verifier: RwLock::new(start_verifier), - engine: engine, + cur_verifier: RwLock::new(None), + engine, } } @@ -53,17 +53,49 @@ impl AncientVerifier { header: &Header, chain: &BlockChain, ) -> Result<(), ::error::Error> { - match rng.gen::() <= HEAVY_VERIFY_RATE { - true => self.cur_verifier.read().verify_heavy(header)?, - false => self.cur_verifier.read().verify_light(header)?, + // perform verification + let verified = if let Some(ref cur_verifier) = *self.cur_verifier.read() { + match rng.gen::() <= HEAVY_VERIFY_RATE { + true => cur_verifier.verify_heavy(header)?, + false => cur_verifier.verify_light(header)?, + } + true + } else { + false + }; + + // when there is no verifier initialize it. + // We use a bool flag to avoid double locking in the happy case + if !verified { + { + let mut cur_verifier = self.cur_verifier.write(); + if cur_verifier.is_none() { + *cur_verifier = Some(self.initial_verifier(header, chain)?); + } + } + // Call again to verify. + return self.verify(rng, header, chain); } // ancient import will only use transitions obtained from the snapshot. if let Some(transition) = chain.epoch_transition(header.number(), header.hash()) { let v = self.engine.epoch_verifier(&header, &transition.proof).known_confirmed()?; - *self.cur_verifier.write() = v; + *self.cur_verifier.write() = Some(v); } Ok(()) } + + fn initial_verifier(&self, header: &Header, chain: &BlockChain) + -> Result>, ::error::Error> + { + trace!(target: "client", "Initializing ancient block restoration."); + let current_epoch_data = chain.epoch_transitions() + .take_while(|&(_, ref t)| t.block_number < header.number()) + .last() + .map(|(_, t)| t.proof) + .expect("At least one epoch entry (genesis) always stored; qed"); + + self.engine.epoch_verifier(&header, ¤t_epoch_data).known_confirmed() + } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8119ebd35f..bffa4e38ba 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -15,15 +15,16 @@ // along with Parity. If not, see . use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; +use std::fmt; use std::str::FromStr; -use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; +use std::sync::{Arc, Weak}; use std::time::{Instant, Duration}; -use itertools::Itertools; // util use hash::keccak; use bytes::Bytes; +use itertools::Itertools; use journaldb; use trie::{TrieSpec, TrieFactory, Trie}; use kvdb::{DBValue, KeyValueDB, DBTransaction}; @@ -45,7 +46,8 @@ use client::{ use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, - ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType + ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType, + IoClient, }; use encoded; use engines::{EthEngine, EpochTransition}; @@ -55,7 +57,7 @@ use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; use factory::{Factories, VmFactory}; use header::{BlockNumber, Header}; -use io::IoChannel; +use io::{IoChannel, IoError}; use log_entry::LocalizedLogEntry; use miner::{Miner, MinerService}; use ethcore_miner::pool::VerifiedTransaction; @@ -85,6 +87,7 @@ pub use verification::queue::QueueInfo as BlockQueueInfo; use_contract!(registry, "Registry", "res/contracts/registrar.json"); const MAX_TX_QUEUE_SIZE: usize = 4096; +const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096; const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2; const MIN_HISTORY_SIZE: u64 = 8; @@ -154,10 +157,7 @@ struct Importer { pub miner: Arc, /// Ancient block verifier: import an ancient sequence of blocks in order from a starting epoch - pub ancient_verifier: Mutex>, - - /// Random number generator used by `AncientVerifier` - pub rng: Mutex, + pub ancient_verifier: AncientVerifier, /// Ethereum engine to be used during import pub engine: Arc, @@ -204,8 +204,13 @@ pub struct Client { /// List of actors to be notified on certain chain events notify: RwLock>>, - /// Count of pending transactions in the queue - queue_transactions: AtomicUsize, + /// Queued transactions from IO + queue_transactions: IoChannelQueue, + /// Ancient blocks import queue + queue_ancient_blocks: IoChannelQueue, + /// Consensus messages import queue + queue_consensus_message: IoChannelQueue, + last_hashes: RwLock>, factories: Factories, @@ -239,8 +244,7 @@ impl Importer { verifier: verification::new(config.verifier_type.clone()), block_queue, miner, - ancient_verifier: Mutex::new(None), - rng: Mutex::new(OsRng::new()?), + ancient_verifier: AncientVerifier::new(engine.clone()), engine, }) } @@ -416,55 +420,25 @@ impl Importer { Ok(locked_block) } + /// Import a block with transaction receipts. /// /// The block is guaranteed to be the next best blocks in the /// first block sequence. Does no sealing or transaction validation. - fn import_old_block(&self, header: &Header, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result { - let receipts = ::rlp::decode_list(&receipts_bytes); + fn import_old_block(&self, header: &Header, block_bytes: &[u8], receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result { + let receipts = ::rlp::decode_list(receipts_bytes); let hash = header.hash(); let _import_lock = self.import_lock.lock(); { trace_time!("import_old_block"); - let mut ancient_verifier = self.ancient_verifier.lock(); - - { - // closure for verifying a block. - let verify_with = |verifier: &AncientVerifier| -> Result<(), ::error::Error> { - // verify the block, passing the chain for updating the epoch - // verifier. - let mut rng = OsRng::new().map_err(UtilError::from)?; - verifier.verify(&mut rng, &header, &chain) - }; - - // initialize the ancient block verifier if we don't have one already. - match &mut *ancient_verifier { - &mut Some(ref verifier) => { - verify_with(verifier)? - } - x @ &mut None => { - // load most recent epoch. - trace!(target: "client", "Initializing ancient block restoration."); - let current_epoch_data = chain.epoch_transitions() - .take_while(|&(_, ref t)| t.block_number < header.number()) - .last() - .map(|(_, t)| t.proof) - .expect("At least one epoch entry (genesis) always stored; qed"); - - let current_verifier = self.engine.epoch_verifier(&header, ¤t_epoch_data) - .known_confirmed()?; - let current_verifier = AncientVerifier::new(self.engine.clone(), current_verifier); - - verify_with(¤t_verifier)?; - *x = Some(current_verifier); - } - } - } + // verify the block, passing the chain for updating the epoch verifier. + let mut rng = OsRng::new().map_err(UtilError::from)?; + self.ancient_verifier.verify(&mut rng, &header, &chain)?; // Commit results let mut batch = DBTransaction::new(); - chain.insert_unordered_block(&mut batch, &block_bytes, receipts, None, false, true); + chain.insert_unordered_block(&mut batch, block_bytes, receipts, None, false, true); // Final commit to the DB db.write_buffered(batch); chain.commit(); @@ -734,7 +708,9 @@ impl Client { report: RwLock::new(Default::default()), io_channel: Mutex::new(message_channel), notify: RwLock::new(Vec::new()), - queue_transactions: AtomicUsize::new(0), + queue_transactions: IoChannelQueue::new(MAX_TX_QUEUE_SIZE), + queue_ancient_blocks: IoChannelQueue::new(MAX_ANCIENT_BLOCKS_QUEUE_SIZE), + queue_consensus_message: IoChannelQueue::new(usize::max_value()), last_hashes: RwLock::new(VecDeque::new()), factories: factories, history: history, @@ -820,7 +796,7 @@ impl Client { } fn notify(&self, f: F) where F: Fn(&ChainNotify) { - for np in self.notify.read().iter() { + for np in &*self.notify.read() { if let Some(n) = np.upgrade() { f(&*n); } @@ -954,24 +930,6 @@ impl Client { } } - /// Import transactions from the IO queue - pub fn import_queued_transactions(&self, transactions: &[Bytes], peer_id: usize) -> usize { - trace_time!("import_queued_transactions"); - self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst); - - let txs: Vec = transactions - .iter() - .filter_map(|bytes| self.engine().decode_transaction(bytes).ok()) - .collect(); - - self.notify(|notify| { - notify.transactions_received(&txs, peer_id); - }); - - let results = self.importer.miner.import_external_transactions(self, txs); - results.len() - } - /// Get shared miner reference. #[cfg(test)] pub fn miner(&self) -> Arc { @@ -1392,22 +1350,6 @@ impl ImportBlock for Client { } Ok(self.importer.block_queue.import(unverified)?) } - - fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { - let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; - { - // check block order - if self.chain.read().is_known(&header.hash()) { - bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); - } - let status = self.block_status(BlockId::Hash(*header.parent_hash())); - if status == BlockStatus::Unknown || status == BlockStatus::Pending { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); - } - } - - self.importer.import_old_block(&header, block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into) - } } impl StateClient for Client { @@ -1958,35 +1900,10 @@ impl BlockChainClient for Client { (*self.build_last_hashes(&self.chain.read().best_block_hash())).clone() } - fn queue_transactions(&self, transactions: Vec, peer_id: usize) { - let queue_size = self.queue_transactions.load(AtomicOrdering::Relaxed); - trace!(target: "external_tx", "Queue size: {}", queue_size); - if queue_size > MAX_TX_QUEUE_SIZE { - debug!("Ignoring {} transactions: queue is full", transactions.len()); - } else { - let len = transactions.len(); - match self.io_channel.lock().send(ClientIoMessage::NewTransactions(transactions, peer_id)) { - Ok(_) => { - self.queue_transactions.fetch_add(len, AtomicOrdering::SeqCst); - } - Err(e) => { - debug!("Ignoring {} transactions: error queueing: {}", len, e); - } - } - } - } - fn ready_transactions(&self) -> Vec> { self.importer.miner.ready_transactions(self) } - fn queue_consensus_message(&self, message: Bytes) { - let channel = self.io_channel.lock().clone(); - if let Err(e) = channel.send(ClientIoMessage::NewMessage(message)) { - debug!("Ignoring the message, error queueing: {}", e); - } - } - fn signing_chain_id(&self) -> Option { self.engine.signing_chain_id(&self.latest_env_info()) } @@ -2034,6 +1951,72 @@ impl BlockChainClient for Client { } } +impl IoClient for Client { + fn queue_transactions(&self, transactions: Vec, peer_id: usize) { + let len = transactions.len(); + self.queue_transactions.queue(&mut self.io_channel.lock(), len, move |client| { + trace_time!("import_queued_transactions"); + + let txs: Vec = transactions + .iter() + .filter_map(|bytes| client.engine.decode_transaction(bytes).ok()) + .collect(); + + client.notify(|notify| { + notify.transactions_received(&txs, peer_id); + }); + + client.importer.miner.import_external_transactions(client, txs); + }).unwrap_or_else(|e| { + debug!(target: "client", "Ignoring {} transactions: {}", len, e); + }); + } + + fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { + let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; + let hash = header.hash(); + + { + // check block order + if self.chain.read().is_known(&header.hash()) { + bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); + } + let status = self.block_status(BlockId::Hash(*header.parent_hash())); + if status == BlockStatus::Unknown || status == BlockStatus::Pending { + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); + } + } + + match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), 1, move |client| { + client.importer.import_old_block( + &header, + &block_bytes, + &receipts_bytes, + &**client.db.read(), + &*client.chain.read() + ).map(|_| ()).unwrap_or_else(|e| { + error!(target: "client", "Error importing ancient block: {}", e); + }); + }) { + Ok(_) => Ok(hash), + Err(e) => bail!(BlockImportErrorKind::Other(format!("{}", e))), + } + } + + fn queue_consensus_message(&self, message: Bytes) { + match self.queue_consensus_message.queue(&mut self.io_channel.lock(), 1, move |client| { + if let Err(e) = client.engine().handle_message(&message) { + debug!(target: "poa", "Invalid message received: {}", e); + } + }) { + Ok(_) => (), + Err(e) => { + debug!(target: "poa", "Ignoring the message, error queueing: {}", e); + } + } + } +} + impl ReopenBlock for Client { fn reopen_block(&self, block: ClosedBlock) -> OpenBlock { let engine = &*self.engine; @@ -2409,3 +2392,54 @@ mod tests { }); } } + +#[derive(Debug)] +enum QueueError { + Channel(IoError), + Full(usize), +} + +impl fmt::Display for QueueError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + QueueError::Channel(ref c) => fmt::Display::fmt(c, fmt), + QueueError::Full(limit) => write!(fmt, "The queue is full ({})", limit), + } + } +} + +/// Queue some items to be processed by IO client. +struct IoChannelQueue { + currently_queued: Arc, + limit: usize, +} + +impl IoChannelQueue { + pub fn new(limit: usize) -> Self { + IoChannelQueue { + currently_queued: Default::default(), + limit, + } + } + + pub fn queue(&self, channel: &mut IoChannel, count: usize, fun: F) -> Result<(), QueueError> where + F: Fn(&Client) + Send + Sync + 'static, + { + let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed); + ensure!(queue_size < self.limit, QueueError::Full(self.limit)); + + let currently_queued = self.currently_queued.clone(); + let result = channel.send(ClientIoMessage::execute(move |client| { + currently_queued.fetch_sub(count, AtomicOrdering::SeqCst); + fun(client); + })); + + match result { + Ok(_) => { + self.currently_queued.fetch_add(count, AtomicOrdering::SeqCst); + Ok(()) + }, + Err(e) => Err(QueueError::Channel(e)), + } + } +} diff --git a/ethcore/src/client/io_message.rs b/ethcore/src/client/io_message.rs index e19d3054fe..817c726020 100644 --- a/ethcore/src/client/io_message.rs +++ b/ethcore/src/client/io_message.rs @@ -14,19 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; +use std::fmt; use bytes::Bytes; +use client::Client; +use ethereum_types::H256; use snapshot::ManifestData; /// Message type for external and internal events -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Debug)] pub enum ClientIoMessage { /// Best Block Hash in chain has been changed NewChainHead, /// A block is ready BlockVerified, - /// New transaction RLPs are ready to be imported - NewTransactions(Vec, usize), /// Begin snapshot restoration BeginRestoration(ManifestData), /// Feed a state chunk to the snapshot service @@ -35,9 +35,23 @@ pub enum ClientIoMessage { FeedBlockChunk(H256, Bytes), /// Take a snapshot for the block with given number. TakeSnapshot(u64), - /// New consensus message received. - NewMessage(Bytes), - /// New private transaction arrived - NewPrivateTransaction, + /// Execute wrapped closure + Execute(Callback), +} + +impl ClientIoMessage { + /// Create new `ClientIoMessage` that executes given procedure. + pub fn execute(fun: F) -> Self { + ClientIoMessage::Execute(Callback(Box::new(fun))) + } +} + +/// A function to invoke in the client thread. +pub struct Callback(pub Box); + +impl fmt::Debug for Callback { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "") + } } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 05e2018258..4c410d3011 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -36,9 +36,8 @@ pub use self::traits::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter }; -//pub use self::private_notify::PrivateNotify; pub use state::StateInfo; -pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient}; +pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient, IoClient}; pub use types::ids::*; pub use types::trace_filter::Filter as TraceFilter; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index c2e06009b6..b229159667 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -39,7 +39,7 @@ use client::{ PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, - Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter + Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, IoClient }; use db::{NUM_COLUMNS, COL_STATE}; use header::{Header as BlockHeader, BlockNumber}; @@ -556,10 +556,6 @@ impl ImportBlock for TestBlockChainClient { } Ok(h) } - - fn import_block_with_receipts(&self, b: Bytes, _r: Bytes) -> Result { - self.import_block(b) - } } impl Call for TestBlockChainClient { @@ -809,16 +805,6 @@ impl BlockChainClient for TestBlockChainClient { self.traces.read().clone() } - fn queue_transactions(&self, transactions: Vec, _peer_id: usize) { - // import right here - let txs = transactions.into_iter().filter_map(|bytes| Rlp::new(&bytes).as_val().ok()).collect(); - self.miner.import_external_transactions(self, txs); - } - - fn queue_consensus_message(&self, message: Bytes) { - self.spec.engine.handle_message(&message).unwrap(); - } - fn ready_transactions(&self) -> Vec> { self.miner.ready_transactions(self) } @@ -863,6 +849,22 @@ impl BlockChainClient for TestBlockChainClient { fn eip86_transition(&self) -> u64 { u64::max_value() } } +impl IoClient for TestBlockChainClient { + fn queue_transactions(&self, transactions: Vec, _peer_id: usize) { + // import right here + let txs = transactions.into_iter().filter_map(|bytes| Rlp::new(&bytes).as_val().ok()).collect(); + self.miner.import_external_transactions(self, txs); + } + + fn queue_ancient_block(&self, b: Bytes, _r: Bytes) -> Result { + self.import_block(b) + } + + fn queue_consensus_message(&self, message: Bytes) { + self.spec.engine.handle_message(&message).unwrap(); + } +} + impl ProvingBlockChainClient for TestBlockChainClient { fn prove_storage(&self, _: H256, _: H256, _: BlockId) -> Option<(Vec, H256)> { None diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 7d4d5846c6..358e24fa90 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -168,9 +168,6 @@ pub trait RegistryInfo { pub trait ImportBlock { /// Import a block into the blockchain. fn import_block(&self, bytes: Bytes) -> Result; - - /// Import a block with transaction receipts. Does no sealing and transaction validation. - fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result; } /// Provides `call_contract` method @@ -201,8 +198,21 @@ pub trait EngineInfo { fn engine(&self) -> &EthEngine; } +/// IO operations that should off-load heavy work to another thread. +pub trait IoClient: Sync + Send { + /// Queue transactions for importing. + fn queue_transactions(&self, transactions: Vec, peer_id: usize); + + /// Queue block import with transaction receipts. Does no sealing and transaction validation. + fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result; + + /// Queue conensus engine message. + fn queue_consensus_message(&self, message: Bytes); +} + /// Blockchain database client. Owns and manages a blockchain and a block queue. -pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock { +pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock ++ IoClient { /// Look up the block number for the given block ID. fn block_number(&self, id: BlockId) -> Option; @@ -310,12 +320,6 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Get last hashes starting from best block. fn last_hashes(&self) -> LastHashes; - /// Queue transactions for importing. - fn queue_transactions(&self, transactions: Vec, peer_id: usize); - - /// Queue conensus engine message. - fn queue_consensus_message(&self, message: Bytes); - /// List all transactions that are allowed into the next block. fn ready_transactions(&self) -> Vec>; diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index f610504d85..3bed1818f2 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -29,7 +29,6 @@ pub struct BlockView<'a> { rlp: ViewRlp<'a> } - impl<'a> BlockView<'a> { /// Creates new view onto block from rlp. /// Use the `view!` macro to create this view in order to capture debugging info. @@ -39,9 +38,9 @@ impl<'a> BlockView<'a> { /// ``` /// #[macro_use] /// extern crate ethcore; - /// + /// /// use ethcore::views::{BlockView}; - /// + /// /// fn main() { /// let bytes : &[u8] = &[]; /// let block_view = view!(BlockView, bytes); diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index d2d060e686..ba03075d0e 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -30,6 +30,7 @@ heapsize = "0.4" semver = "0.9" smallvec = { version = "0.4", features = ["heapsizeof"] } parking_lot = "0.5" +trace-time = { path = "../../util/trace-time" } ipnetwork = "0.12.6" [dev-dependencies] diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 7690eeb864..4fd0cbb54d 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -379,10 +379,12 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { + trace_time!("sync::read"); ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay), *peer, packet_id, data); } fn connected(&self, io: &NetworkContext, peer: &PeerId) { + trace_time!("sync::connected"); // If warp protocol is supported only allow warp handshake let warp_protocol = io.protocol_version(WARP_SYNC_PROTOCOL_ID, *peer).unwrap_or(0) != 0; let warp_context = io.subprotocol_name() == WARP_SYNC_PROTOCOL_ID; @@ -392,12 +394,14 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } fn disconnected(&self, io: &NetworkContext, peer: &PeerId) { + trace_time!("sync::disconnected"); if io.subprotocol_name() != WARP_SYNC_PROTOCOL_ID { self.sync.write().on_peer_aborting(&mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay), *peer); } } fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { + trace_time!("sync::timeout"); let mut io = NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay); self.sync.write().maintain_peers(&mut io); self.sync.write().maintain_sync(&mut io); diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index 4a5acae526..7411fa30cc 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -496,7 +496,7 @@ impl BlockDownloader { } let result = if let Some(receipts) = receipts { - io.chain().import_block_with_receipts(block, receipts) + io.chain().queue_ancient_block(block, receipts) } else { io.chain().import_block(block) }; diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs index 25d9a09f6b..1a6af10115 100644 --- a/ethcore/sync/src/chain.rs +++ b/ethcore/sync/src/chain.rs @@ -1789,10 +1789,13 @@ impl ChainSync { } pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + debug!(target: "sync", "{} -> Dispatching packet: {}", peer, packet_id); + if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) { debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); return; } + let rlp = Rlp::new(data); let result = match packet_id { STATUS_PACKET => self.on_peer_status(io, peer, &rlp), @@ -1831,7 +1834,7 @@ impl ChainSync { PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, }; if timeout { - trace!(target:"sync", "Timeout {}", peer_id); + debug!(target:"sync", "Timeout {}", peer_id); io.disconnect_peer(*peer_id); aborting.push(*peer_id); } diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index a3e24bdb82..3eb2e8332b 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -54,6 +54,8 @@ extern crate macros; extern crate log; #[macro_use] extern crate heapsize; +#[macro_use] +extern crate trace_time; mod chain; mod blocks; diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index dc52fdd8b8..3a4697cc09 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -520,11 +520,9 @@ impl TestIoHandler { impl IoHandler for TestIoHandler { fn message(&self, _io: &IoContext, net_message: &ClientIoMessage) { match *net_message { - ClientIoMessage::NewMessage(ref message) => if let Err(e) = self.client.engine().handle_message(message) { - panic!("Invalid message received: {}", e); - }, - ClientIoMessage::NewPrivateTransaction => { + ClientIoMessage::Execute(ref exec) => { *self.private_tx_queued.lock() += 1; + (*exec.0)(&self.client); }, _ => {} // ignore other messages } diff --git a/ethcore/sync/src/tests/private.rs b/ethcore/sync/src/tests/private.rs index a9e8718e5e..b54240bfb8 100644 --- a/ethcore/sync/src/tests/private.rs +++ b/ethcore/sync/src/tests/private.rs @@ -24,7 +24,7 @@ use ethcore::CreateContractAddress; use transaction::{Transaction, Action}; use ethcore::executive::{contract_address}; use ethcore::test_helpers::{push_block_with_transactions}; -use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor}; +use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer}; use ethcore::account_provider::AccountProvider; use ethkey::{KeyPair}; use tests::helpers::{TestNet, TestIoHandler}; @@ -84,7 +84,7 @@ fn send_private_transaction() { Box::new(NoopEncryptor::default()), signer_config, IoChannel::to_handler(Arc::downgrade(&io_handler0)), - ).unwrap()); + )); pm0.add_notify(net.peers[0].clone()); let pm1 = Arc::new(Provider::new( @@ -94,7 +94,7 @@ fn send_private_transaction() { Box::new(NoopEncryptor::default()), validator_config, IoChannel::to_handler(Arc::downgrade(&io_handler1)), - ).unwrap()); + )); pm1.add_notify(net.peers[1].clone()); // Create and deploy contract @@ -133,7 +133,6 @@ fn send_private_transaction() { //process received private transaction message let private_transaction = received_private_transactions[0].clone(); assert!(pm1.import_private_transaction(&private_transaction).is_ok()); - assert!(pm1.on_private_transaction_queued().is_ok()); //send signed response net.sync(); @@ -147,4 +146,4 @@ fn send_private_transaction() { assert!(pm0.import_signed_private_transaction(&signed_private_transaction).is_ok()); let local_transactions = net.peer(0).miner.local_transactions(); assert_eq!(local_transactions.len(), 1); -} \ No newline at end of file +} diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index 20b908ac91..9232b2a909 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -106,7 +106,7 @@ impl From<::std::io::Error> for IoError { } } -impl From>> for IoError where Message: Send + Clone { +impl From>> for IoError where Message: Send { fn from(_err: NotifyError>) -> IoError { IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error")) } @@ -115,7 +115,7 @@ impl From>> for IoError where M /// Generic IO handler. /// All the handler function are called from within IO event loop. /// `Message` type is used as notification data -pub trait IoHandler: Send + Sync where Message: Send + Sync + Clone + 'static { +pub trait IoHandler: Send + Sync where Message: Send + Sync + 'static { /// Initialize the handler fn initialize(&self, _io: &IoContext) {} /// Timer function called after a timeout created with `HandlerIo::timeout`. diff --git a/util/io/src/service.rs b/util/io/src/service.rs index 19f2d4b3bb..0de674ae12 100644 --- a/util/io/src/service.rs +++ b/util/io/src/service.rs @@ -41,7 +41,7 @@ const MAX_HANDLERS: usize = 8; /// Messages used to communicate with the event loop from other threads. #[derive(Clone)] -pub enum IoMessage where Message: Send + Clone + Sized { +pub enum IoMessage where Message: Send + Sized { /// Shutdown the event loop Shutdown, /// Register a new protocol handler. @@ -74,16 +74,16 @@ pub enum IoMessage where Message: Send + Clone + Sized { token: StreamToken, }, /// Broadcast a message across all protocol handlers. - UserMessage(Message) + UserMessage(Arc) } /// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem. -pub struct IoContext where Message: Send + Clone + Sync + 'static { +pub struct IoContext where Message: Send + Sync + 'static { channel: IoChannel, handler: HandlerId, } -impl IoContext where Message: Send + Clone + Sync + 'static { +impl IoContext where Message: Send + Sync + 'static { /// Create a new IO access point. Takes references to all the data that can be updated within the IO handler. pub fn new(channel: IoChannel, handler: HandlerId) -> IoContext { IoContext { @@ -187,7 +187,7 @@ pub struct IoManager where Message: Send + Sync { work_ready: Arc, } -impl IoManager where Message: Send + Sync + Clone + 'static { +impl IoManager where Message: Send + Sync + 'static { /// Creates a new instance and registers it with the event loop. pub fn start( event_loop: &mut EventLoop>, @@ -219,7 +219,7 @@ impl IoManager where Message: Send + Sync + Clone + 'static { } } -impl Handler for IoManager where Message: Send + Clone + Sync + 'static { +impl Handler for IoManager where Message: Send + Sync + 'static { type Timeout = Token; type Message = IoMessage; @@ -317,7 +317,12 @@ impl Handler for IoManager where Message: Send + Clone + Sync for id in 0 .. MAX_HANDLERS { if let Some(h) = self.handlers.read().get(id) { let handler = h.clone(); - self.worker_channel.push(Work { work_type: WorkType::Message(data.clone()), token: 0, handler: handler, handler_id: id }); + self.worker_channel.push(Work { + work_type: WorkType::Message(data.clone()), + token: 0, + handler: handler, + handler_id: id + }); } } self.work_ready.notify_all(); @@ -326,21 +331,30 @@ impl Handler for IoManager where Message: Send + Clone + Sync } } -#[derive(Clone)] -enum Handlers where Message: Send + Clone { +enum Handlers where Message: Send { SharedCollection(Weak>, HandlerId>>>), Single(Weak>), } +impl Clone for Handlers { + fn clone(&self) -> Self { + use self::Handlers::*; + + match *self { + SharedCollection(ref w) => SharedCollection(w.clone()), + Single(ref w) => Single(w.clone()), + } + } +} + /// Allows sending messages into the event loop. All the IO handlers will get the message /// in the `message` callback. -pub struct IoChannel where Message: Send + Clone{ +pub struct IoChannel where Message: Send { channel: Option>>, handlers: Handlers, - } -impl Clone for IoChannel where Message: Send + Clone + Sync + 'static { +impl Clone for IoChannel where Message: Send + Sync + 'static { fn clone(&self) -> IoChannel { IoChannel { channel: self.channel.clone(), @@ -349,11 +363,11 @@ impl Clone for IoChannel where Message: Send + Clone + Sync + } } -impl IoChannel where Message: Send + Clone + Sync + 'static { +impl IoChannel where Message: Send + Sync + 'static { /// Send a message through the channel pub fn send(&self, message: Message) -> Result<(), IoError> { match self.channel { - Some(ref channel) => channel.send(IoMessage::UserMessage(message))?, + Some(ref channel) => channel.send(IoMessage::UserMessage(Arc::new(message)))?, None => self.send_sync(message)? } Ok(()) @@ -413,13 +427,13 @@ impl IoChannel where Message: Send + Clone + Sync + 'static { /// General IO Service. Starts an event loop and dispatches IO requests. /// 'Message' is a notification message type -pub struct IoService where Message: Send + Sync + Clone + 'static { +pub struct IoService where Message: Send + Sync + 'static { thread: Mutex>>, host_channel: Mutex>>, handlers: Arc>, HandlerId>>>, } -impl IoService where Message: Send + Sync + Clone + 'static { +impl IoService where Message: Send + Sync + 'static { /// Starts IO event loop pub fn start() -> Result, IoError> { let mut config = EventLoopBuilder::new(); @@ -462,7 +476,7 @@ impl IoService where Message: Send + Sync + Clone + 'static { /// Send a message over the network. Normaly `HostIo::send` should be used. This can be used from non-io threads. pub fn send_message(&self, message: Message) -> Result<(), IoError> { - self.host_channel.lock().send(IoMessage::UserMessage(message))?; + self.host_channel.lock().send(IoMessage::UserMessage(Arc::new(message)))?; Ok(()) } @@ -472,7 +486,7 @@ impl IoService where Message: Send + Sync + Clone + 'static { } } -impl Drop for IoService where Message: Send + Sync + Clone { +impl Drop for IoService where Message: Send + Sync { fn drop(&mut self) { self.stop() } diff --git a/util/io/src/worker.rs b/util/io/src/worker.rs index 79570d3612..0f0d448ecb 100644 --- a/util/io/src/worker.rs +++ b/util/io/src/worker.rs @@ -38,7 +38,7 @@ pub enum WorkType { Writable, Hup, Timeout, - Message(Message) + Message(Arc) } pub struct Work { @@ -65,7 +65,7 @@ impl Worker { wait: Arc, wait_mutex: Arc>, ) -> Worker - where Message: Send + Sync + Clone + 'static { + where Message: Send + Sync + 'static { let deleting = Arc::new(AtomicBool::new(false)); let mut worker = Worker { thread: None, @@ -86,7 +86,7 @@ impl Worker { channel: IoChannel, wait: Arc, wait_mutex: Arc>, deleting: Arc) - where Message: Send + Sync + Clone + 'static { + where Message: Send + Sync + 'static { loop { { let lock = wait_mutex.lock().expect("Poisoned work_loop mutex"); @@ -105,7 +105,7 @@ impl Worker { } } - fn do_work(work: Work, channel: IoChannel) where Message: Send + Sync + Clone + 'static { + fn do_work(work: Work, channel: IoChannel) where Message: Send + Sync + 'static { match work.work_type { WorkType::Readable => { work.handler.stream_readable(&IoContext::new(channel, work.handler_id), work.token); @@ -120,7 +120,7 @@ impl Worker { work.handler.timeout(&IoContext::new(channel, work.handler_id), work.token); } WorkType::Message(message) => { - work.handler.message(&IoContext::new(channel, work.handler_id), &message); + work.handler.message(&IoContext::new(channel, work.handler_id), &*message); } } } -- GitLab From f20f9f376ef6a713400e2ba18353268bd35129fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 May 2018 08:54:37 +0200 Subject: [PATCH 130/263] Make trace-time publishable. (#8568) --- transaction-pool/Cargo.toml | 2 +- util/trace-time/Cargo.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index 342c376f63..8965c8cee0 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Parity Technologies "] error-chain = "0.11" log = "0.3" smallvec = "0.4" -trace-time = { path = "../util/trace-time" } +trace-time = { path = "../util/trace-time", version = "0.1" } [dev-dependencies] ethereum-types = "0.3" diff --git a/util/trace-time/Cargo.toml b/util/trace-time/Cargo.toml index 00597ebfc4..288a2c4e47 100644 --- a/util/trace-time/Cargo.toml +++ b/util/trace-time/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "trace-time" +description = "Easily trace time to execute a scope." version = "0.1.0" authors = ["Parity Technologies "] +license = "GPL-3.0" [dependencies] log = "0.3" -- GitLab From b84682168d46716f455c53ee35166ad7e8e6f7ce Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 9 May 2018 14:55:01 +0800 Subject: [PATCH 131/263] Remove State::replace_backend (#8569) --- ethcore/src/state/mod.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 20d564588c..5b969bccb9 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -402,19 +402,6 @@ impl State { self.factories.vm.clone() } - /// Swap the current backend for another. - // TODO: [rob] find a less hacky way to avoid duplication of `Client::state_at`. - pub fn replace_backend(self, backend: T) -> State { - State { - db: backend, - root: self.root, - cache: self.cache, - checkpoints: self.checkpoints, - account_start_nonce: self.account_start_nonce, - factories: self.factories, - } - } - /// Create a recoverable checkpoint of this state. pub fn checkpoint(&mut self) { self.checkpoints.get_mut().push(HashMap::new()); -- GitLab From 8b0ba97cf2cec8c79b368e907d975484acaef504 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 9 May 2018 12:05:34 +0200 Subject: [PATCH 132/263] Refactoring `ethcore-sync` - Fixing warp-sync barrier (#8543) * Start dividing sync chain : first supplier method * WIP - updated chain sync supplier * Finish refactoring the Chain Sync Supplier * Create Chain Sync Requester * Add Propagator for Chain Sync * Add the Chain Sync Handler * Move tests from mod -> handler * Move tests to propagator * Refactor SyncRequester arguments * Refactoring peer fork header handler * Fix wrong highest block number in snapshot sync * Small refactor... * Address PR grumbles * Retry failed CI job * Fix tests * PR Grumbles --- ethcore/sync/src/chain.rs | 3112 -------------------------- ethcore/sync/src/chain/handler.rs | 828 +++++++ ethcore/sync/src/chain/mod.rs | 1379 ++++++++++++ ethcore/sync/src/chain/propagator.rs | 636 ++++++ ethcore/sync/src/chain/requester.rs | 154 ++ ethcore/sync/src/chain/supplier.rs | 446 ++++ ethcore/sync/src/tests/snapshot.rs | 12 +- 7 files changed, 3453 insertions(+), 3114 deletions(-) delete mode 100644 ethcore/sync/src/chain.rs create mode 100644 ethcore/sync/src/chain/handler.rs create mode 100644 ethcore/sync/src/chain/mod.rs create mode 100644 ethcore/sync/src/chain/propagator.rs create mode 100644 ethcore/sync/src/chain/requester.rs create mode 100644 ethcore/sync/src/chain/supplier.rs diff --git a/ethcore/sync/src/chain.rs b/ethcore/sync/src/chain.rs deleted file mode 100644 index 1a6af10115..0000000000 --- a/ethcore/sync/src/chain.rs +++ /dev/null @@ -1,3112 +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 . - -/// `BlockChain` synchronization strategy. -/// Syncs to peers and keeps up to date. -/// This implementation uses ethereum protocol v63 -/// -/// Syncing strategy summary. -/// Split the chain into ranges of N blocks each. Download ranges sequentially. Split each range into subchains of M blocks. Download subchains in parallel. -/// State. -/// Sync state consists of the following data: -/// - s: State enum which can be one of the following values: `ChainHead`, `Blocks`, `Idle` -/// - H: A set of downloaded block headers -/// - B: A set of downloaded block bodies -/// - S: Set of block subchain start block hashes to download. -/// - l: Last imported / common block hash -/// - P: A set of connected peers. For each peer we maintain its last known total difficulty and starting block hash being requested if any. -/// General behaviour. -/// We start with all sets empty, l is set to the best block in the block chain, s is set to `ChainHead`. -/// If at any moment a bad block is reported by the block queue, we set s to `ChainHead`, reset l to the best block in the block chain and clear H, B and S. -/// If at any moment P becomes empty, we set s to `ChainHead`, and clear H, B and S. -/// -/// Workflow for `ChainHead` state. -/// In this state we try to get subchain headers with a single `GetBlockHeaders` request. -/// On `NewPeer` / On `Restart`: -/// If peer's total difficulty is higher and there are less than 5 peers downloading, request N/M headers with interval M+1 starting from l -/// On `BlockHeaders(R)`: -/// If R is empty: -/// If l is equal to genesis block hash or l is more than 1000 blocks behind our best hash: -/// Remove current peer from P. set l to the best block in the block chain. Select peer with maximum total difficulty from P and restart. -/// Else -/// Set l to l’s parent and restart. -/// Else if we already have all the headers in the block chain or the block queue: -/// Set s to `Idle`, -/// Else -/// Set S to R, set s to `Blocks`. -/// -/// All other messages are ignored. -/// -/// Workflow for `Blocks` state. -/// In this state we download block headers and bodies from multiple peers. -/// On `NewPeer` / On `Restart`: -/// For all idle peers: -/// Find a set of 256 or less block hashes in H which are not in B and not being downloaded by other peers. If the set is not empty: -/// Request block bodies for the hashes in the set. -/// Else -/// Find an element in S which is not being downloaded by other peers. If found: Request M headers starting from the element. -/// -/// On `BlockHeaders(R)`: -/// If R is empty remove current peer from P and restart. -/// Validate received headers: -/// For each header find a parent in H or R or the blockchain. Restart if there is a block with unknown parent. -/// Find at least one header from the received list in S. Restart if there is none. -/// Go to `CollectBlocks`. -/// -/// On `BlockBodies(R)`: -/// If R is empty remove current peer from P and restart. -/// Add bodies with a matching header in H to B. -/// Go to `CollectBlocks`. -/// -/// `CollectBlocks`: -/// Find a chain of blocks C in H starting from h where h’s parent equals to l. The chain ends with the first block which does not have a body in B. -/// Add all blocks from the chain to the block queue. Remove them from H and B. Set l to the hash of the last block from C. -/// Update and merge subchain heads in S. For each h in S find a chain of blocks in B starting from h. Remove h from S. if the chain does not include an element from S add the end of the chain to S. -/// If H is empty and S contains a single element set s to `ChainHead`. -/// Restart. -/// -/// All other messages are ignored. -/// Workflow for Idle state. -/// On `NewBlock`: -/// Import the block. If the block is unknown set s to `ChainHead` and restart. -/// On `NewHashes`: -/// Set s to `ChainHead` and restart. -/// -/// All other messages are ignored. -/// - -use std::sync::Arc; -use std::collections::{HashSet, HashMap}; -use std::cmp; -use std::time::{Duration, Instant}; -use hash::keccak; -use heapsize::HeapSizeOf; -use ethereum_types::{H256, U256}; -use plain_hasher::H256FastMap; -use parking_lot::RwLock; -use bytes::Bytes; -use rlp::{Rlp, RlpStream, DecoderError, Encodable}; -use network::{self, PeerId, PacketId}; -use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockImportErrorKind, BlockQueueInfo}; -use ethcore::error::*; -use ethcore::snapshot::{ManifestData, RestorationStatus}; -use transaction::SignedTransaction; -use sync_io::SyncIo; -use super::{WarpSync, SyncConfig}; -use block_sync::{BlockDownloader, BlockRequest, BlockDownloaderImportError as DownloaderImportError, DownloadAction}; -use rand::Rng; -use snapshot::{Snapshot, ChunkType}; -use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; -use private_tx::PrivateTxHandler; -use transactions_stats::{TransactionsStats, Stats as TransactionStats}; -use transaction::UnverifiedTransaction; - -known_heap_size!(0, PeerInfo); - -type PacketDecodeError = DecoderError; - -/// 63 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_63: u8 = 63; -/// 62 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_62: u8 = 62; -/// 1 version of Parity protocol. -pub const PAR_PROTOCOL_VERSION_1: u8 = 1; -/// 2 version of Parity protocol (consensus messages added). -pub const PAR_PROTOCOL_VERSION_2: u8 = 2; -/// 3 version of Parity protocol (private transactions messages added). -pub const PAR_PROTOCOL_VERSION_3: u8 = 3; - -const MAX_BODIES_TO_SEND: usize = 256; -const MAX_HEADERS_TO_SEND: usize = 512; -const MAX_NODE_DATA_TO_SEND: usize = 1024; -const MAX_RECEIPTS_TO_SEND: usize = 1024; -const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256; -const MIN_PEERS_PROPAGATION: usize = 4; -const MAX_PEERS_PROPAGATION: usize = 128; -const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20; -const MAX_NEW_HASHES: usize = 64; -const MAX_NEW_BLOCK_AGE: BlockNumber = 20; -// maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). -const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; -// Maximal number of transactions in sent in single packet. -const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; -// Min number of blocks to be behind for a snapshot sync -const SNAPSHOT_RESTORE_THRESHOLD: BlockNumber = 30000; -const SNAPSHOT_MIN_PEERS: usize = 3; - -const STATUS_PACKET: u8 = 0x00; -const NEW_BLOCK_HASHES_PACKET: u8 = 0x01; -const TRANSACTIONS_PACKET: u8 = 0x02; -const GET_BLOCK_HEADERS_PACKET: u8 = 0x03; -const BLOCK_HEADERS_PACKET: u8 = 0x04; -const GET_BLOCK_BODIES_PACKET: u8 = 0x05; -const BLOCK_BODIES_PACKET: u8 = 0x06; -const NEW_BLOCK_PACKET: u8 = 0x07; - -const GET_NODE_DATA_PACKET: u8 = 0x0d; -const NODE_DATA_PACKET: u8 = 0x0e; -const GET_RECEIPTS_PACKET: u8 = 0x0f; -const RECEIPTS_PACKET: u8 = 0x10; - -pub const ETH_PACKET_COUNT: u8 = 0x11; - -const GET_SNAPSHOT_MANIFEST_PACKET: u8 = 0x11; -const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12; -const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13; -const SNAPSHOT_DATA_PACKET: u8 = 0x14; -const CONSENSUS_DATA_PACKET: u8 = 0x15; -const PRIVATE_TRANSACTION_PACKET: u8 = 0x16; -const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17; - -pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; - -const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; - -const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); -const STATUS_TIMEOUT: Duration = Duration::from_secs(5); -const HEADERS_TIMEOUT: Duration = Duration::from_secs(15); -const BODIES_TIMEOUT: Duration = Duration::from_secs(20); -const RECEIPTS_TIMEOUT: Duration = Duration::from_secs(10); -const FORK_HEADER_TIMEOUT: Duration = Duration::from_secs(3); -const SNAPSHOT_MANIFEST_TIMEOUT: Duration = Duration::from_secs(5); -const SNAPSHOT_DATA_TIMEOUT: Duration = Duration::from_secs(120); - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -/// Sync state -pub enum SyncState { - /// Collecting enough peers to start syncing. - WaitingPeers, - /// Waiting for snapshot manifest download - SnapshotManifest, - /// Downloading snapshot data - SnapshotData, - /// Waiting for snapshot restoration progress. - SnapshotWaiting, - /// Downloading new blocks - Blocks, - /// Initial chain sync complete. Waiting for new packets - Idle, - /// Block downloading paused. Waiting for block queue to process blocks and free some space - Waiting, - /// Downloading blocks learned from `NewHashes` packet - NewBlocks, -} - -/// Syncing status and statistics -#[derive(Clone, Copy)] -pub struct SyncStatus { - /// State - pub state: SyncState, - /// Syncing protocol version. That's the maximum protocol version we connect to. - pub protocol_version: u8, - /// The underlying p2p network version. - pub network_id: u64, - /// `BlockChain` height for the moment the sync started. - pub start_block_number: BlockNumber, - /// Last fully downloaded and imported block number (if any). - pub last_imported_block_number: Option, - /// Highest block number in the download queue (if any). - pub highest_block_number: Option, - /// Total number of blocks for the sync process. - pub blocks_total: BlockNumber, - /// Number of blocks downloaded so far. - pub blocks_received: BlockNumber, - /// Total number of connected peers - pub num_peers: usize, - /// Total number of active peers. - pub num_active_peers: usize, - /// Heap memory used in bytes. - pub mem_used: usize, - /// Snapshot chunks - pub num_snapshot_chunks: usize, - /// Snapshot chunks downloaded - pub snapshot_chunks_done: usize, - /// Last fully downloaded and imported ancient block number (if any). - pub last_imported_old_block_number: Option, -} - -impl SyncStatus { - /// Indicates if snapshot download is in progress - pub fn is_snapshot_syncing(&self) -> bool { - self.state == SyncState::SnapshotManifest - || self.state == SyncState::SnapshotData - || self.state == SyncState::SnapshotWaiting - } - - /// Returns max no of peers to display in informants - pub fn current_max_peers(&self, min_peers: u32, max_peers: u32) -> u32 { - if self.num_peers as u32 > min_peers { - max_peers - } else { - min_peers - } - } - - /// Is it doing a major sync? - pub fn is_syncing(&self, queue_info: BlockQueueInfo) -> bool { - let is_syncing_state = match self.state { SyncState::Idle | SyncState::NewBlocks => false, _ => true }; - let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3; - is_verifying || is_syncing_state - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -/// Peer data type requested -enum PeerAsking { - Nothing, - ForkHeader, - BlockHeaders, - BlockBodies, - BlockReceipts, - SnapshotManifest, - SnapshotData, -} - -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -/// Block downloader channel. -enum BlockSet { - /// New blocks better than out best blocks - NewBlocks, - /// Missing old blocks - OldBlocks, -} -#[derive(Clone, Eq, PartialEq)] -enum ForkConfirmation { - /// Fork block confirmation pending. - Unconfirmed, - /// Peers chain is too short to confirm the fork. - TooShort, - /// Fork is confirmed. - Confirmed, -} - -#[derive(Clone)] -/// Syncing peer information -struct PeerInfo { - /// eth protocol version - protocol_version: u8, - /// Peer chain genesis hash - genesis: H256, - /// Peer network id - network_id: u64, - /// Peer best block hash - latest_hash: H256, - /// Peer total difficulty if known - difficulty: Option, - /// Type of data currenty being requested from peer. - asking: PeerAsking, - /// A set of block numbers being requested - asking_blocks: Vec, - /// Holds requested header hash if currently requesting block header by hash - asking_hash: Option, - /// Holds requested snapshot chunk hash if any. - asking_snapshot_data: Option, - /// Request timestamp - ask_time: Instant, - /// Holds a set of transactions recently sent to this peer to avoid spamming. - last_sent_transactions: HashSet, - /// Pending request is expired and result should be ignored - expired: bool, - /// Peer fork confirmation status - confirmation: ForkConfirmation, - /// Best snapshot hash - snapshot_hash: Option, - /// Best snapshot block number - snapshot_number: Option, - /// Block set requested - block_set: Option, -} - -impl PeerInfo { - fn can_sync(&self) -> bool { - self.confirmation == ForkConfirmation::Confirmed && !self.expired - } - - fn is_allowed(&self) -> bool { - self.confirmation != ForkConfirmation::Unconfirmed && !self.expired - } - - fn reset_asking(&mut self) { - self.asking_blocks.clear(); - self.asking_hash = None; - // mark any pending requests as expired - if self.asking != PeerAsking::Nothing && self.is_allowed() { - self.expired = true; - } - } -} - -#[cfg(not(test))] -mod random { - use rand; - pub fn new() -> rand::ThreadRng { rand::thread_rng() } -} -#[cfg(test)] -mod random { - use rand::{self, SeedableRng}; - pub fn new() -> rand::XorShiftRng { rand::XorShiftRng::from_seed([0, 1, 2, 3]) } -} - -/// Blockchain sync handler. -/// See module documentation for more details. -pub struct ChainSync { - /// Sync state - state: SyncState, - /// Last block number for the start of sync - starting_block: BlockNumber, - /// Highest block number seen - highest_block: Option, - /// All connected peers - peers: HashMap, - /// Peers active for current sync round - active_peers: HashSet, - /// Block download process for new blocks - new_blocks: BlockDownloader, - /// Block download process for ancient blocks - old_blocks: Option, - /// Last propagated block number - last_sent_block_number: BlockNumber, - /// Network ID - network_id: u64, - /// Optional fork block to check - fork_block: Option<(BlockNumber, H256)>, - /// Snapshot downloader. - snapshot: Snapshot, - /// Connected peers pending Status message. - /// Value is request timestamp. - handshaking_peers: HashMap, - /// Sync start timestamp. Measured when first peer is connected - sync_start_time: Option, - /// Transactions propagation statistics - transactions_stats: TransactionsStats, - /// Enable ancient block downloading - download_old_blocks: bool, - /// Shared private tx service. - private_tx_handler: Arc, - /// Enable warp sync. - warp_sync: WarpSync, -} - -type RlpResponseResult = Result, PacketDecodeError>; - -impl ChainSync { - /// Create a new instance of syncing strategy. - pub fn new(config: SyncConfig, chain: &BlockChainClient, private_tx_handler: Arc) -> ChainSync { - let chain_info = chain.chain_info(); - let best_block = chain.chain_info().best_block_number; - let state = match config.warp_sync { - WarpSync::Enabled => SyncState::WaitingPeers, - WarpSync::OnlyAndAfter(block) if block > best_block => SyncState::WaitingPeers, - _ => SyncState::Idle, - }; - - let mut sync = ChainSync { - state, - starting_block: best_block, - highest_block: None, - peers: HashMap::new(), - handshaking_peers: HashMap::new(), - active_peers: HashSet::new(), - new_blocks: BlockDownloader::new(false, &chain_info.best_block_hash, chain_info.best_block_number), - old_blocks: None, - last_sent_block_number: 0, - network_id: config.network_id, - fork_block: config.fork_block, - download_old_blocks: config.download_old_blocks, - snapshot: Snapshot::new(), - sync_start_time: None, - transactions_stats: TransactionsStats::default(), - private_tx_handler, - warp_sync: config.warp_sync, - }; - sync.update_targets(chain); - sync - } - - /// Returns synchonization status - pub fn status(&self) -> SyncStatus { - let last_imported_number = self.new_blocks.last_imported_block_number(); - SyncStatus { - state: self.state.clone(), - protocol_version: ETH_PROTOCOL_VERSION_63, - network_id: self.network_id, - start_block_number: self.starting_block, - last_imported_block_number: Some(last_imported_number), - last_imported_old_block_number: self.old_blocks.as_ref().map(|d| d.last_imported_block_number()), - highest_block_number: self.highest_block.map(|n| cmp::max(n, last_imported_number)), - blocks_received: if last_imported_number > self.starting_block { last_imported_number - self.starting_block } else { 0 }, - blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, - num_peers: self.peers.values().filter(|p| p.is_allowed()).count(), - num_active_peers: self.peers.values().filter(|p| p.is_allowed() && p.asking != PeerAsking::Nothing).count(), - num_snapshot_chunks: self.snapshot.total_chunks(), - snapshot_chunks_done: self.snapshot.done_chunks(), - mem_used: - self.new_blocks.heap_size() - + self.old_blocks.as_ref().map_or(0, |d| d.heap_size()) - + self.peers.heap_size_of_children(), - } - } - - /// Returns information on peers connections - pub fn peer_info(&self, peer_id: &PeerId) -> Option { - self.peers.get(peer_id).map(|peer_data| { - PeerInfoDigest { - version: peer_data.protocol_version as u32, - difficulty: peer_data.difficulty, - head: peer_data.latest_hash, - } - }) - } - - /// Returns transactions propagation statistics - pub fn transactions_stats(&self) -> &H256FastMap { - self.transactions_stats.stats() - } - - /// Updates transactions were received by a peer - pub fn transactions_received(&mut self, txs: &[UnverifiedTransaction], peer_id: PeerId) { - if let Some(peer_info) = self.peers.get_mut(&peer_id) { - peer_info.last_sent_transactions.extend(txs.iter().map(|tx| tx.hash())); - } - } - - /// Abort all sync activity - pub fn abort(&mut self, io: &mut SyncIo) { - self.reset_and_continue(io); - self.peers.clear(); - } - - /// Reset sync. Clear all downloaded data but keep the queue - fn reset(&mut self, io: &mut SyncIo) { - self.new_blocks.reset(); - let chain_info = io.chain().chain_info(); - for (_, ref mut p) in &mut self.peers { - if p.block_set != Some(BlockSet::OldBlocks) { - p.reset_asking(); - if p.difficulty.is_none() { - // assume peer has up to date difficulty - p.difficulty = Some(chain_info.pending_total_difficulty); - } - } - } - self.state = SyncState::Idle; - // Reactivate peers only if some progress has been made - // since the last sync round of if starting fresh. - self.active_peers = self.peers.keys().cloned().collect(); - } - - /// Restart sync - pub fn reset_and_continue(&mut self, io: &mut SyncIo) { - trace!(target: "sync", "Restarting"); - if self.state == SyncState::SnapshotData { - debug!(target:"sync", "Aborting snapshot restore"); - io.snapshot_service().abort_restore(); - } - self.snapshot.clear(); - self.reset(io); - self.continue_sync(io); - } - - /// Remove peer from active peer set. Peer will be reactivated on the next sync - /// round. - fn deactivate_peer(&mut self, _io: &mut SyncIo, peer_id: PeerId) { - trace!(target: "sync", "Deactivating peer {}", peer_id); - self.active_peers.remove(&peer_id); - } - - fn maybe_start_snapshot_sync(&mut self, io: &mut SyncIo) { - if !self.warp_sync.is_enabled() || io.snapshot_service().supported_versions().is_none() { - trace!(target: "sync", "Skipping warp sync. Disabled or not supported."); - return; - } - if self.state != SyncState::WaitingPeers && self.state != SyncState::Blocks && self.state != SyncState::Waiting { - trace!(target: "sync", "Skipping warp sync. State: {:?}", self.state); - return; - } - // Make sure the snapshot block is not too far away from best block and network best block and - // that it is higher than fork detection block - let our_best_block = io.chain().chain_info().best_block_number; - let fork_block = self.fork_block.as_ref().map(|&(n, _)| n).unwrap_or(0); - - let (best_hash, max_peers, snapshot_peers) = { - let expected_warp_block = match self.warp_sync { - WarpSync::OnlyAndAfter(block) => block, - _ => 0, - }; - //collect snapshot infos from peers - let snapshots = self.peers.iter() - .filter(|&(_, p)| p.is_allowed() && p.snapshot_number.map_or(false, |sn| - our_best_block < sn && (sn - our_best_block) > SNAPSHOT_RESTORE_THRESHOLD && - sn > fork_block && - sn > expected_warp_block && - self.highest_block.map_or(true, |highest| highest >= sn && (highest - sn) <= SNAPSHOT_RESTORE_THRESHOLD) - )) - .filter_map(|(p, peer)| peer.snapshot_hash.map(|hash| (p, hash.clone()))) - .filter(|&(_, ref hash)| !self.snapshot.is_known_bad(hash)); - - let mut snapshot_peers = HashMap::new(); - let mut max_peers: usize = 0; - let mut best_hash = None; - for (p, hash) in snapshots { - let peers = snapshot_peers.entry(hash).or_insert_with(Vec::new); - peers.push(*p); - if peers.len() > max_peers { - max_peers = peers.len(); - best_hash = Some(hash); - } - } - (best_hash, max_peers, snapshot_peers) - }; - - let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed() > WAIT_PEERS_TIMEOUT); - - if let (Some(hash), Some(peers)) = (best_hash, best_hash.map_or(None, |h| snapshot_peers.get(&h))) { - if max_peers >= SNAPSHOT_MIN_PEERS { - trace!(target: "sync", "Starting confirmed snapshot sync {:?} with {:?}", hash, peers); - self.start_snapshot_sync(io, peers); - } else if timeout { - trace!(target: "sync", "Starting unconfirmed snapshot sync {:?} with {:?}", hash, peers); - self.start_snapshot_sync(io, peers); - } - } else if timeout && !self.warp_sync.is_warp_only() { - trace!(target: "sync", "No snapshots found, starting full sync"); - self.state = SyncState::Idle; - self.continue_sync(io); - } - } - - fn start_snapshot_sync(&mut self, io: &mut SyncIo, peers: &[PeerId]) { - if !self.snapshot.have_manifest() { - for p in peers { - if self.peers.get(p).map_or(false, |p| p.asking == PeerAsking::Nothing) { - self.request_snapshot_manifest(io, *p); - } - } - self.state = SyncState::SnapshotManifest; - trace!(target: "sync", "New snapshot sync with {:?}", peers); - } else { - self.state = SyncState::SnapshotData; - trace!(target: "sync", "Resumed snapshot sync with {:?}", peers); - } - } - - /// Restart sync disregarding the block queue status. May end up re-downloading up to QUEUE_SIZE blocks - pub fn restart(&mut self, io: &mut SyncIo) { - self.update_targets(io.chain()); - self.reset_and_continue(io); - } - - /// Update sync after the blockchain has been changed externally. - pub fn update_targets(&mut self, chain: &BlockChainClient) { - // Do not assume that the block queue/chain still has our last_imported_block - let chain = chain.chain_info(); - self.new_blocks = BlockDownloader::new(false, &chain.best_block_hash, chain.best_block_number); - self.old_blocks = None; - if self.download_old_blocks { - if let (Some(ancient_block_hash), Some(ancient_block_number)) = (chain.ancient_block_hash, chain.ancient_block_number) { - - trace!(target: "sync", "Downloading old blocks from {:?} (#{}) till {:?} (#{:?})", ancient_block_hash, ancient_block_number, chain.first_block_hash, chain.first_block_number); - let mut downloader = BlockDownloader::with_unlimited_reorg(true, &ancient_block_hash, ancient_block_number); - if let Some(hash) = chain.first_block_hash { - trace!(target: "sync", "Downloader target set to {:?}", hash); - downloader.set_target(&hash); - } - self.old_blocks = Some(downloader); - } - } - } - - /// Called by peer to report status - fn on_peer_status(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - self.handshaking_peers.remove(&peer_id); - let protocol_version: u8 = r.val_at(0)?; - let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer_id) != 0; - let peer = PeerInfo { - protocol_version: protocol_version, - network_id: r.val_at(1)?, - difficulty: Some(r.val_at(2)?), - latest_hash: r.val_at(3)?, - genesis: r.val_at(4)?, - asking: PeerAsking::Nothing, - asking_blocks: Vec::new(), - asking_hash: None, - ask_time: Instant::now(), - last_sent_transactions: HashSet::new(), - expired: false, - confirmation: if self.fork_block.is_none() { ForkConfirmation::Confirmed } else { ForkConfirmation::Unconfirmed }, - asking_snapshot_data: None, - snapshot_hash: if warp_protocol { Some(r.val_at(5)?) } else { None }, - snapshot_number: if warp_protocol { Some(r.val_at(6)?) } else { None }, - block_set: None, - }; - - trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{}, snapshot:{:?})", - peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis, peer.snapshot_number); - if io.is_expired() { - trace!(target: "sync", "Status packet from expired session {}:{}", peer_id, io.peer_info(peer_id)); - return Ok(()); - } - - if self.peers.contains_key(&peer_id) { - debug!(target: "sync", "Unexpected status packet from {}:{}", peer_id, io.peer_info(peer_id)); - return Ok(()); - } - let chain_info = io.chain().chain_info(); - if peer.genesis != chain_info.genesis_hash { - io.disable_peer(peer_id); - trace!(target: "sync", "Peer {} genesis hash mismatch (ours: {}, theirs: {})", peer_id, chain_info.genesis_hash, peer.genesis); - return Ok(()); - } - if peer.network_id != self.network_id { - io.disable_peer(peer_id); - trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, self.network_id, peer.network_id); - return Ok(()); - } - if (warp_protocol && peer.protocol_version != PAR_PROTOCOL_VERSION_1 && peer.protocol_version != PAR_PROTOCOL_VERSION_2 && peer.protocol_version != PAR_PROTOCOL_VERSION_3) - || (!warp_protocol && peer.protocol_version != ETH_PROTOCOL_VERSION_63 && peer.protocol_version != ETH_PROTOCOL_VERSION_62) { - io.disable_peer(peer_id); - trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); - return Ok(()); - } - - if self.sync_start_time.is_none() { - self.sync_start_time = Some(Instant::now()); - } - - self.peers.insert(peer_id.clone(), peer); - // Don't activate peer immediatelly when searching for common block. - // Let the current sync round complete first. - self.active_peers.insert(peer_id.clone()); - debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); - if let Some((fork_block, _)) = self.fork_block { - self.request_fork_header_by_number(io, peer_id, fork_block); - } else { - self.sync_peer(io, peer_id, false); - } - Ok(()) - } - - /// Called by peer once it has new block headers during sync - fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - let confirmed = match self.peers.get_mut(&peer_id) { - Some(ref mut peer) if peer.asking == PeerAsking::ForkHeader => { - peer.asking = PeerAsking::Nothing; - let item_count = r.item_count()?; - let (fork_number, fork_hash) = self.fork_block.expect("ForkHeader request is sent only fork block is Some; qed").clone(); - if item_count == 0 || item_count != 1 { - trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id); - peer.confirmation = ForkConfirmation::TooShort; - } else { - let header = r.at(0)?.as_raw(); - if keccak(&header) == fork_hash { - trace!(target: "sync", "{}: Confirmed peer", peer_id); - peer.confirmation = ForkConfirmation::Confirmed; - if !io.chain_overlay().read().contains_key(&fork_number) { - io.chain_overlay().write().insert(fork_number, header.to_vec()); - } - } else { - trace!(target: "sync", "{}: Fork mismatch", peer_id); - io.disable_peer(peer_id); - return Ok(()); - } - } - true - }, - _ => false, - }; - if confirmed { - self.sync_peer(io, peer_id, false); - return Ok(()); - } - - self.clear_peer_download(peer_id); - let expected_hash = self.peers.get(&peer_id).and_then(|p| p.asking_hash); - let allowed = self.peers.get(&peer_id).map(|p| p.is_allowed()).unwrap_or(false); - let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders) || expected_hash.is_none() || !allowed { - trace!(target: "sync", "{}: Ignored unexpected headers, expected_hash = {:?}", peer_id, expected_hash); - self.continue_sync(io); - return Ok(()); - } - let item_count = r.item_count()?; - trace!(target: "sync", "{} -> BlockHeaders ({} entries), state = {:?}, set = {:?}", peer_id, item_count, self.state, block_set); - if (self.state == SyncState::Idle || self.state == SyncState::WaitingPeers) && self.old_blocks.is_none() { - trace!(target: "sync", "Ignored unexpected block headers"); - self.continue_sync(io); - return Ok(()); - } - if self.state == SyncState::Waiting { - trace!(target: "sync", "Ignored block headers while waiting"); - self.continue_sync(io); - return Ok(()); - } - - let result = { - let downloader = match block_set { - BlockSet::NewBlocks => &mut self.new_blocks, - BlockSet::OldBlocks => { - match self.old_blocks { - None => { - trace!(target: "sync", "Ignored block headers while block download is inactive"); - self.continue_sync(io); - return Ok(()); - }, - Some(ref mut blocks) => blocks, - } - } - }; - downloader.import_headers(io, r, expected_hash) - }; - - match result { - Err(DownloaderImportError::Useless) => { - self.deactivate_peer(io, peer_id); - }, - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - self.deactivate_peer(io, peer_id); - self.continue_sync(io); - return Ok(()); - }, - Ok(DownloadAction::Reset) => { - // mark all outstanding requests as expired - trace!("Resetting downloads for {:?}", block_set); - for (_, ref mut p) in self.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { - p.reset_asking(); - } - - } - Ok(DownloadAction::None) => {}, - } - - self.collect_blocks(io, block_set); - // give a task to the same peer first if received valuable headers. - self.sync_peer(io, peer_id, false); - // give tasks to other peers - self.continue_sync(io); - Ok(()) - } - - /// Called by peer once it has new block bodies - fn on_peer_block_bodies(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - self.clear_peer_download(peer_id); - let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !self.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { - trace!(target: "sync", "{}: Ignored unexpected bodies", peer_id); - self.continue_sync(io); - return Ok(()); - } - let item_count = r.item_count()?; - trace!(target: "sync", "{} -> BlockBodies ({} entries), set = {:?}", peer_id, item_count, block_set); - if item_count == 0 { - self.deactivate_peer(io, peer_id); - } - else if self.state == SyncState::Waiting { - trace!(target: "sync", "Ignored block bodies while waiting"); - } - else - { - let result = { - let downloader = match block_set { - BlockSet::NewBlocks => &mut self.new_blocks, - BlockSet::OldBlocks => match self.old_blocks { - None => { - trace!(target: "sync", "Ignored block headers while block download is inactive"); - self.continue_sync(io); - return Ok(()); - }, - Some(ref mut blocks) => blocks, - } - }; - downloader.import_bodies(io, r) - }; - - match result { - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - self.deactivate_peer(io, peer_id); - self.continue_sync(io); - return Ok(()); - }, - Err(DownloaderImportError::Useless) => { - self.deactivate_peer(io, peer_id); - }, - Ok(()) => (), - } - - self.collect_blocks(io, block_set); - self.sync_peer(io, peer_id, false); - } - self.continue_sync(io); - Ok(()) - } - - /// Called by peer once it has new block receipts - fn on_peer_block_receipts(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - self.clear_peer_download(peer_id); - let block_set = self.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !self.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { - trace!(target: "sync", "{}: Ignored unexpected receipts", peer_id); - self.continue_sync(io); - return Ok(()); - } - let item_count = r.item_count()?; - trace!(target: "sync", "{} -> BlockReceipts ({} entries)", peer_id, item_count); - if item_count == 0 { - self.deactivate_peer(io, peer_id); - } - else if self.state == SyncState::Waiting { - trace!(target: "sync", "Ignored block receipts while waiting"); - } - else - { - let result = { - let downloader = match block_set { - BlockSet::NewBlocks => &mut self.new_blocks, - BlockSet::OldBlocks => match self.old_blocks { - None => { - trace!(target: "sync", "Ignored block headers while block download is inactive"); - self.continue_sync(io); - return Ok(()); - }, - Some(ref mut blocks) => blocks, - } - }; - downloader.import_receipts(io, r) - }; - - match result { - Err(DownloaderImportError::Invalid) => { - io.disable_peer(peer_id); - self.deactivate_peer(io, peer_id); - self.continue_sync(io); - return Ok(()); - }, - Err(DownloaderImportError::Useless) => { - self.deactivate_peer(io, peer_id); - }, - Ok(()) => (), - } - - self.collect_blocks(io, block_set); - self.sync_peer(io, peer_id, false); - } - self.continue_sync(io); - Ok(()) - } - - /// Called by peer once it has new block bodies - fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id); - return Ok(()); - } - let difficulty: U256 = r.val_at(1)?; - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - if peer.difficulty.map_or(true, |pd| difficulty > pd) { - peer.difficulty = Some(difficulty); - } - } - let block_rlp = r.at(0)?; - let header_rlp = block_rlp.at(0)?; - let h = keccak(&header_rlp.as_raw()); - trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); - let header: BlockHeader = header_rlp.as_val()?; - if header.number() > self.highest_block.unwrap_or(0) { - self.highest_block = Some(header.number()); - } - let mut unknown = false; - { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.latest_hash = header.hash(); - } - } - let last_imported_number = self.new_blocks.last_imported_block_number(); - if last_imported_number > header.number() && last_imported_number - header.number() > MAX_NEW_BLOCK_AGE { - trace!(target: "sync", "Ignored ancient new block {:?}", h); - io.disable_peer(peer_id); - return Ok(()); - } - match io.chain().import_block(block_rlp.as_raw().to_vec()) { - Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { - trace!(target: "sync", "New block already in chain {:?}", h); - }, - Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { - trace!(target: "sync", "New block already queued {:?}", h); - }, - Ok(_) => { - // abort current download of the same block - self.complete_sync(io); - self.new_blocks.mark_as_known(&header.hash(), header.number()); - trace!(target: "sync", "New block queued {:?} ({})", h, header.number()); - }, - Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => { - unknown = true; - trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); - }, - Err(e) => { - debug!(target: "sync", "Bad new block {:?} : {:?}", h, e); - io.disable_peer(peer_id); - } - }; - if unknown { - if self.state != SyncState::Idle { - trace!(target: "sync", "NewBlock ignored while seeking"); - } else { - trace!(target: "sync", "New unknown block {:?}", h); - //TODO: handle too many unknown blocks - self.sync_peer(io, peer_id, true); - } - } - self.continue_sync(io); - Ok(()) - } - - /// Handles `NewHashes` packet. Initiates headers download for any unknown hashes. - fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id); - return Ok(()); - } - let hashes: Vec<_> = r.iter().take(MAX_NEW_HASHES).map(|item| (item.val_at::(0), item.val_at::(1))).collect(); - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - // Peer has new blocks with unknown difficulty - peer.difficulty = None; - if let Some(&(Ok(ref h), _)) = hashes.last() { - peer.latest_hash = h.clone(); - } - } - if self.state != SyncState::Idle { - trace!(target: "sync", "Ignoring new hashes since we're already downloading."); - let max = r.iter().take(MAX_NEW_HASHES).map(|item| item.val_at::(1).unwrap_or(0)).fold(0u64, cmp::max); - if max > self.highest_block.unwrap_or(0) { - self.highest_block = Some(max); - } - self.continue_sync(io); - return Ok(()); - } - trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count()?); - let mut max_height: BlockNumber = 0; - let mut new_hashes = Vec::new(); - let last_imported_number = self.new_blocks.last_imported_block_number(); - for (rh, rn) in hashes { - let hash = rh?; - let number = rn?; - if number > self.highest_block.unwrap_or(0) { - self.highest_block = Some(number); - } - if self.new_blocks.is_downloading(&hash) { - continue; - } - if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE { - trace!(target: "sync", "Ignored ancient new block hash {:?}", hash); - io.disable_peer(peer_id); - continue; - } - match io.chain().block_status(BlockId::Hash(hash.clone())) { - BlockStatus::InChain => { - trace!(target: "sync", "New block hash already in chain {:?}", hash); - }, - BlockStatus::Queued => { - trace!(target: "sync", "New hash block already queued {:?}", hash); - }, - BlockStatus::Unknown | BlockStatus::Pending => { - new_hashes.push(hash.clone()); - if number > max_height { - trace!(target: "sync", "New unknown block hash {:?}", hash); - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.latest_hash = hash.clone(); - } - max_height = number; - } - }, - BlockStatus::Bad => { - debug!(target: "sync", "Bad new block hash {:?}", hash); - io.disable_peer(peer_id); - return Ok(()); - } - } - }; - if max_height != 0 { - trace!(target: "sync", "Downloading blocks for new hashes"); - self.new_blocks.reset_to(new_hashes); - self.state = SyncState::NewBlocks; - self.sync_peer(io, peer_id, true); - } - self.continue_sync(io); - Ok(()) - } - - /// Called when snapshot manifest is downloaded from a peer. - fn on_snapshot_manifest(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring snapshot manifest from unconfirmed peer {}", peer_id); - return Ok(()); - } - self.clear_peer_download(peer_id); - if !self.reset_peer_asking(peer_id, PeerAsking::SnapshotManifest) || self.state != SyncState::SnapshotManifest { - trace!(target: "sync", "{}: Ignored unexpected/expired manifest", peer_id); - self.continue_sync(io); - return Ok(()); - } - - let manifest_rlp = r.at(0)?; - let manifest = match ManifestData::from_rlp(manifest_rlp.as_raw()) { - Err(e) => { - trace!(target: "sync", "{}: Ignored bad manifest: {:?}", peer_id, e); - io.disable_peer(peer_id); - self.continue_sync(io); - return Ok(()); - } - Ok(manifest) => manifest, - }; - - let is_supported_version = io.snapshot_service().supported_versions() - .map_or(false, |(l, h)| manifest.version >= l && manifest.version <= h); - - if !is_supported_version { - trace!(target: "sync", "{}: Snapshot manifest version not supported: {}", peer_id, manifest.version); - io.disable_peer(peer_id); - self.continue_sync(io); - return Ok(()); - } - self.snapshot.reset_to(&manifest, &keccak(manifest_rlp.as_raw())); - io.snapshot_service().begin_restore(manifest); - self.state = SyncState::SnapshotData; - - // give a task to the same peer first. - self.sync_peer(io, peer_id, false); - // give tasks to other peers - self.continue_sync(io); - Ok(()) - } - - /// Called when snapshot data is downloaded from a peer. - fn on_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "Ignoring snapshot data from unconfirmed peer {}", peer_id); - return Ok(()); - } - self.clear_peer_download(peer_id); - if !self.reset_peer_asking(peer_id, PeerAsking::SnapshotData) || (self.state != SyncState::SnapshotData && self.state != SyncState::SnapshotWaiting) { - trace!(target: "sync", "{}: Ignored unexpected snapshot data", peer_id); - self.continue_sync(io); - return Ok(()); - } - - // check service status - let status = io.snapshot_service().status(); - match status { - RestorationStatus::Inactive | RestorationStatus::Failed => { - trace!(target: "sync", "{}: Snapshot restoration aborted", peer_id); - self.state = SyncState::WaitingPeers; - - // only note bad if restoration failed. - if let (Some(hash), RestorationStatus::Failed) = (self.snapshot.snapshot_hash(), status) { - trace!(target: "sync", "Noting snapshot hash {} as bad", hash); - self.snapshot.note_bad(hash); - } - - self.snapshot.clear(); - self.continue_sync(io); - return Ok(()); - }, - RestorationStatus::Ongoing { .. } => { - trace!(target: "sync", "{}: Snapshot restoration is ongoing", peer_id); - }, - } - - let snapshot_data: Bytes = r.val_at(0)?; - match self.snapshot.validate_chunk(&snapshot_data) { - Ok(ChunkType::Block(hash)) => { - trace!(target: "sync", "{}: Processing block chunk", peer_id); - io.snapshot_service().restore_block_chunk(hash, snapshot_data); - } - Ok(ChunkType::State(hash)) => { - trace!(target: "sync", "{}: Processing state chunk", peer_id); - io.snapshot_service().restore_state_chunk(hash, snapshot_data); - } - Err(()) => { - trace!(target: "sync", "{}: Got bad snapshot chunk", peer_id); - io.disconnect_peer(peer_id); - self.continue_sync(io); - return Ok(()); - } - } - - if self.snapshot.is_complete() { - // wait for snapshot restoration process to complete - self.state = SyncState::SnapshotWaiting; - } - // give a task to the same peer first. - self.sync_peer(io, peer_id, false); - // give tasks to other peers - self.continue_sync(io); - Ok(()) - } - - /// Called by peer when it is disconnecting - pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) { - trace!(target: "sync", "== Disconnecting {}: {}", peer, io.peer_info(peer)); - self.handshaking_peers.remove(&peer); - if self.peers.contains_key(&peer) { - debug!(target: "sync", "Disconnected {}", peer); - self.clear_peer_download(peer); - self.peers.remove(&peer); - self.active_peers.remove(&peer); - self.continue_sync(io); - } - } - - /// Called when a new peer is connected - pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { - trace!(target: "sync", "== Connected {}: {}", peer, io.peer_info(peer)); - if let Err(e) = self.send_status(io, peer) { - debug!(target:"sync", "Error sending status request: {:?}", e); - io.disconnect_peer(peer); - } else { - self.handshaking_peers.insert(peer, Instant::now()); - } - } - - /// Resume downloading - fn continue_sync(&mut self, io: &mut SyncIo) { - let mut peers: Vec<(PeerId, U256, u8)> = self.peers.iter().filter_map(|(k, p)| - if p.can_sync() { Some((*k, p.difficulty.unwrap_or_else(U256::zero), p.protocol_version)) } else { None }).collect(); - random::new().shuffle(&mut peers); //TODO: sort by rating - // prefer peers with higher protocol version - peers.sort_by(|&(_, _, ref v1), &(_, _, ref v2)| v1.cmp(v2)); - trace!(target: "sync", "Syncing with peers: {} active, {} confirmed, {} total", self.active_peers.len(), peers.len(), self.peers.len()); - for (p, _, _) in peers { - if self.active_peers.contains(&p) { - self.sync_peer(io, p, false); - } - } - - if - self.state != SyncState::WaitingPeers && - self.state != SyncState::SnapshotWaiting && - self.state != SyncState::Waiting && - self.state != SyncState::Idle && - !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.block_set != Some(BlockSet::OldBlocks) && p.can_sync()) - { - self.complete_sync(io); - } - } - - /// Called after all blocks have been downloaded - fn complete_sync(&mut self, io: &mut SyncIo) { - trace!(target: "sync", "Sync complete"); - self.reset(io); - self.state = SyncState::Idle; - } - - /// Enter waiting state - fn pause_sync(&mut self) { - trace!(target: "sync", "Block queue full, pausing sync"); - self.state = SyncState::Waiting; - } - - /// Find something to do for a peer. Called for a new peer or when a peer is done with its task. - fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) { - if !self.active_peers.contains(&peer_id) { - trace!(target: "sync", "Skipping deactivated peer {}", peer_id); - return; - } - let (peer_latest, peer_difficulty, peer_snapshot_number, peer_snapshot_hash) = { - if let Some(peer) = self.peers.get_mut(&peer_id) { - if peer.asking != PeerAsking::Nothing || !peer.can_sync() { - trace!(target: "sync", "Skipping busy peer {}", peer_id); - return; - } - if self.state == SyncState::Waiting { - trace!(target: "sync", "Waiting for the block queue"); - return; - } - if self.state == SyncState::SnapshotWaiting { - trace!(target: "sync", "Waiting for the snapshot restoration"); - return; - } - (peer.latest_hash.clone(), peer.difficulty.clone(), peer.snapshot_number.as_ref().cloned().unwrap_or(0), peer.snapshot_hash.as_ref().cloned()) - } else { - return; - } - }; - let chain_info = io.chain().chain_info(); - let syncing_difficulty = chain_info.pending_total_difficulty; - let num_active_peers = self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(); - - let higher_difficulty = peer_difficulty.map_or(true, |pd| pd > syncing_difficulty); - if force || higher_difficulty || self.old_blocks.is_some() { - match self.state { - SyncState::WaitingPeers => { - trace!( - target: "sync", - "Checking snapshot sync: {} vs {} (peer: {})", - peer_snapshot_number, - chain_info.best_block_number, - peer_id - ); - self.maybe_start_snapshot_sync(io); - }, - SyncState::Idle | SyncState::Blocks | SyncState::NewBlocks => { - if io.chain().queue_info().is_full() { - self.pause_sync(); - return; - } - - let have_latest = io.chain().block_status(BlockId::Hash(peer_latest)) != BlockStatus::Unknown; - trace!(target: "sync", "Considering peer {}, force={}, td={:?}, our td={}, latest={}, have_latest={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, peer_latest, have_latest, self.state); - if !have_latest && (higher_difficulty || force || self.state == SyncState::NewBlocks) { - // check if got new blocks to download - trace!(target: "sync", "Syncing with peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); - if let Some(request) = self.new_blocks.request_blocks(io, num_active_peers) { - self.request_blocks(io, peer_id, request, BlockSet::NewBlocks); - if self.state == SyncState::Idle { - self.state = SyncState::Blocks; - } - return; - } - } - - if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { - self.request_blocks(io, peer_id, request, BlockSet::OldBlocks); - return; - } - }, - SyncState::SnapshotData => { - if let RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } = io.snapshot_service().status() { - if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target: "sync", "Snapshot queue full, pausing sync"); - self.state = SyncState::SnapshotWaiting; - return; - } - } - if peer_snapshot_hash.is_some() && peer_snapshot_hash == self.snapshot.snapshot_hash() { - self.request_snapshot_data(io, peer_id); - } - }, - SyncState::SnapshotManifest | //already downloading from other peer - SyncState::Waiting | SyncState::SnapshotWaiting => () - } - } else { - trace!(target: "sync", "Skipping peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); - } - } - - /// Perofrm block download request` - fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId, request: BlockRequest, block_set: BlockSet) { - match request { - BlockRequest::Headers { start, count, skip } => { - self.request_headers_by_hash(io, peer_id, &start, count, skip, false, block_set); - }, - BlockRequest::Bodies { hashes } => { - self.request_bodies(io, peer_id, hashes, block_set); - }, - BlockRequest::Receipts { hashes } => { - self.request_receipts(io, peer_id, hashes, block_set); - }, - } - } - - /// Find some headers or blocks to download for a peer. - fn request_snapshot_data(&mut self, io: &mut SyncIo, peer_id: PeerId) { - self.clear_peer_download(peer_id); - // find chunk data to download - if let Some(hash) = self.snapshot.needed_chunk() { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.asking_snapshot_data = Some(hash.clone()); - } - self.request_snapshot_chunk(io, peer_id, &hash); - } - } - - /// Clear all blocks/headers marked as being downloaded by a peer. - fn clear_peer_download(&mut self, peer_id: PeerId) { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - match peer.asking { - PeerAsking::BlockHeaders => { - if let Some(ref hash) = peer.asking_hash { - self.new_blocks.clear_header_download(hash); - if let Some(ref mut old) = self.old_blocks { - old.clear_header_download(hash); - } - } - }, - PeerAsking::BlockBodies => { - self.new_blocks.clear_body_download(&peer.asking_blocks); - if let Some(ref mut old) = self.old_blocks { - old.clear_body_download(&peer.asking_blocks); - } - }, - PeerAsking::BlockReceipts => { - self.new_blocks.clear_receipt_download(&peer.asking_blocks); - if let Some(ref mut old) = self.old_blocks { - old.clear_receipt_download(&peer.asking_blocks); - } - }, - PeerAsking::SnapshotData => { - if let Some(hash) = peer.asking_snapshot_data { - self.snapshot.clear_chunk_download(&hash); - } - }, - _ => (), - } - } - } - - /// Checks if there are blocks fully downloaded that can be imported into the blockchain and does the import. - fn collect_blocks(&mut self, io: &mut SyncIo, block_set: BlockSet) { - match block_set { - BlockSet::NewBlocks => { - if self.new_blocks.collect_blocks(io, self.state == SyncState::NewBlocks) == Err(DownloaderImportError::Invalid) { - self.restart(io); - } - }, - BlockSet::OldBlocks => { - if self.old_blocks.as_mut().map_or(false, |downloader| { downloader.collect_blocks(io, false) == Err(DownloaderImportError::Invalid) }) { - self.restart(io); - } else if self.old_blocks.as_ref().map_or(false, |downloader| { downloader.is_complete() }) { - trace!(target: "sync", "Background block download is complete"); - self.old_blocks = None; - } - } - } - } - - /// Request headers from a peer by block hash - fn request_headers_by_hash(&mut self, sync: &mut SyncIo, peer_id: PeerId, h: &H256, count: u64, skip: u64, reverse: bool, set: BlockSet) { - trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}, set = {:?}", peer_id, count, h, set); - let mut rlp = RlpStream::new_list(4); - rlp.append(h); - rlp.append(&count); - rlp.append(&skip); - rlp.append(&if reverse {1u32} else {0u32}); - self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out()); - let peer = self.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); - peer.asking_hash = Some(h.clone()); - peer.block_set = Some(set); - } - - /// Request headers from a peer by block number - fn request_fork_header_by_number(&mut self, sync: &mut SyncIo, peer_id: PeerId, n: BlockNumber) { - trace!(target: "sync", "{} <- GetForkHeader: at {}", peer_id, n); - let mut rlp = RlpStream::new_list(4); - rlp.append(&n); - rlp.append(&1u32); - rlp.append(&0u32); - rlp.append(&0u32); - self.send_request(sync, peer_id, PeerAsking::ForkHeader, GET_BLOCK_HEADERS_PACKET, rlp.out()); - } - - /// Request snapshot manifest from a peer. - fn request_snapshot_manifest(&mut self, sync: &mut SyncIo, peer_id: PeerId) { - trace!(target: "sync", "{} <- GetSnapshotManifest", peer_id); - let rlp = RlpStream::new_list(0); - self.send_request(sync, peer_id, PeerAsking::SnapshotManifest, GET_SNAPSHOT_MANIFEST_PACKET, rlp.out()); - } - - /// Request snapshot chunk from a peer. - fn request_snapshot_chunk(&mut self, sync: &mut SyncIo, peer_id: PeerId, chunk: &H256) { - trace!(target: "sync", "{} <- GetSnapshotData {:?}", peer_id, chunk); - let mut rlp = RlpStream::new_list(1); - rlp.append(chunk); - self.send_request(sync, peer_id, PeerAsking::SnapshotData, GET_SNAPSHOT_DATA_PACKET, rlp.out()); - } - - /// Request block bodies from a peer - fn request_bodies(&mut self, sync: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { - let mut rlp = RlpStream::new_list(hashes.len()); - trace!(target: "sync", "{} <- GetBlockBodies: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); - for h in &hashes { - rlp.append(&h.clone()); - } - self.send_request(sync, peer_id, PeerAsking::BlockBodies, GET_BLOCK_BODIES_PACKET, rlp.out()); - let peer = self.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); - peer.asking_blocks = hashes; - peer.block_set = Some(set); - } - - /// Request block receipts from a peer - fn request_receipts(&mut self, sync: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { - let mut rlp = RlpStream::new_list(hashes.len()); - trace!(target: "sync", "{} <- GetBlockReceipts: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); - for h in &hashes { - rlp.append(&h.clone()); - } - self.send_request(sync, peer_id, PeerAsking::BlockReceipts, GET_RECEIPTS_PACKET, rlp.out()); - let peer = self.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); - peer.asking_blocks = hashes; - peer.block_set = Some(set); - } - - /// Reset peer status after request is complete. - fn reset_peer_asking(&mut self, peer_id: PeerId, asking: PeerAsking) -> bool { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - peer.expired = false; - peer.block_set = None; - if peer.asking != asking { - trace!(target:"sync", "Asking {:?} while expected {:?}", peer.asking, asking); - peer.asking = PeerAsking::Nothing; - return false; - } else { - peer.asking = PeerAsking::Nothing; - return true; - } - } - false - } - - /// Generic request sender - fn send_request(&mut self, sync: &mut SyncIo, peer_id: PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) { - if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { - if peer.asking != PeerAsking::Nothing { - warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking); - } - peer.asking = asking; - peer.ask_time = Instant::now(); - let result = if packet_id >= ETH_PACKET_COUNT { - sync.send_protocol(WARP_SYNC_PROTOCOL_ID, peer_id, packet_id, packet) - } else { - sync.send(peer_id, packet_id, packet) - }; - if let Err(e) = result { - debug!(target:"sync", "Error sending request: {:?}", e); - sync.disconnect_peer(peer_id); - } - } - } - - /// Generic packet sender - fn send_packet(&mut self, sync: &mut SyncIo, peer_id: PeerId, packet_id: PacketId, packet: Bytes) { - if let Err(e) = sync.send(peer_id, packet_id, packet) { - debug!(target:"sync", "Error sending packet: {:?}", e); - sync.disconnect_peer(peer_id); - } - } - - /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - // Accept transactions only when fully synced - if !io.is_chain_queue_empty() || (self.state != SyncState::Idle && self.state != SyncState::NewBlocks) { - trace!(target: "sync", "{} Ignoring transactions while syncing", peer_id); - return Ok(()); - } - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "{} Ignoring transactions from unconfirmed/unknown peer", peer_id); - return Ok(()); - } - - let item_count = r.item_count()?; - trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count); - let mut transactions = Vec::with_capacity(item_count); - for i in 0 .. item_count { - let rlp = r.at(i)?; - let tx = rlp.as_raw().to_vec(); - transactions.push(tx); - } - io.chain().queue_transactions(transactions, peer_id); - Ok(()) - } - - /// Send Status message - fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), network::Error> { - let warp_protocol_version = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer); - let warp_protocol = warp_protocol_version != 0; - let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63 }; - trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol); - let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 }); - let chain = io.chain().chain_info(); - packet.append(&(protocol as u32)); - packet.append(&self.network_id); - packet.append(&chain.total_difficulty); - packet.append(&chain.best_block_hash); - packet.append(&chain.genesis_hash); - if warp_protocol { - let manifest = match self.old_blocks.is_some() { - true => None, - false => io.snapshot_service().manifest(), - }; - let block_number = manifest.as_ref().map_or(0, |m| m.block_number); - let manifest_hash = manifest.map_or(H256::new(), |m| keccak(m.into_rlp())); - packet.append(&manifest_hash); - packet.append(&block_number); - } - io.respond(STATUS_PACKET, packet.out()) - } - - /// Respond to GetBlockHeaders request - fn return_block_headers(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - // Packet layout: - // [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ] - let max_headers: usize = r.val_at(1)?; - let skip: usize = r.val_at(2)?; - let reverse: bool = r.val_at(3)?; - let last = io.chain().chain_info().best_block_number; - let number = if r.at(0)?.size() == 32 { - // id is a hash - let hash: H256 = r.val_at(0)?; - trace!(target: "sync", "{} -> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", peer_id, hash, max_headers, skip, reverse); - match io.chain().block_header(BlockId::Hash(hash)) { - Some(hdr) => { - let number = hdr.number().into(); - debug_assert_eq!(hdr.hash(), hash); - - if max_headers == 1 || io.chain().block_hash(BlockId::Number(number)) != Some(hash) { - // Non canonical header or single header requested - // TODO: handle single-step reverse hashchains of non-canon hashes - trace!(target:"sync", "Returning single header: {:?}", hash); - let mut rlp = RlpStream::new_list(1); - rlp.append_raw(&hdr.into_inner(), 1); - return Ok(Some((BLOCK_HEADERS_PACKET, rlp))); - } - number - } - None => return Ok(Some((BLOCK_HEADERS_PACKET, RlpStream::new_list(0)))) //no such header, return nothing - } - } else { - trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, r.val_at::(0)?, max_headers, skip, reverse); - r.val_at(0)? - }; - - let mut number = if reverse { - cmp::min(last, number) - } else { - cmp::max(0, number) - }; - let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers); - let mut count = 0; - let mut data = Bytes::new(); - let inc = (skip + 1) as BlockNumber; - let overlay = io.chain_overlay().read(); - - while number <= last && count < max_count { - if let Some(hdr) = overlay.get(&number) { - trace!(target: "sync", "{}: Returning cached fork header", peer_id); - data.extend_from_slice(hdr); - count += 1; - } else if let Some(hdr) = io.chain().block_header(BlockId::Number(number)) { - data.append(&mut hdr.into_inner()); - count += 1; - } else { - // No required block. - break; - } - if reverse { - if number <= inc || number == 0 { - break; - } - number -= inc; - } - else { - number += inc; - } - } - let mut rlp = RlpStream::new_list(count as usize); - rlp.append_raw(&data, count as usize); - trace!(target: "sync", "{} -> GetBlockHeaders: returned {} entries", peer_id, count); - Ok(Some((BLOCK_HEADERS_PACKET, rlp))) - } - - /// Respond to GetBlockBodies request - fn return_block_bodies(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = r.item_count().unwrap_or(0); - if count == 0 { - debug!(target: "sync", "Empty GetBlockBodies request, ignoring."); - return Ok(None); - } - count = cmp::min(count, MAX_BODIES_TO_SEND); - let mut added = 0usize; - let mut data = Bytes::new(); - for i in 0..count { - if let Some(body) = io.chain().block_body(BlockId::Hash(r.val_at::(i)?)) { - data.append(&mut body.into_inner()); - added += 1; - } - } - let mut rlp = RlpStream::new_list(added); - rlp.append_raw(&data, added); - trace!(target: "sync", "{} -> GetBlockBodies: returned {} entries", peer_id, added); - Ok(Some((BLOCK_BODIES_PACKET, rlp))) - } - - /// Respond to GetNodeData request - fn return_node_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = r.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetNodeData: {} entries", peer_id, count); - if count == 0 { - debug!(target: "sync", "Empty GetNodeData request, ignoring."); - return Ok(None); - } - count = cmp::min(count, MAX_NODE_DATA_TO_SEND); - let mut added = 0usize; - let mut data = Vec::new(); - for i in 0..count { - if let Some(node) = io.chain().state_data(&r.val_at::(i)?) { - data.push(node); - added += 1; - } - } - trace!(target: "sync", "{} -> GetNodeData: return {} entries", peer_id, added); - let mut rlp = RlpStream::new_list(added); - for d in data { - rlp.append(&d); - } - Ok(Some((NODE_DATA_PACKET, rlp))) - } - - fn return_receipts(io: &SyncIo, rlp: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let mut count = rlp.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetReceipts: {} entries", peer_id, count); - if count == 0 { - debug!(target: "sync", "Empty GetReceipts request, ignoring."); - return Ok(None); - } - count = cmp::min(count, MAX_RECEIPTS_HEADERS_TO_SEND); - let mut added_headers = 0usize; - let mut added_receipts = 0usize; - let mut data = Bytes::new(); - for i in 0..count { - if let Some(mut receipts_bytes) = io.chain().block_receipts(&rlp.val_at::(i)?) { - data.append(&mut receipts_bytes); - added_receipts += receipts_bytes.len(); - added_headers += 1; - if added_receipts > MAX_RECEIPTS_TO_SEND { break; } - } - } - let mut rlp_result = RlpStream::new_list(added_headers); - rlp_result.append_raw(&data, added_headers); - Ok(Some((RECEIPTS_PACKET, rlp_result))) - } - - /// Respond to GetSnapshotManifest request - fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let count = r.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); - if count != 0 { - debug!(target: "sync", "Invalid GetSnapshotManifest request, ignoring."); - return Ok(None); - } - let rlp = match io.snapshot_service().manifest() { - Some(manifest) => { - trace!(target: "sync", "{} <- SnapshotManifest", peer_id); - let mut rlp = RlpStream::new_list(1); - rlp.append_raw(&manifest.into_rlp(), 1); - rlp - }, - None => { - trace!(target: "sync", "{}: No manifest to return", peer_id); - RlpStream::new_list(0) - } - }; - Ok(Some((SNAPSHOT_MANIFEST_PACKET, rlp))) - } - - /// Respond to GetSnapshotData request - fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { - let hash: H256 = r.val_at(0)?; - trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); - let rlp = match io.snapshot_service().chunk(hash) { - Some(data) => { - let mut rlp = RlpStream::new_list(1); - trace!(target: "sync", "{} <- SnapshotData", peer_id); - rlp.append(&data); - rlp - }, - None => { - RlpStream::new_list(0) - } - }; - Ok(Some((SNAPSHOT_DATA_PACKET, rlp))) - } - - fn return_rlp(io: &mut SyncIo, rlp: &Rlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> - where FRlp : Fn(&SyncIo, &Rlp, PeerId) -> RlpResponseResult, - FError : FnOnce(network::Error) -> String - { - let response = rlp_func(io, rlp, peer); - match response { - Err(e) => Err(e), - Ok(Some((packet_id, rlp_stream))) => { - io.respond(packet_id, rlp_stream.out()).unwrap_or_else( - |e| debug!(target: "sync", "{:?}", error_func(e))); - Ok(()) - } - _ => Ok(()) - } - } - - /// Dispatch incoming requests and responses - pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { - let rlp = Rlp::new(data); - let result = match packet_id { - GET_BLOCK_BODIES_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_block_bodies, - |e| format!("Error sending block bodies: {:?}", e)), - - GET_BLOCK_HEADERS_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_block_headers, - |e| format!("Error sending block headers: {:?}", e)), - - GET_RECEIPTS_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_receipts, - |e| format!("Error sending receipts: {:?}", e)), - - GET_NODE_DATA_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_node_data, - |e| format!("Error sending nodes: {:?}", e)), - - GET_SNAPSHOT_MANIFEST_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_snapshot_manifest, - |e| format!("Error sending snapshot manifest: {:?}", e)), - - GET_SNAPSHOT_DATA_PACKET => ChainSync::return_rlp(io, &rlp, peer, - ChainSync::return_snapshot_data, - |e| format!("Error sending snapshot data: {:?}", e)), - CONSENSUS_DATA_PACKET => ChainSync::on_consensus_packet(io, peer, &rlp), - _ => { - sync.write().on_packet(io, peer, packet_id, data); - Ok(()) - } - }; - result.unwrap_or_else(|e| { - debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); - }) - } - - pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { - debug!(target: "sync", "{} -> Dispatching packet: {}", peer, packet_id); - - if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) { - debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); - return; - } - - let rlp = Rlp::new(data); - let result = match packet_id { - STATUS_PACKET => self.on_peer_status(io, peer, &rlp), - TRANSACTIONS_PACKET => self.on_peer_transactions(io, peer, &rlp), - BLOCK_HEADERS_PACKET => self.on_peer_block_headers(io, peer, &rlp), - BLOCK_BODIES_PACKET => self.on_peer_block_bodies(io, peer, &rlp), - RECEIPTS_PACKET => self.on_peer_block_receipts(io, peer, &rlp), - NEW_BLOCK_PACKET => self.on_peer_new_block(io, peer, &rlp), - NEW_BLOCK_HASHES_PACKET => self.on_peer_new_hashes(io, peer, &rlp), - SNAPSHOT_MANIFEST_PACKET => self.on_snapshot_manifest(io, peer, &rlp), - SNAPSHOT_DATA_PACKET => self.on_snapshot_data(io, peer, &rlp), - PRIVATE_TRANSACTION_PACKET => self.on_private_transaction(io, peer, &rlp), - SIGNED_PRIVATE_TRANSACTION_PACKET => self.on_signed_private_transaction(io, peer, &rlp), - _ => { - debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id); - Ok(()) - } - }; - result.unwrap_or_else(|e| { - debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); - }) - } - - pub fn maintain_peers(&mut self, io: &mut SyncIo) { - let tick = Instant::now(); - let mut aborting = Vec::new(); - for (peer_id, peer) in &self.peers { - let elapsed = tick - peer.ask_time; - let timeout = match peer.asking { - PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT, - PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT, - PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT, - PeerAsking::Nothing => false, - PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT, - PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT, - PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, - }; - if timeout { - debug!(target:"sync", "Timeout {}", peer_id); - io.disconnect_peer(*peer_id); - aborting.push(*peer_id); - } - } - for p in aborting { - self.on_peer_aborting(io, p); - } - - // Check for handshake timeouts - for (peer, &ask_time) in &self.handshaking_peers { - let elapsed = (tick - ask_time) / 1_000_000_000; - if elapsed > STATUS_TIMEOUT { - trace!(target:"sync", "Status timeout {}", peer); - io.disconnect_peer(*peer); - } - } - } - - fn check_resume(&mut self, io: &mut SyncIo) { - if self.state == SyncState::Waiting && !io.chain().queue_info().is_full() && self.state == SyncState::Waiting { - self.state = SyncState::Blocks; - self.continue_sync(io); - } else if self.state == SyncState::SnapshotWaiting { - match io.snapshot_service().status() { - RestorationStatus::Inactive => { - trace!(target:"sync", "Snapshot restoration is complete"); - self.restart(io); - self.continue_sync(io); - }, - RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { - if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target:"sync", "Resuming snapshot sync"); - self.state = SyncState::SnapshotData; - self.continue_sync(io); - } - }, - RestorationStatus::Failed => { - trace!(target: "sync", "Snapshot restoration aborted"); - self.state = SyncState::WaitingPeers; - self.snapshot.clear(); - self.continue_sync(io); - }, - } - } - } - - /// creates rlp to send for the tree defined by 'from' and 'to' hashes - fn create_new_hashes_rlp(chain: &BlockChainClient, from: &H256, to: &H256) -> Option { - match chain.tree_route(from, to) { - Some(route) => { - let uncles = chain.find_uncles(from).unwrap_or_else(Vec::new); - match route.blocks.len() { - 0 => None, - _ => { - let mut blocks = route.blocks; - blocks.extend(uncles); - let mut rlp_stream = RlpStream::new_list(blocks.len()); - for block_hash in blocks { - let mut hash_rlp = RlpStream::new_list(2); - let number = chain.block_header(BlockId::Hash(block_hash.clone())) - .expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.").number(); - hash_rlp.append(&block_hash); - hash_rlp.append(&number); - rlp_stream.append_raw(hash_rlp.as_raw(), 1); - } - Some(rlp_stream.out()) - } - } - }, - None => None - } - } - - /// creates rlp from block bytes and total difficulty - fn create_block_rlp(bytes: &Bytes, total_difficulty: U256) -> Bytes { - let mut rlp_stream = RlpStream::new_list(2); - rlp_stream.append_raw(bytes, 1); - rlp_stream.append(&total_difficulty); - rlp_stream.out() - } - - /// creates latest block rlp for the given client - fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes { - ChainSync::create_block_rlp( - &chain.block(BlockId::Hash(chain.chain_info().best_block_hash)) - .expect("Best block always exists").into_inner(), - chain.chain_info().total_difficulty - ) - } - - /// creates given hash block rlp for the given client - fn create_new_block_rlp(chain: &BlockChainClient, hash: &H256) -> Bytes { - ChainSync::create_block_rlp( - &chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed").into_inner(), - chain.block_total_difficulty(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed.") - ) - } - - /// returns peer ids that have different blocks than our chain - fn get_lagging_peers(&mut self, chain_info: &BlockChainInfo) -> Vec { - let latest_hash = chain_info.best_block_hash; - self - .peers - .iter_mut() - .filter_map(|(&id, ref mut peer_info)| { - trace!(target: "sync", "Checking peer our best {} their best {}", latest_hash, peer_info.latest_hash); - if peer_info.latest_hash != latest_hash { - Some(id) - } else { - None - } - }) - .collect::>() - } - - fn select_random_peers(peers: &[PeerId]) -> Vec { - // take sqrt(x) peers - let mut peers = peers.to_vec(); - let mut count = (peers.len() as f64).powf(0.5).round() as usize; - count = cmp::min(count, MAX_PEERS_PROPAGATION); - count = cmp::max(count, MIN_PEERS_PROPAGATION); - random::new().shuffle(&mut peers); - peers.truncate(count); - peers - } - - fn get_consensus_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() - } - - fn get_private_transaction_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3 { Some(*id) } else { None }).collect() - } - - /// propagates latest block to a set of peers - fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, blocks: &[H256], peers: &[PeerId]) -> usize { - trace!(target: "sync", "Sending NewBlocks to {:?}", peers); - let mut sent = 0; - for peer_id in peers { - if blocks.is_empty() { - let rlp = ChainSync::create_latest_block_rlp(io.chain()); - self.send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); - } else { - for h in blocks { - let rlp = ChainSync::create_new_block_rlp(io.chain(), h); - self.send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); - } - } - if let Some(ref mut peer) = self.peers.get_mut(peer_id) { - peer.latest_hash = chain_info.best_block_hash.clone(); - } - sent += 1; - } - sent - } - - /// propagates new known hashes to all peers - fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize { - trace!(target: "sync", "Sending NewHashes to {:?}", peers); - let mut sent = 0; - let last_parent = *io.chain().best_block_header().parent_hash(); - for peer_id in peers { - sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) { - Some(rlp) => { - { - if let Some(ref mut peer) = self.peers.get_mut(peer_id) { - peer.latest_hash = chain_info.best_block_hash.clone(); - } - } - self.send_packet(io, *peer_id, NEW_BLOCK_HASHES_PACKET, rlp); - 1 - }, - None => 0 - } - } - sent - } - - /// propagates new transactions to all peers - pub fn propagate_new_transactions(&mut self, io: &mut SyncIo) -> usize { - // Early out if nobody to send to. - if self.peers.is_empty() { - return 0; - } - - let transactions = io.chain().ready_transactions(); - if transactions.is_empty() { - return 0; - } - - let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.iter() - .map(|tx| tx.signed()) - .partition(|tx| !tx.gas_price.is_zero()); - - // usual transactions could be propagated to all peers - let mut affected_peers = HashSet::new(); - if !transactions.is_empty() { - let peers = self.select_peers_for_transactions(|_| true); - affected_peers = self.propagate_transactions_to_peers(io, peers, transactions); - } - - // most of times service_transactions will be empty - // => there's no need to merge packets - if !service_transactions.is_empty() { - let service_transactions_peers = self.select_peers_for_transactions(|peer_id| accepts_service_transaction(&io.peer_info(*peer_id))); - let service_transactions_affected_peers = self.propagate_transactions_to_peers(io, service_transactions_peers, service_transactions); - affected_peers.extend(&service_transactions_affected_peers); - } - - affected_peers.len() - } - - fn select_peers_for_transactions(&self, filter: F) -> Vec - where F: Fn(&PeerId) -> bool { - // sqrt(x)/x scaled to max u32 - let fraction = ((self.peers.len() as f64).powf(-0.5) * (u32::max_value() as f64).round()) as u32; - let small = self.peers.len() < MIN_PEERS_PROPAGATION; - - let mut random = random::new(); - self.peers.keys() - .cloned() - .filter(filter) - .filter(|_| small || random.next_u32() < fraction) - .take(MAX_PEERS_PROPAGATION) - .collect() - } - - fn propagate_transactions_to_peers(&mut self, io: &mut SyncIo, peers: Vec, transactions: Vec<&SignedTransaction>) -> HashSet { - let all_transactions_hashes = transactions.iter() - .map(|tx| tx.hash()) - .collect::>(); - let all_transactions_rlp = { - let mut packet = RlpStream::new_list(transactions.len()); - for tx in &transactions { packet.append(&**tx); } - packet.out() - }; - - // Clear old transactions from stats - self.transactions_stats.retain(&all_transactions_hashes); - - // sqrt(x)/x scaled to max u32 - let block_number = io.chain().chain_info().best_block_number; - - let lucky_peers = { - peers.into_iter() - .filter_map(|peer_id| { - let stats = &mut self.transactions_stats; - let peer_info = self.peers.get_mut(&peer_id) - .expect("peer_id is form peers; peers is result of select_peers_for_transactions; select_peers_for_transactions selects peers from self.peers; qed"); - - // Send all transactions - if peer_info.last_sent_transactions.is_empty() { - // update stats - for hash in &all_transactions_hashes { - let id = io.peer_session_info(peer_id).and_then(|info| info.id); - stats.propagated(hash, id, block_number); - } - peer_info.last_sent_transactions = all_transactions_hashes.clone(); - return Some((peer_id, all_transactions_hashes.len(), all_transactions_rlp.clone())); - } - - // Get hashes of all transactions to send to this peer - let to_send = all_transactions_hashes.difference(&peer_info.last_sent_transactions) - .take(MAX_TRANSACTIONS_TO_PROPAGATE) - .cloned() - .collect::>(); - if to_send.is_empty() { - return None; - } - - // Construct RLP - let (packet, to_send) = { - let mut to_send = to_send; - let mut packet = RlpStream::new(); - packet.begin_unbounded_list(); - let mut pushed = 0; - for tx in &transactions { - let hash = tx.hash(); - if to_send.contains(&hash) { - let mut transaction = RlpStream::new(); - tx.rlp_append(&mut transaction); - let appended = packet.append_raw_checked(&transaction.drain(), 1, MAX_TRANSACTION_PACKET_SIZE); - if !appended { - // Maximal packet size reached just proceed with sending - debug!("Transaction packet size limit reached. Sending incomplete set of {}/{} transactions.", pushed, to_send.len()); - to_send = to_send.into_iter().take(pushed).collect(); - break; - } - pushed += 1; - } - } - packet.complete_unbounded_list(); - (packet, to_send) - }; - - // Update stats - let id = io.peer_session_info(peer_id).and_then(|info| info.id); - for hash in &to_send { - // update stats - stats.propagated(hash, id, block_number); - } - - peer_info.last_sent_transactions = all_transactions_hashes - .intersection(&peer_info.last_sent_transactions) - .chain(&to_send) - .cloned() - .collect(); - Some((peer_id, to_send.len(), packet.out())) - }) - .collect::>() - }; - - // Send RLPs - let mut peers = HashSet::new(); - if lucky_peers.len() > 0 { - let mut max_sent = 0; - let lucky_peers_len = lucky_peers.len(); - for (peer_id, sent, rlp) in lucky_peers { - peers.insert(peer_id); - self.send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp); - trace!(target: "sync", "{:02} <- Transactions ({} entries)", peer_id, sent); - max_sent = cmp::max(max_sent, sent); - } - debug!(target: "sync", "Sent up to {} transactions to {} peers.", max_sent, lucky_peers_len); - } - - peers - } - - fn propagate_latest_blocks(&mut self, io: &mut SyncIo, sealed: &[H256]) { - let chain_info = io.chain().chain_info(); - if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let mut peers = self.get_lagging_peers(&chain_info); - if sealed.is_empty() { - let hashes = self.propagate_new_hashes(&chain_info, io, &peers); - peers = ChainSync::select_random_peers(&peers); - let blocks = self.propagate_blocks(&chain_info, io, sealed, &peers); - if blocks != 0 || hashes != 0 { - trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); - } - } else { - self.propagate_blocks(&chain_info, io, sealed, &peers); - self.propagate_new_hashes(&chain_info, io, &peers); - trace!(target: "sync", "Sent sealed block to all peers"); - }; - } - self.last_sent_block_number = chain_info.best_block_number; - } - - /// Distribute valid proposed blocks to subset of current peers. - fn propagate_proposed_blocks(&mut self, io: &mut SyncIo, proposed: &[Bytes]) { - let peers = self.get_consensus_peers(); - trace!(target: "sync", "Sending proposed blocks to {:?}", peers); - for block in proposed { - let rlp = ChainSync::create_block_rlp( - block, - io.chain().chain_info().total_difficulty - ); - for peer_id in &peers { - self.send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp.clone()); - } - } - } - - /// Maintain other peers. Send out any new blocks and transactions - pub fn maintain_sync(&mut self, io: &mut SyncIo) { - self.maybe_start_snapshot_sync(io); - self.check_resume(io); - } - - /// called when block is imported to chain - propagates the blocks and updates transactions sent to peers - pub fn chain_new_blocks(&mut self, io: &mut SyncIo, _imported: &[H256], invalid: &[H256], enacted: &[H256], _retracted: &[H256], sealed: &[H256], proposed: &[Bytes]) { - let queue_info = io.chain().queue_info(); - let is_syncing = self.status().is_syncing(queue_info); - - if !is_syncing || !sealed.is_empty() || !proposed.is_empty() { - trace!(target: "sync", "Propagating blocks, state={:?}", self.state); - self.propagate_latest_blocks(io, sealed); - self.propagate_proposed_blocks(io, proposed); - } - if !invalid.is_empty() { - trace!(target: "sync", "Bad blocks in the queue, restarting"); - self.restart(io); - } - - if !is_syncing && !enacted.is_empty() && !self.peers.is_empty() { - // Select random peer to re-broadcast transactions to. - let peer = random::new().gen_range(0, self.peers.len()); - trace!(target: "sync", "Re-broadcasting transactions to a random peer."); - self.peers.values_mut().nth(peer).map(|peer_info| - peer_info.last_sent_transactions.clear() - ); - } - } - - /// Called when peer sends us new consensus packet - fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - trace!(target: "sync", "Received consensus packet from {:?}", peer_id); - io.chain().queue_consensus_message(r.as_raw().to_vec()); - Ok(()) - } - - /// Broadcast consensus message to peers. - pub fn propagate_consensus_packet(&mut self, io: &mut SyncIo, packet: Bytes) { - let lucky_peers = ChainSync::select_random_peers(&self.get_consensus_peers()); - trace!(target: "sync", "Sending consensus packet to {:?}", lucky_peers); - for peer_id in lucky_peers { - self.send_packet(io, peer_id, CONSENSUS_DATA_PACKET, packet.clone()); - } - } - - /// Called when peer sends us new private transaction packet - fn on_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); - return Ok(()); - } - - trace!(target: "sync", "Received private transaction packet from {:?}", peer_id); - - if let Err(e) = self.private_tx_handler.import_private_transaction(r.as_raw()) { - trace!(target: "sync", "Ignoring the message, error queueing: {}", e); - } - Ok(()) - } - - /// Broadcast private transaction message to peers. - pub fn propagate_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { - let lucky_peers = ChainSync::select_random_peers(&self.get_private_transaction_peers()); - trace!(target: "sync", "Sending private transaction packet to {:?}", lucky_peers); - for peer_id in lucky_peers { - self.send_packet(io, peer_id, PRIVATE_TRANSACTION_PACKET, packet.clone()); - } - } - - /// Called when peer sends us signed private transaction packet - fn on_signed_private_transaction(&self, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { - if !self.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { - trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); - return Ok(()); - } - - trace!(target: "sync", "Received signed private transaction packet from {:?}", peer_id); - if let Err(e) = self.private_tx_handler.import_signed_private_transaction(r.as_raw()) { - trace!(target: "sync", "Ignoring the message, error queueing: {}", e); - } - Ok(()) - } - - /// Broadcast signed private transaction message to peers. - pub fn propagate_signed_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { - let lucky_peers = ChainSync::select_random_peers(&self.get_private_transaction_peers()); - trace!(target: "sync", "Sending signed private transaction packet to {:?}", lucky_peers); - for peer_id in lucky_peers { - self.send_packet(io, peer_id, SIGNED_PRIVATE_TRANSACTION_PACKET, packet.clone()); - } - } - -} - -/// Checks if peer is able to process service transactions -fn accepts_service_transaction(client_id: &str) -> bool { - // Parity versions starting from this will accept service-transactions - const SERVICE_TRANSACTIONS_VERSION: (u32, u32) = (1u32, 6u32); - // Parity client string prefix - const PARITY_CLIENT_ID_PREFIX: &'static str = "Parity/v"; - - if !client_id.starts_with(PARITY_CLIENT_ID_PREFIX) { - return false; - } - let ver: Vec = client_id[PARITY_CLIENT_ID_PREFIX.len()..].split('.') - .take(2) - .filter_map(|s| s.parse().ok()) - .collect(); - ver.len() == 2 && (ver[0] > SERVICE_TRANSACTIONS_VERSION.0 || (ver[0] == SERVICE_TRANSACTIONS_VERSION.0 && ver[1] >= SERVICE_TRANSACTIONS_VERSION.1)) -} - -#[cfg(test)] -mod tests { - use std::collections::{HashSet, VecDeque}; - use ethkey; - use network::PeerId; - use tests::helpers::{TestIo}; - use tests::snapshot::TestSnapshotService; - use ethereum_types::{H256, U256, Address}; - use parking_lot::RwLock; - use bytes::Bytes; - use rlp::{Rlp, RlpStream}; - use super::*; - use ::SyncConfig; - use super::{PeerInfo, PeerAsking}; - use ethcore::header::*; - use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; - use ethcore::miner::MinerService; - use private_tx::NoopPrivateTxHandler; - - fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { - let mut header = Header::new(); - header.set_gas_limit(0.into()); - header.set_difficulty((order * 100).into()); - header.set_timestamp((order * 10) as u64); - header.set_number(order as u64); - header.set_parent_hash(parent_hash); - header.set_state_root(H256::zero()); - - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); - rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); - rlp.out() - } - - fn get_dummy_blocks(order: u32, parent_hash: H256) -> Bytes { - let mut rlp = RlpStream::new_list(1); - rlp.append_raw(&get_dummy_block(order, parent_hash), 1); - let difficulty: U256 = (100 * order).into(); - rlp.append(&difficulty); - rlp.out() - } - - fn get_dummy_hashes() -> Bytes { - let mut rlp = RlpStream::new_list(5); - for _ in 0..5 { - let mut hash_d_rlp = RlpStream::new_list(2); - let hash: H256 = H256::from(0u64); - let diff: U256 = U256::from(1u64); - hash_d_rlp.append(&hash); - hash_d_rlp.append(&diff); - - rlp.append_raw(&hash_d_rlp.out(), 1); - } - - rlp.out() - } - - fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo { - BlockQueueInfo { - unverified_queue_size: unverified, - verified_queue_size: verified, - verifying_queue_size: 0, - max_queue_size: 1000, - max_mem_use: 1000, - mem_used: 500 - } - } - - fn sync_status(state: SyncState) -> SyncStatus { - SyncStatus { - state: state, - protocol_version: 0, - network_id: 0, - start_block_number: 0, - last_imported_block_number: None, - highest_block_number: None, - blocks_total: 0, - blocks_received: 0, - num_peers: 0, - num_active_peers: 0, - mem_used: 0, - num_snapshot_chunks: 0, - snapshot_chunks_done: 0, - last_imported_old_block_number: None, - } - } - - #[test] - fn is_still_verifying() { - assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(2, 1))); - assert!(sync_status(SyncState::Idle).is_syncing(queue_info(2, 2))); - } - - #[test] - fn is_synced_state() { - assert!(sync_status(SyncState::Blocks).is_syncing(queue_info(0, 0))); - assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(0, 0))); - } - - #[test] - fn return_receipts_empty() { - let mut client = TestBlockChainClient::new(); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let io = TestIo::new(&mut client, &ss, &queue, None); - - let result = ChainSync::return_receipts(&io, &Rlp::new(&[0xc0]), 0); - - assert!(result.is_ok()); - } - - #[test] - fn return_receipts() { - let mut client = TestBlockChainClient::new(); - let queue = RwLock::new(VecDeque::new()); - let sync = dummy_sync_with_peer(H256::new(), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let mut receipt_list = RlpStream::new_list(4); - receipt_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); - receipt_list.append(&H256::from("ff00000000000000000000000000000000000000000000000000000000000000")); - receipt_list.append(&H256::from("fff0000000000000000000000000000000000000000000000000000000000000")); - receipt_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); - - let receipts_request = receipt_list.out(); - // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_receipts(&io, &Rlp::new(&receipts_request.clone()), 0); - - assert!(result.is_ok()); - let rlp_result = result.unwrap(); - assert!(rlp_result.is_some()); - - // the length of two rlp-encoded receipts - assert_eq!(603, rlp_result.unwrap().1.out().len()); - - io.sender = Some(2usize); - ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, super::GET_RECEIPTS_PACKET, &receipts_request); - assert_eq!(1, io.packets.len()); - } - - #[test] - fn return_block_headers() { - use ethcore::views::HeaderView; - fn make_hash_req(h: &H256, count: usize, skip: usize, reverse: bool) -> Bytes { - let mut rlp = RlpStream::new_list(4); - rlp.append(h); - rlp.append(&count); - rlp.append(&skip); - rlp.append(&if reverse {1u32} else {0u32}); - rlp.out() - } - - fn make_num_req(n: usize, count: usize, skip: usize, reverse: bool) -> Bytes { - let mut rlp = RlpStream::new_list(4); - rlp.append(&n); - rlp.append(&count); - rlp.append(&skip); - rlp.append(&if reverse {1u32} else {0u32}); - rlp.out() - } - fn to_header_vec(rlp: ::chain::RlpResponseResult) -> Vec { - Rlp::new(&rlp.unwrap().unwrap().1.out()).iter().map(|r| r.as_raw().to_vec()).collect() - } - - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Nothing); - let blocks: Vec<_> = (0 .. 100) - .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect(); - let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); - let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); - - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let io = TestIo::new(&mut client, &ss, &queue, None); - - let unknown: H256 = H256::new(); - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); - assert!(to_header_vec(result).is_empty()); - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); - assert!(to_header_vec(result).is_empty()); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[2].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); - - let result = ChainSync::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0); - assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); - } - - #[test] - fn return_nodes() { - let mut client = TestBlockChainClient::new(); - let queue = RwLock::new(VecDeque::new()); - let sync = dummy_sync_with_peer(H256::new(), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let mut node_list = RlpStream::new_list(3); - node_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); - node_list.append(&H256::from("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa")); - node_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); - - let node_request = node_list.out(); - // it returns rlp ONLY for hashes started with "f" - let result = ChainSync::return_node_data(&io, &Rlp::new(&node_request.clone()), 0); - - assert!(result.is_ok()); - let rlp_result = result.unwrap(); - assert!(rlp_result.is_some()); - - // the length of one rlp-encoded hashe - let rlp = rlp_result.unwrap().1.out(); - let rlp = Rlp::new(&rlp); - assert_eq!(Ok(1), rlp.item_count()); - - io.sender = Some(2usize); - - ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, super::GET_NODE_DATA_PACKET, &node_request); - assert_eq!(1, io.packets.len()); - } - - fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync { - let mut sync = ChainSync::new(SyncConfig::default(), client, Arc::new(NoopPrivateTxHandler)); - insert_dummy_peer(&mut sync, 0, peer_latest_hash); - sync - } - - fn insert_dummy_peer(sync: &mut ChainSync, peer_id: PeerId, peer_latest_hash: H256) { - sync.peers.insert(peer_id, - PeerInfo { - protocol_version: 0, - genesis: H256::zero(), - network_id: 0, - latest_hash: peer_latest_hash, - difficulty: None, - asking: PeerAsking::Nothing, - asking_blocks: Vec::new(), - asking_hash: None, - ask_time: Instant::now(), - last_sent_transactions: HashSet::new(), - expired: false, - confirmation: super::ForkConfirmation::Confirmed, - snapshot_number: None, - snapshot_hash: None, - asking_snapshot_data: None, - block_set: None, - }); - - } - - #[test] - fn finds_lagging_peers() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10), &client); - let chain_info = client.chain_info(); - - let lagging_peers = sync.get_lagging_peers(&chain_info); - - assert_eq!(1, lagging_peers.len()); - } - - #[test] - fn calculates_tree_for_lagging_peer() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(15, EachBlockWith::Uncle); - - let start = client.block_hash_delta_minus(4); - let end = client.block_hash_delta_minus(2); - - // wrong way end -> start, should be None - let rlp = ChainSync::create_new_hashes_rlp(&client, &end, &start); - assert!(rlp.is_none()); - - let rlp = ChainSync::create_new_hashes_rlp(&client, &start, &end).unwrap(); - // size of three rlp encoded hash-difficulty - assert_eq!(107, rlp.len()); - } - - #[test] - fn sends_new_hashes_to_lagging_peer() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let peers = sync.get_lagging_peers(&chain_info); - let peer_count = sync.propagate_new_hashes(&chain_info, &mut io, &peers); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated - assert_eq!(1, peer_count); - // NEW_BLOCK_HASHES_PACKET - assert_eq!(0x01, io.packets[0].packet_id); - } - - #[test] - fn sends_latest_block_to_lagging_peer() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peers = sync.get_lagging_peers(&chain_info); - let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[], &peers); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated - assert_eq!(1, peer_count); - // NEW_BLOCK_PACKET - assert_eq!(0x07, io.packets[0].packet_id); - } - - #[test] - fn sends_sealed_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let hash = client.block_hash(BlockId::Number(99)).unwrap(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peers = sync.get_lagging_peers(&chain_info); - let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[hash.clone()], &peers); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated - assert_eq!(1, peer_count); - // NEW_BLOCK_PACKET - assert_eq!(0x07, io.packets[0].packet_id); - } - - #[test] - fn sends_proposed_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(2, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let block = client.block(BlockId::Latest).unwrap().into_inner(); - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - sync.peers.insert(0, - PeerInfo { - // Messaging protocol - protocol_version: 2, - genesis: H256::zero(), - network_id: 0, - latest_hash: client.block_hash_delta_minus(1), - difficulty: None, - asking: PeerAsking::Nothing, - asking_blocks: Vec::new(), - asking_hash: None, - ask_time: Instant::now(), - last_sent_transactions: HashSet::new(), - expired: false, - confirmation: super::ForkConfirmation::Confirmed, - snapshot_number: None, - snapshot_hash: None, - asking_snapshot_data: None, - block_set: None, - }); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - sync.propagate_proposed_blocks(&mut io, &[block]); - - // 1 message should be sent - assert_eq!(1, io.packets.len()); - // NEW_BLOCK_PACKET - assert_eq!(0x07, io.packets[0].packet_id); - } - - #[test] - fn propagates_transactions() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - // Try to propagate same transactions for the second time - let peer_count2 = sync.propagate_new_transactions(&mut io); - // Even after new block transactions should not be propagated twice - sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); - // Try to propagate same transactions for the third time - let peer_count3 = sync.propagate_new_transactions(&mut io); - - // 1 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should be updated but only once - assert_eq!(1, peer_count); - assert_eq!(0, peer_count2); - assert_eq!(0, peer_count3); - // TRANSACTIONS_PACKET - assert_eq!(0x02, io.packets[0].packet_id); - } - - #[test] - fn does_not_propagate_new_transactions_after_new_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - io.chain.insert_transaction_to_queue(); - // New block import should not trigger propagation. - // (we only propagate on timeout) - sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); - - // 2 message should be send - assert_eq!(1, io.packets.len()); - // 1 peer should receive the message - assert_eq!(1, peer_count); - // TRANSACTIONS_PACKET - assert_eq!(0x02, io.packets[0].packet_id); - } - - #[test] - fn does_not_fail_for_no_peers() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - // Sync with no peers - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); - // Try to propagate same transactions for the second time - let peer_count2 = sync.propagate_new_transactions(&mut io); - - assert_eq!(0, io.packets.len()); - assert_eq!(0, peer_count); - assert_eq!(0, peer_count2); - } - - #[test] - fn propagates_transactions_without_alternating() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - // should sent some - { - let mut io = TestIo::new(&mut client, &ss, &queue, None); - let peer_count = sync.propagate_new_transactions(&mut io); - assert_eq!(1, io.packets.len()); - assert_eq!(1, peer_count); - } - // Insert some more - client.insert_transaction_to_queue(); - let (peer_count2, peer_count3) = { - let mut io = TestIo::new(&mut client, &ss, &queue, None); - // Propagate new transactions - let peer_count2 = sync.propagate_new_transactions(&mut io); - // And now the peer should have all transactions - let peer_count3 = sync.propagate_new_transactions(&mut io); - (peer_count2, peer_count3) - }; - - // 2 message should be send (in total) - assert_eq!(2, queue.read().len()); - // 1 peer should be updated but only once after inserting new transaction - assert_eq!(1, peer_count2); - assert_eq!(0, peer_count3); - // TRANSACTIONS_PACKET - assert_eq!(0x02, queue.read()[0].packet_id); - assert_eq!(0x02, queue.read()[1].packet_id); - } - - #[test] - fn should_maintain_transations_propagation_stats() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - client.insert_transaction_to_queue(); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - sync.propagate_new_transactions(&mut io); - - let stats = sync.transactions_stats(); - assert_eq!(stats.len(), 1, "Should maintain stats for single transaction.") - } - - #[test] - fn should_propagate_service_transaction_to_selected_peers_only() { - let mut client = TestBlockChainClient::new(); - client.insert_transaction_with_gas_price_to_queue(U256::zero()); - let block_hash = client.block_hash_delta_minus(1); - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - // when peer#1 is Geth - insert_dummy_peer(&mut sync, 1, block_hash); - io.peers_info.insert(1, "Geth".to_owned()); - // and peer#2 is Parity, accepting service transactions - insert_dummy_peer(&mut sync, 2, block_hash); - io.peers_info.insert(2, "Parity/v1.6".to_owned()); - // and peer#3 is Parity, discarding service transactions - insert_dummy_peer(&mut sync, 3, block_hash); - io.peers_info.insert(3, "Parity/v1.5".to_owned()); - // and peer#4 is Parity, accepting service transactions - insert_dummy_peer(&mut sync, 4, block_hash); - io.peers_info.insert(4, "Parity/v1.7.3-ABCDEFGH".to_owned()); - - // and new service transaction is propagated to peers - sync.propagate_new_transactions(&mut io); - - // peer#2 && peer#4 are receiving service transaction - assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 2)); // TRANSACTIONS_PACKET - assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 4)); // TRANSACTIONS_PACKET - assert_eq!(io.packets.len(), 2); - } - - #[test] - fn should_propagate_service_transaction_is_sent_as_separate_message() { - let mut client = TestBlockChainClient::new(); - let tx1_hash = client.insert_transaction_to_queue(); - let tx2_hash = client.insert_transaction_with_gas_price_to_queue(U256::zero()); - let block_hash = client.block_hash_delta_minus(1); - let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - // when peer#1 is Parity, accepting service transactions - insert_dummy_peer(&mut sync, 1, block_hash); - io.peers_info.insert(1, "Parity/v1.6".to_owned()); - - // and service + non-service transactions are propagated to peers - sync.propagate_new_transactions(&mut io); - - // two separate packets for peer are queued: - // 1) with non-service-transaction - // 2) with service transaction - let sent_transactions: Vec = io.packets.iter() - .filter_map(|p| { - if p.packet_id != 0x02 || p.recipient != 1 { // TRANSACTIONS_PACKET - return None; - } - - let rlp = Rlp::new(&*p.data); - let item_count = rlp.item_count().unwrap_or(0); - if item_count != 1 { - return None; - } - - rlp.at(0).ok().and_then(|r| r.as_val().ok()) - }) - .collect(); - assert_eq!(sent_transactions.len(), 2); - assert!(sent_transactions.iter().any(|tx| tx.hash() == tx1_hash)); - assert!(sent_transactions.iter().any(|tx| tx.hash() == tx2_hash)); - } - - #[test] - fn handles_peer_new_block_malformed() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - - let block_data = get_dummy_block(11, client.chain_info().best_block_hash); - - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - //sync.have_common_block = true; - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let block = Rlp::new(&block_data); - - let result = sync.on_peer_new_block(&mut io, 0, &block); - - assert!(result.is_err()); - } - - #[test] - fn handles_peer_new_block() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - - let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); - - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let block = Rlp::new(&block_data); - - let result = sync.on_peer_new_block(&mut io, 0, &block); - - assert!(result.is_ok()); - } - - #[test] - fn handles_peer_new_block_empty() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let empty_data = vec![]; - let block = Rlp::new(&empty_data); - - let result = sync.on_peer_new_block(&mut io, 0, &block); - - assert!(result.is_err()); - } - - #[test] - fn handles_peer_new_hashes() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let hashes_data = get_dummy_hashes(); - let hashes_rlp = Rlp::new(&hashes_data); - - let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); - - assert!(result.is_ok()); - } - - #[test] - fn handles_peer_new_hashes_empty() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let empty_hashes_data = vec![]; - let hashes_rlp = Rlp::new(&empty_hashes_data); - - let result = sync.on_peer_new_hashes(&mut io, 0, &hashes_rlp); - - assert!(result.is_ok()); - } - - // idea is that what we produce when propagading latest hashes should be accepted in - // on_peer_new_hashes in our code as well - #[test] - fn hashes_rlp_mutually_acceptable() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let peers = sync.get_lagging_peers(&chain_info); - sync.propagate_new_hashes(&chain_info, &mut io, &peers); - - let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_hashes(&mut io, 0, &Rlp::new(data)); - assert!(result.is_ok()); - } - - // idea is that what we produce when propagading latest block should be accepted in - // on_peer_new_block in our code as well - #[test] - fn block_rlp_mutually_acceptable() { - let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); - let queue = RwLock::new(VecDeque::new()); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - let chain_info = client.chain_info(); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - let peers = sync.get_lagging_peers(&chain_info); - sync.propagate_blocks(&chain_info, &mut io, &[], &peers); - - let data = &io.packets[0].data.clone(); - let result = sync.on_peer_new_block(&mut io, 0, &Rlp::new(data)); - assert!(result.is_ok()); - } - - #[test] - fn should_add_transactions_to_queue() { - fn sender(tx: &UnverifiedTransaction) -> Address { - ethkey::public_to_address(&tx.recover_public().unwrap()) - } - - // given - let mut client = TestBlockChainClient::new(); - client.add_blocks(98, EachBlockWith::Uncle); - client.add_blocks(1, EachBlockWith::UncleAndTransaction); - client.add_blocks(1, EachBlockWith::Transaction); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - - let good_blocks = vec![client.block_hash_delta_minus(2)]; - let retracted_blocks = vec![client.block_hash_delta_minus(1)]; - - // Add some balance to clients and reset nonces - for h in &[good_blocks[0], retracted_blocks[0]] { - let block = client.block(BlockId::Hash(*h)).unwrap(); - let sender = sender(&block.transactions()[0]);; - client.set_balance(sender, U256::from(10_000_000_000_000_000_000u64)); - client.set_nonce(sender, U256::from(0)); - } - - - // when - { - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); - } - // We need to update nonce status (because we say that the block has been imported) - for h in &[good_blocks[0]] { - let block = client.block(BlockId::Hash(*h)).unwrap(); - client.set_nonce(sender(&block.transactions()[0]), U256::from(1)); - } - { - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&client, &ss, &queue, None); - io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks, false); - sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); - } - - // then - assert_eq!(client.miner.ready_transactions(&client).len(), 1); - } - - #[test] - fn should_not_add_transactions_to_queue_if_not_synced() { - // given - let mut client = TestBlockChainClient::new(); - client.add_blocks(98, EachBlockWith::Uncle); - client.add_blocks(1, EachBlockWith::UncleAndTransaction); - client.add_blocks(1, EachBlockWith::Transaction); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); - - let good_blocks = vec![client.block_hash_delta_minus(2)]; - let retracted_blocks = vec![client.block_hash_delta_minus(1)]; - - let queue = RwLock::new(VecDeque::new()); - let ss = TestSnapshotService::new(); - let mut io = TestIo::new(&mut client, &ss, &queue, None); - - // when - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.queue_status().status.transaction_count, 0); - sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); - - // then - let status = io.chain.miner.queue_status(); - assert_eq!(status.status.transaction_count, 0); - } -} diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs new file mode 100644 index 0000000000..966b7ce20a --- /dev/null +++ b/ethcore/sync/src/chain/handler.rs @@ -0,0 +1,828 @@ +// Copyright 2015-2018 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 . + +use api::WARP_SYNC_PROTOCOL_ID; +use block_sync::{BlockDownloaderImportError as DownloaderImportError, DownloadAction}; +use bytes::Bytes; +use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind}; +use ethcore::error::*; +use ethcore::header::{BlockNumber, Header as BlockHeader}; +use ethcore::snapshot::{ManifestData, RestorationStatus}; +use ethereum_types::{H256, U256}; +use hash::keccak; +use network::PeerId; +use rlp::Rlp; +use snapshot::ChunkType; +use std::cmp; +use std::collections::HashSet; +use std::time::Instant; +use sync_io::SyncIo; + +use super::{ + BlockSet, + ChainSync, + ForkConfirmation, + PacketDecodeError, + PeerAsking, + PeerInfo, + SyncRequester, + SyncState, + ETH_PROTOCOL_VERSION_62, + ETH_PROTOCOL_VERSION_63, + MAX_NEW_BLOCK_AGE, + MAX_NEW_HASHES, + PAR_PROTOCOL_VERSION_1, + PAR_PROTOCOL_VERSION_2, + PAR_PROTOCOL_VERSION_3, + BLOCK_BODIES_PACKET, + BLOCK_HEADERS_PACKET, + NEW_BLOCK_HASHES_PACKET, + NEW_BLOCK_PACKET, + PRIVATE_TRANSACTION_PACKET, + RECEIPTS_PACKET, + SIGNED_PRIVATE_TRANSACTION_PACKET, + SNAPSHOT_DATA_PACKET, + SNAPSHOT_MANIFEST_PACKET, + STATUS_PACKET, + TRANSACTIONS_PACKET, +}; + +/// The Chain Sync Handler: handles responses from peers +pub struct SyncHandler; + +impl SyncHandler { + /// Handle incoming packet from peer + pub fn on_packet(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + if packet_id != STATUS_PACKET && !sync.peers.contains_key(&peer) { + debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer)); + return; + } + let rlp = Rlp::new(data); + let result = match packet_id { + STATUS_PACKET => SyncHandler::on_peer_status(sync, io, peer, &rlp), + TRANSACTIONS_PACKET => SyncHandler::on_peer_transactions(sync, io, peer, &rlp), + BLOCK_HEADERS_PACKET => SyncHandler::on_peer_block_headers(sync, io, peer, &rlp), + BLOCK_BODIES_PACKET => SyncHandler::on_peer_block_bodies(sync, io, peer, &rlp), + RECEIPTS_PACKET => SyncHandler::on_peer_block_receipts(sync, io, peer, &rlp), + NEW_BLOCK_PACKET => SyncHandler::on_peer_new_block(sync, io, peer, &rlp), + NEW_BLOCK_HASHES_PACKET => SyncHandler::on_peer_new_hashes(sync, io, peer, &rlp), + SNAPSHOT_MANIFEST_PACKET => SyncHandler::on_snapshot_manifest(sync, io, peer, &rlp), + SNAPSHOT_DATA_PACKET => SyncHandler::on_snapshot_data(sync, io, peer, &rlp), + PRIVATE_TRANSACTION_PACKET => SyncHandler::on_private_transaction(sync, io, peer, &rlp), + SIGNED_PRIVATE_TRANSACTION_PACKET => SyncHandler::on_signed_private_transaction(sync, io, peer, &rlp), + _ => { + debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id); + Ok(()) + } + }; + result.unwrap_or_else(|e| { + debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); + }) + } + + /// Called when peer sends us new consensus packet + pub fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + trace!(target: "sync", "Received consensus packet from {:?}", peer_id); + io.chain().queue_consensus_message(r.as_raw().to_vec()); + Ok(()) + } + + /// Called by peer when it is disconnecting + pub fn on_peer_aborting(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId) { + trace!(target: "sync", "== Disconnecting {}: {}", peer, io.peer_info(peer)); + sync.handshaking_peers.remove(&peer); + if sync.peers.contains_key(&peer) { + debug!(target: "sync", "Disconnected {}", peer); + sync.clear_peer_download(peer); + sync.peers.remove(&peer); + sync.active_peers.remove(&peer); + sync.continue_sync(io); + } + } + + /// Called when a new peer is connected + pub fn on_peer_connected(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId) { + trace!(target: "sync", "== Connected {}: {}", peer, io.peer_info(peer)); + if let Err(e) = sync.send_status(io, peer) { + debug!(target:"sync", "Error sending status request: {:?}", e); + io.disconnect_peer(peer); + } else { + sync.handshaking_peers.insert(peer, Instant::now()); + } + } + + /// Called by peer once it has new block bodies + pub fn on_peer_new_block(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring new block from unconfirmed peer {}", peer_id); + return Ok(()); + } + let difficulty: U256 = r.val_at(1)?; + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + if peer.difficulty.map_or(true, |pd| difficulty > pd) { + peer.difficulty = Some(difficulty); + } + } + let block_rlp = r.at(0)?; + let header_rlp = block_rlp.at(0)?; + let h = keccak(&header_rlp.as_raw()); + trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); + let header: BlockHeader = header_rlp.as_val()?; + if header.number() > sync.highest_block.unwrap_or(0) { + sync.highest_block = Some(header.number()); + } + let mut unknown = false; + { + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + peer.latest_hash = header.hash(); + } + } + let last_imported_number = sync.new_blocks.last_imported_block_number(); + if last_imported_number > header.number() && last_imported_number - header.number() > MAX_NEW_BLOCK_AGE { + trace!(target: "sync", "Ignored ancient new block {:?}", h); + io.disable_peer(peer_id); + return Ok(()); + } + match io.chain().import_block(block_rlp.as_raw().to_vec()) { + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { + trace!(target: "sync", "New block already in chain {:?}", h); + }, + Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { + trace!(target: "sync", "New block already queued {:?}", h); + }, + Ok(_) => { + // abort current download of the same block + sync.complete_sync(io); + sync.new_blocks.mark_as_known(&header.hash(), header.number()); + trace!(target: "sync", "New block queued {:?} ({})", h, header.number()); + }, + Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => { + unknown = true; + trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); + }, + Err(e) => { + debug!(target: "sync", "Bad new block {:?} : {:?}", h, e); + io.disable_peer(peer_id); + } + }; + if unknown { + if sync.state != SyncState::Idle { + trace!(target: "sync", "NewBlock ignored while seeking"); + } else { + trace!(target: "sync", "New unknown block {:?}", h); + //TODO: handle too many unknown blocks + sync.sync_peer(io, peer_id, true); + } + } + sync.continue_sync(io); + Ok(()) + } + + /// Handles `NewHashes` packet. Initiates headers download for any unknown hashes. + pub fn on_peer_new_hashes(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring new hashes from unconfirmed peer {}", peer_id); + return Ok(()); + } + let hashes: Vec<_> = r.iter().take(MAX_NEW_HASHES).map(|item| (item.val_at::(0), item.val_at::(1))).collect(); + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + // Peer has new blocks with unknown difficulty + peer.difficulty = None; + if let Some(&(Ok(ref h), _)) = hashes.last() { + peer.latest_hash = h.clone(); + } + } + if sync.state != SyncState::Idle { + trace!(target: "sync", "Ignoring new hashes since we're already downloading."); + let max = r.iter().take(MAX_NEW_HASHES).map(|item| item.val_at::(1).unwrap_or(0)).fold(0u64, cmp::max); + if max > sync.highest_block.unwrap_or(0) { + sync.highest_block = Some(max); + } + sync.continue_sync(io); + return Ok(()); + } + trace!(target: "sync", "{} -> NewHashes ({} entries)", peer_id, r.item_count()?); + let mut max_height: BlockNumber = 0; + let mut new_hashes = Vec::new(); + let last_imported_number = sync.new_blocks.last_imported_block_number(); + for (rh, rn) in hashes { + let hash = rh?; + let number = rn?; + if number > sync.highest_block.unwrap_or(0) { + sync.highest_block = Some(number); + } + if sync.new_blocks.is_downloading(&hash) { + continue; + } + if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE { + trace!(target: "sync", "Ignored ancient new block hash {:?}", hash); + io.disable_peer(peer_id); + continue; + } + match io.chain().block_status(BlockId::Hash(hash.clone())) { + BlockStatus::InChain => { + trace!(target: "sync", "New block hash already in chain {:?}", hash); + }, + BlockStatus::Queued => { + trace!(target: "sync", "New hash block already queued {:?}", hash); + }, + BlockStatus::Unknown | BlockStatus::Pending => { + new_hashes.push(hash.clone()); + if number > max_height { + trace!(target: "sync", "New unknown block hash {:?}", hash); + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + peer.latest_hash = hash.clone(); + } + max_height = number; + } + }, + BlockStatus::Bad => { + debug!(target: "sync", "Bad new block hash {:?}", hash); + io.disable_peer(peer_id); + return Ok(()); + } + } + }; + if max_height != 0 { + trace!(target: "sync", "Downloading blocks for new hashes"); + sync.new_blocks.reset_to(new_hashes); + sync.state = SyncState::NewBlocks; + sync.sync_peer(io, peer_id, true); + } + sync.continue_sync(io); + Ok(()) + } + + /// Called by peer once it has new block bodies + fn on_peer_block_bodies(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + sync.clear_peer_download(peer_id); + let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { + trace!(target: "sync", "{}: Ignored unexpected bodies", peer_id); + sync.continue_sync(io); + return Ok(()); + } + let item_count = r.item_count()?; + trace!(target: "sync", "{} -> BlockBodies ({} entries), set = {:?}", peer_id, item_count, block_set); + if item_count == 0 { + sync.deactivate_peer(io, peer_id); + } + else if sync.state == SyncState::Waiting { + trace!(target: "sync", "Ignored block bodies while waiting"); + } + else + { + let result = { + let downloader = match block_set { + BlockSet::NewBlocks => &mut sync.new_blocks, + BlockSet::OldBlocks => match sync.old_blocks { + None => { + trace!(target: "sync", "Ignored block headers while block download is inactive"); + sync.continue_sync(io); + return Ok(()); + }, + Some(ref mut blocks) => blocks, + } + }; + downloader.import_bodies(io, r) + }; + + match result { + Err(DownloaderImportError::Invalid) => { + io.disable_peer(peer_id); + sync.deactivate_peer(io, peer_id); + sync.continue_sync(io); + return Ok(()); + }, + Err(DownloaderImportError::Useless) => { + sync.deactivate_peer(io, peer_id); + }, + Ok(()) => (), + } + + sync.collect_blocks(io, block_set); + sync.sync_peer(io, peer_id, false); + } + sync.continue_sync(io); + Ok(()) + } + + fn on_peer_confirmed(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + sync.sync_peer(io, peer_id, false); + } + + fn on_peer_fork_header(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + { + let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); + peer.asking = PeerAsking::Nothing; + let item_count = r.item_count()?; + let (fork_number, fork_hash) = sync.fork_block.expect("ForkHeader request is sent only fork block is Some; qed").clone(); + + if item_count == 0 || item_count != 1 { + trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id); + io.disable_peer(peer_id); + return Ok(()); + } + + let header = r.at(0)?.as_raw(); + if keccak(&header) != fork_hash { + trace!(target: "sync", "{}: Fork mismatch", peer_id); + io.disable_peer(peer_id); + return Ok(()); + } + + trace!(target: "sync", "{}: Confirmed peer", peer_id); + peer.confirmation = ForkConfirmation::Confirmed; + if !io.chain_overlay().read().contains_key(&fork_number) { + io.chain_overlay().write().insert(fork_number, header.to_vec()); + } + } + SyncHandler::on_peer_confirmed(sync, io, peer_id); + return Ok(()); + } + + /// Called by peer once it has new block headers during sync + fn on_peer_block_headers(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + let is_fork_header_request = match sync.peers.get(&peer_id) { + Some(peer) if peer.asking == PeerAsking::ForkHeader => true, + _ => false, + }; + + if is_fork_header_request { + return SyncHandler::on_peer_fork_header(sync, io, peer_id, r); + } + + sync.clear_peer_download(peer_id); + let expected_hash = sync.peers.get(&peer_id).and_then(|p| p.asking_hash); + let allowed = sync.peers.get(&peer_id).map(|p| p.is_allowed()).unwrap_or(false); + let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockHeaders) || expected_hash.is_none() || !allowed { + trace!(target: "sync", "{}: Ignored unexpected headers, expected_hash = {:?}", peer_id, expected_hash); + sync.continue_sync(io); + return Ok(()); + } + let item_count = r.item_count()?; + trace!(target: "sync", "{} -> BlockHeaders ({} entries), state = {:?}, set = {:?}", peer_id, item_count, sync.state, block_set); + if (sync.state == SyncState::Idle || sync.state == SyncState::WaitingPeers) && sync.old_blocks.is_none() { + trace!(target: "sync", "Ignored unexpected block headers"); + sync.continue_sync(io); + return Ok(()); + } + if sync.state == SyncState::Waiting { + trace!(target: "sync", "Ignored block headers while waiting"); + sync.continue_sync(io); + return Ok(()); + } + + let result = { + let downloader = match block_set { + BlockSet::NewBlocks => &mut sync.new_blocks, + BlockSet::OldBlocks => { + match sync.old_blocks { + None => { + trace!(target: "sync", "Ignored block headers while block download is inactive"); + sync.continue_sync(io); + return Ok(()); + }, + Some(ref mut blocks) => blocks, + } + } + }; + downloader.import_headers(io, r, expected_hash) + }; + + match result { + Err(DownloaderImportError::Useless) => { + sync.deactivate_peer(io, peer_id); + }, + Err(DownloaderImportError::Invalid) => { + io.disable_peer(peer_id); + sync.deactivate_peer(io, peer_id); + sync.continue_sync(io); + return Ok(()); + }, + Ok(DownloadAction::Reset) => { + // mark all outstanding requests as expired + trace!("Resetting downloads for {:?}", block_set); + for (_, ref mut p) in sync.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { + p.reset_asking(); + } + + } + Ok(DownloadAction::None) => {}, + } + + sync.collect_blocks(io, block_set); + // give a task to the same peer first if received valuable headers. + sync.sync_peer(io, peer_id, false); + // give tasks to other peers + sync.continue_sync(io); + Ok(()) + } + + /// Called by peer once it has new block receipts + fn on_peer_block_receipts(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + sync.clear_peer_download(peer_id); + let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { + trace!(target: "sync", "{}: Ignored unexpected receipts", peer_id); + sync.continue_sync(io); + return Ok(()); + } + let item_count = r.item_count()?; + trace!(target: "sync", "{} -> BlockReceipts ({} entries)", peer_id, item_count); + if item_count == 0 { + sync.deactivate_peer(io, peer_id); + } + else if sync.state == SyncState::Waiting { + trace!(target: "sync", "Ignored block receipts while waiting"); + } + else + { + let result = { + let downloader = match block_set { + BlockSet::NewBlocks => &mut sync.new_blocks, + BlockSet::OldBlocks => match sync.old_blocks { + None => { + trace!(target: "sync", "Ignored block headers while block download is inactive"); + sync.continue_sync(io); + return Ok(()); + }, + Some(ref mut blocks) => blocks, + } + }; + downloader.import_receipts(io, r) + }; + + match result { + Err(DownloaderImportError::Invalid) => { + io.disable_peer(peer_id); + sync.deactivate_peer(io, peer_id); + sync.continue_sync(io); + return Ok(()); + }, + Err(DownloaderImportError::Useless) => { + sync.deactivate_peer(io, peer_id); + }, + Ok(()) => (), + } + + sync.collect_blocks(io, block_set); + sync.sync_peer(io, peer_id, false); + } + sync.continue_sync(io); + Ok(()) + } + + /// Called when snapshot manifest is downloaded from a peer. + fn on_snapshot_manifest(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring snapshot manifest from unconfirmed peer {}", peer_id); + return Ok(()); + } + sync.clear_peer_download(peer_id); + if !sync.reset_peer_asking(peer_id, PeerAsking::SnapshotManifest) || sync.state != SyncState::SnapshotManifest { + trace!(target: "sync", "{}: Ignored unexpected/expired manifest", peer_id); + sync.continue_sync(io); + return Ok(()); + } + + let manifest_rlp = r.at(0)?; + let manifest = match ManifestData::from_rlp(manifest_rlp.as_raw()) { + Err(e) => { + trace!(target: "sync", "{}: Ignored bad manifest: {:?}", peer_id, e); + io.disable_peer(peer_id); + sync.continue_sync(io); + return Ok(()); + } + Ok(manifest) => manifest, + }; + + let is_supported_version = io.snapshot_service().supported_versions() + .map_or(false, |(l, h)| manifest.version >= l && manifest.version <= h); + + if !is_supported_version { + trace!(target: "sync", "{}: Snapshot manifest version not supported: {}", peer_id, manifest.version); + io.disable_peer(peer_id); + sync.continue_sync(io); + return Ok(()); + } + sync.snapshot.reset_to(&manifest, &keccak(manifest_rlp.as_raw())); + io.snapshot_service().begin_restore(manifest); + sync.state = SyncState::SnapshotData; + + // give a task to the same peer first. + sync.sync_peer(io, peer_id, false); + // give tasks to other peers + sync.continue_sync(io); + Ok(()) + } + + /// Called when snapshot data is downloaded from a peer. + fn on_snapshot_data(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "Ignoring snapshot data from unconfirmed peer {}", peer_id); + return Ok(()); + } + sync.clear_peer_download(peer_id); + if !sync.reset_peer_asking(peer_id, PeerAsking::SnapshotData) || (sync.state != SyncState::SnapshotData && sync.state != SyncState::SnapshotWaiting) { + trace!(target: "sync", "{}: Ignored unexpected snapshot data", peer_id); + sync.continue_sync(io); + return Ok(()); + } + + // check service status + let status = io.snapshot_service().status(); + match status { + RestorationStatus::Inactive | RestorationStatus::Failed => { + trace!(target: "sync", "{}: Snapshot restoration aborted", peer_id); + sync.state = SyncState::WaitingPeers; + + // only note bad if restoration failed. + if let (Some(hash), RestorationStatus::Failed) = (sync.snapshot.snapshot_hash(), status) { + trace!(target: "sync", "Noting snapshot hash {} as bad", hash); + sync.snapshot.note_bad(hash); + } + + sync.snapshot.clear(); + sync.continue_sync(io); + return Ok(()); + }, + RestorationStatus::Ongoing { .. } => { + trace!(target: "sync", "{}: Snapshot restoration is ongoing", peer_id); + }, + } + + let snapshot_data: Bytes = r.val_at(0)?; + match sync.snapshot.validate_chunk(&snapshot_data) { + Ok(ChunkType::Block(hash)) => { + trace!(target: "sync", "{}: Processing block chunk", peer_id); + io.snapshot_service().restore_block_chunk(hash, snapshot_data); + } + Ok(ChunkType::State(hash)) => { + trace!(target: "sync", "{}: Processing state chunk", peer_id); + io.snapshot_service().restore_state_chunk(hash, snapshot_data); + } + Err(()) => { + trace!(target: "sync", "{}: Got bad snapshot chunk", peer_id); + io.disconnect_peer(peer_id); + sync.continue_sync(io); + return Ok(()); + } + } + + if sync.snapshot.is_complete() { + // wait for snapshot restoration process to complete + sync.state = SyncState::SnapshotWaiting; + } + // give a task to the same peer first. + sync.sync_peer(io, peer_id, false); + // give tasks to other peers + sync.continue_sync(io); + Ok(()) + } + + /// Called by peer to report status + fn on_peer_status(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + sync.handshaking_peers.remove(&peer_id); + let protocol_version: u8 = r.val_at(0)?; + let warp_protocol = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer_id) != 0; + let peer = PeerInfo { + protocol_version: protocol_version, + network_id: r.val_at(1)?, + difficulty: Some(r.val_at(2)?), + latest_hash: r.val_at(3)?, + genesis: r.val_at(4)?, + asking: PeerAsking::Nothing, + asking_blocks: Vec::new(), + asking_hash: None, + ask_time: Instant::now(), + last_sent_transactions: HashSet::new(), + expired: false, + confirmation: if sync.fork_block.is_none() { ForkConfirmation::Confirmed } else { ForkConfirmation::Unconfirmed }, + asking_snapshot_data: None, + snapshot_hash: if warp_protocol { Some(r.val_at(5)?) } else { None }, + snapshot_number: if warp_protocol { Some(r.val_at(6)?) } else { None }, + block_set: None, + }; + + trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{}, snapshot:{:?})", + peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis, peer.snapshot_number); + if io.is_expired() { + trace!(target: "sync", "Status packet from expired session {}:{}", peer_id, io.peer_info(peer_id)); + return Ok(()); + } + + if sync.peers.contains_key(&peer_id) { + debug!(target: "sync", "Unexpected status packet from {}:{}", peer_id, io.peer_info(peer_id)); + return Ok(()); + } + let chain_info = io.chain().chain_info(); + if peer.genesis != chain_info.genesis_hash { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} genesis hash mismatch (ours: {}, theirs: {})", peer_id, chain_info.genesis_hash, peer.genesis); + return Ok(()); + } + if peer.network_id != sync.network_id { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, sync.network_id, peer.network_id); + return Ok(()); + } + if (warp_protocol && peer.protocol_version != PAR_PROTOCOL_VERSION_1 && peer.protocol_version != PAR_PROTOCOL_VERSION_2 && peer.protocol_version != PAR_PROTOCOL_VERSION_3) + || (!warp_protocol && peer.protocol_version != ETH_PROTOCOL_VERSION_63 && peer.protocol_version != ETH_PROTOCOL_VERSION_62) { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); + return Ok(()); + } + + if sync.sync_start_time.is_none() { + sync.sync_start_time = Some(Instant::now()); + } + + sync.peers.insert(peer_id.clone(), peer); + // Don't activate peer immediatelly when searching for common block. + // Let the current sync round complete first. + sync.active_peers.insert(peer_id.clone()); + debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); + if let Some((fork_block, _)) = sync.fork_block { + SyncRequester::request_fork_header(sync, io, peer_id, fork_block); + } else { + SyncHandler::on_peer_confirmed(sync, io, peer_id); + } + Ok(()) + } + + /// Called when peer sends us new transactions + fn on_peer_transactions(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + // Accept transactions only when fully synced + if !io.is_chain_queue_empty() || (sync.state != SyncState::Idle && sync.state != SyncState::NewBlocks) { + trace!(target: "sync", "{} Ignoring transactions while syncing", peer_id); + return Ok(()); + } + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring transactions from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + let item_count = r.item_count()?; + trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count); + let mut transactions = Vec::with_capacity(item_count); + for i in 0 .. item_count { + let rlp = r.at(i)?; + let tx = rlp.as_raw().to_vec(); + transactions.push(tx); + } + io.chain().queue_transactions(transactions, peer_id); + Ok(()) + } + + /// Called when peer sends us signed private transaction packet + fn on_signed_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + trace!(target: "sync", "Received signed private transaction packet from {:?}", peer_id); + if let Err(e) = sync.private_tx_handler.import_signed_private_transaction(r.as_raw()) { + trace!(target: "sync", "Ignoring the message, error queueing: {}", e); + } + Ok(()) + } + + /// Called when peer sends us new private transaction packet + fn on_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) { + trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id); + return Ok(()); + } + + trace!(target: "sync", "Received private transaction packet from {:?}", peer_id); + + if let Err(e) = sync.private_tx_handler.import_private_transaction(r.as_raw()) { + trace!(target: "sync", "Ignoring the message, error queueing: {}", e); + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use ethcore::client::{ChainInfo, EachBlockWith, TestBlockChainClient}; + use parking_lot::RwLock; + use rlp::{Rlp}; + use std::collections::{VecDeque}; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + + use super::*; + use super::super::tests::{ + dummy_sync_with_peer, + get_dummy_block, + get_dummy_blocks, + get_dummy_hashes, + }; + + #[test] + fn handles_peer_new_hashes() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let hashes_data = get_dummy_hashes(); + let hashes_rlp = Rlp::new(&hashes_data); + + let result = SyncHandler::on_peer_new_hashes(&mut sync, &mut io, 0, &hashes_rlp); + + assert!(result.is_ok()); + } + + #[test] + fn handles_peer_new_block_malformed() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + + let block_data = get_dummy_block(11, client.chain_info().best_block_hash); + + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + //sync.have_common_block = true; + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let block = Rlp::new(&block_data); + + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &block); + + assert!(result.is_err()); + } + + #[test] + fn handles_peer_new_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + + let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); + + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let block = Rlp::new(&block_data); + + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &block); + + assert!(result.is_ok()); + } + + #[test] + fn handles_peer_new_block_empty() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let empty_data = vec![]; + let block = Rlp::new(&empty_data); + + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &block); + + assert!(result.is_err()); + } + + #[test] + fn handles_peer_new_hashes_empty() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let empty_hashes_data = vec![]; + let hashes_rlp = Rlp::new(&empty_hashes_data); + + let result = SyncHandler::on_peer_new_hashes(&mut sync, &mut io, 0, &hashes_rlp); + + assert!(result.is_ok()); + } +} diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs new file mode 100644 index 0000000000..abab1da941 --- /dev/null +++ b/ethcore/sync/src/chain/mod.rs @@ -0,0 +1,1379 @@ +// 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 . + +//! `BlockChain` synchronization strategy. +//! Syncs to peers and keeps up to date. +//! This implementation uses ethereum protocol v63 +//! +//! Syncing strategy summary. +//! Split the chain into ranges of N blocks each. Download ranges sequentially. Split each range into subchains of M blocks. Download subchains in parallel. +//! State. +//! Sync state consists of the following data: +//! - s: State enum which can be one of the following values: `ChainHead`, `Blocks`, `Idle` +//! - H: A set of downloaded block headers +//! - B: A set of downloaded block bodies +//! - S: Set of block subchain start block hashes to download. +//! - l: Last imported / common block hash +//! - P: A set of connected peers. For each peer we maintain its last known total difficulty and starting block hash being requested if any. +//! General behaviour. +//! We start with all sets empty, l is set to the best block in the block chain, s is set to `ChainHead`. +//! If at any moment a bad block is reported by the block queue, we set s to `ChainHead`, reset l to the best block in the block chain and clear H, B and S. +//! If at any moment P becomes empty, we set s to `ChainHead`, and clear H, B and S. +//! +//! Workflow for `ChainHead` state. +//! In this state we try to get subchain headers with a single `GetBlockHeaders` request. +//! On `NewPeer` / On `Restart`: +//! If peer's total difficulty is higher and there are less than 5 peers downloading, request N/M headers with interval M+1 starting from l +//! On `BlockHeaders(R)`: +//! If R is empty: +//! If l is equal to genesis block hash or l is more than 1000 blocks behind our best hash: +//! Remove current peer from P. set l to the best block in the block chain. Select peer with maximum total difficulty from P and restart. +//! Else +//! Set l to l’s parent and restart. +//! Else if we already have all the headers in the block chain or the block queue: +//! Set s to `Idle`, +//! Else +//! Set S to R, set s to `Blocks`. +//! +//! All other messages are ignored. +//! +//! Workflow for `Blocks` state. +//! In this state we download block headers and bodies from multiple peers. +//! On `NewPeer` / On `Restart`: +//! For all idle peers: +//! Find a set of 256 or less block hashes in H which are not in B and not being downloaded by other peers. If the set is not empty: +//! Request block bodies for the hashes in the set. +//! Else +//! Find an element in S which is not being downloaded by other peers. If found: Request M headers starting from the element. +//! +//! On `BlockHeaders(R)`: +//! If R is empty remove current peer from P and restart. +//! Validate received headers: +//! For each header find a parent in H or R or the blockchain. Restart if there is a block with unknown parent. +//! Find at least one header from the received list in S. Restart if there is none. +//! Go to `CollectBlocks`. +//! +//! On `BlockBodies(R)`: +//! If R is empty remove current peer from P and restart. +//! Add bodies with a matching header in H to B. +//! Go to `CollectBlocks`. +//! +//! `CollectBlocks`: +//! Find a chain of blocks C in H starting from h where h’s parent equals to l. The chain ends with the first block which does not have a body in B. +//! Add all blocks from the chain to the block queue. Remove them from H and B. Set l to the hash of the last block from C. +//! Update and merge subchain heads in S. For each h in S find a chain of blocks in B starting from h. Remove h from S. if the chain does not include an element from S add the end of the chain to S. +//! If H is empty and S contains a single element set s to `ChainHead`. +//! Restart. +//! +//! All other messages are ignored. +//! Workflow for Idle state. +//! On `NewBlock`: +//! Import the block. If the block is unknown set s to `ChainHead` and restart. +//! On `NewHashes`: +//! Set s to `ChainHead` and restart. +//! +//! All other messages are ignored. + +mod handler; +mod propagator; +mod requester; +mod supplier; + +use std::sync::Arc; +use std::collections::{HashSet, HashMap}; +use std::cmp; +use std::time::{Duration, Instant}; +use hash::keccak; +use heapsize::HeapSizeOf; +use ethereum_types::{H256, U256}; +use plain_hasher::H256FastMap; +use parking_lot::RwLock; +use bytes::Bytes; +use rlp::{Rlp, RlpStream, DecoderError}; +use network::{self, PeerId, PacketId}; +use ethcore::header::{BlockNumber}; +use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockQueueInfo}; +use ethcore::snapshot::{RestorationStatus}; +use sync_io::SyncIo; +use super::{WarpSync, SyncConfig}; +use block_sync::{BlockDownloader, BlockDownloaderImportError as DownloaderImportError}; +use rand::Rng; +use snapshot::{Snapshot}; +use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; +use private_tx::PrivateTxHandler; +use transactions_stats::{TransactionsStats, Stats as TransactionStats}; +use transaction::UnverifiedTransaction; + +use self::handler::SyncHandler; +use self::propagator::SyncPropagator; +use self::requester::SyncRequester; +use self::supplier::SyncSupplier; + +known_heap_size!(0, PeerInfo); + +pub type PacketDecodeError = DecoderError; + +/// 63 version of Ethereum protocol. +pub const ETH_PROTOCOL_VERSION_63: u8 = 63; +/// 62 version of Ethereum protocol. +pub const ETH_PROTOCOL_VERSION_62: u8 = 62; +/// 1 version of Parity protocol. +pub const PAR_PROTOCOL_VERSION_1: u8 = 1; +/// 2 version of Parity protocol (consensus messages added). +pub const PAR_PROTOCOL_VERSION_2: u8 = 2; +/// 3 version of Parity protocol (private transactions messages added). +pub const PAR_PROTOCOL_VERSION_3: u8 = 3; + +pub const MAX_BODIES_TO_SEND: usize = 256; +pub const MAX_HEADERS_TO_SEND: usize = 512; +pub const MAX_NODE_DATA_TO_SEND: usize = 1024; +pub const MAX_RECEIPTS_TO_SEND: usize = 1024; +pub const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256; +const MIN_PEERS_PROPAGATION: usize = 4; +const MAX_PEERS_PROPAGATION: usize = 128; +const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20; +const MAX_NEW_HASHES: usize = 64; +const MAX_NEW_BLOCK_AGE: BlockNumber = 20; +// maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). +const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; +// Maximal number of transactions in sent in single packet. +const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; +// Min number of blocks to be behind for a snapshot sync +const SNAPSHOT_RESTORE_THRESHOLD: BlockNumber = 30000; +const SNAPSHOT_MIN_PEERS: usize = 3; + +const STATUS_PACKET: u8 = 0x00; +const NEW_BLOCK_HASHES_PACKET: u8 = 0x01; +const TRANSACTIONS_PACKET: u8 = 0x02; +pub const GET_BLOCK_HEADERS_PACKET: u8 = 0x03; +pub const BLOCK_HEADERS_PACKET: u8 = 0x04; +pub const GET_BLOCK_BODIES_PACKET: u8 = 0x05; +const BLOCK_BODIES_PACKET: u8 = 0x06; +const NEW_BLOCK_PACKET: u8 = 0x07; + +pub const GET_NODE_DATA_PACKET: u8 = 0x0d; +pub const NODE_DATA_PACKET: u8 = 0x0e; +pub const GET_RECEIPTS_PACKET: u8 = 0x0f; +pub const RECEIPTS_PACKET: u8 = 0x10; + +pub const ETH_PACKET_COUNT: u8 = 0x11; + +pub const GET_SNAPSHOT_MANIFEST_PACKET: u8 = 0x11; +pub const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12; +pub const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13; +pub const SNAPSHOT_DATA_PACKET: u8 = 0x14; +pub const CONSENSUS_DATA_PACKET: u8 = 0x15; +const PRIVATE_TRANSACTION_PACKET: u8 = 0x16; +const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17; + +pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; + +const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; + +const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); +const STATUS_TIMEOUT: Duration = Duration::from_secs(5); +const HEADERS_TIMEOUT: Duration = Duration::from_secs(15); +const BODIES_TIMEOUT: Duration = Duration::from_secs(20); +const RECEIPTS_TIMEOUT: Duration = Duration::from_secs(10); +const FORK_HEADER_TIMEOUT: Duration = Duration::from_secs(3); +const SNAPSHOT_MANIFEST_TIMEOUT: Duration = Duration::from_secs(5); +const SNAPSHOT_DATA_TIMEOUT: Duration = Duration::from_secs(120); + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +/// Sync state +pub enum SyncState { + /// Collecting enough peers to start syncing. + WaitingPeers, + /// Waiting for snapshot manifest download + SnapshotManifest, + /// Downloading snapshot data + SnapshotData, + /// Waiting for snapshot restoration progress. + SnapshotWaiting, + /// Downloading new blocks + Blocks, + /// Initial chain sync complete. Waiting for new packets + Idle, + /// Block downloading paused. Waiting for block queue to process blocks and free some space + Waiting, + /// Downloading blocks learned from `NewHashes` packet + NewBlocks, +} + +/// Syncing status and statistics +#[derive(Clone, Copy)] +pub struct SyncStatus { + /// State + pub state: SyncState, + /// Syncing protocol version. That's the maximum protocol version we connect to. + pub protocol_version: u8, + /// The underlying p2p network version. + pub network_id: u64, + /// `BlockChain` height for the moment the sync started. + pub start_block_number: BlockNumber, + /// Last fully downloaded and imported block number (if any). + pub last_imported_block_number: Option, + /// Highest block number in the download queue (if any). + pub highest_block_number: Option, + /// Total number of blocks for the sync process. + pub blocks_total: BlockNumber, + /// Number of blocks downloaded so far. + pub blocks_received: BlockNumber, + /// Total number of connected peers + pub num_peers: usize, + /// Total number of active peers. + pub num_active_peers: usize, + /// Heap memory used in bytes. + pub mem_used: usize, + /// Snapshot chunks + pub num_snapshot_chunks: usize, + /// Snapshot chunks downloaded + pub snapshot_chunks_done: usize, + /// Last fully downloaded and imported ancient block number (if any). + pub last_imported_old_block_number: Option, +} + +impl SyncStatus { + /// Indicates if snapshot download is in progress + pub fn is_snapshot_syncing(&self) -> bool { + self.state == SyncState::SnapshotManifest + || self.state == SyncState::SnapshotData + || self.state == SyncState::SnapshotWaiting + } + + /// Returns max no of peers to display in informants + pub fn current_max_peers(&self, min_peers: u32, max_peers: u32) -> u32 { + if self.num_peers as u32 > min_peers { + max_peers + } else { + min_peers + } + } + + /// Is it doing a major sync? + pub fn is_syncing(&self, queue_info: BlockQueueInfo) -> bool { + let is_syncing_state = match self.state { SyncState::Idle | SyncState::NewBlocks => false, _ => true }; + let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3; + is_verifying || is_syncing_state + } +} + +#[derive(PartialEq, Eq, Debug, Clone)] +/// Peer data type requested +pub enum PeerAsking { + Nothing, + ForkHeader, + BlockHeaders, + BlockBodies, + BlockReceipts, + SnapshotManifest, + SnapshotData, +} + +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +/// Block downloader channel. +pub enum BlockSet { + /// New blocks better than out best blocks + NewBlocks, + /// Missing old blocks + OldBlocks, +} +#[derive(Clone, Eq, PartialEq)] +pub enum ForkConfirmation { + /// Fork block confirmation pending. + Unconfirmed, + /// Fork is confirmed. + Confirmed, +} + +#[derive(Clone)] +/// Syncing peer information +pub struct PeerInfo { + /// eth protocol version + protocol_version: u8, + /// Peer chain genesis hash + genesis: H256, + /// Peer network id + network_id: u64, + /// Peer best block hash + latest_hash: H256, + /// Peer total difficulty if known + difficulty: Option, + /// Type of data currenty being requested from peer. + asking: PeerAsking, + /// A set of block numbers being requested + asking_blocks: Vec, + /// Holds requested header hash if currently requesting block header by hash + asking_hash: Option, + /// Holds requested snapshot chunk hash if any. + asking_snapshot_data: Option, + /// Request timestamp + ask_time: Instant, + /// Holds a set of transactions recently sent to this peer to avoid spamming. + last_sent_transactions: HashSet, + /// Pending request is expired and result should be ignored + expired: bool, + /// Peer fork confirmation status + confirmation: ForkConfirmation, + /// Best snapshot hash + snapshot_hash: Option, + /// Best snapshot block number + snapshot_number: Option, + /// Block set requested + block_set: Option, +} + +impl PeerInfo { + fn can_sync(&self) -> bool { + self.confirmation == ForkConfirmation::Confirmed && !self.expired + } + + fn is_allowed(&self) -> bool { + self.confirmation != ForkConfirmation::Unconfirmed && !self.expired + } + + fn reset_asking(&mut self) { + self.asking_blocks.clear(); + self.asking_hash = None; + // mark any pending requests as expired + if self.asking != PeerAsking::Nothing && self.is_allowed() { + self.expired = true; + } + } +} + +#[cfg(not(test))] +pub mod random { + use rand; + pub fn new() -> rand::ThreadRng { rand::thread_rng() } +} +#[cfg(test)] +pub mod random { + use rand::{self, SeedableRng}; + pub fn new() -> rand::XorShiftRng { rand::XorShiftRng::from_seed([0, 1, 2, 3]) } +} + +pub type RlpResponseResult = Result, PacketDecodeError>; +pub type Peers = HashMap; + +/// Blockchain sync handler. +/// See module documentation for more details. +pub struct ChainSync { + /// Sync state + state: SyncState, + /// Last block number for the start of sync + starting_block: BlockNumber, + /// Highest block number seen + highest_block: Option, + /// All connected peers + peers: Peers, + /// Peers active for current sync round + active_peers: HashSet, + /// Block download process for new blocks + new_blocks: BlockDownloader, + /// Block download process for ancient blocks + old_blocks: Option, + /// Last propagated block number + last_sent_block_number: BlockNumber, + /// Network ID + network_id: u64, + /// Optional fork block to check + fork_block: Option<(BlockNumber, H256)>, + /// Snapshot downloader. + snapshot: Snapshot, + /// Connected peers pending Status message. + /// Value is request timestamp. + handshaking_peers: HashMap, + /// Sync start timestamp. Measured when first peer is connected + sync_start_time: Option, + /// Transactions propagation statistics + transactions_stats: TransactionsStats, + /// Enable ancient block downloading + download_old_blocks: bool, + /// Shared private tx service. + private_tx_handler: Arc, + /// Enable warp sync. + warp_sync: WarpSync, +} + +impl ChainSync { + /// Create a new instance of syncing strategy. + pub fn new(config: SyncConfig, chain: &BlockChainClient, private_tx_handler: Arc) -> ChainSync { + let chain_info = chain.chain_info(); + let best_block = chain.chain_info().best_block_number; + let state = ChainSync::get_init_state(config.warp_sync, chain); + + let mut sync = ChainSync { + state, + starting_block: best_block, + highest_block: None, + peers: HashMap::new(), + handshaking_peers: HashMap::new(), + active_peers: HashSet::new(), + new_blocks: BlockDownloader::new(false, &chain_info.best_block_hash, chain_info.best_block_number), + old_blocks: None, + last_sent_block_number: 0, + network_id: config.network_id, + fork_block: config.fork_block, + download_old_blocks: config.download_old_blocks, + snapshot: Snapshot::new(), + sync_start_time: None, + transactions_stats: TransactionsStats::default(), + private_tx_handler, + warp_sync: config.warp_sync, + }; + sync.update_targets(chain); + sync + } + + fn get_init_state(warp_sync: WarpSync, chain: &BlockChainClient) -> SyncState { + let best_block = chain.chain_info().best_block_number; + match warp_sync { + WarpSync::Enabled => SyncState::WaitingPeers, + WarpSync::OnlyAndAfter(block) if block > best_block => SyncState::WaitingPeers, + _ => SyncState::Idle, + } + } + + /// Returns synchonization status + pub fn status(&self) -> SyncStatus { + let last_imported_number = self.new_blocks.last_imported_block_number(); + SyncStatus { + state: self.state.clone(), + protocol_version: ETH_PROTOCOL_VERSION_63, + network_id: self.network_id, + start_block_number: self.starting_block, + last_imported_block_number: Some(last_imported_number), + last_imported_old_block_number: self.old_blocks.as_ref().map(|d| d.last_imported_block_number()), + highest_block_number: self.highest_block.map(|n| cmp::max(n, last_imported_number)), + blocks_received: if last_imported_number > self.starting_block { last_imported_number - self.starting_block } else { 0 }, + blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, + num_peers: self.peers.values().filter(|p| p.is_allowed()).count(), + num_active_peers: self.peers.values().filter(|p| p.is_allowed() && p.asking != PeerAsking::Nothing).count(), + num_snapshot_chunks: self.snapshot.total_chunks(), + snapshot_chunks_done: self.snapshot.done_chunks(), + mem_used: + self.new_blocks.heap_size() + + self.old_blocks.as_ref().map_or(0, |d| d.heap_size()) + + self.peers.heap_size_of_children(), + } + } + + /// Returns information on peers connections + pub fn peer_info(&self, peer_id: &PeerId) -> Option { + self.peers.get(peer_id).map(|peer_data| { + PeerInfoDigest { + version: peer_data.protocol_version as u32, + difficulty: peer_data.difficulty, + head: peer_data.latest_hash, + } + }) + } + + /// Returns transactions propagation statistics + pub fn transactions_stats(&self) -> &H256FastMap { + self.transactions_stats.stats() + } + + /// Updates transactions were received by a peer + pub fn transactions_received(&mut self, txs: &[UnverifiedTransaction], peer_id: PeerId) { + if let Some(peer_info) = self.peers.get_mut(&peer_id) { + peer_info.last_sent_transactions.extend(txs.iter().map(|tx| tx.hash())); + } + } + + /// Abort all sync activity + pub fn abort(&mut self, io: &mut SyncIo) { + self.reset_and_continue(io); + self.peers.clear(); + } + + /// Reset sync. Clear all downloaded data but keep the queue + fn reset(&mut self, io: &mut SyncIo) { + self.new_blocks.reset(); + let chain_info = io.chain().chain_info(); + for (_, ref mut p) in &mut self.peers { + if p.block_set != Some(BlockSet::OldBlocks) { + p.reset_asking(); + if p.difficulty.is_none() { + // assume peer has up to date difficulty + p.difficulty = Some(chain_info.pending_total_difficulty); + } + } + } + self.state = ChainSync::get_init_state(self.warp_sync, io.chain()); + // Reactivate peers only if some progress has been made + // since the last sync round of if starting fresh. + self.active_peers = self.peers.keys().cloned().collect(); + } + + /// Restart sync + pub fn reset_and_continue(&mut self, io: &mut SyncIo) { + trace!(target: "sync", "Restarting"); + if self.state == SyncState::SnapshotData { + debug!(target:"sync", "Aborting snapshot restore"); + io.snapshot_service().abort_restore(); + } + self.snapshot.clear(); + self.reset(io); + self.continue_sync(io); + } + + /// Remove peer from active peer set. Peer will be reactivated on the next sync + /// round. + fn deactivate_peer(&mut self, _io: &mut SyncIo, peer_id: PeerId) { + trace!(target: "sync", "Deactivating peer {}", peer_id); + self.active_peers.remove(&peer_id); + } + + fn maybe_start_snapshot_sync(&mut self, io: &mut SyncIo) { + if !self.warp_sync.is_enabled() || io.snapshot_service().supported_versions().is_none() { + trace!(target: "sync", "Skipping warp sync. Disabled or not supported."); + return; + } + if self.state != SyncState::WaitingPeers && self.state != SyncState::Blocks && self.state != SyncState::Waiting { + trace!(target: "sync", "Skipping warp sync. State: {:?}", self.state); + return; + } + // Make sure the snapshot block is not too far away from best block and network best block and + // that it is higher than fork detection block + let our_best_block = io.chain().chain_info().best_block_number; + let fork_block = self.fork_block.map_or(0, |(n, _)| n); + + let (best_hash, max_peers, snapshot_peers) = { + let expected_warp_block = match self.warp_sync { + WarpSync::OnlyAndAfter(block) => block, + _ => 0, + }; + //collect snapshot infos from peers + let snapshots = self.peers.iter() + .filter(|&(_, p)| p.is_allowed() && p.snapshot_number.map_or(false, |sn| + // Snapshot must be old enough that it's usefull to sync with it + our_best_block < sn && (sn - our_best_block) > SNAPSHOT_RESTORE_THRESHOLD && + // Snapshot must have been taken after the Fork + sn > fork_block && + // Snapshot must be greater than the warp barrier if any + sn > expected_warp_block && + // If we know a highest block, snapshot must be recent enough + self.highest_block.map_or(true, |highest| { + highest < sn || (highest - sn) <= SNAPSHOT_RESTORE_THRESHOLD + }) + )) + .filter_map(|(p, peer)| peer.snapshot_hash.map(|hash| (p, hash.clone()))) + .filter(|&(_, ref hash)| !self.snapshot.is_known_bad(hash)); + + let mut snapshot_peers = HashMap::new(); + let mut max_peers: usize = 0; + let mut best_hash = None; + for (p, hash) in snapshots { + let peers = snapshot_peers.entry(hash).or_insert_with(Vec::new); + peers.push(*p); + if peers.len() > max_peers { + max_peers = peers.len(); + best_hash = Some(hash); + } + } + (best_hash, max_peers, snapshot_peers) + }; + + let timeout = (self.state == SyncState::WaitingPeers) && self.sync_start_time.map_or(false, |t| t.elapsed() > WAIT_PEERS_TIMEOUT); + + if let (Some(hash), Some(peers)) = (best_hash, best_hash.map_or(None, |h| snapshot_peers.get(&h))) { + if max_peers >= SNAPSHOT_MIN_PEERS { + trace!(target: "sync", "Starting confirmed snapshot sync {:?} with {:?}", hash, peers); + self.start_snapshot_sync(io, peers); + } else if timeout { + trace!(target: "sync", "Starting unconfirmed snapshot sync {:?} with {:?}", hash, peers); + self.start_snapshot_sync(io, peers); + } + } else if timeout && !self.warp_sync.is_warp_only() { + trace!(target: "sync", "No snapshots found, starting full sync"); + self.state = SyncState::Idle; + self.continue_sync(io); + } + } + + fn start_snapshot_sync(&mut self, io: &mut SyncIo, peers: &[PeerId]) { + if !self.snapshot.have_manifest() { + for p in peers { + if self.peers.get(p).map_or(false, |p| p.asking == PeerAsking::Nothing) { + SyncRequester::request_snapshot_manifest(self, io, *p); + } + } + self.state = SyncState::SnapshotManifest; + trace!(target: "sync", "New snapshot sync with {:?}", peers); + } else { + self.state = SyncState::SnapshotData; + trace!(target: "sync", "Resumed snapshot sync with {:?}", peers); + } + } + + /// Restart sync disregarding the block queue status. May end up re-downloading up to QUEUE_SIZE blocks + pub fn restart(&mut self, io: &mut SyncIo) { + self.update_targets(io.chain()); + self.reset_and_continue(io); + } + + /// Update sync after the blockchain has been changed externally. + pub fn update_targets(&mut self, chain: &BlockChainClient) { + // Do not assume that the block queue/chain still has our last_imported_block + let chain = chain.chain_info(); + self.new_blocks = BlockDownloader::new(false, &chain.best_block_hash, chain.best_block_number); + self.old_blocks = None; + if self.download_old_blocks { + if let (Some(ancient_block_hash), Some(ancient_block_number)) = (chain.ancient_block_hash, chain.ancient_block_number) { + + trace!(target: "sync", "Downloading old blocks from {:?} (#{}) till {:?} (#{:?})", ancient_block_hash, ancient_block_number, chain.first_block_hash, chain.first_block_number); + let mut downloader = BlockDownloader::with_unlimited_reorg(true, &ancient_block_hash, ancient_block_number); + if let Some(hash) = chain.first_block_hash { + trace!(target: "sync", "Downloader target set to {:?}", hash); + downloader.set_target(&hash); + } + self.old_blocks = Some(downloader); + } + } + } + + /// Resume downloading + fn continue_sync(&mut self, io: &mut SyncIo) { + // Collect active peers that can sync + let confirmed_peers: Vec<(PeerId, u8)> = self.peers.iter().filter_map(|(peer_id, peer)| + if peer.can_sync() { + Some((*peer_id, peer.protocol_version)) + } else { + None + } + ).collect(); + let mut peers: Vec<(PeerId, u8)> = confirmed_peers.iter().filter(|&&(peer_id, _)| + self.active_peers.contains(&peer_id) + ).map(|v| *v).collect(); + + random::new().shuffle(&mut peers); //TODO: sort by rating + // prefer peers with higher protocol version + peers.sort_by(|&(_, ref v1), &(_, ref v2)| v1.cmp(v2)); + trace!( + target: "sync", + "Syncing with peers: {} active, {} confirmed, {} total", + self.active_peers.len(), confirmed_peers.len(), self.peers.len() + ); + for (peer_id, _) in peers { + self.sync_peer(io, peer_id, false); + } + + if + (self.state == SyncState::Blocks || self.state == SyncState::NewBlocks) && + !self.peers.values().any(|p| p.asking != PeerAsking::Nothing && p.block_set != Some(BlockSet::OldBlocks) && p.can_sync()) + { + self.complete_sync(io); + } + } + + /// Called after all blocks have been downloaded + fn complete_sync(&mut self, io: &mut SyncIo) { + trace!(target: "sync", "Sync complete"); + self.reset(io); + } + + /// Enter waiting state + fn pause_sync(&mut self) { + trace!(target: "sync", "Block queue full, pausing sync"); + self.state = SyncState::Waiting; + } + + /// Find something to do for a peer. Called for a new peer or when a peer is done with its task. + fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) { + if !self.active_peers.contains(&peer_id) { + trace!(target: "sync", "Skipping deactivated peer {}", peer_id); + return; + } + let (peer_latest, peer_difficulty, peer_snapshot_number, peer_snapshot_hash) = { + if let Some(peer) = self.peers.get_mut(&peer_id) { + if peer.asking != PeerAsking::Nothing || !peer.can_sync() { + trace!(target: "sync", "Skipping busy peer {}", peer_id); + return; + } + if self.state == SyncState::Waiting { + trace!(target: "sync", "Waiting for the block queue"); + return; + } + if self.state == SyncState::SnapshotWaiting { + trace!(target: "sync", "Waiting for the snapshot restoration"); + return; + } + (peer.latest_hash.clone(), peer.difficulty.clone(), peer.snapshot_number.as_ref().cloned().unwrap_or(0), peer.snapshot_hash.as_ref().cloned()) + } else { + return; + } + }; + let chain_info = io.chain().chain_info(); + let syncing_difficulty = chain_info.pending_total_difficulty; + let num_active_peers = self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(); + + let higher_difficulty = peer_difficulty.map_or(true, |pd| pd > syncing_difficulty); + if force || higher_difficulty || self.old_blocks.is_some() { + match self.state { + SyncState::WaitingPeers => { + trace!( + target: "sync", + "Checking snapshot sync: {} vs {} (peer: {})", + peer_snapshot_number, + chain_info.best_block_number, + peer_id + ); + self.maybe_start_snapshot_sync(io); + }, + SyncState::Idle | SyncState::Blocks | SyncState::NewBlocks => { + if io.chain().queue_info().is_full() { + self.pause_sync(); + return; + } + + let have_latest = io.chain().block_status(BlockId::Hash(peer_latest)) != BlockStatus::Unknown; + trace!(target: "sync", "Considering peer {}, force={}, td={:?}, our td={}, latest={}, have_latest={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, peer_latest, have_latest, self.state); + if !have_latest && (higher_difficulty || force || self.state == SyncState::NewBlocks) { + // check if got new blocks to download + trace!(target: "sync", "Syncing with peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); + if let Some(request) = self.new_blocks.request_blocks(io, num_active_peers) { + SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::NewBlocks); + if self.state == SyncState::Idle { + self.state = SyncState::Blocks; + } + return; + } + } + + if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { + SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); + return; + } + }, + SyncState::SnapshotData => { + if let RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } = io.snapshot_service().status() { + if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target: "sync", "Snapshot queue full, pausing sync"); + self.state = SyncState::SnapshotWaiting; + return; + } + } + if peer_snapshot_hash.is_some() && peer_snapshot_hash == self.snapshot.snapshot_hash() { + self.clear_peer_download(peer_id); + SyncRequester::request_snapshot_data(self, io, peer_id); + } + }, + SyncState::SnapshotManifest | //already downloading from other peer + SyncState::Waiting | SyncState::SnapshotWaiting => () + } + } else { + trace!(target: "sync", "Skipping peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); + } + } + + /// Clear all blocks/headers marked as being downloaded by a peer. + fn clear_peer_download(&mut self, peer_id: PeerId) { + if let Some(ref peer) = self.peers.get(&peer_id) { + match peer.asking { + PeerAsking::BlockHeaders => { + if let Some(ref hash) = peer.asking_hash { + self.new_blocks.clear_header_download(hash); + if let Some(ref mut old) = self.old_blocks { + old.clear_header_download(hash); + } + } + }, + PeerAsking::BlockBodies => { + self.new_blocks.clear_body_download(&peer.asking_blocks); + if let Some(ref mut old) = self.old_blocks { + old.clear_body_download(&peer.asking_blocks); + } + }, + PeerAsking::BlockReceipts => { + self.new_blocks.clear_receipt_download(&peer.asking_blocks); + if let Some(ref mut old) = self.old_blocks { + old.clear_receipt_download(&peer.asking_blocks); + } + }, + PeerAsking::SnapshotData => { + if let Some(hash) = peer.asking_snapshot_data { + self.snapshot.clear_chunk_download(&hash); + } + }, + _ => (), + } + } + } + + /// Checks if there are blocks fully downloaded that can be imported into the blockchain and does the import. + fn collect_blocks(&mut self, io: &mut SyncIo, block_set: BlockSet) { + match block_set { + BlockSet::NewBlocks => { + if self.new_blocks.collect_blocks(io, self.state == SyncState::NewBlocks) == Err(DownloaderImportError::Invalid) { + self.restart(io); + } + }, + BlockSet::OldBlocks => { + if self.old_blocks.as_mut().map_or(false, |downloader| { downloader.collect_blocks(io, false) == Err(DownloaderImportError::Invalid) }) { + self.restart(io); + } else if self.old_blocks.as_ref().map_or(false, |downloader| { downloader.is_complete() }) { + trace!(target: "sync", "Background block download is complete"); + self.old_blocks = None; + } + } + } + } + + /// Reset peer status after request is complete. + fn reset_peer_asking(&mut self, peer_id: PeerId, asking: PeerAsking) -> bool { + if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { + peer.expired = false; + peer.block_set = None; + if peer.asking != asking { + trace!(target:"sync", "Asking {:?} while expected {:?}", peer.asking, asking); + peer.asking = PeerAsking::Nothing; + return false; + } else { + peer.asking = PeerAsking::Nothing; + return true; + } + } + false + } + + /// Send Status message + fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), network::Error> { + let warp_protocol_version = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer); + let warp_protocol = warp_protocol_version != 0; + let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63 }; + trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol); + let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 }); + let chain = io.chain().chain_info(); + packet.append(&(protocol as u32)); + packet.append(&self.network_id); + packet.append(&chain.total_difficulty); + packet.append(&chain.best_block_hash); + packet.append(&chain.genesis_hash); + if warp_protocol { + let manifest = match self.old_blocks.is_some() { + true => None, + false => io.snapshot_service().manifest(), + }; + let block_number = manifest.as_ref().map_or(0, |m| m.block_number); + let manifest_hash = manifest.map_or(H256::new(), |m| keccak(m.into_rlp())); + packet.append(&manifest_hash); + packet.append(&block_number); + } + io.respond(STATUS_PACKET, packet.out()) + } + + pub fn maintain_peers(&mut self, io: &mut SyncIo) { + let tick = Instant::now(); + let mut aborting = Vec::new(); + for (peer_id, peer) in &self.peers { + let elapsed = tick - peer.ask_time; + let timeout = match peer.asking { + PeerAsking::BlockHeaders => elapsed > HEADERS_TIMEOUT, + PeerAsking::BlockBodies => elapsed > BODIES_TIMEOUT, + PeerAsking::BlockReceipts => elapsed > RECEIPTS_TIMEOUT, + PeerAsking::Nothing => false, + PeerAsking::ForkHeader => elapsed > FORK_HEADER_TIMEOUT, + PeerAsking::SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT, + PeerAsking::SnapshotData => elapsed > SNAPSHOT_DATA_TIMEOUT, + }; + if timeout { + debug!(target:"sync", "Timeout {}", peer_id); + io.disconnect_peer(*peer_id); + aborting.push(*peer_id); + } + } + for p in aborting { + SyncHandler::on_peer_aborting(self, io, p); + } + + // Check for handshake timeouts + for (peer, &ask_time) in &self.handshaking_peers { + let elapsed = (tick - ask_time) / 1_000_000_000; + if elapsed > STATUS_TIMEOUT { + trace!(target:"sync", "Status timeout {}", peer); + io.disconnect_peer(*peer); + } + } + } + + fn check_resume(&mut self, io: &mut SyncIo) { + if self.state == SyncState::Waiting && !io.chain().queue_info().is_full() { + self.state = SyncState::Blocks; + self.continue_sync(io); + } else if self.state == SyncState::SnapshotWaiting { + match io.snapshot_service().status() { + RestorationStatus::Inactive => { + trace!(target:"sync", "Snapshot restoration is complete"); + self.restart(io); + }, + RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { + if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target:"sync", "Resuming snapshot sync"); + self.state = SyncState::SnapshotData; + self.continue_sync(io); + } + }, + RestorationStatus::Failed => { + trace!(target: "sync", "Snapshot restoration aborted"); + self.state = SyncState::WaitingPeers; + self.snapshot.clear(); + self.continue_sync(io); + }, + } + } + } + + /// creates rlp to send for the tree defined by 'from' and 'to' hashes + fn create_new_hashes_rlp(chain: &BlockChainClient, from: &H256, to: &H256) -> Option { + match chain.tree_route(from, to) { + Some(route) => { + let uncles = chain.find_uncles(from).unwrap_or_else(Vec::new); + match route.blocks.len() { + 0 => None, + _ => { + let mut blocks = route.blocks; + blocks.extend(uncles); + let mut rlp_stream = RlpStream::new_list(blocks.len()); + for block_hash in blocks { + let mut hash_rlp = RlpStream::new_list(2); + let number = chain.block_header(BlockId::Hash(block_hash.clone())) + .expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.").number(); + hash_rlp.append(&block_hash); + hash_rlp.append(&number); + rlp_stream.append_raw(hash_rlp.as_raw(), 1); + } + Some(rlp_stream.out()) + } + } + }, + None => None + } + } + + /// creates rlp from block bytes and total difficulty + fn create_block_rlp(bytes: &Bytes, total_difficulty: U256) -> Bytes { + let mut rlp_stream = RlpStream::new_list(2); + rlp_stream.append_raw(bytes, 1); + rlp_stream.append(&total_difficulty); + rlp_stream.out() + } + + /// creates latest block rlp for the given client + fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes { + ChainSync::create_block_rlp( + &chain.block(BlockId::Hash(chain.chain_info().best_block_hash)) + .expect("Best block always exists").into_inner(), + chain.chain_info().total_difficulty + ) + } + + /// creates given hash block rlp for the given client + fn create_new_block_rlp(chain: &BlockChainClient, hash: &H256) -> Bytes { + ChainSync::create_block_rlp( + &chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed").into_inner(), + chain.block_total_difficulty(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed.") + ) + } + + /// returns peer ids that have different blocks than our chain + fn get_lagging_peers(&mut self, chain_info: &BlockChainInfo) -> Vec { + let latest_hash = chain_info.best_block_hash; + self + .peers + .iter_mut() + .filter_map(|(&id, ref mut peer_info)| { + trace!(target: "sync", "Checking peer our best {} their best {}", latest_hash, peer_info.latest_hash); + if peer_info.latest_hash != latest_hash { + Some(id) + } else { + None + } + }) + .collect::>() + } + + fn select_random_peers(peers: &[PeerId]) -> Vec { + // take sqrt(x) peers + let mut peers = peers.to_vec(); + let mut count = (peers.len() as f64).powf(0.5).round() as usize; + count = cmp::min(count, MAX_PEERS_PROPAGATION); + count = cmp::max(count, MIN_PEERS_PROPAGATION); + random::new().shuffle(&mut peers); + peers.truncate(count); + peers + } + + fn get_consensus_peers(&self) -> Vec { + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() + } + + fn get_private_transaction_peers(&self) -> Vec { + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3 { Some(*id) } else { None }).collect() + } + + /// Maintain other peers. Send out any new blocks and transactions + pub fn maintain_sync(&mut self, io: &mut SyncIo) { + self.maybe_start_snapshot_sync(io); + self.check_resume(io); + } + + /// called when block is imported to chain - propagates the blocks and updates transactions sent to peers + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, _imported: &[H256], invalid: &[H256], enacted: &[H256], _retracted: &[H256], sealed: &[H256], proposed: &[Bytes]) { + let queue_info = io.chain().queue_info(); + let is_syncing = self.status().is_syncing(queue_info); + + if !is_syncing || !sealed.is_empty() || !proposed.is_empty() { + trace!(target: "sync", "Propagating blocks, state={:?}", self.state); + SyncPropagator::propagate_latest_blocks(self, io, sealed); + SyncPropagator::propagate_proposed_blocks(self, io, proposed); + } + if !invalid.is_empty() { + trace!(target: "sync", "Bad blocks in the queue, restarting"); + self.restart(io); + } + + if !is_syncing && !enacted.is_empty() && !self.peers.is_empty() { + // Select random peer to re-broadcast transactions to. + let peer = random::new().gen_range(0, self.peers.len()); + trace!(target: "sync", "Re-broadcasting transactions to a random peer."); + self.peers.values_mut().nth(peer).map(|peer_info| + peer_info.last_sent_transactions.clear() + ); + } + } + + /// Dispatch incoming requests and responses + pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + SyncSupplier::dispatch_packet(sync, io, peer, packet_id, data) + } + + pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + debug!(target: "sync", "{} -> Dispatching packet: {}", peer, packet_id); + SyncHandler::on_packet(self, io, peer, packet_id, data); + } + + /// Called when peer sends us new consensus packet + pub fn on_consensus_packet(io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { + SyncHandler::on_consensus_packet(io, peer_id, r) + } + + /// Called by peer when it is disconnecting + pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) { + SyncHandler::on_peer_aborting(self, io, peer); + } + + /// Called when a new peer is connected + pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { + SyncHandler::on_peer_connected(self, io, peer); + } + + /// propagates new transactions to all peers + pub fn propagate_new_transactions(&mut self, io: &mut SyncIo) -> usize { + SyncPropagator::propagate_new_transactions(self, io) + } + + /// Broadcast consensus message to peers. + pub fn propagate_consensus_packet(&mut self, io: &mut SyncIo, packet: Bytes) { + SyncPropagator::propagate_consensus_packet(self, io, packet); + } + + /// Broadcast private transaction message to peers. + pub fn propagate_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { + SyncPropagator::propagate_private_transaction(self, io, packet); + } + + /// Broadcast signed private transaction message to peers. + pub fn propagate_signed_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) { + SyncPropagator::propagate_signed_private_transaction(self, io, packet); + } +} + +#[cfg(test)] +pub mod tests { + use std::collections::{HashSet, VecDeque}; + use ethkey; + use network::PeerId; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + use ethereum_types::{H256, U256, Address}; + use parking_lot::RwLock; + use bytes::Bytes; + use rlp::{Rlp, RlpStream}; + use super::*; + use ::SyncConfig; + use super::{PeerInfo, PeerAsking}; + use ethcore::header::*; + use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; + use ethcore::miner::MinerService; + use private_tx::NoopPrivateTxHandler; + + pub fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { + let mut header = Header::new(); + header.set_gas_limit(0.into()); + header.set_difficulty((order * 100).into()); + header.set_timestamp((order * 10) as u64); + header.set_number(order as u64); + header.set_parent_hash(parent_hash); + header.set_state_root(H256::zero()); + + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); + rlp.append_raw(&::rlp::EMPTY_LIST_RLP, 1); + rlp.out() + } + + pub fn get_dummy_blocks(order: u32, parent_hash: H256) -> Bytes { + let mut rlp = RlpStream::new_list(1); + rlp.append_raw(&get_dummy_block(order, parent_hash), 1); + let difficulty: U256 = (100 * order).into(); + rlp.append(&difficulty); + rlp.out() + } + + pub fn get_dummy_hashes() -> Bytes { + let mut rlp = RlpStream::new_list(5); + for _ in 0..5 { + let mut hash_d_rlp = RlpStream::new_list(2); + let hash: H256 = H256::from(0u64); + let diff: U256 = U256::from(1u64); + hash_d_rlp.append(&hash); + hash_d_rlp.append(&diff); + + rlp.append_raw(&hash_d_rlp.out(), 1); + } + + rlp.out() + } + + fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo { + BlockQueueInfo { + unverified_queue_size: unverified, + verified_queue_size: verified, + verifying_queue_size: 0, + max_queue_size: 1000, + max_mem_use: 1000, + mem_used: 500 + } + } + + fn sync_status(state: SyncState) -> SyncStatus { + SyncStatus { + state: state, + protocol_version: 0, + network_id: 0, + start_block_number: 0, + last_imported_block_number: None, + highest_block_number: None, + blocks_total: 0, + blocks_received: 0, + num_peers: 0, + num_active_peers: 0, + mem_used: 0, + num_snapshot_chunks: 0, + snapshot_chunks_done: 0, + last_imported_old_block_number: None, + } + } + + #[test] + fn is_still_verifying() { + assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(2, 1))); + assert!(sync_status(SyncState::Idle).is_syncing(queue_info(2, 2))); + } + + #[test] + fn is_synced_state() { + assert!(sync_status(SyncState::Blocks).is_syncing(queue_info(0, 0))); + assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(0, 0))); + } + + pub fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync { + let mut sync = ChainSync::new(SyncConfig::default(), client, Arc::new(NoopPrivateTxHandler)); + insert_dummy_peer(&mut sync, 0, peer_latest_hash); + sync + } + + pub fn insert_dummy_peer(sync: &mut ChainSync, peer_id: PeerId, peer_latest_hash: H256) { + sync.peers.insert(peer_id, + PeerInfo { + protocol_version: 0, + genesis: H256::zero(), + network_id: 0, + latest_hash: peer_latest_hash, + difficulty: None, + asking: PeerAsking::Nothing, + asking_blocks: Vec::new(), + asking_hash: None, + ask_time: Instant::now(), + last_sent_transactions: HashSet::new(), + expired: false, + confirmation: super::ForkConfirmation::Confirmed, + snapshot_number: None, + snapshot_hash: None, + asking_snapshot_data: None, + block_set: None, + }); + + } + + #[test] + fn finds_lagging_peers() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10), &client); + let chain_info = client.chain_info(); + + let lagging_peers = sync.get_lagging_peers(&chain_info); + + assert_eq!(1, lagging_peers.len()); + } + + #[test] + fn calculates_tree_for_lagging_peer() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(15, EachBlockWith::Uncle); + + let start = client.block_hash_delta_minus(4); + let end = client.block_hash_delta_minus(2); + + // wrong way end -> start, should be None + let rlp = ChainSync::create_new_hashes_rlp(&client, &end, &start); + assert!(rlp.is_none()); + + let rlp = ChainSync::create_new_hashes_rlp(&client, &start, &end).unwrap(); + // size of three rlp encoded hash-difficulty + assert_eq!(107, rlp.len()); + } + // idea is that what we produce when propagading latest hashes should be accepted in + // on_peer_new_hashes in our code as well + #[test] + fn hashes_rlp_mutually_acceptable() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let peers = sync.get_lagging_peers(&chain_info); + SyncPropagator::propagate_new_hashes(&mut sync, &chain_info, &mut io, &peers); + + let data = &io.packets[0].data.clone(); + let result = SyncHandler::on_peer_new_hashes(&mut sync, &mut io, 0, &Rlp::new(data)); + assert!(result.is_ok()); + } + + // idea is that what we produce when propagading latest block should be accepted in + // on_peer_new_block in our code as well + #[test] + fn block_rlp_mutually_acceptable() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let peers = sync.get_lagging_peers(&chain_info); + SyncPropagator::propagate_blocks(&mut sync, &chain_info, &mut io, &[], &peers); + + let data = &io.packets[0].data.clone(); + let result = SyncHandler::on_peer_new_block(&mut sync, &mut io, 0, &Rlp::new(data)); + assert!(result.is_ok()); + } + + #[test] + fn should_add_transactions_to_queue() { + fn sender(tx: &UnverifiedTransaction) -> Address { + ethkey::public_to_address(&tx.recover_public().unwrap()) + } + + // given + let mut client = TestBlockChainClient::new(); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + + // Add some balance to clients and reset nonces + for h in &[good_blocks[0], retracted_blocks[0]] { + let block = client.block(BlockId::Hash(*h)).unwrap(); + let sender = sender(&block.transactions()[0]);; + client.set_balance(sender, U256::from(10_000_000_000_000_000_000u64)); + client.set_nonce(sender, U256::from(0)); + } + + + // when + { + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); + assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); + } + // We need to update nonce status (because we say that the block has been imported) + for h in &[good_blocks[0]] { + let block = client.block(BlockId::Hash(*h)).unwrap(); + client.set_nonce(sender(&block.transactions()[0]), U256::from(1)); + } + { + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&client, &ss, &queue, None); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks, false); + sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); + } + + // then + assert_eq!(client.miner.ready_transactions(&client).len(), 1); + } + + #[test] + fn should_not_add_transactions_to_queue_if_not_synced() { + // given + let mut client = TestBlockChainClient::new(); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + // when + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); + assert_eq!(io.chain.miner.queue_status().status.transaction_count, 0); + sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks, &[], &[]); + + // then + let status = io.chain.miner.queue_status(); + assert_eq!(status.status.transaction_count, 0); + } +} diff --git a/ethcore/sync/src/chain/propagator.rs b/ethcore/sync/src/chain/propagator.rs new file mode 100644 index 0000000000..4ae0518a53 --- /dev/null +++ b/ethcore/sync/src/chain/propagator.rs @@ -0,0 +1,636 @@ +// Copyright 2015-2018 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 . + +use bytes::Bytes; +use ethereum_types::H256; +use ethcore::client::BlockChainInfo; +use ethcore::header::BlockNumber; +use network::{PeerId, PacketId}; +use rand::Rng; +use rlp::{Encodable, RlpStream}; +use sync_io::SyncIo; +use std::cmp; +use std::collections::HashSet; +use transaction::SignedTransaction; + +use super::{ + random, + ChainSync, + MAX_PEER_LAG_PROPAGATION, + MAX_PEERS_PROPAGATION, + MAX_TRANSACTION_PACKET_SIZE, + MAX_TRANSACTIONS_TO_PROPAGATE, + MIN_PEERS_PROPAGATION, + CONSENSUS_DATA_PACKET, + NEW_BLOCK_HASHES_PACKET, + NEW_BLOCK_PACKET, + PRIVATE_TRANSACTION_PACKET, + SIGNED_PRIVATE_TRANSACTION_PACKET, + TRANSACTIONS_PACKET, +}; + +/// Checks if peer is able to process service transactions +fn accepts_service_transaction(client_id: &str) -> bool { + // Parity versions starting from this will accept service-transactions + const SERVICE_TRANSACTIONS_VERSION: (u32, u32) = (1u32, 6u32); + // Parity client string prefix + const PARITY_CLIENT_ID_PREFIX: &'static str = "Parity/v"; + + if !client_id.starts_with(PARITY_CLIENT_ID_PREFIX) { + return false; + } + let ver: Vec = client_id[PARITY_CLIENT_ID_PREFIX.len()..].split('.') + .take(2) + .filter_map(|s| s.parse().ok()) + .collect(); + ver.len() == 2 && (ver[0] > SERVICE_TRANSACTIONS_VERSION.0 || (ver[0] == SERVICE_TRANSACTIONS_VERSION.0 && ver[1] >= SERVICE_TRANSACTIONS_VERSION.1)) +} + +/// The Chain Sync Propagator: propagates data to peers +pub struct SyncPropagator; + +impl SyncPropagator { + /// propagates latest block to a set of peers + pub fn propagate_blocks(sync: &mut ChainSync, chain_info: &BlockChainInfo, io: &mut SyncIo, blocks: &[H256], peers: &[PeerId]) -> usize { + trace!(target: "sync", "Sending NewBlocks to {:?}", peers); + let mut sent = 0; + for peer_id in peers { + if blocks.is_empty() { + let rlp = ChainSync::create_latest_block_rlp(io.chain()); + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); + } else { + for h in blocks { + let rlp = ChainSync::create_new_block_rlp(io.chain(), h); + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp); + } + } + if let Some(ref mut peer) = sync.peers.get_mut(peer_id) { + peer.latest_hash = chain_info.best_block_hash.clone(); + } + sent += 1; + } + sent + } + + /// propagates new known hashes to all peers + pub fn propagate_new_hashes(sync: &mut ChainSync, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize { + trace!(target: "sync", "Sending NewHashes to {:?}", peers); + let mut sent = 0; + let last_parent = *io.chain().best_block_header().parent_hash(); + for peer_id in peers { + sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) { + Some(rlp) => { + { + if let Some(ref mut peer) = sync.peers.get_mut(peer_id) { + peer.latest_hash = chain_info.best_block_hash.clone(); + } + } + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_HASHES_PACKET, rlp); + 1 + }, + None => 0 + } + } + sent + } + + /// propagates new transactions to all peers + pub fn propagate_new_transactions(sync: &mut ChainSync, io: &mut SyncIo) -> usize { + // Early out if nobody to send to. + if sync.peers.is_empty() { + return 0; + } + + let transactions = io.chain().ready_transactions(); + if transactions.is_empty() { + return 0; + } + + let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.iter() + .map(|tx| tx.signed()) + .partition(|tx| !tx.gas_price.is_zero()); + + // usual transactions could be propagated to all peers + let mut affected_peers = HashSet::new(); + if !transactions.is_empty() { + let peers = SyncPropagator::select_peers_for_transactions(sync, |_| true); + affected_peers = SyncPropagator::propagate_transactions_to_peers(sync, io, peers, transactions); + } + + // most of times service_transactions will be empty + // => there's no need to merge packets + if !service_transactions.is_empty() { + let service_transactions_peers = SyncPropagator::select_peers_for_transactions(sync, |peer_id| accepts_service_transaction(&io.peer_info(*peer_id))); + let service_transactions_affected_peers = SyncPropagator::propagate_transactions_to_peers(sync, io, service_transactions_peers, service_transactions); + affected_peers.extend(&service_transactions_affected_peers); + } + + affected_peers.len() + } + + fn propagate_transactions_to_peers(sync: &mut ChainSync, io: &mut SyncIo, peers: Vec, transactions: Vec<&SignedTransaction>) -> HashSet { + let all_transactions_hashes = transactions.iter() + .map(|tx| tx.hash()) + .collect::>(); + let all_transactions_rlp = { + let mut packet = RlpStream::new_list(transactions.len()); + for tx in &transactions { packet.append(&**tx); } + packet.out() + }; + + // Clear old transactions from stats + sync.transactions_stats.retain(&all_transactions_hashes); + + // sqrt(x)/x scaled to max u32 + let block_number = io.chain().chain_info().best_block_number; + + let lucky_peers = { + peers.into_iter() + .filter_map(|peer_id| { + let stats = &mut sync.transactions_stats; + let peer_info = sync.peers.get_mut(&peer_id) + .expect("peer_id is form peers; peers is result of select_peers_for_transactions; select_peers_for_transactions selects peers from self.peers; qed"); + + // Send all transactions + if peer_info.last_sent_transactions.is_empty() { + // update stats + for hash in &all_transactions_hashes { + let id = io.peer_session_info(peer_id).and_then(|info| info.id); + stats.propagated(hash, id, block_number); + } + peer_info.last_sent_transactions = all_transactions_hashes.clone(); + return Some((peer_id, all_transactions_hashes.len(), all_transactions_rlp.clone())); + } + + // Get hashes of all transactions to send to this peer + let to_send = all_transactions_hashes.difference(&peer_info.last_sent_transactions) + .take(MAX_TRANSACTIONS_TO_PROPAGATE) + .cloned() + .collect::>(); + if to_send.is_empty() { + return None; + } + + // Construct RLP + let (packet, to_send) = { + let mut to_send = to_send; + let mut packet = RlpStream::new(); + packet.begin_unbounded_list(); + let mut pushed = 0; + for tx in &transactions { + let hash = tx.hash(); + if to_send.contains(&hash) { + let mut transaction = RlpStream::new(); + tx.rlp_append(&mut transaction); + let appended = packet.append_raw_checked(&transaction.drain(), 1, MAX_TRANSACTION_PACKET_SIZE); + if !appended { + // Maximal packet size reached just proceed with sending + debug!("Transaction packet size limit reached. Sending incomplete set of {}/{} transactions.", pushed, to_send.len()); + to_send = to_send.into_iter().take(pushed).collect(); + break; + } + pushed += 1; + } + } + packet.complete_unbounded_list(); + (packet, to_send) + }; + + // Update stats + let id = io.peer_session_info(peer_id).and_then(|info| info.id); + for hash in &to_send { + // update stats + stats.propagated(hash, id, block_number); + } + + peer_info.last_sent_transactions = all_transactions_hashes + .intersection(&peer_info.last_sent_transactions) + .chain(&to_send) + .cloned() + .collect(); + Some((peer_id, to_send.len(), packet.out())) + }) + .collect::>() + }; + + // Send RLPs + let mut peers = HashSet::new(); + if lucky_peers.len() > 0 { + let mut max_sent = 0; + let lucky_peers_len = lucky_peers.len(); + for (peer_id, sent, rlp) in lucky_peers { + peers.insert(peer_id); + SyncPropagator::send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp); + trace!(target: "sync", "{:02} <- Transactions ({} entries)", peer_id, sent); + max_sent = cmp::max(max_sent, sent); + } + debug!(target: "sync", "Sent up to {} transactions to {} peers.", max_sent, lucky_peers_len); + } + + peers + } + + pub fn propagate_latest_blocks(sync: &mut ChainSync, io: &mut SyncIo, sealed: &[H256]) { + let chain_info = io.chain().chain_info(); + if (((chain_info.best_block_number as i64) - (sync.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { + let mut peers = sync.get_lagging_peers(&chain_info); + if sealed.is_empty() { + let hashes = SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers); + peers = ChainSync::select_random_peers(&peers); + let blocks = SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers); + if blocks != 0 || hashes != 0 { + trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); + } + } else { + SyncPropagator::propagate_blocks(sync, &chain_info, io, sealed, &peers); + SyncPropagator::propagate_new_hashes(sync, &chain_info, io, &peers); + trace!(target: "sync", "Sent sealed block to all peers"); + }; + } + sync.last_sent_block_number = chain_info.best_block_number; + } + + /// Distribute valid proposed blocks to subset of current peers. + pub fn propagate_proposed_blocks(sync: &mut ChainSync, io: &mut SyncIo, proposed: &[Bytes]) { + let peers = sync.get_consensus_peers(); + trace!(target: "sync", "Sending proposed blocks to {:?}", peers); + for block in proposed { + let rlp = ChainSync::create_block_rlp( + block, + io.chain().chain_info().total_difficulty + ); + for peer_id in &peers { + SyncPropagator::send_packet(io, *peer_id, NEW_BLOCK_PACKET, rlp.clone()); + } + } + } + + /// Broadcast consensus message to peers. + pub fn propagate_consensus_packet(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&sync.get_consensus_peers()); + trace!(target: "sync", "Sending consensus packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + SyncPropagator::send_packet(io, peer_id, CONSENSUS_DATA_PACKET, packet.clone()); + } + } + + /// Broadcast private transaction message to peers. + pub fn propagate_private_transaction(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&sync.get_private_transaction_peers()); + trace!(target: "sync", "Sending private transaction packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + SyncPropagator::send_packet(io, peer_id, PRIVATE_TRANSACTION_PACKET, packet.clone()); + } + } + + /// Broadcast signed private transaction message to peers. + pub fn propagate_signed_private_transaction(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) { + let lucky_peers = ChainSync::select_random_peers(&sync.get_private_transaction_peers()); + trace!(target: "sync", "Sending signed private transaction packet to {:?}", lucky_peers); + for peer_id in lucky_peers { + SyncPropagator::send_packet(io, peer_id, SIGNED_PRIVATE_TRANSACTION_PACKET, packet.clone()); + } + } + + fn select_peers_for_transactions(sync: &ChainSync, filter: F) -> Vec + where F: Fn(&PeerId) -> bool { + // sqrt(x)/x scaled to max u32 + let fraction = ((sync.peers.len() as f64).powf(-0.5) * (u32::max_value() as f64).round()) as u32; + let small = sync.peers.len() < MIN_PEERS_PROPAGATION; + + let mut random = random::new(); + sync.peers.keys() + .cloned() + .filter(filter) + .filter(|_| small || random.next_u32() < fraction) + .take(MAX_PEERS_PROPAGATION) + .collect() + } + + /// Generic packet sender + fn send_packet(sync: &mut SyncIo, peer_id: PeerId, packet_id: PacketId, packet: Bytes) { + if let Err(e) = sync.send(peer_id, packet_id, packet) { + debug!(target:"sync", "Error sending packet: {:?}", e); + sync.disconnect_peer(peer_id); + } + } +} + +#[cfg(test)] +mod tests { + use ethcore::client::{BlockInfo, ChainInfo, EachBlockWith, TestBlockChainClient}; + use parking_lot::RwLock; + use private_tx::NoopPrivateTxHandler; + use rlp::{Rlp}; + use std::collections::{VecDeque}; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + + use super::{*, super::{*, tests::*}}; + + #[test] + fn sends_new_hashes_to_lagging_peer() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let peers = sync.get_lagging_peers(&chain_info); + let peer_count = SyncPropagator::propagate_new_hashes(&mut sync, &chain_info, &mut io, &peers); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated + assert_eq!(1, peer_count); + // NEW_BLOCK_HASHES_PACKET + assert_eq!(0x01, io.packets[0].packet_id); + } + + #[test] + fn sends_latest_block_to_lagging_peer() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peers = sync.get_lagging_peers(&chain_info); + let peer_count = SyncPropagator::propagate_blocks(&mut sync, &chain_info, &mut io, &[], &peers); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated + assert_eq!(1, peer_count); + // NEW_BLOCK_PACKET + assert_eq!(0x07, io.packets[0].packet_id); + } + + #[test] + fn sends_sealed_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let hash = client.block_hash(BlockId::Number(99)).unwrap(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); + let chain_info = client.chain_info(); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peers = sync.get_lagging_peers(&chain_info); + let peer_count = SyncPropagator::propagate_blocks(&mut sync ,&chain_info, &mut io, &[hash.clone()], &peers); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated + assert_eq!(1, peer_count); + // NEW_BLOCK_PACKET + assert_eq!(0x07, io.packets[0].packet_id); + } + + #[test] + fn sends_proposed_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(2, EachBlockWith::Uncle); + let queue = RwLock::new(VecDeque::new()); + let block = client.block(BlockId::Latest).unwrap().into_inner(); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + sync.peers.insert(0, + PeerInfo { + // Messaging protocol + protocol_version: 2, + genesis: H256::zero(), + network_id: 0, + latest_hash: client.block_hash_delta_minus(1), + difficulty: None, + asking: PeerAsking::Nothing, + asking_blocks: Vec::new(), + asking_hash: None, + ask_time: Instant::now(), + last_sent_transactions: HashSet::new(), + expired: false, + confirmation: ForkConfirmation::Confirmed, + snapshot_number: None, + snapshot_hash: None, + asking_snapshot_data: None, + block_set: None, + }); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + SyncPropagator::propagate_proposed_blocks(&mut sync, &mut io, &[block]); + + // 1 message should be sent + assert_eq!(1, io.packets.len()); + // NEW_BLOCK_PACKET + assert_eq!(0x07, io.packets[0].packet_id); + } + + #[test] + fn propagates_transactions() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + // Try to propagate same transactions for the second time + let peer_count2 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + // Even after new block transactions should not be propagated twice + sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); + // Try to propagate same transactions for the third time + let peer_count3 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + // 1 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should be updated but only once + assert_eq!(1, peer_count); + assert_eq!(0, peer_count2); + assert_eq!(0, peer_count3); + // TRANSACTIONS_PACKET + assert_eq!(0x02, io.packets[0].packet_id); + } + + #[test] + fn does_not_propagate_new_transactions_after_new_block() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + io.chain.insert_transaction_to_queue(); + // New block import should not trigger propagation. + // (we only propagate on timeout) + sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); + + // 2 message should be send + assert_eq!(1, io.packets.len()); + // 1 peer should receive the message + assert_eq!(1, peer_count); + // TRANSACTIONS_PACKET + assert_eq!(0x02, io.packets[0].packet_id); + } + + #[test] + fn does_not_fail_for_no_peers() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + // Sync with no peers + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + sync.chain_new_blocks(&mut io, &[], &[], &[], &[], &[], &[]); + // Try to propagate same transactions for the second time + let peer_count2 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + assert_eq!(0, io.packets.len()); + assert_eq!(0, peer_count); + assert_eq!(0, peer_count2); + } + + #[test] + fn propagates_transactions_without_alternating() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + // should sent some + { + let mut io = TestIo::new(&mut client, &ss, &queue, None); + let peer_count = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + assert_eq!(1, io.packets.len()); + assert_eq!(1, peer_count); + } + // Insert some more + client.insert_transaction_to_queue(); + let (peer_count2, peer_count3) = { + let mut io = TestIo::new(&mut client, &ss, &queue, None); + // Propagate new transactions + let peer_count2 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + // And now the peer should have all transactions + let peer_count3 = SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + (peer_count2, peer_count3) + }; + + // 2 message should be send (in total) + assert_eq!(2, queue.read().len()); + // 1 peer should be updated but only once after inserting new transaction + assert_eq!(1, peer_count2); + assert_eq!(0, peer_count3); + // TRANSACTIONS_PACKET + assert_eq!(0x02, queue.read()[0].packet_id); + assert_eq!(0x02, queue.read()[1].packet_id); + } + + #[test] + fn should_maintain_transations_propagation_stats() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + client.insert_transaction_to_queue(); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(1), &client); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + let stats = sync.transactions_stats(); + assert_eq!(stats.len(), 1, "Should maintain stats for single transaction.") + } + + #[test] + fn should_propagate_service_transaction_to_selected_peers_only() { + let mut client = TestBlockChainClient::new(); + client.insert_transaction_with_gas_price_to_queue(U256::zero()); + let block_hash = client.block_hash_delta_minus(1); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + // when peer#1 is Geth + insert_dummy_peer(&mut sync, 1, block_hash); + io.peers_info.insert(1, "Geth".to_owned()); + // and peer#2 is Parity, accepting service transactions + insert_dummy_peer(&mut sync, 2, block_hash); + io.peers_info.insert(2, "Parity/v1.6".to_owned()); + // and peer#3 is Parity, discarding service transactions + insert_dummy_peer(&mut sync, 3, block_hash); + io.peers_info.insert(3, "Parity/v1.5".to_owned()); + // and peer#4 is Parity, accepting service transactions + insert_dummy_peer(&mut sync, 4, block_hash); + io.peers_info.insert(4, "Parity/v1.7.3-ABCDEFGH".to_owned()); + + // and new service transaction is propagated to peers + SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + // peer#2 && peer#4 are receiving service transaction + assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 2)); // TRANSACTIONS_PACKET + assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 4)); // TRANSACTIONS_PACKET + assert_eq!(io.packets.len(), 2); + } + + #[test] + fn should_propagate_service_transaction_is_sent_as_separate_message() { + let mut client = TestBlockChainClient::new(); + let tx1_hash = client.insert_transaction_to_queue(); + let tx2_hash = client.insert_transaction_with_gas_price_to_queue(U256::zero()); + let block_hash = client.block_hash_delta_minus(1); + let mut sync = ChainSync::new(SyncConfig::default(), &client, Arc::new(NoopPrivateTxHandler)); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + // when peer#1 is Parity, accepting service transactions + insert_dummy_peer(&mut sync, 1, block_hash); + io.peers_info.insert(1, "Parity/v1.6".to_owned()); + + // and service + non-service transactions are propagated to peers + SyncPropagator::propagate_new_transactions(&mut sync, &mut io); + + // two separate packets for peer are queued: + // 1) with non-service-transaction + // 2) with service transaction + let sent_transactions: Vec = io.packets.iter() + .filter_map(|p| { + if p.packet_id != 0x02 || p.recipient != 1 { // TRANSACTIONS_PACKET + return None; + } + + let rlp = Rlp::new(&*p.data); + let item_count = rlp.item_count().unwrap_or(0); + if item_count != 1 { + return None; + } + + rlp.at(0).ok().and_then(|r| r.as_val().ok()) + }) + .collect(); + assert_eq!(sent_transactions.len(), 2); + assert!(sent_transactions.iter().any(|tx| tx.hash() == tx1_hash)); + assert!(sent_transactions.iter().any(|tx| tx.hash() == tx2_hash)); + } +} diff --git a/ethcore/sync/src/chain/requester.rs b/ethcore/sync/src/chain/requester.rs new file mode 100644 index 0000000000..e6acf6bc53 --- /dev/null +++ b/ethcore/sync/src/chain/requester.rs @@ -0,0 +1,154 @@ +// Copyright 2015-2018 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 . + +use api::WARP_SYNC_PROTOCOL_ID; +use block_sync::BlockRequest; +use bytes::Bytes; +use ethcore::header::BlockNumber; +use ethereum_types::H256; +use network::{PeerId, PacketId}; +use rlp::RlpStream; +use std::time::Instant; +use sync_io::SyncIo; + +use super::{ + BlockSet, + ChainSync, + PeerAsking, + ETH_PACKET_COUNT, + GET_BLOCK_BODIES_PACKET, + GET_BLOCK_HEADERS_PACKET, + GET_RECEIPTS_PACKET, + GET_SNAPSHOT_DATA_PACKET, + GET_SNAPSHOT_MANIFEST_PACKET, +}; + +/// The Chain Sync Requester: requesting data to other peers +pub struct SyncRequester; + +impl SyncRequester { + /// Perform block download request` + pub fn request_blocks(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, request: BlockRequest, block_set: BlockSet) { + match request { + BlockRequest::Headers { start, count, skip } => { + SyncRequester::request_headers_by_hash(sync, io, peer_id, &start, count, skip, false, block_set); + }, + BlockRequest::Bodies { hashes } => { + SyncRequester::request_bodies(sync, io, peer_id, hashes, block_set); + }, + BlockRequest::Receipts { hashes } => { + SyncRequester::request_receipts(sync, io, peer_id, hashes, block_set); + }, + } + } + + /// Request block bodies from a peer + fn request_bodies(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { + let mut rlp = RlpStream::new_list(hashes.len()); + trace!(target: "sync", "{} <- GetBlockBodies: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); + for h in &hashes { + rlp.append(&h.clone()); + } + SyncRequester::send_request(sync, io, peer_id, PeerAsking::BlockBodies, GET_BLOCK_BODIES_PACKET, rlp.out()); + let peer = sync.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); + peer.asking_blocks = hashes; + peer.block_set = Some(set); + } + + /// Request headers from a peer by block number + pub fn request_fork_header(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, n: BlockNumber) { + trace!(target: "sync", "{} <- GetForkHeader: at {}", peer_id, n); + let mut rlp = RlpStream::new_list(4); + rlp.append(&n); + rlp.append(&1u32); + rlp.append(&0u32); + rlp.append(&0u32); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::ForkHeader, GET_BLOCK_HEADERS_PACKET, rlp.out()); + } + + /// Find some headers or blocks to download for a peer. + pub fn request_snapshot_data(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + // find chunk data to download + if let Some(hash) = sync.snapshot.needed_chunk() { + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + peer.asking_snapshot_data = Some(hash.clone()); + } + SyncRequester::request_snapshot_chunk(sync, io, peer_id, &hash); + } + } + + /// Request snapshot manifest from a peer. + pub fn request_snapshot_manifest(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + trace!(target: "sync", "{} <- GetSnapshotManifest", peer_id); + let rlp = RlpStream::new_list(0); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::SnapshotManifest, GET_SNAPSHOT_MANIFEST_PACKET, rlp.out()); + } + + /// Request headers from a peer by block hash + fn request_headers_by_hash(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, h: &H256, count: u64, skip: u64, reverse: bool, set: BlockSet) { + trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}, set = {:?}", peer_id, count, h, set); + let mut rlp = RlpStream::new_list(4); + rlp.append(h); + rlp.append(&count); + rlp.append(&skip); + rlp.append(&if reverse {1u32} else {0u32}); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out()); + let peer = sync.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); + peer.asking_hash = Some(h.clone()); + peer.block_set = Some(set); + } + + /// Request block receipts from a peer + fn request_receipts(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, hashes: Vec, set: BlockSet) { + let mut rlp = RlpStream::new_list(hashes.len()); + trace!(target: "sync", "{} <- GetBlockReceipts: {} entries starting from {:?}, set = {:?}", peer_id, hashes.len(), hashes.first(), set); + for h in &hashes { + rlp.append(&h.clone()); + } + SyncRequester::send_request(sync, io, peer_id, PeerAsking::BlockReceipts, GET_RECEIPTS_PACKET, rlp.out()); + let peer = sync.peers.get_mut(&peer_id).expect("peer_id may originate either from on_packet, where it is already validated or from enumerating self.peers. qed"); + peer.asking_blocks = hashes; + peer.block_set = Some(set); + } + + /// Request snapshot chunk from a peer. + fn request_snapshot_chunk(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, chunk: &H256) { + trace!(target: "sync", "{} <- GetSnapshotData {:?}", peer_id, chunk); + let mut rlp = RlpStream::new_list(1); + rlp.append(chunk); + SyncRequester::send_request(sync, io, peer_id, PeerAsking::SnapshotData, GET_SNAPSHOT_DATA_PACKET, rlp.out()); + } + + /// Generic request sender + fn send_request(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) { + if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) { + if peer.asking != PeerAsking::Nothing { + warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking); + } + peer.asking = asking; + peer.ask_time = Instant::now(); + let result = if packet_id >= ETH_PACKET_COUNT { + io.send_protocol(WARP_SYNC_PROTOCOL_ID, peer_id, packet_id, packet) + } else { + io.send(peer_id, packet_id, packet) + }; + if let Err(e) = result { + debug!(target:"sync", "Error sending request: {:?}", e); + io.disconnect_peer(peer_id); + } + } + } +} diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs new file mode 100644 index 0000000000..0bfb856982 --- /dev/null +++ b/ethcore/sync/src/chain/supplier.rs @@ -0,0 +1,446 @@ +// Copyright 2015-2018 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 . + +use bytes::Bytes; +use ethcore::client::BlockId; +use ethcore::header::BlockNumber; +use ethereum_types::H256; +use network::{self, PeerId}; +use parking_lot::RwLock; +use rlp::{Rlp, RlpStream}; +use std::cmp; +use sync_io::SyncIo; + +use super::{ + ChainSync, + RlpResponseResult, + PacketDecodeError, + BLOCK_BODIES_PACKET, + BLOCK_HEADERS_PACKET, + CONSENSUS_DATA_PACKET, + GET_BLOCK_BODIES_PACKET, + GET_BLOCK_HEADERS_PACKET, + GET_NODE_DATA_PACKET, + GET_RECEIPTS_PACKET, + GET_SNAPSHOT_DATA_PACKET, + GET_SNAPSHOT_MANIFEST_PACKET, + MAX_BODIES_TO_SEND, + MAX_HEADERS_TO_SEND, + MAX_NODE_DATA_TO_SEND, + MAX_RECEIPTS_HEADERS_TO_SEND, + MAX_RECEIPTS_TO_SEND, + NODE_DATA_PACKET, + RECEIPTS_PACKET, + SNAPSHOT_DATA_PACKET, + SNAPSHOT_MANIFEST_PACKET, +}; + +/// The Chain Sync Supplier: answers requests from peers with available data +pub struct SyncSupplier; + +impl SyncSupplier { + /// Dispatch incoming requests and responses + pub fn dispatch_packet(sync: &RwLock, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) { + let rlp = Rlp::new(data); + let result = match packet_id { + GET_BLOCK_BODIES_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_block_bodies, + |e| format!("Error sending block bodies: {:?}", e)), + + GET_BLOCK_HEADERS_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_block_headers, + |e| format!("Error sending block headers: {:?}", e)), + + GET_RECEIPTS_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_receipts, + |e| format!("Error sending receipts: {:?}", e)), + + GET_NODE_DATA_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_node_data, + |e| format!("Error sending nodes: {:?}", e)), + + GET_SNAPSHOT_MANIFEST_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_snapshot_manifest, + |e| format!("Error sending snapshot manifest: {:?}", e)), + + GET_SNAPSHOT_DATA_PACKET => SyncSupplier::return_rlp(io, &rlp, peer, + SyncSupplier::return_snapshot_data, + |e| format!("Error sending snapshot data: {:?}", e)), + CONSENSUS_DATA_PACKET => ChainSync::on_consensus_packet(io, peer, &rlp), + _ => { + sync.write().on_packet(io, peer, packet_id, data); + Ok(()) + } + }; + result.unwrap_or_else(|e| { + debug!(target:"sync", "{} -> Malformed packet {} : {}", peer, packet_id, e); + }) + } + + /// Respond to GetBlockHeaders request + fn return_block_headers(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + // Packet layout: + // [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ] + let max_headers: usize = r.val_at(1)?; + let skip: usize = r.val_at(2)?; + let reverse: bool = r.val_at(3)?; + let last = io.chain().chain_info().best_block_number; + let number = if r.at(0)?.size() == 32 { + // id is a hash + let hash: H256 = r.val_at(0)?; + trace!(target: "sync", "{} -> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", peer_id, hash, max_headers, skip, reverse); + match io.chain().block_header(BlockId::Hash(hash)) { + Some(hdr) => { + let number = hdr.number().into(); + debug_assert_eq!(hdr.hash(), hash); + + if max_headers == 1 || io.chain().block_hash(BlockId::Number(number)) != Some(hash) { + // Non canonical header or single header requested + // TODO: handle single-step reverse hashchains of non-canon hashes + trace!(target:"sync", "Returning single header: {:?}", hash); + let mut rlp = RlpStream::new_list(1); + rlp.append_raw(&hdr.into_inner(), 1); + return Ok(Some((BLOCK_HEADERS_PACKET, rlp))); + } + number + } + None => return Ok(Some((BLOCK_HEADERS_PACKET, RlpStream::new_list(0)))) //no such header, return nothing + } + } else { + trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, r.val_at::(0)?, max_headers, skip, reverse); + r.val_at(0)? + }; + + let mut number = if reverse { + cmp::min(last, number) + } else { + cmp::max(0, number) + }; + let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers); + let mut count = 0; + let mut data = Bytes::new(); + let inc = (skip + 1) as BlockNumber; + let overlay = io.chain_overlay().read(); + + while number <= last && count < max_count { + if let Some(hdr) = overlay.get(&number) { + trace!(target: "sync", "{}: Returning cached fork header", peer_id); + data.extend_from_slice(hdr); + count += 1; + } else if let Some(hdr) = io.chain().block_header(BlockId::Number(number)) { + data.append(&mut hdr.into_inner()); + count += 1; + } else { + // No required block. + break; + } + if reverse { + if number <= inc || number == 0 { + break; + } + number -= inc; + } + else { + number += inc; + } + } + let mut rlp = RlpStream::new_list(count as usize); + rlp.append_raw(&data, count as usize); + trace!(target: "sync", "{} -> GetBlockHeaders: returned {} entries", peer_id, count); + Ok(Some((BLOCK_HEADERS_PACKET, rlp))) + } + + /// Respond to GetBlockBodies request + fn return_block_bodies(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let mut count = r.item_count().unwrap_or(0); + if count == 0 { + debug!(target: "sync", "Empty GetBlockBodies request, ignoring."); + return Ok(None); + } + count = cmp::min(count, MAX_BODIES_TO_SEND); + let mut added = 0usize; + let mut data = Bytes::new(); + for i in 0..count { + if let Some(body) = io.chain().block_body(BlockId::Hash(r.val_at::(i)?)) { + data.append(&mut body.into_inner()); + added += 1; + } + } + let mut rlp = RlpStream::new_list(added); + rlp.append_raw(&data, added); + trace!(target: "sync", "{} -> GetBlockBodies: returned {} entries", peer_id, added); + Ok(Some((BLOCK_BODIES_PACKET, rlp))) + } + + /// Respond to GetNodeData request + fn return_node_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let mut count = r.item_count().unwrap_or(0); + trace!(target: "sync", "{} -> GetNodeData: {} entries", peer_id, count); + if count == 0 { + debug!(target: "sync", "Empty GetNodeData request, ignoring."); + return Ok(None); + } + count = cmp::min(count, MAX_NODE_DATA_TO_SEND); + let mut added = 0usize; + let mut data = Vec::new(); + for i in 0..count { + if let Some(node) = io.chain().state_data(&r.val_at::(i)?) { + data.push(node); + added += 1; + } + } + trace!(target: "sync", "{} -> GetNodeData: return {} entries", peer_id, added); + let mut rlp = RlpStream::new_list(added); + for d in data { + rlp.append(&d); + } + Ok(Some((NODE_DATA_PACKET, rlp))) + } + + fn return_receipts(io: &SyncIo, rlp: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let mut count = rlp.item_count().unwrap_or(0); + trace!(target: "sync", "{} -> GetReceipts: {} entries", peer_id, count); + if count == 0 { + debug!(target: "sync", "Empty GetReceipts request, ignoring."); + return Ok(None); + } + count = cmp::min(count, MAX_RECEIPTS_HEADERS_TO_SEND); + let mut added_headers = 0usize; + let mut added_receipts = 0usize; + let mut data = Bytes::new(); + for i in 0..count { + if let Some(mut receipts_bytes) = io.chain().block_receipts(&rlp.val_at::(i)?) { + data.append(&mut receipts_bytes); + added_receipts += receipts_bytes.len(); + added_headers += 1; + if added_receipts > MAX_RECEIPTS_TO_SEND { break; } + } + } + let mut rlp_result = RlpStream::new_list(added_headers); + rlp_result.append_raw(&data, added_headers); + Ok(Some((RECEIPTS_PACKET, rlp_result))) + } + + /// Respond to GetSnapshotManifest request + fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let count = r.item_count().unwrap_or(0); + trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); + if count != 0 { + debug!(target: "sync", "Invalid GetSnapshotManifest request, ignoring."); + return Ok(None); + } + let rlp = match io.snapshot_service().manifest() { + Some(manifest) => { + trace!(target: "sync", "{} <- SnapshotManifest", peer_id); + let mut rlp = RlpStream::new_list(1); + rlp.append_raw(&manifest.into_rlp(), 1); + rlp + }, + None => { + trace!(target: "sync", "{}: No manifest to return", peer_id); + RlpStream::new_list(0) + } + }; + Ok(Some((SNAPSHOT_MANIFEST_PACKET, rlp))) + } + + /// Respond to GetSnapshotData request + fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { + let hash: H256 = r.val_at(0)?; + trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); + let rlp = match io.snapshot_service().chunk(hash) { + Some(data) => { + let mut rlp = RlpStream::new_list(1); + trace!(target: "sync", "{} <- SnapshotData", peer_id); + rlp.append(&data); + rlp + }, + None => { + RlpStream::new_list(0) + } + }; + Ok(Some((SNAPSHOT_DATA_PACKET, rlp))) + } + + fn return_rlp(io: &mut SyncIo, rlp: &Rlp, peer: PeerId, rlp_func: FRlp, error_func: FError) -> Result<(), PacketDecodeError> + where FRlp : Fn(&SyncIo, &Rlp, PeerId) -> RlpResponseResult, + FError : FnOnce(network::Error) -> String + { + let response = rlp_func(io, rlp, peer); + match response { + Err(e) => Err(e), + Ok(Some((packet_id, rlp_stream))) => { + io.respond(packet_id, rlp_stream.out()).unwrap_or_else( + |e| debug!(target: "sync", "{:?}", error_func(e))); + Ok(()) + } + _ => Ok(()) + } + } +} + +#[cfg(test)] +mod test { + use std::collections::{VecDeque}; + use tests::helpers::{TestIo}; + use tests::snapshot::TestSnapshotService; + use ethereum_types::{H256}; + use parking_lot::RwLock; + use bytes::Bytes; + use rlp::{Rlp, RlpStream}; + use super::{*, super::tests::*}; + use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient}; + + #[test] + fn return_block_headers() { + use ethcore::views::HeaderView; + fn make_hash_req(h: &H256, count: usize, skip: usize, reverse: bool) -> Bytes { + let mut rlp = RlpStream::new_list(4); + rlp.append(h); + rlp.append(&count); + rlp.append(&skip); + rlp.append(&if reverse {1u32} else {0u32}); + rlp.out() + } + + fn make_num_req(n: usize, count: usize, skip: usize, reverse: bool) -> Bytes { + let mut rlp = RlpStream::new_list(4); + rlp.append(&n); + rlp.append(&count); + rlp.append(&skip); + rlp.append(&if reverse {1u32} else {0u32}); + rlp.out() + } + fn to_header_vec(rlp: ::chain::RlpResponseResult) -> Vec { + Rlp::new(&rlp.unwrap().unwrap().1.out()).iter().map(|r| r.as_raw().to_vec()).collect() + } + + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Nothing); + let blocks: Vec<_> = (0 .. 100) + .map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect(); + let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).unwrap().as_raw().to_vec()).collect(); + let hashes: Vec<_> = headers.iter().map(|h| view!(HeaderView, h).hash()).collect(); + + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let io = TestIo::new(&mut client, &ss, &queue, None); + + let unknown: H256 = H256::new(); + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, false)), 0); + assert!(to_header_vec(result).is_empty()); + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&unknown, 1, 0, true)), 0); + assert!(to_header_vec(result).is_empty()); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[2], 1, 0, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_hash_req(&hashes[50], 3, 5, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(2, 1, 0, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[2].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, false)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[56].clone(), headers[62].clone()]); + + let result = SyncSupplier::return_block_headers(&io, &Rlp::new(&make_num_req(50, 3, 5, true)), 0); + assert_eq!(to_header_vec(result), vec![headers[50].clone(), headers[44].clone(), headers[38].clone()]); + } + + #[test] + fn return_nodes() { + let mut client = TestBlockChainClient::new(); + let queue = RwLock::new(VecDeque::new()); + let sync = dummy_sync_with_peer(H256::new(), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let mut node_list = RlpStream::new_list(3); + node_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); + node_list.append(&H256::from("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa")); + node_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); + + let node_request = node_list.out(); + // it returns rlp ONLY for hashes started with "f" + let result = SyncSupplier::return_node_data(&io, &Rlp::new(&node_request.clone()), 0); + + assert!(result.is_ok()); + let rlp_result = result.unwrap(); + assert!(rlp_result.is_some()); + + // the length of one rlp-encoded hashe + let rlp = rlp_result.unwrap().1.out(); + let rlp = Rlp::new(&rlp); + assert_eq!(Ok(1), rlp.item_count()); + + io.sender = Some(2usize); + + ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, GET_NODE_DATA_PACKET, &node_request); + assert_eq!(1, io.packets.len()); + } + + #[test] + fn return_receipts_empty() { + let mut client = TestBlockChainClient::new(); + let queue = RwLock::new(VecDeque::new()); + let ss = TestSnapshotService::new(); + let io = TestIo::new(&mut client, &ss, &queue, None); + + let result = SyncSupplier::return_receipts(&io, &Rlp::new(&[0xc0]), 0); + + assert!(result.is_ok()); + } + + #[test] + fn return_receipts() { + let mut client = TestBlockChainClient::new(); + let queue = RwLock::new(VecDeque::new()); + let sync = dummy_sync_with_peer(H256::new(), &client); + let ss = TestSnapshotService::new(); + let mut io = TestIo::new(&mut client, &ss, &queue, None); + + let mut receipt_list = RlpStream::new_list(4); + receipt_list.append(&H256::from("0000000000000000000000000000000000000000000000005555555555555555")); + receipt_list.append(&H256::from("ff00000000000000000000000000000000000000000000000000000000000000")); + receipt_list.append(&H256::from("fff0000000000000000000000000000000000000000000000000000000000000")); + receipt_list.append(&H256::from("aff0000000000000000000000000000000000000000000000000000000000000")); + + let receipts_request = receipt_list.out(); + // it returns rlp ONLY for hashes started with "f" + let result = SyncSupplier::return_receipts(&io, &Rlp::new(&receipts_request.clone()), 0); + + assert!(result.is_ok()); + let rlp_result = result.unwrap(); + assert!(rlp_result.is_some()); + + // the length of two rlp-encoded receipts + assert_eq!(603, rlp_result.unwrap().1.out().len()); + + io.sender = Some(2usize); + ChainSync::dispatch_packet(&RwLock::new(sync), &mut io, 0usize, GET_RECEIPTS_PACKET, &receipts_request); + assert_eq!(1, io.packets.len()); + } +} diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index 2f6441f4f2..804ebe9c53 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -22,7 +22,7 @@ use parking_lot::Mutex; use bytes::Bytes; use ethcore::snapshot::{SnapshotService, ManifestData, RestorationStatus}; use ethcore::header::BlockNumber; -use ethcore::client::{EachBlockWith}; +use ethcore::client::EachBlockWith; use super::helpers::*; use {SyncConfig, WarpSync}; @@ -99,7 +99,15 @@ impl SnapshotService for TestSnapshotService { } fn begin_restore(&self, manifest: ManifestData) { - *self.restoration_manifest.lock() = Some(manifest); + let mut restoration_manifest = self.restoration_manifest.lock(); + + if let Some(ref c_manifest) = *restoration_manifest { + if c_manifest.state_root == manifest.state_root { + return; + } + } + + *restoration_manifest = Some(manifest); self.state_restoration_chunks.lock().clear(); self.block_restoration_chunks.lock().clear(); } -- GitLab From 842b75c0e63f76e1b77d75529c7f6c3f4969d8d7 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 9 May 2018 12:05:56 +0200 Subject: [PATCH 133/263] Decoding headers can fail (#8570) * rlp::decode returns Result * Fix journaldb to handle rlp::decode Result * Fix ethcore to work with rlp::decode returning Result * Light client handles rlp::decode returning Result * Fix tests in rlp_derive * Fix tests * Cleanup * cleanup * Allow panic rather than breaking out of iterator * Let decoding failures when reading from disk blow up * syntax * Fix the trivial grumbles * Fix failing tests * Make Account::from_rlp return Result * Syntx, sigh * Temp-fix for decoding failures * Header::decode returns Result Handle new return type throughout the code base. * Do not continue reading from the DB when a value could not be read * Fix tests * Handle header decoding in light_sync * Handling header decoding errors * Let the DecodeError bubble up unchanged * Remove redundant error conversion --- ethcore/light/src/client/header_chain.rs | 10 ++++--- ethcore/light/src/client/mod.rs | 12 ++++++-- ethcore/src/client/client.rs | 14 ++++++---- ethcore/src/client/test_client.rs | 5 ++-- ethcore/src/encoded.rs | 6 ++-- ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/error.rs | 10 +++++-- ethcore/src/miner/miner.rs | 11 ++++++-- ethcore/src/snapshot/mod.rs | 2 +- ethcore/src/verification/verification.rs | 5 ++-- ethcore/sync/src/light_sync/response.rs | 32 ++++++++++++---------- ethcore/sync/src/light_sync/tests/mod.rs | 2 +- rpc/src/v1/helpers/errors.rs | 13 +++++++++ rpc/src/v1/impls/eth.rs | 13 +++++---- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 2 +- rpc/src/v1/impls/parity.rs | 4 +-- rpc/src/v1/impls/traces.rs | 6 ++-- 18 files changed, 98 insertions(+), 53 deletions(-) diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 02a18a60df..b85091e53b 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -305,7 +305,7 @@ impl HeaderChain { batch.put(col, cht_key(cht_num as u64).as_bytes(), &::rlp::encode(cht_root)); } - let decoded_header = hardcoded_sync.header.decode(); + let decoded_header = hardcoded_sync.header.decode()?; let decoded_header_num = decoded_header.number(); // write the block in the DB. @@ -585,7 +585,7 @@ impl HeaderChain { bail!(ErrorKind::Database(msg.into())); }; - let decoded = header.decode(); + let decoded = header.decode().expect("decoding db value failed"); let entry: Entry = { let bytes = self.db.get(self.col, era_key(h_num).as_bytes())? @@ -815,7 +815,9 @@ impl HeaderChain { 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)) + return hdr.decode().map(|decoded_hdr| { + (decoded_hdr, transition.proof) + }).ok(); } } @@ -1224,7 +1226,7 @@ mod tests { let hardcoded_sync = chain.read_hardcoded_sync().expect("failed reading hardcoded sync").expect("failed unwrapping hardcoded sync"); assert_eq!(hardcoded_sync.chts.len(), 3); assert_eq!(hardcoded_sync.total_difficulty, total_difficulty); - let decoded: Header = hardcoded_sync.header.decode(); + let decoded: Header = hardcoded_sync.header.decode().expect("decoding failed"); assert_eq!(decoded.number(), h_num); } } diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index cf603d853f..82b424cc83 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -318,7 +318,7 @@ impl Client { 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.block_header(BlockId::Hash(h)).and_then(|hdr| hdr.decode().ok()), &|h| self.chain.pending_transition(h), ); @@ -426,7 +426,15 @@ impl Client { }; // Verify Block Family - let verify_family_result = self.engine.verify_block_family(&verified_header, &parent_header.decode()); + + let verify_family_result = { + parent_header.decode() + .map_err(|dec_err| dec_err.into()) + .and_then(|decoded| { + self.engine.verify_block_family(&verified_header, &decoded) + }) + + }; if let Err(e) = verify_family_result { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", verified_header.number(), verified_header.hash(), e); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index bffa4e38ba..76d78e3df6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1219,8 +1219,7 @@ impl Client { => Some(self.chain.read().best_block_header()), BlockId::Number(number) if number == self.chain.read().best_block_number() => Some(self.chain.read().best_block_header()), - _ - => self.block_header(id).map(|h| h.decode()), + _ => self.block_header(id).and_then(|h| h.decode().ok()) } } } @@ -1915,7 +1914,11 @@ impl BlockChainClient for Client { fn uncle_extra_info(&self, id: UncleId) -> Option> { self.uncle(id) - .map(|header| self.engine.extra_info(&header.decode())) + .and_then(|h| { + h.decode().map(|dh| { + self.engine.extra_info(&dh) + }).ok() + }) } fn pruning_info(&self) -> PruningInfo { @@ -2033,7 +2036,8 @@ impl ReopenBlock for Client { for h in uncles { if !block.uncles().iter().any(|header| header.hash() == h) { let uncle = chain.block_header_data(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed"); - block.push_uncle(uncle.decode()).expect("pushing up to maximum_uncle_count; + let uncle = uncle.decode().expect("decoding failure"); + block.push_uncle(uncle).expect("pushing up to maximum_uncle_count; push_uncle is not ok only if more than maximum_uncle_count is pushed; so all push_uncle are Ok; qed"); @@ -2074,7 +2078,7 @@ impl PrepareOpenBlock for Client { .into_iter() .take(engine.maximum_uncle_count(open_block.header().number())) .foreach(|h| { - open_block.push_uncle(h.decode()).expect("pushing maximum_uncle_count; + open_block.push_uncle(h.decode().expect("decoding failure")).expect("pushing maximum_uncle_count; open_block was just created; push_uncle is not ok only if more than maximum_uncle_count is pushed; so all push_uncle are Ok; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index b229159667..6a3166f7c0 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -289,7 +289,7 @@ impl TestBlockChainClient { /// Make a bad block by setting invalid extra data. pub fn corrupt_block(&self, n: BlockNumber) { let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode(); + let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode().expect("decoding failed"); header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec()); let mut rlp = RlpStream::new_list(3); rlp.append(&header); @@ -301,7 +301,7 @@ impl TestBlockChainClient { /// Make a bad block by setting invalid parent hash. pub fn corrupt_block_parent(&self, n: BlockNumber) { let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode(); + let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode().expect("decoding failed"); header.set_parent_hash(H256::from(42)); let mut rlp = RlpStream::new_list(3); rlp.append(&header); @@ -479,6 +479,7 @@ impl BlockInfo for TestBlockChainClient { self.block_header(BlockId::Hash(self.chain_info().best_block_hash)) .expect("Best block always has header.") .decode() + .expect("decoding failed") } fn block(&self, id: BlockId) -> Option { diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 01df386cc2..c436607f8c 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -28,7 +28,7 @@ use ethereum_types::{H256, Bloom, U256, Address}; use hash::keccak; use header::{BlockNumber, Header as FullHeader}; use heapsize::HeapSizeOf; -use rlp::{Rlp, RlpStream}; +use rlp::{self, Rlp, RlpStream}; use transaction::UnverifiedTransaction; use views::{self, BlockView, HeaderView, BodyView}; @@ -47,7 +47,9 @@ impl Header { pub fn new(encoded: Vec) -> Self { Header(encoded) } /// Upgrade this encoded view to a fully owned `Header` object. - pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0).expect("decoding failure") } + pub fn decode(&self) -> Result { + rlp::decode(&self.0) + } /// Get a borrowed header view onto the data. #[inline] diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index c2aee7c6ef..ed9a9a4f25 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -996,7 +996,7 @@ impl Engine for AuthorityRound { let parent = client.block_header(::client::BlockId::Hash(*block.header().parent_hash())) .expect("hash is from parent; parent header must exist; qed") - .decode(); + .decode()?; let parent_step = header_step(&parent, self.empty_steps_transition)?; let current_step = self.step.load(); diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 561701e762..bec749297c 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -290,6 +290,12 @@ error_chain! { description("Unknown engine name") display("Unknown engine name ({})", name) } + + #[doc = "RLP decoding errors"] + Decoder(err: ::rlp::DecoderError) { + description("decoding value failed") + display("decoding value failed with error: {}", err) + } } } @@ -310,11 +316,11 @@ impl From for Error { fn from(err: AccountsError) -> Error { ErrorKind::AccountProvider(err).into() } -} +} impl From<::rlp::DecoderError> for Error { fn from(err: ::rlp::DecoderError) -> Error { - UtilError::from(err).into() + ErrorKind::Decoder(err).into() } } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 76a011343f..3168ff1a84 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -528,8 +528,8 @@ impl Miner { } /// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal. - fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool where - C: BlockChain + SealedBlockImporter, + fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool + where C: BlockChain + SealedBlockImporter, { { let sealing = self.sealing.lock(); @@ -544,7 +544,12 @@ impl Miner { trace!(target: "miner", "seal_block_internally: attempting internal seal."); let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) { - Some(hdr) => hdr.decode(), + Some(h) => { + match h.decode() { + Ok(decoded_hdr) => decoded_hdr, + Err(_) => return false + } + } None => return false, }; diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 94236e9e95..8871ced26f 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -487,7 +487,7 @@ pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &EthEngine, ch if always || rng.gen::() <= POW_VERIFY_RATE { engine.verify_block_unordered(header)?; match chain.block_header_data(header.parent_hash()) { - Some(parent) => engine.verify_block_family(header, &parent.decode()), + Some(parent) => engine.verify_block_family(header, &parent.decode()?), None => Ok(()), } } else { diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 92f3e77f90..03a6d6f8d4 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -224,7 +224,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth return Err(From::from(BlockError::UncleParentNotInChain(uncle_parent.hash()))); } - let uncle_parent = uncle_parent.decode(); + let uncle_parent = uncle_parent.decode()?; verify_parent(&uncle, &uncle_parent, engine)?; engine.verify_block_family(&uncle, &uncle_parent)?; verified.insert(uncle.hash()); @@ -500,10 +500,9 @@ mod tests { // no existing tests need access to test, so having this not function // is fine. let client = ::client::TestBlockChainClient::default(); - let parent = bc.block_header_data(header.parent_hash()) .ok_or(BlockError::UnknownParent(header.parent_hash().clone()))? - .decode(); + .decode()?; let full_params = FullFamilyParams { block_bytes: bytes, diff --git a/ethcore/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs index 4dfb383d46..74665118b7 100644 --- a/ethcore/sync/src/light_sync/response.rs +++ b/ethcore/sync/src/light_sync/response.rs @@ -16,13 +16,11 @@ //! Helpers for decoding and verifying responses for headers. -use std::fmt; - -use ethcore::encoded; -use ethcore::header::Header; +use ethcore::{self, encoded, header::Header}; +use ethereum_types::H256; use light::request::{HashOrNumber, CompleteHeadersRequest as HeadersRequest}; use rlp::DecoderError; -use ethereum_types::H256; +use std::fmt; /// Errors found when decoding headers and verifying with basic constraints. #[derive(Debug, PartialEq)] @@ -74,19 +72,23 @@ pub trait Constraint { /// Do basic verification of provided headers against a request. pub fn verify(headers: &[encoded::Header], request: &HeadersRequest) -> Result, BasicError> { - let headers: Vec<_> = headers.iter().map(|h| h.decode()).collect(); + let headers: Result, _> = headers.iter().map(|h| h.decode() ).collect(); + match headers { + Ok(headers) => { + let reverse = request.reverse; + + Max(request.max as usize).verify(&headers, reverse)?; + match request.start { + HashOrNumber::Number(ref num) => StartsAtNumber(*num).verify(&headers, reverse)?, + HashOrNumber::Hash(ref hash) => StartsAtHash(*hash).verify(&headers, reverse)?, + } - let reverse = request.reverse; + SkipsBetween(request.skip).verify(&headers, reverse)?; - Max(request.max as usize).verify(&headers, reverse)?; - match request.start { - HashOrNumber::Number(ref num) => StartsAtNumber(*num).verify(&headers, reverse)?, - HashOrNumber::Hash(ref hash) => StartsAtHash(*hash).verify(&headers, reverse)?, + Ok(headers) + }, + Err(e) => Err(e.into()) } - - SkipsBetween(request.skip).verify(&headers, reverse)?; - - Ok(headers) } struct StartsAtNumber(u64); diff --git a/ethcore/sync/src/light_sync/tests/mod.rs b/ethcore/sync/src/light_sync/tests/mod.rs index 9fd270838b..3fee1c7170 100644 --- a/ethcore/sync/src/light_sync/tests/mod.rs +++ b/ethcore/sync/src/light_sync/tests/mod.rs @@ -45,7 +45,7 @@ fn fork_post_cht() { for id in (0..CHAIN_LENGTH).map(|x| x + 1).map(BlockId::Number) { let (light_peer, full_peer) = (net.peer(0), net.peer(1)); let light_chain = light_peer.light_chain(); - let header = full_peer.chain().block_header(id).unwrap().decode(); + let header = full_peer.chain().block_header(id).unwrap().decode().expect("decoding failure"); let _ = light_chain.import_header(header); light_chain.flush_queue(); light_chain.import_verified(); diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 4f3289a116..c85beef7d5 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -360,6 +360,19 @@ pub fn transaction>(error: T) -> Error { } } +pub fn decode>(error: T) -> Error { + let error = error.into(); + match *error.kind() { + ErrorKind::Decoder(ref dec_err) => rlp(dec_err.clone()), + _ => Error { + code: ErrorCode::InternalError, + message: "decoding error".into(), + data: None, + } + + } +} + pub fn rlp(error: DecoderError) -> Error { Error { code: ErrorCode::InvalidParams, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a7ff4916de..389805c176 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -343,7 +343,10 @@ impl EthClient hdr.decode(), + Some(hdr) => match hdr.decode() { + Ok(h) => h, + Err(e) => return Err(errors::decode(e)) + }, None => { return Ok(None); } }; @@ -851,9 +854,9 @@ impl Eth for EthClient< }; let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned())); - let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned())); + let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned()).and_then(|h| h.decode().map_err(errors::decode))); - (state, header.decode()) + (state, header) }; let result = self.client.call(&signed, Default::default(), &mut state, &header); @@ -890,9 +893,9 @@ impl Eth for EthClient< }; let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned())); - let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned())); + let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned()).and_then(|h| h.decode().map_err(errors::decode))); - (state, header.decode()) + (state, header) }; Box::new(future::done(self.client.estimate_gas(&signed, &state, &header) diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index eeef12da6e..35f7792b52 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -371,7 +371,7 @@ impl Eth for EthClient { } fn send_raw_transaction(&self, raw: Bytes) -> Result { - let best_header = self.client.best_block_header().decode(); + let best_header = self.client.best_block_header().decode().map_err(errors::decode)?; Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 3d31d9e676..982c7ff363 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -395,7 +395,7 @@ impl Parity for ParityClient { let engine = self.light_dispatch.client.engine().clone(); let from_encoded = move |encoded: encoded::Header| { - let header = encoded.decode(); + let header = encoded.decode().expect("decoding error"); // REVIEW: not sure what to do here; what is a decent return value for the error case here? let extra_info = engine.extra_info(&header); RichHeader { inner: Header { diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index db66bddc7e..08d5147202 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -487,9 +487,9 @@ impl Parity for ParityClient where }; let state = self.client.state_at(id).ok_or(errors::state_pruned())?; - let header = self.client.block_header(id).ok_or(errors::state_pruned())?; + let header = self.client.block_header(id).ok_or(errors::state_pruned())?.decode().map_err(errors::decode)?; - (state, header.decode()) + (state, header) }; self.client.call_many(&requests, &mut state, &header) diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index bf4dc83beb..0130b3b9c1 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -104,7 +104,7 @@ impl Traces for TracesClient where let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; let header = self.client.block_header(id).ok_or(errors::state_pruned())?; - self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode()) + self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode().map_err(errors::decode)?) .map(TraceResults::from) .map_err(errors::call) } @@ -131,7 +131,7 @@ impl Traces for TracesClient where let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; let header = self.client.block_header(id).ok_or(errors::state_pruned())?; - self.client.call_many(&requests, &mut state, &header.decode()) + self.client.call_many(&requests, &mut state, &header.decode().map_err(errors::decode)?) .map(|results| results.into_iter().map(TraceResults::from).collect()) .map_err(errors::call) } @@ -153,7 +153,7 @@ impl Traces for TracesClient where let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?; let header = self.client.block_header(id).ok_or(errors::state_pruned())?; - self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode()) + self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode().map_err(errors::decode)?) .map(TraceResults::from) .map_err(errors::call) } -- GitLab From 25536c5ffb42136291a371efe0998c1b21354b47 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 9 May 2018 14:11:36 +0200 Subject: [PATCH 134/263] Update CHANGELOG for 1.9, 1.10, and 1.11 (#8556) * Move changelog for 1.10.x * Mark 1.9 EOL * Prepare changelog for 1.10.3 stable * Prepare changelog for 1.11.0 stable * Update changelogs * Update CHANGELOG for 1.10.3 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Format changelog --- CHANGELOG.md | 530 +++++++++++++++++++++-------------------- docs/CHANGELOG-1.10.md | 325 +++++++++++++++++++++++++ docs/CHANGELOG-1.9.md | 2 + 3 files changed, 594 insertions(+), 263 deletions(-) create mode 100644 docs/CHANGELOG-1.10.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6272c32a7e..0c7dcf878b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,272 +1,276 @@ -## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24) - -Parity 1.10.2 is a bug-fix release to improve performance and stability. - -The full list of included changes: - -- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455)) - - Update Parity beta to 1.10.2 - - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) - - Disable 32-bit targets for Gitlab - - Rename Linux pipelines - - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) - - Fix Cargo.lock -- Backports ([#8450](https://github.com/paritytech/parity/pull/8450)) - - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) - - Remove unused app_dirs dependency in CLI - - Use forked app_dirs crate for reverted Windows dir behavior - - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) - - Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) - - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) - - Improve VM executor stack size estimation rules - - Typo: docs add "(Debug build)" comment - - Fix an off by one typo and set minimal stack size - - Use saturating_sub to avoid potential overflow - -## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) - -Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. - -The full list of included changes: - -- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350)) - - Bump beta to 1.10.1 - - Unflag critical release -- Backports ([#8346](https://github.com/paritytech/parity/pull/8346)) - - Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) - - Warp-only sync with warp-after [blocknumber] flag. - - Fix tests. - - Fix configuration tests. - - Rename to warp barrier. - - Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) - - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) - - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) - - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) - - Include suicided accounts in state diff - - Shorten form match -> if let - - Test suicide trace diff in State - - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) - - Replace_home for password_files, reserved_peers and log_file - - Typo: arg_log_file is Option - - Enable UI by default, but only display info page. - - Fix test. - - Fix naming and remove old todo. - - Change "wallet" with "browser UI" -- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205)) - - Change name Wallet -> UI - - Make warning bold -- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132)) -- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220)) - - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) - - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) -- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203)) -- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181)) - - Updated jsonrpc to include latest backports - - Update dependencies. - -## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22) - -This is the Parity 1.10.0-beta release! Cool! - -### Disabling the Parity Wallet - -The **Parity Wallet (a.k.a. "UI") is now disabled by default**. We are preparing to split the wallet from the core client. - -To reactivate the parity wallet, you have to run Parity either with `parity --force-ui` (not recommended) or `parity ui` (deprecated) from the command line. Or, if you feel super fancy and want to test our pre-releases of the stand-alone electron wallet, head over to the [Parity-JS repositories and check the releases](https://github.com/Parity-JS/shell/releases). - -Further reading: - -- [Docs: Parity Wallet](https://wiki.parity.io/Parity-Wallet) -- [Docs: How to customize Parity UI?](https://wiki.parity.io/FAQ-Customize-Parity-UI.html) -- [Github: Parity-JS](https://github.com/parity-js) - -### Introducing the Wasm VM - -We are excited to announce support for **Wasm Smart Contracts on Kovan network**. The hard-fork to activate the Wasm-VM will take place on block `6_600_000`. - -To enable Wasm contracts on your custom network, just schedule a `wasmActivationTransition` at your favorite block number (e.g., `42`, `666`, or `0xbada55`). To hack your first Wasm smart contracts in Rust, have a look at the [Parity Wasm Tutorials](https://github.com/paritytech/pwasm-tutorial). - -Further reading: - -- [Docs: WebAssembly (wasm)](https://wiki.parity.io/WebAssembly-Home) -- [Docs: Wasm VM Design](https://wiki.parity.io/WebAssembly-Design) -- [Docs: Wasm tutorials and examples](https://wiki.parity.io/WebAssembly-Links) - -### Empty step messages in PoA - -To **reduce blockchain bloat, proof-of-authority networks can now enable _empty step messages_ which replace empty blocks**. Each step message will be signed and broadcasted by the issuing authorities, and included and rewarded in the next non-empty block. - -To enable empty step messages, set the `emptyStepsTransition` to your favorite block number. You can also specify a maximum number of empty steps with `maximumEmptySteps` in your chain spec. - -### Other noteworthy changes - -We removed the old database migrations from 2016. In case you upgrade Parity from a really, really old version, you will have to reset your database manually first with `parity db kill`. - -We fixed DELEGATECALL `from` and `to` fields, see [#7166](https://github.com/paritytech/parity/issues/7166). - -We reduced the default USD per transaction value to 0.0001. Thanks, @MysticRyuujin! - -The Musicoin chain is now enabled with Byzantium features starting at block `2_222_222`. - -### Overview of all changes included +## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-05-09) + +This is the Parity 1.11.0-beta release! Hurray! + +Notable changes in reversed alphabetical order: + +- TOOLING: **Whisper CLI** [#8201](https://github.com/paritytech/parity/pull/8201) + - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. + - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. + - All whisper RPC APIs are enabled and can be directly acessed. +I'm not used to writing these changelogs but I guess that would explain it +- JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) + - This changes the behaviors of `eth_call` to respect VM errors if any. + - In case of `REVERT`, it will also return the reverted return data in hex format. +- ENGINES: **Block reward contract** [#8419](https://github.com/paritytech/parity/pull/8419) + - The _AuRa_ PoA engine has now support for having a contract to calculate the block rewards. + - The engine passes a list of benefactors and reward types to the contract which then returns a list of addresses and respective rewards. +- CORE: **Private transactions integration pr** [#6422](https://github.com/paritytech/parity/pull/6422) + - Parity now provides a private transactions system. + - Please, check out our wiki to get and [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). +- CORE: **New Transaction Queue implementation** [#8074](https://github.com/paritytech/parity/pull/8074) + - Verification is now done in parallel. + - Previous queue had `O(1)` time to get pending set, but `O(n^2)` insertion time. And obviously insertion/removal happens much more often than retrieving the pending set (only for propagation and pending block building) Currently we have `O(n * log(senders))` pending set time (with cache) and `O(tx_per_sender)` (usually within `log(tx_per_sender)`) insertion time. + - `Scoring` and `Readiness` are separated from the pool, so it's easier to customize them or introduce different definitions (for instance for [EIP-859](https://github.com/ethereum/EIPs/issues/859) or private transactions, etc). + - Banning removed, soft-penalization introduced instead: if transaction exceeds the limit other transactions from that sender get lower priority. + - There is no explicit distinction between current and future transactions in the pool - `Readiness` determines that. Because of this we additionally remove `future` transactions that occupy the pool for long time. +- CONFIGURATION: **Warp-only sync with --warp-barrier [block-number] flag.** [#8228](https://github.com/paritytech/parity/pull/8228) + - Enables warp-only sync in case `--warp-barrier [block-number]` is provided. + - This avoids clients to warp to outdated snapshots that are too far away from the best block. + - This avoids clients to fall back to normal sync if there are no recent snapshots available currently. +- CONFIGURATION: **Disable UI by default.** [#8105](https://github.com/paritytech/parity/pull/8105) + - The user interface is now disabled by default. It still can be activated with the `--force-ui` flag. + - To get the stand-alone Parity UI, please check the dedicated [releases page](https://github.com/parity-js/shell/releases). +- CONFIGURATION: **Auto-updater improvements** [#8078](https://github.com/paritytech/parity/pull/8078) + - Added `--auto-update-delay` to randomly delay updates by `n` blocks. This takes into account the number of the block of the update release (old updates aren't delayed). + - Added `--auto-update-check-frequency` to define the periodicity of auto-update checks in number of blocks. + - This is an important improvement to ensure the network does not update all clients at the same time. +- CHAIN SPECS: **Enable WebAssembly and Byzantium for Ellaism** [#8520](https://github.com/paritytech/parity/pull/8520) + - This activates the Ellaism Byzantium hardfork ([2018-0004-byzantium](https://github.com/ellaism/specs/blob/master/specs/2018-0004-byzantium.md)) at block `2_000_000`. + - This enables the Wasm VM on Ellaism ([2018-0003-wasm-hardfork](https://github.com/ellaism/specs/blob/master/specs/2018-0003-wasm-hardfork.md)) at block `2_000_000`. + - Please, upgrade your clients if you run an Ellaism configuration. +- CHAIN SPECS: **Dev chain - increase gasLimit to 8_000_000** [#8362](https://github.com/paritytech/parity/pull/8362) + - This increases the default block gas limit on development chains to `8_000_000`. + - Please note, this makes previous dev chain configurations incompatible. +- CHAIN SPECS: **Add MCIP-6 Byzyantium transition to Musicoin spec** [#7841](https://github.com/paritytech/parity/pull/7841) + - This activates the Musicoin Byzantium hardfork ([MCIP-6](https://github.com/Musicoin/MCIPs/blob/master/MCIPS/mcip-6.md)) at block `2_222_222`. + - Please, upgrade your clients if you run a Musicoin configuration. The full list of included changes: -- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) ([#8168](https://github.com/paritytech/parity/pull/8168)) - - Re-enable signer, even with no UI. - - Fix message. -- Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136)) - - Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) - - updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) - - updater: apply exponential backoff after download failure - - updater: reset backoff on new release - - Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) - - Enable code size limit on kovan - - Fix formatting. - - Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) - - Limit ingress connections - - Optimized handshakes logging - - WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) - - update wasmi, parity-wasm, wasm-utils to latest version - - Update to new wasmi & error handling - - also utilize new stack limiter - - fix typo - - replace dependency url - - Cargo.lock update - - add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) - - revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) - - Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)" - - Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))" - - fixed broken logs - - bring back old lock order - - remove migration v13 - - revert CURRENT_VERSION to 12 in migration.rs - - more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) - - Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) - - Use `subtle::slices_equal` for constant time comparison. - - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 - - Test specifically for InvalidPassword error. - - fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098)) - - network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) - - network: init discovery using healthy nodes - - network: fix style grumble - - network: fix typo - - Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) - - ethcore: postpone Kovan hard fork - - util: update version fork metadata - - Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) - - dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) -- Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135)) -- Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053)) - - CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) - - Fix cache - - Only clean locked cargo cache on windows - - fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) - - fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) - - fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) - - fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) - - Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) - - Add test chain spec for musicoin byzantium testnet - - Add MCIP-6 Byzyantium transition to Musicoin spec - - Update mcip6_byz.json - - ethcore: update musicoin byzantium block number - - ethcore: update musicoin bootnodes - - Update musicoin.json - - More bootnodes. -- Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022)) - - Make 1.10 beta - - Fix gitlab builds -- SecretStore: secretstore_generateDocumentKey RPC ([#7864](https://github.com/paritytech/parity/pull/7864)) -- SecretStore: ECDSA session for cases when 2*t < N ([#7739](https://github.com/paritytech/parity/pull/7739)) -- bump tiny-keccak ([#8019](https://github.com/paritytech/parity/pull/8019)) -- Remove un-necessary comment ([#8014](https://github.com/paritytech/parity/pull/8014)) -- clean up account fmt::Debug ([#7983](https://github.com/paritytech/parity/pull/7983)) -- improve quality of vote_collector module ([#7984](https://github.com/paritytech/parity/pull/7984)) -- ExecutedBlock cleanup ([#7991](https://github.com/paritytech/parity/pull/7991)) -- Hardware-wallet/usb-subscribe-refactor ([#7860](https://github.com/paritytech/parity/pull/7860)) -- remove wildcard imports from views, make tests more idiomatic ([#7986](https://github.com/paritytech/parity/pull/7986)) -- moved PerfTimer to a separate crate - "trace-time" ([#7985](https://github.com/paritytech/parity/pull/7985)) -- clean up ethcore::spec module imports ([#7990](https://github.com/paritytech/parity/pull/7990)) -- rpc: don't include current block in new_block_filter ([#7982](https://github.com/paritytech/parity/pull/7982)) -- fix traces, removed bloomchain crate ([#7979](https://github.com/paritytech/parity/pull/7979)) -- simplify compression and move it out of rlp crate ([#7957](https://github.com/paritytech/parity/pull/7957)) -- removed old migrations ([#7974](https://github.com/paritytech/parity/pull/7974)) -- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977)) -- fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934)) -- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965)) -- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953)) -- Add changelog for 1.8.10 stable and 1.9.3 beta ([#7947](https://github.com/paritytech/parity/pull/7947)) -- kvdb-rocksdb: remove buffered operations when committing transaction ([#7950](https://github.com/paritytech/parity/pull/7950)) -- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952)) -- removed redundant Bloom conversions ([#7932](https://github.com/paritytech/parity/pull/7932)) -- simplify RefInfo fmt ([#7929](https://github.com/paritytech/parity/pull/7929)) -- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849)) -- bring back trie and triehash benches ([#7926](https://github.com/paritytech/parity/pull/7926)) -- removed redundant PodAccount::new method ([#7928](https://github.com/paritytech/parity/pull/7928)) -- removed dummy wrapper structure - LogGroupPosition ([#7922](https://github.com/paritytech/parity/pull/7922)) -- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933)) -- simplify Client::filter_traces method ([#7936](https://github.com/paritytech/parity/pull/7936)) -- gitlab cache ([#7921](https://github.com/paritytech/parity/pull/7921)) -- Fix a division by zero in light client RPC handler ([#7917](https://github.com/paritytech/parity/pull/7917)) -- triehash optimisations ([#7920](https://github.com/paritytech/parity/pull/7920)) -- removed redundant Blockchain::db method ([#7919](https://github.com/paritytech/parity/pull/7919)) -- removed redundant Blockchain::rewind method ([#7918](https://github.com/paritytech/parity/pull/7918)) -- Pending transactions subscription ([#7906](https://github.com/paritytech/parity/pull/7906)) -- removed redundant otry! macro from ethcore ([#7916](https://github.com/paritytech/parity/pull/7916)) -- Make block generator easier to use ([#7888](https://github.com/paritytech/parity/pull/7888)) -- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905)) -- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867)) -- Fix gitlab ([#7901](https://github.com/paritytech/parity/pull/7901)) -- Gitlb snap master patch ([#7900](https://github.com/paritytech/parity/pull/7900)) -- fix snap build master ([#7896](https://github.com/paritytech/parity/pull/7896)) -- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873)) -- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884)) -- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848)) -- SecretStore: fixed test ([#7878](https://github.com/paritytech/parity/pull/7878)) -- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846)) -- Forward-port snap fixes ([#7831](https://github.com/paritytech/parity/pull/7831)) -- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883)) -- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881)) -- Fix string typo: "develoopment" -> "development" ([#7874](https://github.com/paritytech/parity/pull/7874)) -- Update the instructions to install the stable snap ([#7876](https://github.com/paritytech/parity/pull/7876)) -- SecretStore: 'broadcast' decryption session ([#7843](https://github.com/paritytech/parity/pull/7843)) -- Flush keyfiles. Resolves #7632 ([#7868](https://github.com/paritytech/parity/pull/7868)) -- Read registry_address from given block ([#7866](https://github.com/paritytech/parity/pull/7866)) -- Clean up docs formatting for Wasm runtime ([#7869](https://github.com/paritytech/parity/pull/7869)) -- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842)) -- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855)) -- ethabi version 5 ([#7723](https://github.com/paritytech/parity/pull/7723)) -- Light client: randomize the peer we dispatch requests to ([#7844](https://github.com/paritytech/parity/pull/7844)) -- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832)) -- Add new EF ropstens nodes. ([#7824](https://github.com/paritytech/parity/pull/7824)) -- refactor stratum to remove retain cycle ([#7827](https://github.com/paritytech/parity/pull/7827)) -- Bump jsonrpc. ([#7828](https://github.com/paritytech/parity/pull/7828)) -- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830)) -- Update references to UI shell & wallet ([#7808](https://github.com/paritytech/parity/pull/7808)) -- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812)) -- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796)) -- SecretStore: ignore removed authorities when running auto-migration ([#7674](https://github.com/paritytech/parity/pull/7674)) -- Fix build ([#7807](https://github.com/paritytech/parity/pull/7807)) -- Move js & js-old code to github.com/parity-js ([#7685](https://github.com/paritytech/parity/pull/7685)) -- More changelogs :) ([#7782](https://github.com/paritytech/parity/pull/7782)) -- Actualized API set in help ([#7790](https://github.com/paritytech/parity/pull/7790)) -- Removed obsolete file ([#7788](https://github.com/paritytech/parity/pull/7788)) -- Update ropsten bootnodes ([#7776](https://github.com/paritytech/parity/pull/7776)) -- CHANGELOG for 1.9.1 and 1.8.8 ([#7775](https://github.com/paritytech/parity/pull/7775)) -- Enable byzantium features on non-ethash chains ([#7753](https://github.com/paritytech/parity/pull/7753)) -- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695)) -- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716)) -- Removes redundant parentheses ([#7721](https://github.com/paritytech/parity/pull/7721)) -- Transaction-pool fixes ([#7741](https://github.com/paritytech/parity/pull/7741)) -- More visible download link in README.md ([#7707](https://github.com/paritytech/parity/pull/7707)) -- Changelog for 1.9.0 ([#7664](https://github.com/paritytech/parity/pull/7664)) -- Add scroll when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677)) -- SecretStore: return HTTP 403 (access denied) if consensus is unreachable ([#7656](https://github.com/paritytech/parity/pull/7656)) -- Moved StopGaurd to it's own crate ([#7635](https://github.com/paritytech/parity/pull/7635)) +- Backports ([#8558](https://github.com/paritytech/parity/pull/8558)) + - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) + - Fetch logs by hash in blockchain database + - Fix tests + - Add unit test for branch block logs fetching + - Add docs that blocks must already be sorted + - Handle branch block cases properly + - typo: empty -> is_empty + - Remove return_empty_if_none by using a closure + - Use BTreeSet to avoid sorting again + - Move is_canon to BlockChain + - typo: pass value by reference + - Use loop and wrap inside blocks to simplify the code + - typo: missed a comment + - Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity/pull/8491)) + - Pass on storage keys even if it is not modified + - typo: account and storage query + - Fix tests + - Use state query directly because of suicided accounts + - Fix a RefCell borrow issue + - Add tests for unmodified storage trace + - Address grumbles + - typo: remove unwanted empty line + - ensure_cached compiles with the original signature + - Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity/pull/8493)) + - Update wasmi to 0.2 + - Update pwasm-utils to 0.1.5 + - Show imported messages for light client ([#8517](https://github.com/paritytech/parity/pull/8517)) + - Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity/pull/8520)) + - Enable WebAssembly and Byzantium for Ellaism + - Fix indentation + - Remove empty lines + - Don't panic in import_block if invalid rlp ([#8522](https://github.com/paritytech/parity/pull/8522)) + - Don't panic in import_block if invalid rlp + - Remove redundant type annotation + - Replace RLP header view usage with safe decoding + - Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity/pull/8541)) + - network-devp2p: sort nodes in node table using last contact data + - network-devp2p: rename node contact types in node table json output + - network-devp2p: fix node table tests + - network-devp2p: note node failure when failed to establish connection + - network-devp2p: handle UselessPeer error + - network-devp2p: note failure when marking node as useless +- Betalize 1.11 :) ([#8475](https://github.com/paritytech/parity/pull/8475)) + - Betalize 1.11 :) + - Update Gitlab scripts + - Use master as gitlab latest + - Fix snap builds ([#8483](https://github.com/paritytech/parity/pull/8483)) + - Update hardcodedSync for Ethereum, Kovan, and Ropsten ([#8489](https://github.com/paritytech/parity/pull/8489)) +- Fix typos in vm description comment ([#8446](https://github.com/paritytech/parity/pull/8446)) +- Add changelog for 1.9.7 and 1.10.2 ([#8460](https://github.com/paritytech/parity/pull/8460)) +- Fix docker build ([#8462](https://github.com/paritytech/parity/pull/8462)) +- Parityshell::open `Return result` ([#8377](https://github.com/paritytech/parity/pull/8377)) +- Return error in case eth_call returns VM errors ([#8448](https://github.com/paritytech/parity/pull/8448)) +- Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) +- Allow 32 bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) +- Update Cargo hidapi-rs dependency ([#8447](https://github.com/paritytech/parity/pull/8447)) +- Private transactions processing error handling ([#8431](https://github.com/paritytech/parity/pull/8431)) +- Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) +- Block reward contract ([#8419](https://github.com/paritytech/parity/pull/8419)) +- Permission fix ([#8441](https://github.com/paritytech/parity/pull/8441)) +- Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) +- Remove From::from. ([#8390](https://github.com/paritytech/parity/pull/8390)) +- Move ethcore::Error to error_chain ([#8386](https://github.com/paritytech/parity/pull/8386)) +- Changelogs for 1.9.6 and 1.10.1 ([#8411](https://github.com/paritytech/parity/pull/8411)) +- Fix receipts stripping. ([#8414](https://github.com/paritytech/parity/pull/8414)) +- Typo, docs parity_chainId: empty string -> None ([#8434](https://github.com/paritytech/parity/pull/8434)) +- Update zip to 0.3 ([#8381](https://github.com/paritytech/parity/pull/8381)) +- Fix TODO comments ([#8413](https://github.com/paritytech/parity/pull/8413)) +- Replace legacy Rlp with UntrustedRlp and use in ethcore rlp views ([#8316](https://github.com/paritytech/parity/pull/8316)) +- Tokio-core v0.1.16 -> v0.1.17 ([#8408](https://github.com/paritytech/parity/pull/8408)) +- More code refactoring to integrate Duration ([#8322](https://github.com/paritytech/parity/pull/8322)) +- Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) +- Use tokio::spawn in secret_store listener and fix Uri ([#8373](https://github.com/paritytech/parity/pull/8373)) +- Unify and limit rocksdb dependency places ([#8371](https://github.com/paritytech/parity/pull/8371)) +- Clarify that windows need perl and yasm ([#8402](https://github.com/paritytech/parity/pull/8402)) +- New Transaction Queue implementation ([#8074](https://github.com/paritytech/parity/pull/8074)) +- Some tweaks to main.rs for parity as a library ([#8370](https://github.com/paritytech/parity/pull/8370)) +- Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) +- Ci: fix change detection in master builds ([#8382](https://github.com/paritytech/parity/pull/8382)) +- Fix config test by adding no-hardcodec-sync ([#8380](https://github.com/paritytech/parity/pull/8380)) +- Fixed unsafe shell call on windows ([#8372](https://github.com/paritytech/parity/pull/8372)) +- Parity uses winapi 0.3.4 ([#8366](https://github.com/paritytech/parity/pull/8366)) +- No hardcoded client name ([#8368](https://github.com/paritytech/parity/pull/8368)) +- Add `util/mem` to zero out memory on drop. ([#8356](https://github.com/paritytech/parity/pull/8356)) +- Use atty instead of isatty ([#8365](https://github.com/paritytech/parity/pull/8365)) +- Increase gasLimit to 8'000'000 ([#8362](https://github.com/paritytech/parity/pull/8362)) +- Util `fake-fetch` ([#8363](https://github.com/paritytech/parity/pull/8363)) +- Bump snappy and ring, use single rayon version, closes [#8296](https://github.com/paritytech/parity/issues/8296) ([#8364](https://github.com/paritytech/parity/pull/8364)) +- Use async hyper server in secret_store and upgrade igd ([#8359](https://github.com/paritytech/parity/pull/8359)) +- Enable UI by default, but only display deprecation notice ([#8262](https://github.com/paritytech/parity/pull/8262)) +- Ethcrypto renamed to ethcore-crypto and moved to ethcore dir ([#8340](https://github.com/paritytech/parity/pull/8340)) +- Use hyper 0.11 in ethcore-miner and improvements in parity-reactor ([#8335](https://github.com/paritytech/parity/pull/8335)) +- Ethcore-sync ([#8347](https://github.com/paritytech/parity/pull/8347)) +- Rpc, eth_filter: return error if the filter id does not exist ([#8341](https://github.com/paritytech/parity/pull/8341)) +- Ethcore-stratum crate moved to ethcore directory ([#8338](https://github.com/paritytech/parity/pull/8338)) +- Secretstore: get rid of engine.signer dependency ([#8173](https://github.com/paritytech/parity/pull/8173)) +- Whisper cli ([#8201](https://github.com/paritytech/parity/pull/8201)) +- Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) +- Add Ethereum Social support ([#8325](https://github.com/paritytech/parity/pull/8325)) +- Private transactions integration pr ([#6422](https://github.com/paritytech/parity/pull/6422)) +- Decouple rocksdb dependency from ethcore ([#8320](https://github.com/paritytech/parity/pull/8320)) +- Remove the clone operation of code_cache ([#8334](https://github.com/paritytech/parity/pull/8334)) +- Fix the JSONRPC API not running with the light client ([#8326](https://github.com/paritytech/parity/pull/8326)) +- Read registry_address from block with REQUEST_CONFIRMATIONS_REQUIRED ([#8309](https://github.com/paritytech/parity/pull/8309)) +- Tweaks and add a Dockerfile for Android ([#8036](https://github.com/paritytech/parity/pull/8036)) +- Use associated type M::Error instead of Error ([#8308](https://github.com/paritytech/parity/pull/8308)) +- Remove InvalidParentHash in favor of assert! ([#8300](https://github.com/paritytech/parity/pull/8300)) +- Bump proc macro deps ([#8310](https://github.com/paritytech/parity/pull/8310)) +- Decouple timestamp open-block-assignment/verification to Engine ([#8305](https://github.com/paritytech/parity/pull/8305)) +- Validate if gas limit is not zero ([#8307](https://github.com/paritytech/parity/pull/8307)) +- Implement Easthub chain spec ([#8295](https://github.com/paritytech/parity/pull/8295)) +- Update some dependencies ([#8285](https://github.com/paritytech/parity/pull/8285)) +- Ethcore now uses Rayon 1.0 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8304](https://github.com/paritytech/parity/pull/8304)) +- Upgrader `remove raw unwrap` and bump semver ([#8251](https://github.com/paritytech/parity/pull/8251)) +- Cleaner binary shutdown system ([#8284](https://github.com/paritytech/parity/pull/8284)) +- Ethcore now uses rayon to 0.9 as a dependency ([#8296](https://github.com/paritytech/parity/pull/8296)) ([#8302](https://github.com/paritytech/parity/pull/8302)) +- Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) +- Remove evmjit ([#8229](https://github.com/paritytech/parity/pull/8229)) +- Build: fix updater rand dependency in Cargo.lock ([#8298](https://github.com/paritytech/parity/pull/8298)) +- Honor --max-peers if --min-peers is not specified ([#8087](https://github.com/paritytech/parity/pull/8087)) +- Auto-updater improvements ([#8078](https://github.com/paritytech/parity/pull/8078)) +- Dapps-fetcher: calculate keccak in-flight while reading the response ([#8294](https://github.com/paritytech/parity/pull/8294)) +- Cleanup Ellaism bootnodes ([#8276](https://github.com/paritytech/parity/pull/8276)) +- Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) +- Remove RefCell from Header ([#8227](https://github.com/paritytech/parity/pull/8227)) +- Typo fix: todo with no content ([#8292](https://github.com/paritytech/parity/pull/8292)) +- Revert "ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118))" ([#8287](https://github.com/paritytech/parity/pull/8287)) +- Bump ethabi & ethereum-types. ([#8258](https://github.com/paritytech/parity/pull/8258)) +- Allow customization of max WS connections. ([#8257](https://github.com/paritytech/parity/pull/8257)) +- Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) +- Return null number for pending block in eth_getBlockByNumber ([#8281](https://github.com/paritytech/parity/pull/8281)) +- Use constant durations ([#8278](https://github.com/paritytech/parity/pull/8278)) +- Typo fix: Mode doc - RLP should be client ([#8283](https://github.com/paritytech/parity/pull/8283)) +- Eth_uninstallfilter should return false for non-existent filter ([#8280](https://github.com/paritytech/parity/pull/8280)) +- Update `app_dirs` to 1.2.1 ([#8268](https://github.com/paritytech/parity/pull/8268)) +- Add missing license header for runtime.rs ([#8252](https://github.com/paritytech/parity/pull/8252)) +- Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) +- Replace all Rlp usages with UntrustedRlp except for ethcore views ([#8233](https://github.com/paritytech/parity/pull/8233)) +- Add test for ethstore-cli, fixes [#8027](https://github.com/paritytech/parity/issues/8027) ([#8187](https://github.com/paritytech/parity/pull/8187)) +- Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) +- Fixed ethcore tx_filter ([#8200](https://github.com/paritytech/parity/pull/8200)) +- Update CLI help for jsonrpc-apis, ws-apis and ipc-apis ([#8234](https://github.com/paritytech/parity/pull/8234)) +- Remove network stats ([#8225](https://github.com/paritytech/parity/pull/8225)) +- Node-filter does not use ChainNotify ([#8231](https://github.com/paritytech/parity/pull/8231)) +- Implement hardcoded sync in the light client ([#8075](https://github.com/paritytech/parity/pull/8075)) +- Update some of the dependencies for WASM ([#8223](https://github.com/paritytech/parity/pull/8223)) +- Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Updated jsonrpc to point to the 1.11 branch ([#8180](https://github.com/paritytech/parity/pull/8180)) +- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) +- Introduce Parity UI ([#8202](https://github.com/paritytech/parity/pull/8202)) +- Update Changelogs ([#8175](https://github.com/paritytech/parity/pull/8175)) +- Returns number of topcis to take fr.. ([#8199](https://github.com/paritytech/parity/pull/8199)) +- Make docopt usage non-const ([#8189](https://github.com/paritytech/parity/pull/8189)) +- Avoid allocations when computing triehash. ([#8176](https://github.com/paritytech/parity/pull/8176)) +- Handle rlp decoding Result in patricia trie ([#8166](https://github.com/paritytech/parity/pull/8166)) +- Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) +- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) +- Update daemonize ([#8165](https://github.com/paritytech/parity/pull/8165)) +- Some tiny modifications. ([#8163](https://github.com/paritytech/parity/pull/8163)) +- Secretstore: store key author address in db ([#7887](https://github.com/paritytech/parity/pull/7887)) +- Rename DatabaseValueView::new to from_rlp ([#8159](https://github.com/paritytech/parity/pull/8159)) +- Dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) +- Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) +- Fix wasmi x32 builds ([#8155](https://github.com/paritytech/parity/pull/8155)) +- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) +- Secretstore: ability to identify requester via Public/Address ([#7886](https://github.com/paritytech/parity/pull/7886)) +- Optional dependency on secp256k1 for ethcrypto ([#8109](https://github.com/paritytech/parity/pull/8109)) +- Network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) +- Check one step deeper if we're on release track branches ([#8134](https://github.com/paritytech/parity/pull/8134)) +- Explicitly mention pruning_history uses RAM ([#8130](https://github.com/paritytech/parity/pull/8130)) +- Remove `ethcrypto::{en,de}crypt_single_message`. ([#8126](https://github.com/paritytech/parity/pull/8126)) +- Fix typo ([#8124](https://github.com/paritytech/parity/pull/8124)) +- Secret_store: use `ecies::encrypt`/`ecies::decrypt`. ([#8125](https://github.com/paritytech/parity/pull/8125)) +- Fix comment for fn gas() in wasm/runtime ([#8122](https://github.com/paritytech/parity/pull/8122)) +- Structured rlp encoding in journaldb ([#8047](https://github.com/paritytech/parity/pull/8047)) +- Ci: disable link-dead-code in coverage build ([#8118](https://github.com/paritytech/parity/pull/8118)) +- Fix trace filter returning returning unrelated reward calls, closes [#8070](https://github.com/paritytech/parity/issues/8070) ([#8098](https://github.com/paritytech/parity/pull/8098)) +- Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) +- Replace reqwest with hyper ([#8099](https://github.com/paritytech/parity/pull/8099)) +- More dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) +- Remove the time dependency where possible ([#8100](https://github.com/paritytech/parity/pull/8100)) +- Fix comment for gas extern in Wasm runtime ([#8101](https://github.com/paritytech/parity/pull/8101)) +- Replace std::env::temp_dir with tempdir in tests ([#8103](https://github.com/paritytech/parity/pull/8103)) +- Fix Cargo.lock not parsable ([#8102](https://github.com/paritytech/parity/pull/8102)) +- Additional data in EVMTestClient ([#7964](https://github.com/paritytech/parity/pull/7964)) +- Update serde, serde-derive, ethabi-derive, syn, quote and rlp_derive ([#8085](https://github.com/paritytech/parity/pull/8085)) +- Ethcore-service ([#8089](https://github.com/paritytech/parity/pull/8089)) +- [contract-client] refactor ([#7978](https://github.com/paritytech/parity/pull/7978)) +- Revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) +- Ethcore test::helpers cleanup ([#8086](https://github.com/paritytech/parity/pull/8086)) +- Add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) +- Wasm libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) +- Echo back the message hash of a ping in the pong request ([#8042](https://github.com/paritytech/parity/pull/8042)) +- Add Kovan WASM activation blocknumber ([#8057](https://github.com/paritytech/parity/pull/8057)) +- [ethkey] Unify debug/display for Address/Public/Secret ([#8076](https://github.com/paritytech/parity/pull/8076)) +- Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) +- Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) +- Updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) +- Make blockchain functions more idiomatic, avoid needless writes to cache_man ([#8054](https://github.com/paritytech/parity/pull/8054)) +- Make patricia-trie more idiomatic and remove redundant code ([#8056](https://github.com/paritytech/parity/pull/8056)) +- Abstract devp2p ([#8048](https://github.com/paritytech/parity/pull/8048)) +- Update refs to shell ([#8051](https://github.com/paritytech/parity/pull/8051)) +- Fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) +- Prelude to the block module cleanup ([#8025](https://github.com/paritytech/parity/pull/8025)) +- Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) +- Bump master to 1.11.0 ([#8021](https://github.com/paritytech/parity/pull/8021)) +- `client` refactoring ([#7038](https://github.com/paritytech/parity/pull/7038)) +- [hardware wallet] sleeping -> pollling ([#8018](https://github.com/paritytech/parity/pull/8018)) +- Fixed broken link in README ([#8012](https://github.com/paritytech/parity/pull/8012)) +- Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) +- Add changelog for 1.8.11 stable and 1.9.4 beta ([#8017](https://github.com/paritytech/parity/pull/8017)) +- Fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) +- Extract the hard dependency on rocksdb from the light client ([#8034](https://github.com/paritytech/parity/pull/8034)) +- Fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) +- Fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) +- Ci: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) +- Update ref to new shell ([#8024](https://github.com/paritytech/parity/pull/8024)) ## Previous releases -- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (_stable_) +- [CHANGELOG-1.10](docs/CHANGELOG-1.10.md) (_stable_) +- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (EOL: 2018-05-09) - [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (EOL: 2018-03-22) - [CHANGELOG-1.7](docs/CHANGELOG-1.7.md) (EOL: 2018-01-25) - [CHANGELOG-1.6](docs/CHANGELOG-1.6.md) (EOL: 2017-10-15) diff --git a/docs/CHANGELOG-1.10.md b/docs/CHANGELOG-1.10.md new file mode 100644 index 0000000000..4db8f32bb6 --- /dev/null +++ b/docs/CHANGELOG-1.10.md @@ -0,0 +1,325 @@ +## Parity [v1.10.3](https://github.com/paritytech/parity/releases/tag/v1.10.3) (2018-05-08) + +Parity 1.10.3 marks the first stable release on the 1.10 track. Among others, it improves performance and stability. + +The full list of included changes: + +- Backports ([#8557](https://github.com/paritytech/parity/pull/8557)) + - Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity/pull/8493)) + - Update wasmi to 0.2 + - Update pwasm-utils to 0.1.5 + - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) + - Fetch logs by hash in blockchain database + - Fix tests + - Add unit test for branch block logs fetching + - Add docs that blocks must already be sorted + - Handle branch block cases properly + - typo: empty -> is_empty + - Remove return_empty_if_none by using a closure + - Use BTreeSet to avoid sorting again + - Move is_canon to BlockChain + - typo: pass value by reference + - Use loop and wrap inside blocks to simplify the code + - typo: missed a comment + - Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity/pull/8491)) + - Pass on storage keys even if it is not modified + - typo: account and storage query `to_pod_diff` builds both `touched_addresses` merge and storage keys merge. + - Fix tests + - Use state query directly because of suicided accounts + - Fix a RefCell borrow issue + - Add tests for unmodified storage trace + - Address grumbles + - typo: remove unwanted empty line + - ensure_cached compiles with the original signature + - Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity/pull/8520)) + - Enable WebAssembly and Byzantium for Ellaism + - Fix indentation + - Remove empty lines + - Fix compilation. +- Stabilize 1.10.3 ([#8474](https://github.com/paritytech/parity/pull/8474)) + - Stabelize 1.10 + - Bump stable to 1.10.3 + - Update Gitlab scripts + - Fix snap builds ([#8483](https://github.com/paritytech/parity/pull/8483)) + - Fix docker build ([#8462](https://github.com/paritytech/parity/pull/8462)) + - Use `master` as Docker's `latest` (`beta-release` is not used anymore) + +## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24) + +Parity 1.10.2 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455)) + - Update Parity beta to 1.10.2 + - Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454)) + - Disable 32-bit targets for Gitlab + - Rename Linux pipelines + - Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452)) + - Fix Cargo.lock +- Backports ([#8450](https://github.com/paritytech/parity/pull/8450)) + - Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438)) + - Remove unused app_dirs dependency in CLI + - Use forked app_dirs crate for reverted Windows dir behavior + - Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367)) + - Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385)) + - Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439)) + - Improve VM executor stack size estimation rules + - Typo: docs add "(Debug build)" comment + - Fix an off by one typo and set minimal stack size + - Use saturating_sub to avoid potential overflow + +## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17) + +Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head. + +The full list of included changes: + +- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350)) + - Bump beta to 1.10.1 + - Unflag critical release +- Backports ([#8346](https://github.com/paritytech/parity/pull/8346)) + - Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228)) + - Warp-only sync with warp-after [blocknumber] flag. + - Fix tests. + - Fix configuration tests. + - Rename to warp barrier. + - Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204)) + - Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242)) + - Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256)) + - Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297)) + - Include suicided accounts in state diff + - Shorten form match -> if let + - Test suicide trace diff in State + - Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324)) + - Replace_home for password_files, reserved_peers and log_file + - Typo: arg_log_file is Option + - Enable UI by default, but only display info page. + - Fix test. + - Fix naming and remove old todo. + - Change "wallet" with "browser UI" +- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205)) + - Change name Wallet -> UI + - Make warning bold +- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132)) +- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220)) + - Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171)) + - Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209)) +- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203)) +- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181)) + - Updated jsonrpc to include latest backports + - Update dependencies. + +## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22) + +This is the Parity 1.10.0-beta release! Cool! + +### Disabling the Parity Wallet + +The **Parity Wallet (a.k.a. "UI") is now disabled by default**. We are preparing to split the wallet from the core client. + +To reactivate the parity wallet, you have to run Parity either with `parity --force-ui` (not recommended) or `parity ui` (deprecated) from the command line. Or, if you feel super fancy and want to test our pre-releases of the stand-alone electron wallet, head over to the [Parity-JS repositories and check the releases](https://github.com/Parity-JS/shell/releases). + +Further reading: + +- [Docs: Parity Wallet](https://wiki.parity.io/Parity-Wallet) +- [Docs: How to customize Parity UI?](https://wiki.parity.io/FAQ-Customize-Parity-UI.html) +- [Github: Parity-JS](https://github.com/parity-js) + +### Introducing the Wasm VM + +We are excited to announce support for **Wasm Smart Contracts on Kovan network**. The hard-fork to activate the Wasm-VM will take place on block `6_600_000`. + +To enable Wasm contracts on your custom network, just schedule a `wasmActivationTransition` at your favorite block number (e.g., `42`, `666`, or `0xbada55`). To hack your first Wasm smart contracts in Rust, have a look at the [Parity Wasm Tutorials](https://github.com/paritytech/pwasm-tutorial). + +Further reading: + +- [Docs: WebAssembly (wasm)](https://wiki.parity.io/WebAssembly-Home) +- [Docs: Wasm VM Design](https://wiki.parity.io/WebAssembly-Design) +- [Docs: Wasm tutorials and examples](https://wiki.parity.io/WebAssembly-Links) + +### Empty step messages in PoA + +To **reduce blockchain bloat, proof-of-authority networks can now enable _empty step messages_ which replace empty blocks**. Each step message will be signed and broadcasted by the issuing authorities, and included and rewarded in the next non-empty block. + +To enable empty step messages, set the `emptyStepsTransition` to your favorite block number. You can also specify a maximum number of empty steps with `maximumEmptySteps` in your chain spec. + +### Other noteworthy changes + +We removed the old database migrations from 2016. In case you upgrade Parity from a really, really old version, you will have to reset your database manually first with `parity db kill`. + +We fixed DELEGATECALL `from` and `to` fields, see [#7166](https://github.com/paritytech/parity/issues/7166). + +We reduced the default USD per transaction value to 0.0001. Thanks, @MysticRyuujin! + +The Musicoin chain is now enabled with Byzantium features starting at block `2_222_222`. + +### Overview of all changes included + +The full list of included changes: + +- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) ([#8168](https://github.com/paritytech/parity/pull/8168)) + - Re-enable signer, even with no UI. + - Fix message. +- Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136)) + - Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) + - updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) + - updater: apply exponential backoff after download failure + - updater: reset backoff on new release + - Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) + - Enable code size limit on kovan + - Fix formatting. + - Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) + - Limit ingress connections + - Optimized handshakes logging + - WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) + - update wasmi, parity-wasm, wasm-utils to latest version + - Update to new wasmi & error handling + - also utilize new stack limiter + - fix typo + - replace dependency url + - Cargo.lock update + - add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) + - revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) + - Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)" + - Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))" + - fixed broken logs + - bring back old lock order + - remove migration v13 + - revert CURRENT_VERSION to 12 in migration.rs + - more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) + - Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) + - Use `subtle::slices_equal` for constant time comparison. + - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 + - Test specifically for InvalidPassword error. + - fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098)) + - network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) + - network: init discovery using healthy nodes + - network: fix style grumble + - network: fix typo + - Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) + - ethcore: postpone Kovan hard fork + - util: update version fork metadata + - Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) + - dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) +- Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135)) +- Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053)) + - CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) + - Fix cache + - Only clean locked cargo cache on windows + - fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) + - fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) + - fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) + - fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) + - Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) + - Add test chain spec for musicoin byzantium testnet + - Add MCIP-6 Byzyantium transition to Musicoin spec + - Update mcip6_byz.json + - ethcore: update musicoin byzantium block number + - ethcore: update musicoin bootnodes + - Update musicoin.json + - More bootnodes. +- Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022)) + - Make 1.10 beta + - Fix gitlab builds +- SecretStore: secretstore_generateDocumentKey RPC ([#7864](https://github.com/paritytech/parity/pull/7864)) +- SecretStore: ECDSA session for cases when 2*t < N ([#7739](https://github.com/paritytech/parity/pull/7739)) +- bump tiny-keccak ([#8019](https://github.com/paritytech/parity/pull/8019)) +- Remove un-necessary comment ([#8014](https://github.com/paritytech/parity/pull/8014)) +- clean up account fmt::Debug ([#7983](https://github.com/paritytech/parity/pull/7983)) +- improve quality of vote_collector module ([#7984](https://github.com/paritytech/parity/pull/7984)) +- ExecutedBlock cleanup ([#7991](https://github.com/paritytech/parity/pull/7991)) +- Hardware-wallet/usb-subscribe-refactor ([#7860](https://github.com/paritytech/parity/pull/7860)) +- remove wildcard imports from views, make tests more idiomatic ([#7986](https://github.com/paritytech/parity/pull/7986)) +- moved PerfTimer to a separate crate - "trace-time" ([#7985](https://github.com/paritytech/parity/pull/7985)) +- clean up ethcore::spec module imports ([#7990](https://github.com/paritytech/parity/pull/7990)) +- rpc: don't include current block in new_block_filter ([#7982](https://github.com/paritytech/parity/pull/7982)) +- fix traces, removed bloomchain crate ([#7979](https://github.com/paritytech/parity/pull/7979)) +- simplify compression and move it out of rlp crate ([#7957](https://github.com/paritytech/parity/pull/7957)) +- removed old migrations ([#7974](https://github.com/paritytech/parity/pull/7974)) +- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977)) +- fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934)) +- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965)) +- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953)) +- Add changelog for 1.8.10 stable and 1.9.3 beta ([#7947](https://github.com/paritytech/parity/pull/7947)) +- kvdb-rocksdb: remove buffered operations when committing transaction ([#7950](https://github.com/paritytech/parity/pull/7950)) +- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952)) +- removed redundant Bloom conversions ([#7932](https://github.com/paritytech/parity/pull/7932)) +- simplify RefInfo fmt ([#7929](https://github.com/paritytech/parity/pull/7929)) +- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849)) +- bring back trie and triehash benches ([#7926](https://github.com/paritytech/parity/pull/7926)) +- removed redundant PodAccount::new method ([#7928](https://github.com/paritytech/parity/pull/7928)) +- removed dummy wrapper structure - LogGroupPosition ([#7922](https://github.com/paritytech/parity/pull/7922)) +- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933)) +- simplify Client::filter_traces method ([#7936](https://github.com/paritytech/parity/pull/7936)) +- gitlab cache ([#7921](https://github.com/paritytech/parity/pull/7921)) +- Fix a division by zero in light client RPC handler ([#7917](https://github.com/paritytech/parity/pull/7917)) +- triehash optimisations ([#7920](https://github.com/paritytech/parity/pull/7920)) +- removed redundant Blockchain::db method ([#7919](https://github.com/paritytech/parity/pull/7919)) +- removed redundant Blockchain::rewind method ([#7918](https://github.com/paritytech/parity/pull/7918)) +- Pending transactions subscription ([#7906](https://github.com/paritytech/parity/pull/7906)) +- removed redundant otry! macro from ethcore ([#7916](https://github.com/paritytech/parity/pull/7916)) +- Make block generator easier to use ([#7888](https://github.com/paritytech/parity/pull/7888)) +- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905)) +- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867)) +- Fix gitlab ([#7901](https://github.com/paritytech/parity/pull/7901)) +- Gitlb snap master patch ([#7900](https://github.com/paritytech/parity/pull/7900)) +- fix snap build master ([#7896](https://github.com/paritytech/parity/pull/7896)) +- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873)) +- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884)) +- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848)) +- SecretStore: fixed test ([#7878](https://github.com/paritytech/parity/pull/7878)) +- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846)) +- Forward-port snap fixes ([#7831](https://github.com/paritytech/parity/pull/7831)) +- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883)) +- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881)) +- Fix string typo: "develoopment" -> "development" ([#7874](https://github.com/paritytech/parity/pull/7874)) +- Update the instructions to install the stable snap ([#7876](https://github.com/paritytech/parity/pull/7876)) +- SecretStore: 'broadcast' decryption session ([#7843](https://github.com/paritytech/parity/pull/7843)) +- Flush keyfiles. Resolves #7632 ([#7868](https://github.com/paritytech/parity/pull/7868)) +- Read registry_address from given block ([#7866](https://github.com/paritytech/parity/pull/7866)) +- Clean up docs formatting for Wasm runtime ([#7869](https://github.com/paritytech/parity/pull/7869)) +- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842)) +- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855)) +- ethabi version 5 ([#7723](https://github.com/paritytech/parity/pull/7723)) +- Light client: randomize the peer we dispatch requests to ([#7844](https://github.com/paritytech/parity/pull/7844)) +- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832)) +- Add new EF ropstens nodes. ([#7824](https://github.com/paritytech/parity/pull/7824)) +- refactor stratum to remove retain cycle ([#7827](https://github.com/paritytech/parity/pull/7827)) +- Bump jsonrpc. ([#7828](https://github.com/paritytech/parity/pull/7828)) +- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830)) +- Update references to UI shell & wallet ([#7808](https://github.com/paritytech/parity/pull/7808)) +- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812)) +- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796)) +- SecretStore: ignore removed authorities when running auto-migration ([#7674](https://github.com/paritytech/parity/pull/7674)) +- Fix build ([#7807](https://github.com/paritytech/parity/pull/7807)) +- Move js & js-old code to github.com/parity-js ([#7685](https://github.com/paritytech/parity/pull/7685)) +- More changelogs :) ([#7782](https://github.com/paritytech/parity/pull/7782)) +- Actualized API set in help ([#7790](https://github.com/paritytech/parity/pull/7790)) +- Removed obsolete file ([#7788](https://github.com/paritytech/parity/pull/7788)) +- Update ropsten bootnodes ([#7776](https://github.com/paritytech/parity/pull/7776)) +- CHANGELOG for 1.9.1 and 1.8.8 ([#7775](https://github.com/paritytech/parity/pull/7775)) +- Enable byzantium features on non-ethash chains ([#7753](https://github.com/paritytech/parity/pull/7753)) +- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695)) +- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716)) +- Removes redundant parentheses ([#7721](https://github.com/paritytech/parity/pull/7721)) +- Transaction-pool fixes ([#7741](https://github.com/paritytech/parity/pull/7741)) +- More visible download link in README.md ([#7707](https://github.com/paritytech/parity/pull/7707)) +- Changelog for 1.9.0 ([#7664](https://github.com/paritytech/parity/pull/7664)) +- Add scroll when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677)) +- SecretStore: return HTTP 403 (access denied) if consensus is unreachable ([#7656](https://github.com/paritytech/parity/pull/7656)) +- Moved StopGaurd to it's own crate ([#7635](https://github.com/paritytech/parity/pull/7635)) + +## Previous releases + +- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (_stable_) +- [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (EOL: 2018-03-22) +- [CHANGELOG-1.7](docs/CHANGELOG-1.7.md) (EOL: 2018-01-25) +- [CHANGELOG-1.6](docs/CHANGELOG-1.6.md) (EOL: 2017-10-15) +- [CHANGELOG-1.5](docs/CHANGELOG-1.5.md) (EOL: 2017-07-28) +- [CHANGELOG-1.4](docs/CHANGELOG-1.4.md) (EOL: 2017-03-13) +- [CHANGELOG-1.3](docs/CHANGELOG-1.3.md) (EOL: 2017-01-19) +- [CHANGELOG-1.2](docs/CHANGELOG-1.2.md) (EOL: 2016-11-07) +- [CHANGELOG-1.1](docs/CHANGELOG-1.1.md) (EOL: 2016-08-12) +- [CHANGELOG-1.0](docs/CHANGELOG-1.0.md) (EOL: 2016-06-24) +- [CHANGELOG-0.9](docs/CHANGELOG-0.9.md) (EOL: 2016-05-02) diff --git a/docs/CHANGELOG-1.9.md b/docs/CHANGELOG-1.9.md index 133c93c477..2be3fcf27b 100644 --- a/docs/CHANGELOG-1.9.md +++ b/docs/CHANGELOG-1.9.md @@ -1,3 +1,5 @@ +Note: Parity 1.9 reached End-of-Life on 2018-05-09 (EOL). + ## Parity [v1.9.7](https://github.com/paritytech/parity/releases/tag/v1.9.7) (2018-04-23) Parity 1.9.7 is a bug-fix release to improve performance and stability. -- GitLab From cb7ad2366dc2b62ac95e844287e516ebf6024772 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 9 May 2018 15:58:02 +0200 Subject: [PATCH 135/263] Handle socket address parsing errors (#8545) Unpack errors and check for io::ErrorKind::InvalidInput and return our own AddressParse error. Remove the foreign link to std::net::AddrParseError and add an `impl From` for that error. Test parsing properly. --- Cargo.lock | 7 ++++ util/network-devp2p/Cargo.toml | 1 + util/network-devp2p/src/lib.rs | 2 ++ util/network-devp2p/src/node_table.rs | 52 ++++++++++++++++++++++----- util/network/src/error.rs | 11 +++++- 5 files changed, 63 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b02fcbd24e..edd76f9f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,11 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "assert_matches" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aster" version = "0.41.0" @@ -699,6 +704,7 @@ name = "ethcore-network-devp2p" version = "1.12.0" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", @@ -3767,6 +3773,7 @@ dependencies = [ "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "664470abf00fae0f31c0eb6e1ca12d82961b2a2541ef898bc9dd51a9254d218b" "checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index a8207ca615..3ec9684393 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -38,6 +38,7 @@ error-chain = { version = "0.11", default-features = false } [dev-dependencies] tempdir = "0.3" +assert_matches = "1.2" [features] default = [] diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 8faf21e465..239763cbe1 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -95,6 +95,8 @@ extern crate serde_derive; #[cfg(test)] extern crate tempdir; +#[cfg(test)] #[macro_use] +extern crate assert_matches; mod host; mod connection; diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 5079455866..8640901cd0 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use discovery::{TableUpdates, NodeEntry}; +use ethereum_types::H512; +use ip_utils::*; +use network::{Error, ErrorKind, AllowIP, IpFilter}; +use rlp::{Rlp, RlpStream, DecoderError}; +use serde_json; use std::collections::{HashMap, HashSet}; use std::fmt::{self, Display, Formatter}; use std::hash::{Hash, Hasher}; @@ -23,12 +29,6 @@ use std::str::FromStr; use std::{fs, mem, slice}; use std::time::{self, Duration, SystemTime}; use rand::{self, Rng}; -use ethereum_types::H512; -use rlp::{Rlp, RlpStream, DecoderError}; -use network::{Error, ErrorKind, AllowIP, IpFilter}; -use discovery::{TableUpdates, NodeEntry}; -use ip_utils::*; -use serde_json; /// Node public key pub type NodeId = H512; @@ -124,8 +124,8 @@ impl FromStr for NodeEndpoint { address: a, udp_port: a.port() }), - Ok(_) => Err(ErrorKind::AddressResolve(None).into()), - Err(e) => Err(ErrorKind::AddressResolve(Some(e)).into()) + Ok(None) => bail!(ErrorKind::AddressResolve(None)), + Err(_) => Err(ErrorKind::AddressParse.into()) // always an io::Error of InvalidInput kind } } } @@ -534,11 +534,34 @@ mod tests { assert!(endpoint.is_ok()); let v4 = match endpoint.unwrap().address { SocketAddr::V4(v4address) => v4address, - _ => panic!("should ve v4 address") + _ => panic!("should be v4 address") }; assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4); } + #[test] + fn endpoint_parse_empty_ip_string_returns_error() { + let endpoint = NodeEndpoint::from_str(""); + assert!(endpoint.is_err()); + assert_matches!(endpoint.unwrap_err().kind(), &ErrorKind::AddressParse); + } + + #[test] + fn endpoint_parse_invalid_ip_string_returns_error() { + let endpoint = NodeEndpoint::from_str("beef"); + assert!(endpoint.is_err()); + assert_matches!(endpoint.unwrap_err().kind(), &ErrorKind::AddressParse); + } + + #[test] + fn endpoint_parse_valid_ip_without_port_returns_error() { + let endpoint = NodeEndpoint::from_str("123.123.123.123"); + assert!(endpoint.is_err()); + assert_matches!(endpoint.unwrap_err().kind(), &ErrorKind::AddressParse); + let endpoint = NodeEndpoint::from_str("123.123.123.123:123"); + assert!(endpoint.is_ok()) + } + #[test] fn node_parse() { assert!(validate_node_url("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").is_none()); @@ -555,6 +578,17 @@ mod tests { node.id); } + #[test] + fn node_parse_fails_for_invalid_urls() { + let node = Node::from_str("foo"); + assert!(node.is_err()); + assert_matches!(node.unwrap_err().kind(), &ErrorKind::AddressParse); + + let node = Node::from_str("enode://foo@bar"); + assert!(node.is_err()); + assert_matches!(node.unwrap_err().kind(), &ErrorKind::AddressParse); + } + #[test] fn table_last_contact_order() { let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 6342bfe4ad..6104486696 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -84,11 +84,16 @@ error_chain! { foreign_links { SocketIo(IoError) #[doc = "Socket IO error."]; Io(io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; - AddressParse(net::AddrParseError) #[doc = "Error concerning the network address parsing subsystem."]; Decompression(snappy::InvalidInput) #[doc = "Decompression error."]; } errors { + #[doc = "Error concerning the network address parsing subsystem."] + AddressParse { + description("Failed to parse network address"), + display("Failed to parse network address"), + } + #[doc = "Error concerning the network address resolution subsystem."] AddressResolve(err: Option) { description("Failed to resolve network address"), @@ -163,6 +168,10 @@ impl From for Error { } } +impl From for Error { + fn from(_err: net::AddrParseError) -> Self { ErrorKind::AddressParse.into() } +} + #[test] fn test_errors() { assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8)); -- GitLab From cddc33bb24edf5e8b5d9052338965247829c5f4b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 10 May 2018 00:41:56 +0800 Subject: [PATCH 136/263] Remove unnecessary cloning in overwrite_with (#8580) * Remove unnecessary cloning in overwrite_with * Remove into_iter --- ethcore/src/state/account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index ff7d70bd3a..5c1dd40396 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -460,7 +460,7 @@ impl Account { self.address_hash = other.address_hash; let mut cache = self.storage_cache.borrow_mut(); for (k, v) in other.storage_cache.into_inner() { - cache.insert(k.clone() , v.clone()); //TODO: cloning should not be required here + cache.insert(k, v); } self.storage_changes = other.storage_changes; } -- GitLab From 1d42b7f0d1f44a3495f973704be494fd52644285 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 9 May 2018 23:21:16 +0200 Subject: [PATCH 137/263] changelog nit (#8585) --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c7dcf878b..f839802e7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ Notable changes in reversed alphabetical order: - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. - All whisper RPC APIs are enabled and can be directly acessed. -I'm not used to writing these changelogs but I guess that would explain it - JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) - This changes the behaviors of `eth_call` to respect VM errors if any. - In case of `REVERT`, it will also return the reverted return data in hex format. -- GitLab From 21dad1d41ec3d1336a9a6a7c7e8eb4c9194dc2bd Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 9 May 2018 23:25:58 +0200 Subject: [PATCH 138/263] Rename `whisper-cli binary` to `whisper` (#8579) * rename whisper-cli binary to whisper * fix tests --- whisper/cli/Cargo.toml | 4 +++- whisper/cli/src/main.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/whisper/cli/Cargo.toml b/whisper/cli/Cargo.toml index 363471a1a3..9aea1a8776 100644 --- a/whisper/cli/Cargo.toml +++ b/whisper/cli/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "whisper-cli" +description = "Whisper command line interface" version = "0.1.0" authors = ["Parity Technologies "] +license = "GPL-3.0" [dependencies] ethcore-network-devp2p = { path = "../../util/network-devp2p" } @@ -18,5 +20,5 @@ jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branc log = "0.3" [[bin]] -name = "whisper-cli" +name = "whisper" path = "src/main.rs" diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index d0866cd66a..f9211b993b 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -46,7 +46,7 @@ use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation}; const POOL_UNIT: usize = 1024 * 1024; const USAGE: &'static str = r#" Whisper CLI. - Copyright 2017 Parity Technologies (UK) Ltd + Copyright 2018 Parity Technologies (UK) Ltd Usage: whisper [options] @@ -56,7 +56,7 @@ Options: --whisper-pool-size SIZE Specify Whisper pool size [default: 10]. -p, --port PORT Specify which RPC port to use [default: 8545]. -a, --address ADDRESS Specify which address to use [default: 127.0.0.1]. - -l, --log LEVEL Specify the logging level. Must conform to the same format as RUST_LOG [default: Error]. + -l, --log LEVEL Specify the logging level. Must conform to the same format as RUST_LOG [default: Error]. -h, --help Display this message and exit. "#; @@ -259,7 +259,7 @@ mod tests { #[test] fn invalid_argument() { - let command = vec!["whisper-cli", "--foo=12"] + let command = vec!["whisper", "--foo=12"] .into_iter() .map(Into::into) .collect::>(); @@ -270,7 +270,7 @@ mod tests { #[test] #[ignore] fn privileged_port() { - let command = vec!["whisper-cli", "--port=3"] + let command = vec!["whisper", "--port=3"] .into_iter() .map(Into::into) .collect::>(); @@ -280,7 +280,7 @@ mod tests { #[test] fn invalid_ip_address() { - let command = vec!["whisper-cli", "--address=x.x.x.x"] + let command = vec!["whisper", "--address=x.x.x.x"] .into_iter() .map(Into::into) .collect::>(); @@ -290,7 +290,7 @@ mod tests { #[test] fn invalid_whisper_pool_size() { - let command = vec!["whisper-cli", "--whisper-pool-size=-100000000000000000000000000000000000000"] + let command = vec!["whisper", "--whisper-pool-size=-100000000000000000000000000000000000000"] .into_iter() .map(Into::into) .collect::>(); -- GitLab From b2cc1c54f891c35364627757280ee33e836987ef Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 9 May 2018 23:26:30 +0200 Subject: [PATCH 139/263] Add whisper CLI to the pipelines (#8578) * Add whisper CLI to the pipelines * Address todo, ref #8579 --- scripts/gitlab-build.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/gitlab-build.sh b/scripts/gitlab-build.sh index 89fa2a0854..2f1b7b8d08 100755 --- a/scripts/gitlab-build.sh +++ b/scripts/gitlab-build.sh @@ -62,13 +62,16 @@ build () { cargo build --target $PLATFORM --release -p ethstore-cli echo "Build ethkey-cli:" cargo build --target $PLATFORM --release -p ethkey-cli + echo "Build whisper-cli:" + cargo build --target $PLATFORM --release -p whisper-cli } strip_binaries () { echo "Strip binaries:" $STRIP_BIN -v target/$PLATFORM/release/parity $STRIP_BIN -v target/$PLATFORM/release/parity-evm $STRIP_BIN -v target/$PLATFORM/release/ethstore - $STRIP_BIN -v target/$PLATFORM/release/ethkey; + $STRIP_BIN -v target/$PLATFORM/release/ethkey + $STRIP_BIN -v target/$PLATFORM/release/whisper; } calculate_checksums () { echo "Checksum calculation:" @@ -89,6 +92,8 @@ calculate_checksums () { $SHA256_BIN target/$PLATFORM/release/ethstore$S3WIN > ethstore$S3WIN.sha256 $MD5_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.md5 $SHA256_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.sha256 + $MD5_BIN target/$PLATFORM/release/whisper$S3WIN > whisper$S3WIN.md5 + $SHA256_BIN target/$PLATFORM/release/whisper$S3WIN > whisper$S3WIN.sha256 } make_deb () { rm -rf deb @@ -122,6 +127,7 @@ make_deb () { cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey + cp target/$PLATFORM/release/whisper deb/usr/bin/whisper dpkg-deb -b deb "parity_"$VER"_"$IDENT"_"$ARC".deb" $MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.md5" $SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.sha256" @@ -133,6 +139,7 @@ make_rpm () { cp target/$PLATFORM/release/parity-evm /install/usr/bin/parity-evm cp target/$PLATFORM/release/ethstore /install/usr/bin/ethstore cp target/$PLATFORM/release/ethkey /install/usr/bin/ethkey + cp target/$PLATFORM/release/whisper /install/usr/bin/whisper rm -rf "parity-"$VER"-1."$ARC".rpm" || true fpm -s dir -t rpm -n parity -v $VER --epoch 1 --license GPLv3 -d openssl --provides parity --url https://parity.io --vendor "Parity Technologies" -a x86_64 -m "" --description "Ethereum network client by Parity Technologies" -C /install/ @@ -146,6 +153,7 @@ make_pkg () { cp target/$PLATFORM/release/parity-evm target/release/parity-evm cp target/$PLATFORM/release/ethstore target/release/ethstore cp target/$PLATFORM/release/ethkey target/release/ethkey + cp target/$PLATFORM/release/whisper target/release/whisper cd mac xcodebuild -configuration Release cd .. @@ -194,6 +202,9 @@ push_binaries () { aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN --body target/$PLATFORM/release/ethkey$S3WIN aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.md5 --body ethkey$S3WIN.md5 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.sha256 --body ethkey$S3WIN.sha256 + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN --body target/$PLATFORM/release/whisper$S3WIN + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN.md5 --body whisper$S3WIN.md5 + aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN.sha256 --body whisper$S3WIN.sha256 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" @@ -201,7 +212,7 @@ push_binaries () { make_archive () { echo "add artifacts to archive" rm -rf parity.zip - zip -r parity.zip target/$PLATFORM/release/parity$S3WIN target/$PLATFORM/release/parity-evm$S3WIN target/$PLATFORM/release/ethstore$S3WIN target/$PLATFORM/release/ethkey$S3WIN parity$S3WIN.md5 parity-evm$S3WIN.md5 ethstore$S3WIN.md5 ethkey$S3WIN.md5 parity$S3WIN.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256 + zip -r parity.zip target/$PLATFORM/release/parity$S3WIN target/$PLATFORM/release/parity-evm$S3WIN target/$PLATFORM/release/ethstore$S3WIN target/$PLATFORM/release/ethkey$S3WIN target/$PLATFORM/release/whisper$S3WIN parity$S3WIN.md5 parity-evm$S3WIN.md5 ethstore$S3WIN.md5 ethkey$S3WIN.md5 whisper$S3WIN.md5 parity$S3WIN.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256 whisper$S3WIN.sha256 } updater_push_release () { -- GitLab From a57c45bb1c79799a5ec68dd30eedb755545809bc Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 9 May 2018 23:28:16 +0200 Subject: [PATCH 140/263] Added Dockerfile for alpine linux by @andresilva, closes #3565 (#8587) --- docker/alpine/Dockerfile | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 docker/alpine/Dockerfile diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile new file mode 100644 index 0000000000..ad8879ecf7 --- /dev/null +++ b/docker/alpine/Dockerfile @@ -0,0 +1,29 @@ +FROM alpine:3.7 + +WORKDIR /build + +# install tools and dependencies +RUN apk add --no-cache gcc musl-dev openssl-dev pkgconfig g++ make curl \ + eudev-dev rust cargo git file binutils libusb-dev \ + linux-headers + +# show backtraces +ENV RUST_BACKTRACE 1 + +# show tools +RUN rustc -vV && \ +cargo -V && \ +gcc -v &&\ +g++ -v + +# build parity +ADD . /build/parity +RUN cd parity && \ + cargo build --release --verbose && \ + ls /build/parity/target/release/parity && \ + strip /build/parity/target/release/parity + +RUN file /build/parity/target/release/parity + +EXPOSE 8080 8545 8180 +ENTRYPOINT ["/build/parity/target/release/parity"] -- GitLab From fb0e6cf0d0759bf0f0657f9995b666e1d9ec3e7b Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Thu, 10 May 2018 12:33:40 +0200 Subject: [PATCH 141/263] Changelog and Readme (#8591) * Move changelog for 1.10.x * Mark 1.9 EOL * Prepare changelog for 1.10.3 stable * Prepare changelog for 1.11.0 stable * Update changelogs * Update CHANGELOG for 1.10.3 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Format changelog * Update README for 1.11 * Fix typo --- README.md | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index bfa7bde7bf..36e855fe42 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,7 @@ Get in touch with us on Gitter: Or join our community on Matrix: [![Riot: +Parity](https://img.shields.io/badge/riot-%2Bparity%3Amatrix.parity.io-orange.svg)](https://riot.im/app/#/group/+parity:matrix.parity.io) -Official website: https://parity.io - -Be sure to check out [our wiki](https://wiki.parity.io) for more information. +Official website: https://parity.io | Be sure to check out [our wiki](https://wiki.parity.io) for more information. ---- @@ -29,28 +27,19 @@ Be sure to check out [our wiki](https://wiki.parity.io) for more information. Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. -Parity comes with a built-in wallet, to install it please follow [these instructions](https://wiki.parity.io/Parity-Wallet). It includes various functionality allowing you to: - -- create and manage your Ethereum accounts; -- manage your Ether and any Ethereum tokens; -- create and register your own tokens; -- and much more. - -From Parity Ethereum client version >=1.10, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want). +From Parity Ethereum client version 1.10.0, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want). By default, Parity will also run a JSONRPC server on `127.0.0.1:8545` and a websockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs. -If you run into an issue while using Parity, feel free to file one in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! - -**For security-critical issues**, please refer to the security policy outlined in [SECURITY.MD](SECURITY.md). +If you run into an issue while using Parity, feel free to file one in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! **For security-critical issues**, please refer to the security policy outlined in [SECURITY.MD](SECURITY.md). -Parity's current release is 1.9. You can download it at https://github.com/paritytech/parity/releases or follow the instructions below to build from source. +Parity's current beta-release is 1.11. You can download it at https://github.com/paritytech/parity/releases or follow the instructions below to build from source. ---- ## Build dependencies -**Parity requires Rust version 1.23.0 to build** +**Parity requires Rust version 1.26.0 to build** We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this: @@ -124,13 +113,7 @@ Note: if cargo fails to parse manifest try: $ ~/.cargo/bin/cargo build --release ``` -Note: When compiling a crate and you receive the following error: - -``` -error: the crate is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` -``` - -Cleaning the repository will most likely solve the issue, try: +Note, when compiling a crate and you receive errors, it's in most cases your outdated version of Rust, or some of your crates have to be recompiled. Cleaning the repository will most likely solve the issue if you are on the latest stable version of Rust, try: ```bash $ cargo clean -- GitLab From 6e2e08628a91ae248729030e3ece3b8e926c805f Mon Sep 17 00:00:00 2001 From: David Date: Thu, 10 May 2018 12:33:56 +0200 Subject: [PATCH 142/263] Attempt to fix intermittent test failures (#8584) Occasionally should_return_correct_nonces_when_dropped_because_of_limit fails, possibly because of multiple threads competing to finish. See CI logs here for an example: https://gitlab.parity.io/parity/parity/-/jobs/86738 --- miner/src/pool/tests/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 0d8e38a6e1..5d80c2d5bf 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -63,8 +63,10 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() { let nonce = tx1.nonce; // when - let result = txq.import(TestClient::new(), vec![tx1, tx2].local()); - assert_eq!(result, vec![Ok(()), Err(transaction::Error::LimitReached)]); + let r1= txq.import(TestClient::new(), vec![tx1].local()); + let r2= txq.import(TestClient::new(), vec![tx2].local()); + assert_eq!(r1, vec![Ok(())]); + assert_eq!(r2, vec![Err(transaction::Error::LimitReached)]); assert_eq!(txq.status().status.transaction_count, 1); // then -- GitLab From 1b8f299df2e6a29738a090c47911cc218db49b8d Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 10 May 2018 12:34:36 +0200 Subject: [PATCH 143/263] Make mio optional in ethcore-io (#8537) * Make mio optional in ethcore-io * Add some annotations, plus a check for features * Increase timer for test --- Cargo.lock | 46 ++- ethcore/sync/Cargo.toml | 1 + test.sh | 2 + util/io/Cargo.toml | 9 +- util/io/src/lib.rs | 145 +++++++-- util/io/src/{service.rs => service_mio.rs} | 16 +- util/io/src/service_non_mio.rs | 334 +++++++++++++++++++++ util/io/src/worker.rs | 11 +- util/network-devp2p/Cargo.toml | 2 +- 9 files changed, 508 insertions(+), 58 deletions(-) rename util/io/src/{service.rs => service_mio.rs} (97%) create mode 100644 util/io/src/service_non_mio.rs diff --git a/Cargo.lock b/Cargo.lock index edd76f9f4d..b4d6bd315f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -209,6 +209,16 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "chrono" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cid" version = "0.2.3" @@ -542,7 +552,7 @@ dependencies = [ "memory-cache 0.1.0", "memorydb 0.1.1", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-machine 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", @@ -597,10 +607,14 @@ name = "ethcore-io" version = "1.12.0" dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -991,7 +1005,7 @@ dependencies = [ "dir 0.1.0", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethstore 0.2.0", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1117,7 +1131,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1483,7 +1497,7 @@ dependencies = [ "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)", @@ -1888,7 +1902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1981,7 +1995,7 @@ dependencies = [ "migration-rocksdb 0.1.0", "node-filter 1.12.0", "node-health 0.1.0", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parity-dapps 1.12.0", @@ -2680,7 +2694,7 @@ dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3183,7 +3197,7 @@ name = "threadpool" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3197,6 +3211,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "timer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tiny-keccak" version = "1.4.1" @@ -3350,7 +3372,7 @@ dependencies = [ "crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3795,6 +3817,7 @@ dependencies = [ "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" "checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" @@ -3903,7 +3926,7 @@ dependencies = [ "checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" -"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" +"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902" "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efa535d5117d3661134dbf1719b6f0ffe06f2375843b13935db186cd094105eb" @@ -4001,6 +4024,7 @@ dependencies = [ "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" +"checksum timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b" "checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" "checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index ba03075d0e..cf163cc7bd 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -34,6 +34,7 @@ trace-time = { path = "../../util/trace-time" } ipnetwork = "0.12.6" [dev-dependencies] +ethcore-io = { path = "../../util/io", features = ["mio"] } ethkey = { path = "../../ethkey" } kvdb-memorydb = { path = "../../util/kvdb-memorydb" } ethcore-private-tx = { path = "../private-tx" } diff --git a/test.sh b/test.sh index 6dcd258ea3..9bb527b708 100755 --- a/test.sh +++ b/test.sh @@ -33,6 +33,8 @@ if [ "$VALIDATE" -eq "1" ]; then # Validate --no-default-features build echo "________Validate build________" cargo check --no-default-features +cargo check --manifest-path util/io/Cargo.toml --no-default-features +cargo check --manifest-path util/io/Cargo.toml --features "mio" # Validate chainspecs echo "________Validate chainspecs________" diff --git a/util/io/Cargo.toml b/util/io/Cargo.toml index 8538863d03..7168866160 100644 --- a/util/io/Cargo.toml +++ b/util/io/Cargo.toml @@ -7,9 +7,12 @@ version = "1.12.0" authors = ["Parity Technologies "] [dependencies] -mio = "0.6.8" +fnv = "1.0" +mio = { version = "0.6.8", optional = true } crossbeam = "0.3" parking_lot = "0.5" log = "0.3" -slab = "0.2" - +slab = "0.4" +num_cpus = "1.8" +timer = "0.2" +time = "0.1" diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index 9232b2a909..ef8c3adc7e 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -54,30 +54,59 @@ //! // Drop the service //! } //! ``` +//! +//! # Mio vs non-mio +//! +//! This library has two modes: mio and not mio. The `mio` feature can be activated or deactivated +//! when compiling or depending on the library. +//! +//! Without mio, only timers and message-passing are available. With mio, you can also use +//! low-level sockets provided by mio. +//! +//! The non-mio mode exists because the `mio` library doesn't compile on platforms such as +//! emscripten. //TODO: use Poll from mio #![allow(deprecated)] +#[cfg(feature = "mio")] extern crate mio; #[macro_use] extern crate log as rlog; extern crate slab; extern crate crossbeam; extern crate parking_lot; +extern crate num_cpus; +extern crate timer; +extern crate fnv; +extern crate time; -mod service; +#[cfg(feature = "mio")] +mod service_mio; +#[cfg(not(feature = "mio"))] +mod service_non_mio; +#[cfg(feature = "mio")] mod worker; +use std::cell::Cell; use std::{fmt, error}; +#[cfg(feature = "mio")] use mio::deprecated::{EventLoop, NotifyError}; +#[cfg(feature = "mio")] use mio::Token; -pub use worker::LOCAL_STACK_SIZE; +thread_local! { + /// Stack size + /// Should be modified if it is changed in Rust since it is no way + /// to know or get it + pub static LOCAL_STACK_SIZE: Cell = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024)); +} #[derive(Debug)] /// IO Error pub enum IoError { /// Low level error from mio crate + #[cfg(feature = "mio")] Mio(::std::io::Error), /// Error concerning the Rust standard library's IO subsystem. StdIo(::std::io::Error), @@ -88,6 +117,7 @@ impl fmt::Display for IoError { // just defer to the std implementation for now. // we can refine the formatting when more variants are added. match *self { + #[cfg(feature = "mio")] IoError::Mio(ref std_err) => std_err.fmt(f), IoError::StdIo(ref std_err) => std_err.fmt(f), } @@ -106,8 +136,9 @@ impl From<::std::io::Error> for IoError { } } -impl From>> for IoError where Message: Send { - fn from(_err: NotifyError>) -> IoError { +#[cfg(feature = "mio")] +impl From>> for IoError where Message: Send { + fn from(_err: NotifyError>) -> IoError { IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error")) } } @@ -123,58 +154,120 @@ pub trait IoHandler: Send + Sync where Message: Send + Sync + 'static { /// Called when a broadcasted message is received. The message can only be sent from a different IO handler. fn message(&self, _io: &IoContext, _message: &Message) {} /// Called when an IO stream gets closed + #[cfg(feature = "mio")] fn stream_hup(&self, _io: &IoContext, _stream: StreamToken) {} /// Called when an IO stream can be read from + #[cfg(feature = "mio")] fn stream_readable(&self, _io: &IoContext, _stream: StreamToken) {} /// Called when an IO stream can be written to + #[cfg(feature = "mio")] fn stream_writable(&self, _io: &IoContext, _stream: StreamToken) {} /// Register a new stream with the event loop + #[cfg(feature = "mio")] fn register_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop>) {} /// Re-register a stream with the event loop + #[cfg(feature = "mio")] fn update_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop>) {} /// Deregister a stream. Called whenstream is removed from event loop + #[cfg(feature = "mio")] fn deregister_stream(&self, _stream: StreamToken, _event_loop: &mut EventLoop>) {} } -pub use service::TimerToken; -pub use service::StreamToken; -pub use service::IoContext; -pub use service::IoService; -pub use service::IoChannel; -pub use service::IoManager; -pub use service::TOKENS_PER_HANDLER; +#[cfg(feature = "mio")] +pub use service_mio::{TimerToken, StreamToken, IoContext, IoService, IoChannel, IoManager, TOKENS_PER_HANDLER}; +#[cfg(not(feature = "mio"))] +pub use service_non_mio::{TimerToken, IoContext, IoService, IoChannel, TOKENS_PER_HANDLER}; #[cfg(test)] mod tests { - use std::sync::Arc; + use std::sync::atomic; + use std::thread; use std::time::Duration; use super::*; - struct MyHandler; + #[test] + fn send_message_to_handler() { + struct MyHandler(atomic::AtomicBool); - #[derive(Clone)] - struct MyMessage { - data: u32 - } + #[derive(Clone)] + struct MyMessage { + data: u32 + } - impl IoHandler for MyHandler { - fn initialize(&self, io: &IoContext) { - io.register_timer(0, Duration::from_secs(1)).unwrap(); + impl IoHandler for MyHandler { + fn message(&self, _io: &IoContext, message: &MyMessage) { + assert_eq!(message.data, 5); + self.0.store(true, atomic::Ordering::SeqCst); + } } - fn timeout(&self, _io: &IoContext, timer: TimerToken) { - println!("Timeout {}", timer); + let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false))); + + let service = IoService::::start().expect("Error creating network service"); + service.register_handler(handler.clone()).unwrap(); + + service.send_message(MyMessage { data: 5 }).unwrap(); + + thread::sleep(Duration::from_secs(5)); + assert!(handler.0.load(atomic::Ordering::SeqCst)); + } + + #[test] + fn timeout_working() { + struct MyHandler(atomic::AtomicBool); + + #[derive(Clone)] + struct MyMessage { + data: u32 } - fn message(&self, _io: &IoContext, message: &MyMessage) { - println!("Message {}", message.data); + impl IoHandler for MyHandler { + fn initialize(&self, io: &IoContext) { + io.register_timer_once(1234, Duration::from_millis(500)).unwrap(); + } + + fn timeout(&self, _io: &IoContext, timer: TimerToken) { + assert_eq!(timer, 1234); + assert!(!self.0.swap(true, atomic::Ordering::SeqCst)); + } } + + let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false))); + + let service = IoService::::start().expect("Error creating network service"); + service.register_handler(handler.clone()).unwrap(); + + thread::sleep(Duration::from_secs(2)); + assert!(handler.0.load(atomic::Ordering::SeqCst)); } #[test] - fn test_service_register_handler () { + fn multi_timeout_working() { + struct MyHandler(atomic::AtomicUsize); + + #[derive(Clone)] + struct MyMessage { + data: u32 + } + + impl IoHandler for MyHandler { + fn initialize(&self, io: &IoContext) { + io.register_timer(1234, Duration::from_millis(500)).unwrap(); + } + + fn timeout(&self, _io: &IoContext, timer: TimerToken) { + assert_eq!(timer, 1234); + self.0.fetch_add(1, atomic::Ordering::SeqCst); + } + } + + let handler = Arc::new(MyHandler(atomic::AtomicUsize::new(0))); + let service = IoService::::start().expect("Error creating network service"); - service.register_handler(Arc::new(MyHandler)).unwrap(); + service.register_handler(handler.clone()).unwrap(); + + thread::sleep(Duration::from_secs(2)); + assert!(handler.0.load(atomic::Ordering::SeqCst) >= 2); } } diff --git a/util/io/src/service.rs b/util/io/src/service_mio.rs similarity index 97% rename from util/io/src/service.rs rename to util/io/src/service_mio.rs index 0de674ae12..f7c9f1976c 100644 --- a/util/io/src/service.rs +++ b/util/io/src/service_mio.rs @@ -181,7 +181,7 @@ struct UserTimer { /// Root IO handler. Manages user handlers, messages and IO timers. pub struct IoManager where Message: Send + Sync { timers: Arc>>, - handlers: Arc>, HandlerId>>>, + handlers: Arc>>>>, workers: Vec, worker_channel: chase_lev::Worker>, work_ready: Arc, @@ -191,7 +191,7 @@ impl IoManager where Message: Send + Sync + 'static { /// Creates a new instance and registers it with the event loop. pub fn start( event_loop: &mut EventLoop>, - handlers: Arc>, HandlerId>>> + handlers: Arc>>>> ) -> Result<(), IoError> { let (worker, stealer) = chase_lev::deque(); let num_workers = 4; @@ -267,7 +267,8 @@ impl Handler for IoManager where Message: Send + Sync + 'stati event_loop.shutdown(); }, IoMessage::AddHandler { handler } => { - let handler_id = self.handlers.write().insert(handler.clone()).unwrap_or_else(|_| panic!("Too many handlers registered")); + let handler_id = self.handlers.write().insert(handler.clone()); + assert!(handler_id <= MAX_HANDLERS, "Too many handlers registered"); handler.initialize(&IoContext::new(IoChannel::new(event_loop.channel(), Arc::downgrade(&self.handlers)), handler_id)); }, IoMessage::RemoveHandler { handler_id } => { @@ -332,7 +333,7 @@ impl Handler for IoManager where Message: Send + Sync + 'stati } enum Handlers where Message: Send { - SharedCollection(Weak>, HandlerId>>>), + SharedCollection(Weak>>>>), Single(Weak>), } @@ -417,7 +418,7 @@ impl IoChannel where Message: Send + Sync + 'static { handlers: Handlers::Single(handler), } } - fn new(channel: Sender>, handlers: Weak>, HandlerId>>>) -> IoChannel { + fn new(channel: Sender>, handlers: Weak>>>>) -> IoChannel { IoChannel { channel: Some(channel), handlers: Handlers::SharedCollection(handlers), @@ -430,7 +431,7 @@ impl IoChannel where Message: Send + Sync + 'static { pub struct IoService where Message: Send + Sync + 'static { thread: Mutex>>, host_channel: Mutex>>, - handlers: Arc>, HandlerId>>>, + handlers: Arc>>>>, } impl IoService where Message: Send + Sync + 'static { @@ -440,7 +441,7 @@ impl IoService where Message: Send + Sync + 'static { config.messages_per_tick(1024); let mut event_loop = config.build().expect("Error creating event loop"); let channel = event_loop.channel(); - let handlers = Arc::new(RwLock::new(Slab::new(MAX_HANDLERS))); + let handlers = Arc::new(RwLock::new(Slab::with_capacity(MAX_HANDLERS))); let h = handlers.clone(); let thread = thread::spawn(move || { IoManager::::start(&mut event_loop, h).expect("Error starting IO service"); @@ -491,4 +492,3 @@ impl Drop for IoService where Message: Send + Sync { self.stop() } } - diff --git a/util/io/src/service_non_mio.rs b/util/io/src/service_non_mio.rs new file mode 100644 index 0000000000..22a795e4e8 --- /dev/null +++ b/util/io/src/service_non_mio.rs @@ -0,0 +1,334 @@ +// 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 . + +use std::sync::{Arc, Weak}; +use std::thread; +use crossbeam::sync::chase_lev; +use slab::Slab; +use fnv::FnvHashMap; +use {IoError, IoHandler}; +use parking_lot::{RwLock, Mutex}; +use num_cpus; +use std::time::Duration; +use timer::{Timer, Guard as TimerGuard}; +use time::Duration as TimeDuration; + +/// Timer ID +pub type TimerToken = usize; +/// IO Handler ID +pub type HandlerId = usize; + +/// Maximum number of tokens a handler can use +pub const TOKENS_PER_HANDLER: usize = 16384; +const MAX_HANDLERS: usize = 8; + +/// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem. +pub struct IoContext where Message: Send + Sync + 'static { + handler: HandlerId, + shared: Arc>, +} + +impl IoContext where Message: Send + Sync + 'static { + /// Register a new recurring IO timer. 'IoHandler::timeout' will be called with the token. + pub fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { + let channel = self.channel(); + + let msg = WorkTask::TimerTrigger { + handler_id: self.handler, + token: token, + }; + + let delay = TimeDuration::from_std(delay) + .map_err(|e| ::std::io::Error::new(::std::io::ErrorKind::Other, e))?; + let guard = self.shared.timer.lock().schedule_repeating(delay, move || { + channel.send_raw(msg.clone()); + }); + + self.shared.timers.lock().insert(token, guard); + + Ok(()) + } + + /// Register a new IO timer once. 'IoHandler::timeout' will be called with the token. + pub fn register_timer_once(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> { + let channel = self.channel(); + + let msg = WorkTask::TimerTrigger { + handler_id: self.handler, + token: token, + }; + + let delay = TimeDuration::from_std(delay) + .map_err(|e| ::std::io::Error::new(::std::io::ErrorKind::Other, e))?; + let guard = self.shared.timer.lock().schedule_with_delay(delay, move || { + channel.send_raw(msg.clone()); + }); + + self.shared.timers.lock().insert(token, guard); + + Ok(()) + } + + /// Delete a timer. + pub fn clear_timer(&self, token: TimerToken) -> Result<(), IoError> { + self.shared.timers.lock().remove(&token); + Ok(()) + } + + /// Broadcast a message to other IO clients + pub fn message(&self, message: Message) -> Result<(), IoError> { + if let Some(ref channel) = *self.shared.channel.lock() { + channel.push(WorkTask::UserMessage(Arc::new(message))); + } + for thread in self.shared.threads.read().iter() { + thread.unpark(); + } + + Ok(()) + } + + /// Get message channel + pub fn channel(&self) -> IoChannel { + IoChannel { shared: Arc::downgrade(&self.shared) } + } + + /// Unregister current IO handler. + pub fn unregister_handler(&self) -> Result<(), IoError> { + self.shared.handlers.write().remove(self.handler); + Ok(()) + } +} + +/// Allows sending messages into the event loop. All the IO handlers will get the message +/// in the `message` callback. +pub struct IoChannel where Message: Send + Sync + 'static { + shared: Weak>, +} + +impl Clone for IoChannel where Message: Send + Sync + 'static { + fn clone(&self) -> IoChannel { + IoChannel { + shared: self.shared.clone(), + } + } +} + +impl IoChannel where Message: Send + Sync + 'static { + /// Send a message through the channel + pub fn send(&self, message: Message) -> Result<(), IoError> { + if let Some(shared) = self.shared.upgrade() { + match *shared.channel.lock() { + Some(ref channel) => channel.push(WorkTask::UserMessage(Arc::new(message))), + None => self.send_sync(message)? + }; + + for thread in shared.threads.read().iter() { + thread.unpark(); + } + } + + Ok(()) + } + + /// Send a message through the channel and handle it synchronously + pub fn send_sync(&self, message: Message) -> Result<(), IoError> { + if let Some(shared) = self.shared.upgrade() { + for id in 0 .. MAX_HANDLERS { + if let Some(h) = shared.handlers.read().get(id) { + let handler = h.clone(); + let ctxt = IoContext { handler: id, shared: shared.clone() }; + handler.message(&ctxt, &message); + } + } + } + + Ok(()) + } + + // Send low level io message + fn send_raw(&self, message: WorkTask) { + if let Some(shared) = self.shared.upgrade() { + if let Some(ref channel) = *shared.channel.lock() { + channel.push(message); + } + + for thread in shared.threads.read().iter() { + thread.unpark(); + } + } + } + + /// Create a new channel disconnected from an event loop. + pub fn disconnected() -> IoChannel { + IoChannel { + shared: Weak::default(), + } + } +} + +/// General IO Service. Starts an event loop and dispatches IO requests. +/// 'Message' is a notification message type +pub struct IoService where Message: Send + Sync + 'static { + thread_joins: Mutex>>, + shared: Arc>, +} + +// Struct shared throughout the whole implementation. +struct Shared where Message: Send + Sync + 'static { + // All the I/O handlers that have been registered. + handlers: RwLock>>>, + // All the background threads, so that we can unpark them. + threads: RwLock>, + // Used to create timeouts. + timer: Mutex, + // List of created timers. We need to keep them in a data struct so that we can cancel them if + // necessary. + timers: Mutex>, + // Channel used to send work to the worker threads. + channel: Mutex>>>, +} + +// Messages used to communicate with the event loop from other threads. +enum WorkTask where Message: Send + Sized { + Shutdown, + TimerTrigger { + handler_id: HandlerId, + token: TimerToken, + }, + UserMessage(Arc) +} + +impl Clone for WorkTask where Message: Send + Sized { + fn clone(&self) -> WorkTask { + match *self { + WorkTask::Shutdown => WorkTask::Shutdown, + WorkTask::TimerTrigger { handler_id, token } => WorkTask::TimerTrigger { handler_id, token }, + WorkTask::UserMessage(ref msg) => WorkTask::UserMessage(msg.clone()), + } + } +} + +impl IoService where Message: Send + Sync + 'static { + /// Starts IO event loop + pub fn start() -> Result, IoError> { + let (tx, rx) = chase_lev::deque(); + + let shared = Arc::new(Shared { + handlers: RwLock::new(Slab::with_capacity(MAX_HANDLERS)), + threads: RwLock::new(Vec::new()), + timer: Mutex::new(Timer::new()), + timers: Mutex::new(FnvHashMap::default()), + channel: Mutex::new(Some(tx)), + }); + + let thread_joins = (0 .. num_cpus::get()).map(|_| { + let rx = rx.clone(); + let shared = shared.clone(); + thread::spawn(move || { + do_work(&shared, rx) + }) + }).collect::>(); + + *shared.threads.write() = thread_joins.iter().map(|t| t.thread().clone()).collect(); + + Ok(IoService { + thread_joins: Mutex::new(thread_joins), + shared, + }) + } + + /// Stops the IO service. + pub fn stop(&self) { + trace!(target: "shutdown", "[IoService] Closing..."); + // Clear handlers so that shared pointers are not stuck on stack + // in Channel::send_sync + self.shared.handlers.write().clear(); + let channel = self.shared.channel.lock().take(); + let mut thread_joins = self.thread_joins.lock(); + if let Some(channel) = channel { + for _ in 0 .. thread_joins.len() { + channel.push(WorkTask::Shutdown); + } + } + for thread in thread_joins.drain(..) { + thread.thread().unpark(); + thread.join().unwrap_or_else(|e| { + debug!(target: "shutdown", "Error joining IO service worker thread: {:?}", e); + }); + } + trace!(target: "shutdown", "[IoService] Closed."); + } + + /// Register an IO handler with the event loop. + pub fn register_handler(&self, handler: Arc+Send>) -> Result<(), IoError> { + let id = self.shared.handlers.write().insert(handler.clone()); + assert!(id <= MAX_HANDLERS, "Too many handlers registered"); + let ctxt = IoContext { handler: id, shared: self.shared.clone() }; + handler.initialize(&ctxt); + Ok(()) + } + + /// Send a message over the network. Normaly `HostIo::send` should be used. This can be used from non-io threads. + pub fn send_message(&self, message: Message) -> Result<(), IoError> { + if let Some(ref channel) = *self.shared.channel.lock() { + channel.push(WorkTask::UserMessage(Arc::new(message))); + } + for thread in self.shared.threads.read().iter() { + thread.unpark(); + } + Ok(()) + } + + /// Create a new message channel + #[inline] + pub fn channel(&self) -> IoChannel { + IoChannel { + shared: Arc::downgrade(&self.shared) + } + } +} + +impl Drop for IoService where Message: Send + Sync { + fn drop(&mut self) { + self.stop() + } +} + +fn do_work(shared: &Arc>, rx: chase_lev::Stealer>) + where Message: Send + Sync + 'static +{ + loop { + match rx.steal() { + chase_lev::Steal::Abort => continue, + chase_lev::Steal::Empty => thread::park(), + chase_lev::Steal::Data(WorkTask::Shutdown) => break, + chase_lev::Steal::Data(WorkTask::UserMessage(message)) => { + for id in 0 .. MAX_HANDLERS { + if let Some(handler) = shared.handlers.read().get(id) { + let ctxt = IoContext { handler: id, shared: shared.clone() }; + handler.message(&ctxt, &message); + } + } + }, + chase_lev::Steal::Data(WorkTask::TimerTrigger { handler_id, token }) => { + if let Some(handler) = shared.handlers.read().get(handler_id) { + let ctxt = IoContext { handler: handler_id, shared: shared.clone() }; + handler.timeout(&ctxt, token); + } + }, + } + } +} diff --git a/util/io/src/worker.rs b/util/io/src/worker.rs index 0f0d448ecb..89657810dc 100644 --- a/util/io/src/worker.rs +++ b/util/io/src/worker.rs @@ -18,21 +18,14 @@ use std::sync::Arc; use std::thread::{JoinHandle, self}; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use crossbeam::sync::chase_lev; -use service::{HandlerId, IoChannel, IoContext}; +use service_mio::{HandlerId, IoChannel, IoContext}; use IoHandler; -use std::cell::Cell; +use LOCAL_STACK_SIZE; use std::sync::{Condvar as SCondvar, Mutex as SMutex}; const STACK_SIZE: usize = 16*1024*1024; -thread_local! { - /// Stack size - /// Should be modified if it is changed in Rust since it is no way - /// to know or get it - pub static LOCAL_STACK_SIZE: Cell = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024)); -} - pub enum WorkType { Readable, Writable, diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 3ec9684393..f4889fe26d 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -19,7 +19,7 @@ libc = "0.2.7" parking_lot = "0.5" ansi_term = "0.10" rustc-hex = "1.0" -ethcore-io = { path = "../io" } +ethcore-io = { path = "../io", features = ["mio"] } ethcore-bytes = { path = "../bytes" } ethcore-crypto = { path = "../../ethcore/crypto" } ethcore-logger = { path ="../../logger" } -- GitLab From aea26dcc640696a712befd5339ab3186bcc3426b Mon Sep 17 00:00:00 2001 From: Thibaut S <33178835+Tbaut@users.noreply.github.com> Date: Fri, 11 May 2018 08:04:04 +0100 Subject: [PATCH 144/263] Fix Parity UI link (#8600) Fix link https://github.com/paritytech/parity/issues/8599 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36e855fe42..9255d014b6 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Official website: https://parity.io | Be sure to check out [our wiki](https://wi Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. -From Parity Ethereum client version 1.10.0, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want). +From Parity Ethereum client version 1.10.0, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization#the-parity-ui-application-isnt-working-the-way-i-want). By default, Parity will also run a JSONRPC server on `127.0.0.1:8545` and a websockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs. -- GitLab From ecd7caa93d803d1f07b4f6888e5f13de6d189fb8 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 11 May 2018 11:23:19 +0200 Subject: [PATCH 145/263] fix compiler warning (#8590) --- ethcore/sync/src/light_sync/response.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs index 74665118b7..3629613224 100644 --- a/ethcore/sync/src/light_sync/response.rs +++ b/ethcore/sync/src/light_sync/response.rs @@ -16,7 +16,7 @@ //! Helpers for decoding and verifying responses for headers. -use ethcore::{self, encoded, header::Header}; +use ethcore::{encoded, header::Header}; use ethereum_types::H256; use light::request::{HashOrNumber, CompleteHeadersRequest as HeadersRequest}; use rlp::DecoderError; -- GitLab From 61ec02248aa4acb21ff35999dd2c8945478eeb32 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 11 May 2018 11:33:13 +0200 Subject: [PATCH 146/263] Block::decode() returns Result (#8586) --- ethcore/src/encoded.rs | 2 +- ethcore/src/snapshot/consensus/authority.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index c436607f8c..5a2d376a2a 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -206,7 +206,7 @@ impl Block { pub fn header_view(&self) -> HeaderView { self.view().header_view() } /// Decode to a full block. - pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0).expect("decoding failure") } + pub fn decode(&self) -> Result { rlp::decode(&self.0) } /// Decode the header. pub fn decode_header(&self) -> FullHeader { self.view().rlp().val_at(0) } diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index 474f5d350c..38d2c184ca 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -100,7 +100,7 @@ impl SnapshotComponents for PoaSnapshot { let (block, receipts) = chain.block(&block_at) .and_then(|b| chain.block_receipts(&block_at).map(|r| (b, r))) .ok_or(Error::BlockNotFound(block_at))?; - let block = block.decode(); + let block = block.decode()?; let parent_td = chain.block_details(block.header.parent_hash()) .map(|d| d.total_difficulty) -- GitLab From 25dc1c2155c8e84f2263e46b830f24f51a6e5195 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 11 May 2018 11:34:07 +0200 Subject: [PATCH 147/263] block_header can fail so return Result (#8581) * block_header can fail so return Result * Restore previous return type based on feedback * Fix failing doc tests running on non-code --- rpc/src/v1/impls/light/parity.rs | 9 ++++----- util/journaldb/src/earlymergedb.rs | 6 +++--- util/journaldb/src/refcounteddb.rs | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 982c7ff363..025538fc42 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -395,9 +395,9 @@ impl Parity for ParityClient { let engine = self.light_dispatch.client.engine().clone(); let from_encoded = move |encoded: encoded::Header| { - let header = encoded.decode().expect("decoding error"); // REVIEW: not sure what to do here; what is a decent return value for the error case here? + let header = encoded.decode().map_err(errors::decode)?; let extra_info = engine.extra_info(&header); - RichHeader { + Ok(RichHeader { inner: Header { hash: Some(header.hash().into()), size: Some(encoded.rlp().as_raw().len().into()), @@ -418,9 +418,8 @@ impl Parity for ParityClient { extra_data: Bytes::new(header.extra_data().clone()), }, extra_info: extra_info, - } + }) }; - // Note: Here we treat `Pending` as `Latest`. // Since light clients don't produce pending blocks // (they don't have state) we can safely fallback to `Latest`. @@ -430,7 +429,7 @@ impl Parity for ParityClient { BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, }; - Box::new(self.fetcher().header(id).map(from_encoded)) + Box::new(self.fetcher().header(id).and_then(from_encoded)) } fn ipfs_cid(&self, content: Bytes) -> Result { diff --git a/util/journaldb/src/earlymergedb.rs b/util/journaldb/src/earlymergedb.rs index e76cdcd313..c26a67e0ad 100644 --- a/util/journaldb/src/earlymergedb.rs +++ b/util/journaldb/src/earlymergedb.rs @@ -57,7 +57,7 @@ enum RemoveFrom { /// the removals actually take effect. /// /// journal format: -/// ``` +/// ```text /// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, n] => [ ... ] @@ -76,7 +76,7 @@ enum RemoveFrom { /// which includes an original key, if any. /// /// The semantics of the `counter` are: -/// ``` +/// ```text /// insert key k: /// counter already contains k: count += 1 /// counter doesn't contain k: @@ -92,7 +92,7 @@ enum RemoveFrom { /// /// Practically, this means that for each commit block turning from recent to ancient we do the /// following: -/// ``` +/// ```text /// is_canonical: /// inserts: Ignored (left alone in the backing database). /// deletes: Enacted; however, recent history queue is checked for ongoing references. This is diff --git a/util/journaldb/src/refcounteddb.rs b/util/journaldb/src/refcounteddb.rs index 944d81d373..d182d5cf80 100644 --- a/util/journaldb/src/refcounteddb.rs +++ b/util/journaldb/src/refcounteddb.rs @@ -40,7 +40,7 @@ use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef}; /// the removals actually take effect. /// /// journal format: -/// ``` +/// ```text /// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] /// [era, n] => [ ... ] -- GitLab From 1fa95ac236ab280afc9eccb4d6ea51b494f11422 Mon Sep 17 00:00:00 2001 From: Axel Chalon Date: Fri, 11 May 2018 12:09:42 +0200 Subject: [PATCH 148/263] Remove inject.js server-side injection for dapps (#8539) * Remove inject.js server-side injection for dapps * Remove dapps test `should_inject_js` Parity doesn't inject a "#, - apps::UTILS_PATH, - ); - - content.as_bytes().to_vec() - } else { - Vec::new() - }; - - let (reader, body) = Reader::pair(file.into_reader(), initial_content); + let (reader, body) = Reader::pair(file.into_reader(), Vec::new()); res.set_body(body); (Some(reader), res) } diff --git a/dapps/src/tests/home.rs b/dapps/src/tests/home.rs index 0ee0653648..fa5c5b4c46 100644 --- a/dapps/src/tests/home.rs +++ b/dapps/src/tests/home.rs @@ -60,32 +60,3 @@ fn should_serve_home() { response.assert_header("Content-Type", "text/html"); assert_security_headers(&response.headers); } - - -#[test] -fn should_inject_js() { - // given - let server = serve_ui(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "text/html"); - assert_eq!( - response.body.contains(r#"/inject.js">"#), - true, - "Expected inject script tag in: {}", - response.body - ); - assert_security_headers(&response.headers); -} -- GitLab From 57d1f2b4d35d79a69aabe4d4460463a8e2569ad3 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 11 May 2018 13:45:07 +0200 Subject: [PATCH 149/263] Fix the mio test again (#8602) --- util/io/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index ef8c3adc7e..cd635121ff 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -186,7 +186,12 @@ mod tests { use std::time::Duration; use super::*; + // Mio's behaviour is too unstable for this test. Sometimes we have to wait a few milliseconds, + // sometimes more than 5 seconds for the message to arrive. + // Therefore we ignore this test in order to not have spurious failure when running continuous + // integration. #[test] + #[cfg_attr(feature = "mio", ignore)] fn send_message_to_handler() { struct MyHandler(atomic::AtomicBool); @@ -209,7 +214,7 @@ mod tests { service.send_message(MyMessage { data: 5 }).unwrap(); - thread::sleep(Duration::from_secs(5)); + thread::sleep(Duration::from_secs(1)); assert!(handler.0.load(atomic::Ordering::SeqCst)); } -- GitLab From 979af3d3143a4219f8d7428f969d7c1b221d0133 Mon Sep 17 00:00:00 2001 From: lihuafeng <31607114+EighteenZi@users.noreply.github.com> Date: Sun, 13 May 2018 04:46:08 +0800 Subject: [PATCH 150/263] 2 tiny modification on snapshot (#8601) * Some tiny modifications. 1. fix some typo in the comment. 2. sort the order of methods in 'impl state::Backend for StateDB` * Remove the clone of code_cache, as it has been done in clone_basic. * remove From::from. It seems not necessary. * change mode: remove rust files' executable mode. * 2 tiny modifications on snapshot. --- ethcore/src/snapshot/consensus/work.rs | 2 +- ethcore/src/snapshot/service.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index 5414ed5963..b71f7b9d1d 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -229,7 +229,7 @@ impl Rebuilder for PowRebuilder { let item_count = rlp.item_count()?; let num_blocks = (item_count - 3) as u64; - trace!(target: "snapshot", "restoring block chunk with {} blocks.", item_count - 3); + trace!(target: "snapshot", "restoring block chunk with {} blocks.", num_blocks); if self.fed_blocks + num_blocks > self.snapshot_blocks { return Err(Error::TooManyBlocks(self.snapshot_blocks, self.fed_blocks + num_blocks).into()) diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 9cfb2eb63f..c5b9123e10 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -176,7 +176,7 @@ impl Restoration { // verify final state root. let root = self.state.state_root(); if root != self.final_state_root { - warn!("Final restored state has wrong state root: expected {:?}, got {:?}", root, self.final_state_root); + warn!("Final restored state has wrong state root: expected {:?}, got {:?}", self.final_state_root, root); return Err(TrieError::InvalidStateRoot(root).into()); } -- GitLab From 981554cf74980c9470abf23039ad39e75246eef8 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 15:22:59 +0800 Subject: [PATCH 151/263] Use full qualified syntax for itertools::Itertools::flatten (#8606) --- ethstore/src/accounts_dir/memory.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethstore/src/accounts_dir/memory.rs b/ethstore/src/accounts_dir/memory.rs index bd162b5ef0..5cfdba0e5c 100644 --- a/ethstore/src/accounts_dir/memory.rs +++ b/ethstore/src/accounts_dir/memory.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use parking_lot::RwLock; -use itertools::Itertools; +use itertools; use ethkey::Address; use {SafeAccount, Error}; @@ -30,7 +30,7 @@ pub struct MemoryDirectory { impl KeyDirectory for MemoryDirectory { fn load(&self) -> Result, Error> { - Ok(self.accounts.read().values().cloned().flatten().collect()) + Ok(itertools::Itertools::flatten(self.accounts.read().values().cloned()).collect()) } fn update(&self, account: SafeAccount) -> Result { -- GitLab From 08abf67a5118ad7846eb0a438cca5b0d54fb9666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 14 May 2018 10:09:05 +0200 Subject: [PATCH 152/263] Fix packet count when talking with PAR2 peers (#8555) * Support diferent packet counts in different protocol versions. * Fix light timeouts and eclipse protection. * Fix devp2p tests. * Fix whisper-cli compilation. * Fix compilation. * Fix ethcore-sync tests. * Revert "Fix light timeouts and eclipse protection." This reverts commit 06285ea8c1d9d184d809f64b5507aece633da6cc. * Increase timeouts. --- ethcore/light/src/net/mod.rs | 17 ++++++++++------- ethcore/sync/src/api.rs | 17 +++++++---------- ethcore/sync/src/chain/handler.rs | 8 +++++--- ethcore/sync/src/chain/mod.rs | 24 ++++++++++-------------- ethcore/sync/src/chain/requester.rs | 5 +++-- ethcore/sync/src/tests/helpers.rs | 4 ++-- parity/whisper.rs | 2 -- util/network-devp2p/src/host.rs | 13 +++++++++---- util/network-devp2p/src/lib.rs | 2 +- util/network-devp2p/src/service.rs | 13 +++++++++---- util/network-devp2p/tests/tests.rs | 4 ++-- util/network/src/lib.rs | 6 ++---- whisper/cli/src/main.rs | 4 ++-- whisper/src/net/mod.rs | 10 ++++++---- 14 files changed, 68 insertions(+), 61 deletions(-) diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index d58d90fac4..27d5c12a5f 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -75,14 +75,17 @@ const RECALCULATE_COSTS_INTERVAL: Duration = Duration::from_secs(60 * 60); // minimum interval between updates. const UPDATE_INTERVAL: Duration = Duration::from_millis(5000); +/// Packet count for PIP. +const PACKET_COUNT_V1: u8 = 9; + /// Supported protocol versions. -pub const PROTOCOL_VERSIONS: &'static [u8] = &[1]; +pub const PROTOCOL_VERSIONS: &'static [(u8, u8)] = &[ + (1, PACKET_COUNT_V1), +]; /// Max protocol version. pub const MAX_PROTOCOL_VERSION: u8 = 1; -/// Packet count for PIP. -pub const PACKET_COUNT: u8 = 9; // packet ID definitions. mod packet { @@ -111,9 +114,9 @@ mod packet { mod timeout { use std::time::Duration; - pub const HANDSHAKE: Duration = Duration::from_millis(2500); - pub const ACKNOWLEDGE_UPDATE: Duration = Duration::from_millis(5000); - pub const BASE: u64 = 1500; // base timeout for packet. + pub const HANDSHAKE: Duration = Duration::from_millis(4_000); + pub const ACKNOWLEDGE_UPDATE: Duration = Duration::from_millis(5_000); + pub const BASE: u64 = 2_500; // base timeout for packet. // timeouts per request within packet. pub const HEADERS: u64 = 250; // per header? @@ -688,7 +691,7 @@ impl LightProtocol { Err(e) => { punish(*peer, io, e); return } }; - if PROTOCOL_VERSIONS.iter().find(|x| **x == proto_version).is_none() { + if PROTOCOL_VERSIONS.iter().find(|x| x.0 == proto_version).is_none() { punish(*peer, io, Error::UnsupportedProtocolVersion(proto_version)); return; } diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 4fd0cbb54d..e901528e41 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -33,7 +33,7 @@ use chain::{ChainSync, SyncStatus as EthSyncStatus}; use std::net::{SocketAddr, AddrParseError}; use std::str::FromStr; use parking_lot::RwLock; -use chain::{ETH_PACKET_COUNT, SNAPSHOT_SYNC_PACKET_COUNT, ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_62, +use chain::{ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_62, PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3}; use light::client::AsLightClient; use light::Provider; @@ -202,10 +202,8 @@ pub struct AttachedProtocol { pub handler: Arc, /// 3-character ID for the protocol. pub protocol_id: ProtocolId, - /// Packet count. - pub packet_count: u8, - /// Supported versions. - pub versions: &'static [u8], + /// Supported versions and their packet counts. + pub versions: &'static [(u8, u8)], } impl AttachedProtocol { @@ -213,7 +211,6 @@ impl AttachedProtocol { let res = network.register_protocol( self.handler.clone(), self.protocol_id, - self.packet_count, self.versions ); @@ -459,15 +456,15 @@ impl ChainNotify for EthSync { Err(err) => warn!("Error starting network: {}", err), _ => {}, } - self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, ETH_PACKET_COUNT, &[ETH_PROTOCOL_VERSION_62, ETH_PROTOCOL_VERSION_63]) + self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, &[ETH_PROTOCOL_VERSION_62, ETH_PROTOCOL_VERSION_63]) .unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e)); // register the warp sync subprotocol - self.network.register_protocol(self.eth_handler.clone(), WARP_SYNC_PROTOCOL_ID, SNAPSHOT_SYNC_PACKET_COUNT, &[PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3]) + self.network.register_protocol(self.eth_handler.clone(), WARP_SYNC_PROTOCOL_ID, &[PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3]) .unwrap_or_else(|e| warn!("Error registering snapshot sync protocol: {:?}", e)); // register the light protocol. if let Some(light_proto) = self.light_proto.as_ref().map(|x| x.clone()) { - self.network.register_protocol(light_proto, self.light_subprotocol_name, ::light::net::PACKET_COUNT, ::light::net::PROTOCOL_VERSIONS) + self.network.register_protocol(light_proto, self.light_subprotocol_name, ::light::net::PROTOCOL_VERSIONS) .unwrap_or_else(|e| warn!("Error registering light client protocol: {:?}", e)); } @@ -827,7 +824,7 @@ impl ManageNetwork for LightSync { let light_proto = self.proto.clone(); - self.network.register_protocol(light_proto, self.subprotocol_name, ::light::net::PACKET_COUNT, ::light::net::PROTOCOL_VERSIONS) + self.network.register_protocol(light_proto, self.subprotocol_name, ::light::net::PROTOCOL_VERSIONS) .unwrap_or_else(|e| warn!("Error registering light client protocol: {:?}", e)); for proto in &self.attached_protos { proto.register(&self.network) } diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index 966b7ce20a..a55c0319b3 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -45,7 +45,6 @@ use super::{ MAX_NEW_BLOCK_AGE, MAX_NEW_HASHES, PAR_PROTOCOL_VERSION_1, - PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3, BLOCK_BODIES_PACKET, BLOCK_HEADERS_PACKET, @@ -641,8 +640,11 @@ impl SyncHandler { trace!(target: "sync", "Peer {} network id mismatch (ours: {}, theirs: {})", peer_id, sync.network_id, peer.network_id); return Ok(()); } - if (warp_protocol && peer.protocol_version != PAR_PROTOCOL_VERSION_1 && peer.protocol_version != PAR_PROTOCOL_VERSION_2 && peer.protocol_version != PAR_PROTOCOL_VERSION_3) - || (!warp_protocol && peer.protocol_version != ETH_PROTOCOL_VERSION_63 && peer.protocol_version != ETH_PROTOCOL_VERSION_62) { + + if false + || (warp_protocol && (peer.protocol_version < PAR_PROTOCOL_VERSION_1.0 || peer.protocol_version > PAR_PROTOCOL_VERSION_3.0)) + || (!warp_protocol && (peer.protocol_version < ETH_PROTOCOL_VERSION_62.0 || peer.protocol_version > ETH_PROTOCOL_VERSION_63.0)) + { io.disable_peer(peer_id); trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version); return Ok(()); diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index abab1da941..381936949b 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -127,15 +127,15 @@ known_heap_size!(0, PeerInfo); pub type PacketDecodeError = DecoderError; /// 63 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_63: u8 = 63; +pub const ETH_PROTOCOL_VERSION_63: (u8, u8) = (63, 0x11); /// 62 version of Ethereum protocol. -pub const ETH_PROTOCOL_VERSION_62: u8 = 62; -/// 1 version of Parity protocol. -pub const PAR_PROTOCOL_VERSION_1: u8 = 1; +pub const ETH_PROTOCOL_VERSION_62: (u8, u8) = (62, 0x11); +/// 1 version of Parity protocol and the packet count. +pub const PAR_PROTOCOL_VERSION_1: (u8, u8) = (1, 0x15); /// 2 version of Parity protocol (consensus messages added). -pub const PAR_PROTOCOL_VERSION_2: u8 = 2; +pub const PAR_PROTOCOL_VERSION_2: (u8, u8) = (2, 0x16); /// 3 version of Parity protocol (private transactions messages added). -pub const PAR_PROTOCOL_VERSION_3: u8 = 3; +pub const PAR_PROTOCOL_VERSION_3: (u8, u8) = (3, 0x18); pub const MAX_BODIES_TO_SEND: usize = 256; pub const MAX_HEADERS_TO_SEND: usize = 512; @@ -169,8 +169,6 @@ pub const NODE_DATA_PACKET: u8 = 0x0e; pub const GET_RECEIPTS_PACKET: u8 = 0x0f; pub const RECEIPTS_PACKET: u8 = 0x10; -pub const ETH_PACKET_COUNT: u8 = 0x11; - pub const GET_SNAPSHOT_MANIFEST_PACKET: u8 = 0x11; pub const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12; pub const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13; @@ -179,8 +177,6 @@ pub const CONSENSUS_DATA_PACKET: u8 = 0x15; const PRIVATE_TRANSACTION_PACKET: u8 = 0x16; const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17; -pub const SNAPSHOT_SYNC_PACKET_COUNT: u8 = 0x18; - const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3; const WAIT_PEERS_TIMEOUT: Duration = Duration::from_secs(5); @@ -453,7 +449,7 @@ impl ChainSync { let last_imported_number = self.new_blocks.last_imported_block_number(); SyncStatus { state: self.state.clone(), - protocol_version: ETH_PROTOCOL_VERSION_63, + protocol_version: ETH_PROTOCOL_VERSION_63.0, network_id: self.network_id, start_block_number: self.starting_block, last_imported_block_number: Some(last_imported_number), @@ -855,7 +851,7 @@ impl ChainSync { fn send_status(&mut self, io: &mut SyncIo, peer: PeerId) -> Result<(), network::Error> { let warp_protocol_version = io.protocol_version(&WARP_SYNC_PROTOCOL_ID, peer); let warp_protocol = warp_protocol_version != 0; - let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63 }; + let protocol = if warp_protocol { warp_protocol_version } else { ETH_PROTOCOL_VERSION_63.0 }; trace!(target: "sync", "Sending status to {}, protocol version {}", peer, protocol); let mut packet = RlpStream::new_list(if warp_protocol { 7 } else { 5 }); let chain = io.chain().chain_info(); @@ -1019,11 +1015,11 @@ impl ChainSync { } fn get_consensus_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2 { Some(*id) } else { None }).collect() + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2.0 { Some(*id) } else { None }).collect() } fn get_private_transaction_peers(&self) -> Vec { - self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3 { Some(*id) } else { None }).collect() + self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3.0 { Some(*id) } else { None }).collect() } /// Maintain other peers. Send out any new blocks and transactions diff --git a/ethcore/sync/src/chain/requester.rs b/ethcore/sync/src/chain/requester.rs index e6acf6bc53..a85874d292 100644 --- a/ethcore/sync/src/chain/requester.rs +++ b/ethcore/sync/src/chain/requester.rs @@ -28,7 +28,7 @@ use super::{ BlockSet, ChainSync, PeerAsking, - ETH_PACKET_COUNT, + ETH_PROTOCOL_VERSION_63, GET_BLOCK_BODIES_PACKET, GET_BLOCK_HEADERS_PACKET, GET_RECEIPTS_PACKET, @@ -140,7 +140,8 @@ impl SyncRequester { } peer.asking = asking; peer.ask_time = Instant::now(); - let result = if packet_id >= ETH_PACKET_COUNT { + // TODO [ToDr] This seems quite fragile. Be careful when protocol is updated. + let result = if packet_id >= ETH_PROTOCOL_VERSION_63.1 { io.send_protocol(WARP_SYNC_PROTOCOL_ID, peer_id, packet_id, packet) } else { io.send(peer_id, packet_id, packet) diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 3a4697cc09..407f699e0e 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -134,11 +134,11 @@ impl<'p, C> SyncIo for TestIo<'p, C> where C: FlushingBlockChainClient, C: 'p { } fn eth_protocol_version(&self, _peer: PeerId) -> u8 { - ETH_PROTOCOL_VERSION_63 + ETH_PROTOCOL_VERSION_63.0 } fn protocol_version(&self, protocol: &ProtocolId, peer_id: PeerId) -> u8 { - if protocol == &WARP_SYNC_PROTOCOL_ID { PAR_PROTOCOL_VERSION_3 } else { self.eth_protocol_version(peer_id) } + if protocol == &WARP_SYNC_PROTOCOL_ID { PAR_PROTOCOL_VERSION_3.0 } else { self.eth_protocol_version(peer_id) } } fn chain_overlay(&self) -> &RwLock> { diff --git a/parity/whisper.rs b/parity/whisper.rs index c7acd8f9d6..bb9aebf0b9 100644 --- a/parity/whisper.rs +++ b/parity/whisper.rs @@ -89,7 +89,6 @@ pub fn setup(target_pool_size: usize, protos: &mut Vec) protos.push(AttachedProtocol { handler: net.clone() as Arc<_>, - packet_count: whisper_net::PACKET_COUNT, versions: whisper_net::SUPPORTED_VERSIONS, protocol_id: whisper_net::PROTOCOL_ID, }); @@ -97,7 +96,6 @@ pub fn setup(target_pool_size: usize, protos: &mut Vec) // parity-only extensions to whisper. protos.push(AttachedProtocol { handler: Arc::new(whisper_net::ParityExtensions), - packet_count: whisper_net::PACKET_COUNT, versions: whisper_net::SUPPORTED_VERSIONS, protocol_id: whisper_net::PARITY_PROTOCOL_ID, }); diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 2de9a1884c..3c8643fe62 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -79,7 +79,9 @@ const NODE_TABLE_TIMEOUT: Duration = Duration::from_secs(300); #[derive(Debug, PartialEq, Eq)] /// Protocol info pub struct CapabilityInfo { + /// Protocol ID pub protocol: ProtocolId, + /// Protocol version pub version: u8, /// Total number of packet IDs this protocol support. pub packet_count: u8, @@ -687,7 +689,7 @@ impl Host { Err(e) => { let s = session.lock(); trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); - if let ErrorKind::Disconnect(DisconnectReason::UselessPeer) = *e.kind() { + if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() { if let Some(id) = s.id() { if !self.reserved_nodes.read().contains(id) { let mut nodes = self.nodes.write(); @@ -990,7 +992,6 @@ impl IoHandler for Host { ref handler, ref protocol, ref versions, - ref packet_count, } => { let h = handler.clone(); let reserved = self.reserved_nodes.read(); @@ -1000,8 +1001,12 @@ impl IoHandler for Host { ); self.handlers.write().insert(*protocol, h); let mut info = self.info.write(); - for v in versions { - info.capabilities.push(CapabilityInfo { protocol: *protocol, version: *v, packet_count: *packet_count }); + for &(version, packet_count) in versions { + info.capabilities.push(CapabilityInfo { + protocol: *protocol, + version, + packet_count, + }); } }, NetworkIoMessage::AddTimer { diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 239763cbe1..e5bb95f220 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -49,7 +49,7 @@ //! fn main () { //! let mut service = NetworkService::new(NetworkConfiguration::new_local(), None).expect("Error creating network service"); //! service.start().expect("Error starting service"); -//! service.register_protocol(Arc::new(MyHandler), *b"myp", 1, &[1u8]); +//! service.register_protocol(Arc::new(MyHandler), *b"myp", &[(1u8, 1u8)]); //! //! // Wait for quit condition //! // ... diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 711ee95cf3..10a1e9abc8 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -67,12 +67,17 @@ impl NetworkService { } /// Regiter a new protocol handler with the event loop. - pub fn register_protocol(&self, handler: Arc, protocol: ProtocolId, packet_count: u8, versions: &[u8]) -> Result<(), Error> { + pub fn register_protocol( + &self, + handler: Arc, + protocol: ProtocolId, + // version id + packet count + versions: &[(u8, u8)] + ) -> Result<(), Error> { self.io_service.send_message(NetworkIoMessage::AddHandler { - handler: handler, - protocol: protocol, + handler, + protocol, versions: versions.to_vec(), - packet_count: packet_count, })?; Ok(()) } diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index 4788e0d442..e8c8eddde4 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -52,7 +52,7 @@ impl TestProtocol { /// Creates and register protocol with the network service pub fn register(service: &mut NetworkService, drop_session: bool) -> Arc { let handler = Arc::new(TestProtocol::new(drop_session)); - service.register_protocol(handler.clone(), *b"tst", 1, &[42u8, 43u8]).expect("Error registering test protocol handler"); + service.register_protocol(handler.clone(), *b"tst", &[(42u8, 1u8), (43u8, 1u8)]).expect("Error registering test protocol handler"); handler } @@ -104,7 +104,7 @@ impl NetworkProtocolHandler for TestProtocol { fn net_service() { let service = NetworkService::new(NetworkConfiguration::new_local(), None).expect("Error creating network service"); service.start().unwrap(); - service.register_protocol(Arc::new(TestProtocol::new(false)), *b"myp", 1, &[1u8]).unwrap(); + service.register_protocol(Arc::new(TestProtocol::new(false)), *b"myp", &[(1u8, 1u8)]).unwrap(); } #[test] diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 5077a953d4..673e4dab35 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -64,10 +64,8 @@ pub enum NetworkIoMessage { handler: Arc, /// Protocol Id. protocol: ProtocolId, - /// Supported protocol versions. - versions: Vec, - /// Number of packet IDs reserved by the protocol. - packet_count: u8, + /// Supported protocol versions and number of packet IDs reserved by the protocol (packet count). + versions: Vec<(u8, u8)>, }, /// Register a new protocol timer AddTimer { diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index f9211b993b..c3a4dc8c3a 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -218,10 +218,10 @@ fn execute(command: I) -> Result<(), Error> where I: IntoIterator, network.start()?; // Attach whisper protocol to the network service - network.register_protocol(whisper_network_handler.clone(), whisper::net::PROTOCOL_ID, whisper::net::PACKET_COUNT, + network.register_protocol(whisper_network_handler.clone(), whisper::net::PROTOCOL_ID, whisper::net::SUPPORTED_VERSIONS)?; network.register_protocol(Arc::new(whisper::net::ParityExtensions), whisper::net::PARITY_PROTOCOL_ID, - whisper::net::PACKET_COUNT, whisper::net::SUPPORTED_VERSIONS)?; + whisper::net::SUPPORTED_VERSIONS)?; // Request handler let mut io = MetaIoHandler::default(); diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index fc6138cf1d..c462baa9d7 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -41,15 +41,17 @@ const RALLY_TIMEOUT: Duration = Duration::from_millis(2500); /// Current protocol version. pub const PROTOCOL_VERSION: usize = 6; +/// Number of packets. A bunch are reserved. +const PACKET_COUNT: u8 = 128; + /// Supported protocol versions. -pub const SUPPORTED_VERSIONS: &'static [u8] = &[PROTOCOL_VERSION as u8]; +pub const SUPPORTED_VERSIONS: &'static [(u8, u8)] = &[ + (PROTOCOL_VERSION as u8, PACKET_COUNT) +]; // maximum tolerated delay between messages packets. const MAX_TOLERATED_DELAY: Duration = Duration::from_millis(5000); -/// Number of packets. A bunch are reserved. -pub const PACKET_COUNT: u8 = 128; - /// Whisper protocol ID pub const PROTOCOL_ID: ::network::ProtocolId = *b"shh"; -- GitLab From cfd50538bb5daa2a1ca2e097f08a6c6ce73af65e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 16:10:11 +0800 Subject: [PATCH 153/263] typo: wrong indentation in kovan config (#8610) --- ethcore/res/ethereum/kovan.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 1cd74d973c..02d22bb419 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -4,8 +4,8 @@ "engine": { "authorityRound": { "params": { - "stepDuration": "4", - "blockReward": "0x4563918244F40000", + "stepDuration": "4", + "blockReward": "0x4563918244F40000", "validators" : { "list": [ "0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED", -- GitLab From 272ebc1ef7ff2f6fab76d0e1999eebd899e23485 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 16:10:28 +0800 Subject: [PATCH 154/263] Fix account list double 0x display (#8596) * Remove unused self import * Fix account list double 0x display --- parity/account.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/account.rs b/parity/account.rs index 3db1844a1b..676cf93e73 100644 --- a/parity/account.rs +++ b/parity/account.rs @@ -94,7 +94,7 @@ fn new(n: NewAccount) -> Result { let secret_store = Box::new(secret_store(dir, Some(n.iterations))?); let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default()); let new_account = acc_provider.new_account(&password).map_err(|e| format!("Could not create new account: {}", e))?; - Ok(format!("0x{:?}", new_account)) + Ok(format!("0x{:x}", new_account)) } fn list(list_cmd: ListAccounts) -> Result { @@ -103,7 +103,7 @@ fn list(list_cmd: ListAccounts) -> Result { let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default()); let accounts = acc_provider.accounts().map_err(|e| format!("{}", e))?; let result = accounts.into_iter() - .map(|a| format!("0x{:?}", a)) + .map(|a| format!("0x{:x}", a)) .collect::>() .join("\n"); -- GitLab From 1b95af18ff4f5898786fcd044d3c42fe6f5fcd4a Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 14 May 2018 10:11:10 +0200 Subject: [PATCH 155/263] Remove manually added text to the errors (#8595) These messages were confusing for the users especially the help message. --- whisper/cli/src/main.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index c3a4dc8c3a..f245e99e48 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -170,12 +170,12 @@ impl From for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { - Error::SockAddr(ref e) => write!(f, "SockAddrError: {}", e), - Error::Docopt(ref e) => write!(f, "DocoptError: {}", e), - Error::Io(ref e) => write!(f, "IoError: {}", e), - Error::JsonRpc(ref e) => write!(f, "JsonRpcError: {:?}", e), - Error::Network(ref e) => write!(f, "NetworkError: {}", e), - Error::Logger(ref e) => write!(f, "LoggerError: {}", e), + Error::SockAddr(ref e) => write!(f, "{}", e), + Error::Docopt(ref e) => write!(f, "{}", e), + Error::Io(ref e) => write!(f, "{}", e), + Error::JsonRpc(ref e) => write!(f, "{:?}", e), + Error::Network(ref e) => write!(f, "{}", e), + Error::Logger(ref e) => write!(f, "{}", e), } } } @@ -252,7 +252,6 @@ fn initialize_logger(log_level: String) -> Result<(), String> { Ok(()) } - #[cfg(test)] mod tests { use super::execute; -- GitLab From 938c3707fc63c5d37bb7a16a9f0c39742d841ad5 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Mon, 14 May 2018 11:28:41 +0200 Subject: [PATCH 156/263] Gitlab test script fixes (#8573) * Exclude /docs from modified files. * Ensure all references in the working tree are available * Remove duplicated line from test script --- scripts/gitlab-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/gitlab-test.sh b/scripts/gitlab-test.sh index a617f68e22..57cf7c6b6c 100755 --- a/scripts/gitlab-test.sh +++ b/scripts/gitlab-test.sh @@ -7,8 +7,8 @@ if [[ "$CI_COMMIT_REF_NAME" = "master" || "$CI_COMMIT_REF_NAME" = "beta" || "$CI else export GIT_COMPARE=master; fi -export RUST_FILES_MODIFIED="$(git --no-pager diff --name-only $GIT_COMPARE...$CI_COMMIT_SHA | grep -v -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e ^mac/ -e ^nsis/ | wc -l)" -echo "RUST_FILES_MODIFIED: $RUST_FILES_MODIFIED" +git fetch -a +export RUST_FILES_MODIFIED="$(git --no-pager diff --name-only $GIT_COMPARE...$CI_COMMIT_SHA | grep -v -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e ^mac/ -e ^nsis/ -e ^docs/ | wc -l)" echo "RUST_FILES_MODIFIED: $RUST_FILES_MODIFIED" TEST_SWITCH=$1 rust_test () { -- GitLab From af90fbfb3344fdc2447d97d4c48dcdfd69899a4f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 14 May 2018 22:26:18 +0800 Subject: [PATCH 157/263] Fix BlockReward contract "arithmetic operation overflow" (#8611) * Fix BlockReward contract "arithmetic operation overflow" * Add docs on how execute_as_system works * Fix typo --- ethcore/src/machine.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 4aa72b50d9..d0d434b1de 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -122,7 +122,13 @@ impl EthereumMachine { } impl EthereumMachine { - /// Execute a call as the system address. + /// Execute a call as the system address. Block environment information passed to the + /// VM is modified to have its gas limit bounded at the upper limit of possible used + /// gases including this system call, capped at the maximum value able to be + /// represented by U256. This system call modifies the block state, but discards other + /// information. If suicides, logs or refunds happen within the system call, they + /// will not be executed or recorded. Gas used by this system call will not be counted + /// on the block. pub fn execute_as_system( &self, block: &mut ExecutedBlock, @@ -132,7 +138,7 @@ impl EthereumMachine { ) -> Result, Error> { let env_info = { let mut env_info = block.env_info(); - env_info.gas_limit = env_info.gas_used + gas; + env_info.gas_limit = env_info.gas_used.saturating_add(gas); env_info }; -- GitLab From 8f56606cac19d7a55735e214c8c96fc7cebb49f1 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 15 May 2018 07:46:37 +0200 Subject: [PATCH 158/263] =?UTF-8?q?=C2=B4main.rs=C2=B4=20typo=20(#8629)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Typo * Update main.rs --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index e489ad865e..03b04a8c82 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -71,7 +71,7 @@ fn take_spec_name_override() -> Option { #[cfg(windows)] fn global_cleanup() { - // We need to cleanup all sockets before spawning another Parity process. This makes shure everything is cleaned up. + // We need to cleanup all sockets before spawning another Parity process. This makes sure everything is cleaned up. // The loop is required because of internal reference counter for winsock dll. We don't know how many crates we use do // initialize it. There's at least 2 now. for _ in 0.. 10 { -- GitLab From e4614e49ae532bbef239f9eb3cf1741a2bdc7093 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 15 May 2018 12:57:32 +0200 Subject: [PATCH 159/263] Store morden db and keys in "path/to/parity/data/Morden" (ropsten uses "test", like before) (#8621) * Store morden db and keys in "path/to/parity/data/morden" (ropsten uses "test", like before) --- .gitignore | 2 +- ethcore/res/ethereum/morden.json | 2 +- util/dir/src/lib.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 0675bc41eb..3bc041c908 100644 --- a/.gitignore +++ b/.gitignore @@ -40,5 +40,5 @@ node_modules out/ .vscode - +rls/ /parity.* diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 04c5a12444..bca9919903 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -1,6 +1,6 @@ { "name": "Morden", - "dataDir": "test", + "dataDir": "morden", "engine": { "Ethash": { "params": { diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index b2ffed329c..bb36a46a83 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -104,9 +104,9 @@ impl Directories { DatabaseDirectories { path: self.db.clone(), legacy_path: self.base.clone(), - genesis_hash: genesis_hash, - fork_name: fork_name, - spec_name: spec_name, + genesis_hash, + fork_name, + spec_name, } } -- GitLab From 0c4d2fbc703608c05b17b0bc5b97a38ea76e7525 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 15 May 2018 15:35:52 +0200 Subject: [PATCH 160/263] Fix light sync with initial validator-set contract (#8528) * Fix #8468 * Use U256::max_value() instead * Fix again * Also change initial transaction gas --- ethcore/src/spec/spec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index ef69f4847b..1ee8cf7032 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -783,7 +783,7 @@ impl Spec { author: *genesis.author(), timestamp: genesis.timestamp(), difficulty: *genesis.difficulty(), - gas_limit: *genesis.gas_limit(), + gas_limit: U256::max_value(), last_hashes: Arc::new(Vec::new()), gas_used: 0.into(), }; @@ -792,7 +792,7 @@ impl Spec { 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: U256::max_value(), gas_price: U256::default(), value: U256::default(), data: d, -- GitLab From 8e078b1d83bf708ef29bbbb166ab5c6edfdaa7b3 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 15 May 2018 17:03:09 +0200 Subject: [PATCH 161/263] Remove NetworkContext::io_channel() (#8625) * Remove io_channel() * Fix warning --- util/network-devp2p/src/host.rs | 4 ---- util/network/src/lib.rs | 8 -------- 2 files changed, 12 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 3c8643fe62..4cca2e6e5a 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -153,10 +153,6 @@ impl<'s> NetworkContextTrait for NetworkContext<'s> { self.session_id.map_or_else(|| Err(ErrorKind::Expired.into()), |id| self.send(id, packet_id, data)) } - fn io_channel(&self) -> IoChannel { - self.io.channel() - } - fn disable_peer(&self, peer: PeerId) { self.io.message(NetworkIoMessage::DisablePeer(peer)) .unwrap_or_else(|e| warn!("Error sending network IO message: {:?}", e)); diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 673e4dab35..1327a9ad59 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -39,7 +39,6 @@ use std::str::{self, FromStr}; use std::sync::Arc; use std::time::Duration; use ipnetwork::{IpNetwork, IpNetworkError}; -use io::IoChannel; use ethkey::Secret; use ethereum_types::{H256, H512}; use rlp::{Decodable, DecoderError, Rlp}; @@ -257,9 +256,6 @@ pub trait NetworkContext { /// Respond to a current network message. Panics if no there is no packet in the context. If the session is expired returns nothing. fn respond(&self, packet_id: PacketId, data: Vec) -> Result<(), Error>; - /// Get an IoChannel. - fn io_channel(&self) -> IoChannel; - /// Disconnect a peer and prevent it from connecting again. fn disable_peer(&self, peer: PeerId); @@ -298,10 +294,6 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { (**self).respond(packet_id, data) } - fn io_channel(&self) -> IoChannel { - (**self).io_channel() - } - fn disable_peer(&self, peer: PeerId) { (**self).disable_peer(peer) } -- GitLab From 3bb5ad7204dcdabf841910799814bccc5019729e Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 15 May 2018 23:11:14 +0200 Subject: [PATCH 162/263] Check that the Android build doesn't dep on c++_shared (#8538) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 347b5a57ba..95a7ebcb5e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -190,7 +190,7 @@ android-armv7: - triggers script: - cargo build --target=armv7-linux-androideabi - # TODO: check that `arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/release/parity | grep c++_shared` is empty + - if [ $(arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/debug/parity | grep -i 'c++_shared' | wc -l) -ne 0]; then echo "FAIL!!" fi tags: - rust-arm artifacts: -- GitLab From 0ecbb3ec02a5b36c95f09a20d5958a374c32511f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 16 May 2018 14:58:01 +0800 Subject: [PATCH 163/263] Fork choice and metadata framework for Engine (#8401) * Add light client TODO item * Move existing total-difficulty-based fork choice check to Engine * Abstract total difficulty and block provider as Machine::BlockMetadata and Machine::BlockProvider * Decouple "generate_metadata" logic to Engine * Use fixed BlockMetadata and BlockProvider type for null and instantseal In this way they can use total difficulty fork choice check * Extend blockdetails with metadatas and finalized info * Extra data update: mark_finalized and update_metadatas * Check finalized block in Blockchain * Fix a test constructor in verification mod * Add total difficulty trait * Fix type import * Db migration to V13 with metadata column * Address grumbles * metadatas -> metadata * Use generic type for update_metadata to avoid passing HashMap all around * Remove metadata in blockdetails * [WIP] Implement a generic metadata architecture * [WIP] Metadata insertion logic in BlockChain * typo: Value -> Self::Value * [WIP] Temporarily remove Engine::is_new_best interface So that we don't have too many type errors. * [WIP] Fix more type errors * [WIP] ExtendedHeader::PartialEq * [WIP] Change metadata type Option> to Vec * [WIP] Remove Metadata Error * [WIP] Clean up error conversion * [WIP] finalized -> is_finalized * [WIP] Mark all fields in ExtrasInsert as pub * [WIP] Remove unused import * [WIP] Keep only local metadata info * Mark metadata as optional * [WIP] Revert metadata db change in BlockChain * [WIP] Put finalization in unclosed state * Use metadata interface in BlockDetail * [WIP] Fix current build failures * [WIP] Remove unused blockmetadata struct * Remove DB migration info * [WIP] Typo * Use ExtendedHeader to implement fork choice check * Implement is_new_best using Ancestry iterator * Use expect instead of panic * [WIP] Add ancestry Engine support via on_new_block * Fix tests * Emission of ancestry actions * use_short_version should take account of metadata * Engine::is_new_best -> Engine::fork_choice * Use proper expect format as defined in #1026 * panic -> expect * ancestry_header -> ancestry_with_metadata * Boxed iterator -> &mut iterator * Fix tests * is_new_best -> primitive_fork_choice * Document how fork_choice works * Engine::fork_choice -> Engine::primitive_fork_choice * comment: clarify types of finalization where Engine::primitive_fork_choice works * Expose FinalizationInfo to Engine * Fix tests due to merging * Remove TotalDifficulty trait * Do not pass FinalizationInfo to Engine If there's finalized blocks in from route, choose the old branch without calling `Engine::fork_choice`. * Fix compile * Fix unused import * Remove is_to_route_finalized When no block reorg passes a finalized block, this variable is always false. * Address format grumbles * Fix docs: mark_finalized returns None if block hash is not found `blockchain` mod does not yet have an Error type, so we still temporarily use None here. * Fix inaccurate tree_route None expect description --- ethcore/light/src/client/header_chain.rs | 1 + ethcore/src/block.rs | 51 +++- ethcore/src/blockchain/blockchain.rs | 258 ++++++++++++++------ ethcore/src/blockchain/extras.rs | 54 +++- ethcore/src/blockchain/mod.rs | 1 + ethcore/src/blockchain/update.rs | 10 + ethcore/src/client/client.rs | 67 ++++- ethcore/src/client/test_client.rs | 4 +- ethcore/src/engines/authority_round/mod.rs | 33 ++- ethcore/src/engines/basic_authority.rs | 8 +- ethcore/src/engines/instant_seal.rs | 12 +- ethcore/src/engines/mod.rs | 31 ++- ethcore/src/engines/null_engine.rs | 11 +- ethcore/src/engines/tendermint/mod.rs | 10 +- ethcore/src/ethereum/ethash.rs | 20 +- ethcore/src/header.rs | 48 +++- ethcore/src/machine.rs | 4 +- ethcore/src/snapshot/tests/proof_of_work.rs | 8 +- ethcore/src/test_helpers.rs | 17 +- ethcore/src/tests/trace.rs | 5 +- ethcore/src/verification/verification.rs | 2 + ethcore/types/src/ancestry_action.rs | 27 ++ ethcore/types/src/lib.rs | 1 + ethcore/types/src/tree_route.rs | 2 + machine/src/lib.rs | 48 +++- 25 files changed, 592 insertions(+), 141 deletions(-) create mode 100644 ethcore/types/src/ancestry_action.rs diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index b85091e53b..60c7d288a7 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -445,6 +445,7 @@ impl HeaderChain { let raw = header.encoded().into_inner(); transaction.put_vec(self.col, &hash[..], raw); + // TODO: For engines when required, use cryptoeconomic guarantees. let (best_num, is_new_best) = { let cur_best = self.best_block.read(); if cur_best.total_difficulty < total_difficulty { diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d9f3d27afb..4c47089677 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -31,7 +31,7 @@ use vm::{EnvInfo, LastHashes}; use engines::EthEngine; use error::{Error, BlockError}; use factory::Factories; -use header::Header; +use header::{Header, ExtendedHeader}; use receipt::{Receipt, TransactionOutcome}; use state::State; use state_db::StateDB; @@ -94,6 +94,8 @@ pub struct ExecutedBlock { state: State, traces: Tracing, last_hashes: Arc, + is_finalized: bool, + metadata: Option>, } impl ExecutedBlock { @@ -112,6 +114,8 @@ impl ExecutedBlock { Tracing::Disabled }, last_hashes: last_hashes, + is_finalized: false, + metadata: None, } } @@ -206,6 +210,26 @@ impl ::parity_machine::Transactions for ExecutedBlock { } } +impl ::parity_machine::Finalizable for ExecutedBlock { + fn is_finalized(&self) -> bool { + self.is_finalized + } + + fn mark_finalized(&mut self) { + self.is_finalized = true; + } +} + +impl ::parity_machine::WithMetadata for ExecutedBlock { + fn metadata(&self) -> Option<&[u8]> { + self.metadata.as_ref().map(|v| v.as_ref()) + } + + fn set_metadata(&mut self, value: Option>) { + self.metadata = value; + } +} + /// Block that is ready for transactions to be added. /// /// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and @@ -224,6 +248,8 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, unclosed_state: State, + unclosed_finalization_state: bool, + unclosed_metadata: Option>, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. @@ -245,7 +271,7 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new `OpenBlock` ready for transaction pushing. - pub fn new( + pub fn new<'a>( engine: &'x EthEngine, factories: Factories, tracing: bool, @@ -256,6 +282,7 @@ impl<'x> OpenBlock<'x> { gas_range_target: (U256, U256), extra_data: Bytes, is_epoch_begin: bool, + ancestry: &mut Iterator, ) -> Result { let number = parent.number() + 1; let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?; @@ -277,7 +304,7 @@ impl<'x> OpenBlock<'x> { engine.populate_from_parent(&mut r.block.header, parent); engine.machine().on_new_block(&mut r.block)?; - engine.on_new_block(&mut r.block, is_epoch_begin)?; + engine.on_new_block(&mut r.block, is_epoch_begin, ancestry)?; Ok(r) } @@ -387,6 +414,8 @@ impl<'x> OpenBlock<'x> { let mut s = self; let unclosed_state = s.block.state.clone(); + let unclosed_metadata = s.block.metadata.clone(); + let unclosed_finalization_state = s.block.is_finalized; if let Err(e) = s.engine.on_close_block(&mut s.block) { warn!("Encountered error on closing the block: {}", e); @@ -410,6 +439,8 @@ impl<'x> OpenBlock<'x> { block: s.block, uncle_bytes, unclosed_state, + unclosed_metadata, + unclosed_finalization_state, } } @@ -483,6 +514,8 @@ impl ClosedBlock { // revert rewards (i.e. set state back at last transaction's state). let mut block = self.block; block.state = self.unclosed_state; + block.metadata = self.unclosed_metadata; + block.is_finalized = self.unclosed_finalization_state; OpenBlock { block: block, engine: engine, @@ -588,6 +621,7 @@ fn enact( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, + ancestry: &mut Iterator, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { @@ -608,6 +642,7 @@ fn enact( (3141562.into(), 31415620.into()), vec![], is_epoch_begin, + ancestry, )?; b.populate_from(&header); @@ -630,6 +665,7 @@ pub fn enact_verified( last_hashes: Arc, factories: Factories, is_epoch_begin: bool, + ancestry: &mut Iterator, ) -> Result { let view = view!(BlockView, &block.bytes); @@ -644,6 +680,7 @@ pub fn enact_verified( last_hashes, factories, is_epoch_begin, + ancestry, ) } @@ -701,6 +738,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), )?; b.populate_from(&header); @@ -734,7 +772,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); let _ = b.seal(&*spec.engine, vec![]); } @@ -748,7 +786,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap() + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap() .close_and_lock().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -772,7 +810,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let mut uncle1_header = Header::new(); uncle1_header.set_extra_data(b"uncle1".to_vec()); let mut uncle2_header = Header::new(); @@ -797,4 +835,3 @@ mod tests { assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); } } - diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 0e18c5f889..f2621d00e1 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -38,11 +38,12 @@ use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainD use blockchain::extras::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions}; use types::blockchain_info::BlockChainInfo; use types::tree_route::TreeRoute; -use blockchain::update::ExtrasUpdate; +use blockchain::update::{ExtrasUpdate, ExtrasInsert}; use blockchain::{CacheSize, ImportRoute, Config}; use db::{self, Writable, Readable, CacheUpdatePolicy}; use cache_manager::CacheManager; use encoded; +use engines::ForkChoice; use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition}; use rayon::prelude::*; use ansi_term::Colour; @@ -417,6 +418,42 @@ impl<'a> Iterator for AncestryIter<'a> { } } +/// An iterator which walks the blockchain towards the genesis, with metadata information. +pub struct AncestryWithMetadataIter<'a> { + current: H256, + chain: &'a BlockChain, +} + +impl<'a> Iterator for AncestryWithMetadataIter<'a> { + type Item = ExtendedHeader; + fn next(&mut self) -> Option { + if self.current.is_zero() { + None + } else { + let details = self.chain.block_details(&self.current); + let header = self.chain.block_header_data(&self.current) + .map(|h| h.decode().expect("Stored block header data is valid RLP; qed")); + + match (details, header) { + (Some(details), Some(header)) => { + self.current = details.parent; + Some(ExtendedHeader { + parent_total_difficulty: details.total_difficulty - *header.difficulty(), + is_finalized: details.is_finalized, + metadata: details.metadata, + + header: header, + }) + }, + _ => { + self.current = H256::default(); + None + }, + } + } + } +} + /// An iterator which walks all epoch transitions. /// Returns epoch transitions. pub struct EpochTransitionIter<'a> { @@ -510,6 +547,8 @@ impl BlockChain { total_difficulty: header.difficulty(), parent: header.parent_hash(), children: vec![], + is_finalized: false, + metadata: None, }; let mut batch = DBTransaction::new(); @@ -649,6 +688,7 @@ impl BlockChain { /// `None` is returned. pub fn tree_route(&self, from: H256, to: H256) -> Option { let mut from_branch = vec![]; + let mut is_from_route_finalized = false; let mut to_branch = vec![]; let mut from_details = self.block_details(&from)?; @@ -661,6 +701,7 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; + is_from_route_finalized = is_from_route_finalized || from_details.is_finalized; } while to_details.number > from_details.number { @@ -676,6 +717,7 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; + is_from_route_finalized = is_from_route_finalized || from_details.is_finalized; to_branch.push(current_to); current_to = to_details.parent.clone(); @@ -689,7 +731,8 @@ impl BlockChain { Some(TreeRoute { blocks: from_branch, ancestor: current_from, - index: index + index: index, + is_from_route_finalized: is_from_route_finalized, }) } @@ -733,7 +776,7 @@ impl BlockChain { self.prepare_update(batch, ExtrasUpdate { block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info, false, None), block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), @@ -769,11 +812,14 @@ impl BlockChain { location: BlockLocation::CanonChain, }; + // TODO [sorpaas] support warp sync insertion of finalization and metadata. let block_details = BlockDetails { number: header.number(), total_difficulty: info.total_difficulty, parent: header.parent_hash(), children: Vec::new(), + is_finalized: false, + metadata: None, }; let mut update = HashMap::new(); @@ -898,7 +944,22 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec) -> ImportRoute { + pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras: ExtrasInsert) -> ImportRoute { + let block = view!(BlockView, bytes); + let header = block.header_view(); + + let parent_hash = header.parent_hash(); + let best_hash = self.best_block_hash(); + + let route = self.tree_route(best_hash, parent_hash).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); + + self.insert_block_with_route(batch, bytes, receipts, route, extras) + } + + /// Inserts the block into backing cache database with already generated route information. + /// Expects the block to be valid and already verified and route is tree route information from current best block to new block's parent. + /// If the block is already known, does nothing. + pub fn insert_block_with_route(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, route: TreeRoute, extras: ExtrasInsert) -> ImportRoute { // create views onto rlp let block = view!(BlockView, bytes); let header = block.header_view(); @@ -917,7 +978,7 @@ impl BlockChain { batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header); + let info = self.block_info(&header, route, &extras); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -930,7 +991,7 @@ impl BlockChain { self.prepare_update(batch, ExtrasUpdate { block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info, extras.is_finalized, extras.metadata), block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), @@ -942,45 +1003,59 @@ impl BlockChain { } /// Get inserted block info which is critical to prepare extras updates. - fn block_info(&self, header: &HeaderView) -> BlockInfo { + fn block_info(&self, header: &HeaderView, route: TreeRoute, extras: &ExtrasInsert) -> BlockInfo { let hash = header.hash(); let number = header.number(); let parent_hash = header.parent_hash(); let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - let is_new_best = parent_details.total_difficulty + header.difficulty() > self.best_block_total_difficulty(); BlockInfo { hash: hash, number: number, total_difficulty: parent_details.total_difficulty + header.difficulty(), - location: if is_new_best { - // on new best block we need to make sure that all ancestors - // are moved to "canon chain" - // find the route between old best block and the new one - let best_hash = self.best_block_hash(); - let route = self.tree_route(best_hash, parent_hash) - .expect("blocks being imported always within recent history; qed"); - - assert_eq!(number, parent_details.number + 1); - - match route.blocks.len() { - 0 => BlockLocation::CanonChain, - _ => { - let retracted = route.blocks.iter().take(route.index).cloned().collect::>().into_iter().collect::>(); - let enacted = route.blocks.into_iter().skip(route.index).collect::>(); - BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { - ancestor: route.ancestor, - enacted: enacted, - retracted: retracted, - }) + location: match extras.fork_choice { + ForkChoice::New => { + // On new best block we need to make sure that all ancestors + // are moved to "canon chain" + // find the route between old best block and the new one + match route.blocks.len() { + 0 => BlockLocation::CanonChain, + _ => { + let retracted = route.blocks.iter().take(route.index).cloned().collect::>().into_iter().collect::>(); + let enacted = route.blocks.into_iter().skip(route.index).collect::>(); + BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { + ancestor: route.ancestor, + enacted: enacted, + retracted: retracted, + }) + } } - } - } else { - BlockLocation::Branch - } + }, + ForkChoice::Old => BlockLocation::Branch, + }, } } + /// Mark a block to be considered finalized. Returns `Some(())` if the operation succeeds, and `None` if the block + /// hash is not found. + pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) -> Option<()> { + let mut block_details = self.block_details(&block_hash)?; + block_details.is_finalized = true; + + self.update_block_details(batch, block_hash, block_details); + Some(()) + } + + /// Prepares extras block detail update. + fn update_block_details(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) { + let mut details_map = HashMap::new(); + details_map.insert(block_hash, block_details); + + // We're only updating one existing value. So it shouldn't suffer from cache decoherence problem. + let mut write_details = self.pending_block_details.write(); + batch.extend_with_cache(db::COL_EXTRA, &mut *write_details, details_map, CacheUpdatePolicy::Overwrite); + } + /// Prepares extras update. fn prepare_update(&self, batch: &mut DBTransaction, update: ExtrasUpdate, is_best: bool) { @@ -1101,6 +1176,18 @@ impl BlockChain { } } + /// Iterator that lists `first` and then all of `first`'s ancestors, by extended header. + pub fn ancestry_with_metadata_iter<'a>(&'a self, first: H256) -> AncestryWithMetadataIter { + AncestryWithMetadataIter { + current: if self.is_known(&first) { + first + } else { + H256::default() // zero hash + }, + chain: self + } + } + /// Given a block's `parent`, find every block header which represents a valid possible uncle. pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { self.find_uncle_hashes(parent, uncle_generations) @@ -1166,7 +1253,7 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. - fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, is_finalized: bool, metadata: Option>) -> HashMap { let block = view!(BlockView, block_bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); @@ -1181,6 +1268,8 @@ impl BlockChain { total_difficulty: info.total_difficulty, parent: parent_hash, children: vec![], + is_finalized: is_finalized, + metadata: metadata, }; // write to batch @@ -1418,7 +1507,7 @@ mod tests { use std::sync::Arc; use rustc_hex::FromHex; use hash::keccak; - use kvdb::KeyValueDB; + use kvdb::{KeyValueDB, DBTransaction}; use kvdb_memorydb; use ethereum_types::*; use receipt::{Receipt, TransactionOutcome}; @@ -1441,6 +1530,42 @@ mod tests { BlockChain::new(Config::default(), genesis, db) } + fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { + insert_block_commit(db, bc, bytes, receipts, true) + } + + fn insert_block_commit(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec, commit: bool) -> ImportRoute { + let mut batch = db.transaction(); + let res = insert_block_batch(&mut batch, bc, bytes, receipts); + db.write(batch).unwrap(); + if commit { + bc.commit(); + } + res + } + + fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { + use views::BlockView; + use blockchain::ExtrasInsert; + + let block = view!(BlockView, bytes); + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); + let fork_choice = if block_total_difficulty > bc.best_block_total_difficulty() { + ::engines::ForkChoice::New + } else { + ::engines::ForkChoice::Old + }; + + bc.insert_block(batch, bytes, receipts, ExtrasInsert { + fork_choice: fork_choice, + is_finalized: false, + metadata: None + }) + } + #[test] fn should_cache_best_block() { // given @@ -1452,8 +1577,7 @@ mod tests { assert_eq!(bc.best_block_number(), 0); // when - let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![]); + insert_block_commit(&db, &bc, &first.last().encoded(), vec![], false); assert_eq!(bc.best_block_number(), 0); bc.commit(); // NOTE no db.write here (we want to check if best block is cached) @@ -1483,7 +1607,7 @@ mod tests { assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &first.encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); @@ -1509,7 +1633,7 @@ mod tests { let mut batch = db.transaction(); for block in generator { block_hashes.push(block.hash()); - bc.insert_block(&mut batch, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.commit(); } db.write(batch).unwrap(); @@ -1549,14 +1673,10 @@ mod tests { let db = new_db(); let bc = new_chain(&genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); for b in generator { - bc.insert_block(&mut batch, &b.encoded(), vec![]); - bc.commit(); + insert_block(&db, &bc, &b.encoded(), vec![]); } - db.write(batch).unwrap(); - assert_eq!(uncle_headers, bc.find_uncle_headers(&b4a_hash, 3).unwrap()); // TODO: insert block that already includes one of them as an uncle to check it's not allowed. } @@ -1590,9 +1710,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1604,7 +1724,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1665,9 +1785,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1683,7 +1803,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1723,16 +1843,16 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let ir1 = bc.insert_block(&mut batch, &b1.last().encoded(), vec![]); + let ir1 = insert_block_batch(&mut batch, &bc, &b1.last().encoded(), vec![]); bc.commit(); - let ir2 = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let ir2 = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); - let ir3b = bc.insert_block(&mut batch, &b3b.last().encoded(), vec![]); + let ir3b = insert_block_batch(&mut batch, &bc, &b3b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.block_hash(3).unwrap(), b3b_hash); let mut batch = db.transaction(); - let ir3a = bc.insert_block(&mut batch, &b3a.last().encoded(), vec![]); + let ir3a = insert_block_batch(&mut batch, &bc, &b3a.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1837,7 +1957,7 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &first.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); assert_eq!(bc.best_block_hash(), first_hash); @@ -1896,7 +2016,7 @@ mod tests { let db = new_db(); let bc = new_chain(&genesis, db.clone()); let mut batch =db.transaction(); - bc.insert_block(&mut batch, &b1, vec![]); + insert_block_batch(&mut batch, &bc, &b1, vec![]); db.write(batch).unwrap(); bc.commit(); @@ -1907,14 +2027,6 @@ mod tests { } } - fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { - let mut batch = db.transaction(); - let res = bc.insert_block(&mut batch, bytes, receipts); - db.write(batch).unwrap(); - bc.commit(); - res - } - #[test] fn test_logs() { let t1 = Transaction { @@ -2198,12 +2310,12 @@ mod tests { let mut batch = db.transaction(); // create a longer fork for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.commit(); } assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); } @@ -2230,7 +2342,7 @@ mod tests { // create a longer fork for (i, block) in generator.into_iter().enumerate() { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.insert_epoch_transition(&mut batch, i as u64, EpochTransition { block_hash: block.hash(), block_number: i as u64 + 1, @@ -2241,7 +2353,7 @@ mod tests { assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); + insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); bc.insert_epoch_transition(&mut batch, 999, EpochTransition { block_hash: uncle.last().hash(), block_number: 1, @@ -2291,11 +2403,7 @@ mod tests { // and a non-canonical fork of 8 from genesis. let fork_hash = { for block in fork_generator { - let mut batch = db.transaction(); - - bc.insert_block(&mut batch, &block.encoded(), vec![]); - bc.commit(); - db.write(batch).unwrap(); + insert_block(&db, &bc, &block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 7); @@ -2303,11 +2411,7 @@ mod tests { }; for block in next_generator { - let mut batch = db.transaction(); - bc.insert_block(&mut batch, &block.encoded(), vec![]); - bc.commit(); - - db.write(batch).unwrap(); + insert_block(&db, &bc, &block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 10); diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 97583a693a..3fb25e7b1b 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -23,6 +23,7 @@ use db::Key; use engines::epoch::{Transition as EpochTransition}; use header::BlockNumber; use receipt::Receipt; +use rlp; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; @@ -167,7 +168,7 @@ impl Key for u64 { } /// Familial details concerning a block -#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] +#[derive(Debug, Clone)] pub struct BlockDetails { /// Block number pub number: BlockNumber, @@ -177,6 +178,57 @@ pub struct BlockDetails { pub parent: H256, /// List of children block hashes pub children: Vec, + /// Whether the block is considered finalized + pub is_finalized: bool, + /// Additional block metadata + pub metadata: Option>, +} + +impl rlp::Encodable for BlockDetails { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + let use_short_version = self.metadata.is_none() && !self.is_finalized; + + match use_short_version { + true => { stream.begin_list(4); }, + false => { stream.begin_list(6); }, + } + + stream.append(&self.number); + stream.append(&self.total_difficulty); + stream.append(&self.parent); + stream.append_list(&self.children); + if !use_short_version { + stream.append(&self.is_finalized); + stream.append(&self.metadata); + } + } +} + +impl rlp::Decodable for BlockDetails { + fn decode(rlp: &rlp::Rlp) -> Result { + let use_short_version = match rlp.item_count()? { + 4 => true, + 6 => false, + _ => return Err(rlp::DecoderError::RlpIncorrectListLen), + }; + + Ok(BlockDetails { + number: rlp.val_at(0)?, + total_difficulty: rlp.val_at(1)?, + parent: rlp.val_at(2)?, + children: rlp.list_at(3)?, + is_finalized: if use_short_version { + false + } else { + rlp.val_at(4)? + }, + metadata: if use_short_version { + None + } else { + rlp.val_at(5)? + }, + }) + } } impl HeapSizeOf for BlockDetails { diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 062068c704..f991692ded 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -33,4 +33,5 @@ pub use self::cache::CacheSize; pub use self::config::Config; pub use self::extras::{BlockReceipts, BlockDetails, TransactionAddress}; pub use self::import_route::ImportRoute; +pub use self::update::ExtrasInsert; pub use types::tree_route::TreeRoute; diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index a5251c1ed8..b695b9236b 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -22,3 +22,13 @@ pub struct ExtrasUpdate<'a> { /// Modified transaction addresses (None signifies removed transactions). pub transactions_addresses: HashMap>, } + +/// Extra information in block insertion. +pub struct ExtrasInsert { + /// The primitive fork choice before applying finalization rules. + pub fork_choice: ::engines::ForkChoice, + /// Is the inserted block considered finalized. + pub is_finalized: bool, + /// New block local metadata. + pub metadata: Option>, +} diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 76d78e3df6..993ecdda21 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -33,7 +33,7 @@ use util_error::UtilError; // other use ethereum_types::{H256, Address, U256}; use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert}; use client::ancient_import::AncientVerifier; use client::Error as ClientError; use client::{ @@ -50,13 +50,13 @@ use client::{ IoClient, }; use encoded; -use engines::{EthEngine, EpochTransition}; +use engines::{EthEngine, EpochTransition, ForkChoice}; use error::{ImportErrorKind, BlockImportErrorKind, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use vm::{EnvInfo, LastHashes}; use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; use factory::{Factories, VmFactory}; -use header::{BlockNumber, Header}; +use header::{BlockNumber, Header, ExtendedHeader}; use io::{IoChannel, IoError}; use log_entry::LocalizedLogEntry; use miner::{Miner, MinerService}; @@ -73,10 +73,12 @@ use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Databa use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, Action}; use types::filter::Filter; use types::mode::Mode as IpcMode; +use types::ancestry_action::AncestryAction; use verification; use verification::{PreverifiedBlock, Verifier}; use verification::queue::BlockQueue; use views::BlockView; +use parity_machine::{Finalizable, WithMetadata}; // re-export pub use types::blockchain_info::BlockChainInfo; @@ -396,6 +398,7 @@ impl Importer { last_hashes, client.factories.clone(), is_epoch_begin, + &mut chain.ancestry_with_metadata_iter(*header.parent_hash()), ); let mut locked_block = enact_result.map_err(|e| { @@ -467,6 +470,44 @@ impl Importer { let mut batch = DBTransaction::new(); + let ancestry_actions = self.engine.ancestry_actions(block.block(), &mut chain.ancestry_with_metadata_iter(*parent)); + + let best_hash = chain.best_block_hash(); + let metadata = block.block().metadata().map(Into::into); + let is_finalized = block.block().is_finalized(); + + let new = ExtendedHeader { + header: header.clone(), + is_finalized: is_finalized, + metadata: metadata, + parent_total_difficulty: chain.block_details(&parent).expect("Parent block is in the database; qed").total_difficulty + }; + + let best = { + let hash = best_hash; + let header = chain.block_header_data(&hash) + .expect("Best block is in the database; qed") + .decode() + .expect("Stored block header is valid RLP; qed"); + let details = chain.block_details(&hash) + .expect("Best block is in the database; qed"); + + ExtendedHeader { + parent_total_difficulty: details.total_difficulty - *header.difficulty(), + is_finalized: details.is_finalized, + metadata: details.metadata, + + header: header, + } + }; + + let route = chain.tree_route(best_hash, *parent).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); + let fork_choice = if route.is_from_route_finalized { + ForkChoice::Old + } else { + self.engine.fork_choice(&new, &best) + }; + // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. // TODO: Prove it with a test. @@ -485,7 +526,17 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); - let route = chain.insert_block(&mut batch, block_data, receipts.clone()); + + for ancestry_action in ancestry_actions { + let AncestryAction::MarkFinalized(ancestry) = ancestry_action; + chain.mark_finalized(&mut batch, ancestry).expect("Engine's ancestry action must be known blocks; qed"); + } + + let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { + fork_choice: fork_choice, + is_finalized: is_finalized, + metadata: new.metadata, + }); client.tracedb.read().import(&mut batch, TraceImportRequest { traces: traces.into(), @@ -2069,6 +2120,7 @@ impl PrepareOpenBlock for Client { gas_range_target, extra_data, is_epoch_begin, + &mut chain.ancestry_with_metadata_iter(best_header.hash()), ).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed"); // Add uncles @@ -2284,6 +2336,7 @@ mod tests { use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use kvdb::DBTransaction; + use blockchain::ExtrasInsert; let client = generate_dummy_client(0); let genesis = client.chain_info().best_block_hash; @@ -2296,7 +2349,11 @@ mod tests { let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new()); + another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); go_thread.store(true, Ordering::SeqCst); }); go diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 6a3166f7c0..fab3234657 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -392,6 +392,7 @@ impl PrepareOpenBlock for TestBlockChainClient { gas_range_target, extra_data, false, + &mut Vec::new().into_iter(), ).expect("Opening block for tests will not fail."); // TODO [todr] Override timestamp for predictability open_block.set_timestamp(*self.latest_block_timestamp.read()); @@ -739,7 +740,8 @@ impl BlockChainClient for TestBlockChainClient { } } if adding { Vec::new() } else { blocks } - } + }, + is_from_route_finalized: false, }) } diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index ed9a9a4f25..02bb88c51f 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -33,7 +33,7 @@ use error::{Error, BlockError}; use ethjson; use machine::{AuxiliaryData, Call, EthereumMachine}; use hash::keccak; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; @@ -957,6 +957,7 @@ impl Engine for AuthorityRound { &self, block: &mut ExecutedBlock, epoch_begin: bool, + _ancestry: &mut Iterator, ) -> Result<(), Error> { // with immediate transitions, we don't use the epoch mechanism anyway. // the genesis is always considered an epoch, but we ignore it intentionally. @@ -1348,6 +1349,10 @@ impl Engine for AuthorityRound { Some(Box::new(::snapshot::PoaSnapshot)) } } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -1407,9 +1412,9 @@ mod tests { let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1441,9 +1446,9 @@ mod tests { let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1696,7 +1701,7 @@ mod tests { let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); let client = generate_dummy_client(0); @@ -1731,7 +1736,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1740,7 +1745,7 @@ mod tests { engine.step(); // step 3 - let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); b2.push_transaction(Transaction { action: Action::Create, nonce: U256::from(0), @@ -1779,7 +1784,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1788,7 +1793,7 @@ mod tests { engine.step(); // step 3 - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr2, "0".into()); assert_eq!(engine.generate_seal(b2.block(), &genesis_header), Seal::None); @@ -1796,7 +1801,7 @@ mod tests { // step 4 // the spec sets the maximum_empty_steps to 2 so we will now seal an empty block and include the empty step messages - let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b3 = b3.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1829,7 +1834,7 @@ mod tests { engine.register_client(Arc::downgrade(&client) as _); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1839,7 +1844,7 @@ mod tests { // step 3 // the signer of the accumulated empty step message should be rewarded - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let addr1_balance = b2.block().state().balance(&addr1).unwrap(); // after closing the block `addr1` should be reward twice, one for the included empty step message and another for block creation @@ -1962,6 +1967,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); let b1 = b1.close_and_lock(); @@ -1983,6 +1989,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); let addr1_balance = b2.block().state().balance(&addr1).unwrap(); diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index bbefddccb7..e99fd88dcb 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -25,7 +25,7 @@ use block::*; use engines::{Engine, Seal, ConstructedVerifier, EngineError}; use error::{BlockError, Error}; use ethjson; -use header::Header; +use header::{Header, ExtendedHeader}; use client::EngineClient; use machine::{AuxiliaryData, Call, EthereumMachine}; use super::signer::EngineSigner; @@ -191,6 +191,10 @@ impl Engine for BasicAuthority { fn snapshot_components(&self) -> Option> { None } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -247,7 +251,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 40a96e2b71..c16203f105 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use engines::{Engine, Seal}; -use parity_machine::{Machine, Transactions}; +use parity_machine::{Machine, Transactions, TotalScoredHeader}; /// An engine which does not provide any consensus mechanism, just seals blocks internally. /// Only seals blocks which have transactions. @@ -33,7 +33,9 @@ impl InstantSeal { } impl Engine for InstantSeal - where M::LiveBlock: Transactions + where M::LiveBlock: Transactions, + M::ExtendedHeader: TotalScoredHeader, + ::Value: Ord { fn name(&self) -> &str { "InstantSeal" @@ -61,6 +63,10 @@ impl Engine for InstantSeal fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp >= parent_timestamp } + + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -80,7 +86,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index e019636f53..0878b4595f 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -52,15 +52,25 @@ use spec::CommonParams; use transaction::{self, UnverifiedTransaction, SignedTransaction}; use ethkey::Signature; -use parity_machine::{Machine, LocalizedMachine as Localized}; +use parity_machine::{Machine, LocalizedMachine as Localized, TotalScoredHeader}; use ethereum_types::{H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; use bytes::Bytes; +use types::ancestry_action::AncestryAction; /// Default EIP-210 contract code. /// As defined in https://github.com/ethereum/EIPs/pull/210 pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b"; +/// Fork choice. +#[derive(Debug, PartialEq, Eq)] +pub enum ForkChoice { + /// Choose the new block. + New, + /// Choose the current best block. + Old, +} + /// Voting errors. #[derive(Debug)] pub enum EngineError { @@ -208,6 +218,7 @@ pub trait Engine: Sync + Send { &self, _block: &mut M::LiveBlock, _epoch_begin: bool, + _ancestry: &mut Iterator, ) -> Result<(), M::Error> { Ok(()) } @@ -348,6 +359,24 @@ pub trait Engine: Sync + Send { fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp > parent_timestamp } + + /// Gather all ancestry actions. Called at the last stage when a block is committed. The Engine must guarantee that + /// the ancestry exists. + fn ancestry_actions(&self, _block: &M::LiveBlock, _ancestry: &mut Iterator) -> Vec { + Vec::new() + } + + /// Check whether the given new block is the best block, after finalization check. + fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; +} + +/// Check whether a given block is the best block based on the default total difficulty rule. +pub fn total_difficulty_fork_choice(new: &T, best: &T) -> ForkChoice where ::Value: Ord { + if new.total_score() > best.total_score() { + ForkChoice::New + } else { + ForkChoice::Old + } } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 278eb037c0..c6025e6247 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -19,7 +19,7 @@ use engines::Engine; use engines::block_reward::{self, RewardKind}; use header::BlockNumber; use machine::WithRewards; -use parity_machine::{Header, LiveBlock, WithBalances}; +use parity_machine::{Header, LiveBlock, WithBalances, TotalScoredHeader}; /// Params for a null engine. #[derive(Clone, Default)] @@ -58,7 +58,10 @@ impl Default for NullEngine { } } -impl Engine for NullEngine { +impl Engine for NullEngine + where M::ExtendedHeader: TotalScoredHeader, + ::Value: Ord +{ fn name(&self) -> &str { "NullEngine" } @@ -101,4 +104,8 @@ impl Engine for NullEngine { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } + + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 93fc347e94..52bf5ff67b 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -35,7 +35,7 @@ use unexpected::{OutOfBounds, Mismatch}; use client::EngineClient; use bytes::Bytes; use error::{Error, BlockError}; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use rlp::Rlp; use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; @@ -530,7 +530,7 @@ impl Engine for Tendermint { Ok(()) } - fn on_new_block(&self, block: &mut ExecutedBlock, epoch_begin: bool) -> Result<(), Error> { + fn on_new_block(&self, block: &mut ExecutedBlock, epoch_begin: bool, _ancestry: &mut Iterator) -> Result<(), Error> { if !epoch_begin { return Ok(()) } // genesis is never a new block, but might as well check. @@ -765,6 +765,10 @@ impl Engine for Tendermint { *self.client.write() = Some(client.clone()); self.validators.register_client(client); } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } } #[cfg(test)] @@ -800,7 +804,7 @@ mod tests { let db = spec.ensure_db_good(db, &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block(), &genesis_header) { (b, seal) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 09151415c8..9b3945e38b 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -25,7 +25,7 @@ use ethereum_types::{H256, H64, U256, Address}; use unexpected::{OutOfBounds, Mismatch}; use block::*; use error::{BlockError, Error}; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use engines::{self, Engine}; use ethjson; use rlp::Rlp; @@ -222,14 +222,6 @@ impl Engine for Arc { header.set_difficulty(difficulty); } - fn on_new_block( - &self, - _block: &mut ExecutedBlock, - _begins_epoch: bool, - ) -> Result<(), Error> { - Ok(()) - } - /// Apply the block reward on finalisation of the block. /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { @@ -364,6 +356,10 @@ impl Engine for Arc { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> engines::ForkChoice { + engines::total_difficulty_fork_choice(new, current) + } } impl Ethash { @@ -538,7 +534,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap()); } @@ -587,7 +583,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let mut uncle = Header::new(); let uncle_author: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into(); uncle.set_author(uncle_author); @@ -605,7 +601,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); let ubi_contract: Address = "00efdd5883ec628983e9063c7d969fe268bbf310".into(); diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index ba71eb3049..3e9675aa35 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -34,6 +34,19 @@ enum Seal { Without, } +/// Extended block header, wrapping `Header` with finalized and total difficulty information. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExtendedHeader { + /// The actual header. + pub header: Header, + /// Whether the block underlying this header is considered finalized. + pub is_finalized: bool, + /// The parent block difficulty. + pub parent_total_difficulty: U256, + /// The block metadata information. + pub metadata: Option>, +} + /// A block header. /// /// Reflects the specific RLP fields of a block in the chain with additional room for the seal @@ -368,21 +381,48 @@ impl HeapSizeOf for Header { impl ::parity_machine::Header for Header { fn bare_hash(&self) -> H256 { Header::bare_hash(self) } - fn hash(&self) -> H256 { Header::hash(self) } - fn seal(&self) -> &[Vec] { Header::seal(self) } - fn author(&self) -> &Address { Header::author(self) } - fn number(&self) -> BlockNumber { Header::number(self) } } impl ::parity_machine::ScoredHeader for Header { + type Value = U256; + fn score(&self) -> &U256 { self.difficulty() } fn set_score(&mut self, score: U256) { self.set_difficulty(score) } } +impl ::parity_machine::Header for ExtendedHeader { + fn bare_hash(&self) -> H256 { self.header.bare_hash() } + fn hash(&self) -> H256 { self.header.hash() } + fn seal(&self) -> &[Vec] { self.header.seal() } + fn author(&self) -> &Address { self.header.author() } + fn number(&self) -> BlockNumber { self.header.number() } +} + +impl ::parity_machine::ScoredHeader for ExtendedHeader { + type Value = U256; + + fn score(&self) -> &U256 { self.header.difficulty() } + fn set_score(&mut self, score: U256) { self.header.set_difficulty(score) } +} + +impl ::parity_machine::TotalScoredHeader for ExtendedHeader { + type Value = U256; + + fn total_score(&self) -> U256 { self.parent_total_difficulty + *self.header.difficulty() } +} + +impl ::parity_machine::FinalizableHeader for ExtendedHeader { + fn is_finalized(&self) -> bool { self.is_finalized } +} + +impl ::parity_machine::WithMetadataHeader for ExtendedHeader { + fn metadata(&self) -> Option<&[u8]> { self.metadata.as_ref().map(|v| v.as_ref()) } +} + #[cfg(test)] mod tests { use rustc_hex::FromHex; diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index d0d434b1de..1bd3805ef3 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -25,7 +25,7 @@ use builtin::Builtin; use client::{BlockInfo, CallContract}; use error::Error; use executive::Executive; -use header::{BlockNumber, Header}; +use header::{BlockNumber, Header, ExtendedHeader}; use spec::CommonParams; use state::{CleanupMode, Substate}; use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType, Tracing}; @@ -422,10 +422,12 @@ pub enum AuxiliaryRequest { impl ::parity_machine::Machine for EthereumMachine { type Header = Header; + type ExtendedHeader = ExtendedHeader; type LiveBlock = ExecutedBlock; type EngineClient = ::client::EngineClient; type AuxiliaryRequest = AuxiliaryRequest; + type AncestryAction = ::types::ancestry_action::AncestryAction; type Error = Error; } diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index ae1805e85b..3c3b47ce9c 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -22,7 +22,7 @@ use tempdir::TempDir; use error::{Error, ErrorKind}; use blockchain::generator::{BlockGenerator, BlockBuilder}; -use blockchain::BlockChain; +use blockchain::{BlockChain, ExtrasInsert}; use snapshot::{chunk_secondary, Error as SnapshotError, Progress, SnapshotComponents}; use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; @@ -49,7 +49,11 @@ fn chunk_and_restore(amount: u64) { // build the blockchain. let mut batch = DBTransaction::new(); for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![], ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); bc.commit(); } diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 32b8beab83..e57d16a654 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -19,7 +19,7 @@ use account_provider::AccountProvider; use ethereum_types::{H256, U256, Address}; use block::{OpenBlock, Drain}; -use blockchain::{BlockChain, Config as BlockChainConfig}; +use blockchain::{BlockChain, Config as BlockChainConfig, ExtrasInsert}; use bytes::Bytes; use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify, ChainMessageType, PrepareOpenBlock}; use ethkey::KeyPair; @@ -148,6 +148,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; b.set_timestamp(rolling_timestamp); @@ -265,7 +266,12 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![]); + // Total difficulty is always 0 here. + bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); bc.commit(); } db.write(batch).unwrap(); @@ -280,7 +286,12 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![]); + // Total difficulty is always 0 here. + bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], ExtrasInsert { + fork_choice: ::engines::ForkChoice::New, + is_finalized: false, + metadata: None, + }); bc.commit(); } db.write(batch).unwrap(); diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 72d0d47371..a98667b142 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -87,6 +87,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; root_block.set_timestamp(rolling_timestamp); @@ -115,6 +116,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; parent_block.set_timestamp(rolling_timestamp); @@ -141,7 +143,8 @@ fn can_trace_block_and_uncle_reward() { author.clone(), (3141562.into(), 31415620.into()), vec![], - false + false, + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; block.set_timestamp(rolling_timestamp); diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 03a6d6f8d4..de2f6c7195 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -455,6 +455,8 @@ mod tests { total_difficulty: header.difficulty().clone(), parent: header.parent_hash().clone(), children: Vec::new(), + is_finalized: false, + metadata: None, } }) } diff --git a/ethcore/types/src/ancestry_action.rs b/ethcore/types/src/ancestry_action.rs new file mode 100644 index 0000000000..d9915cfee4 --- /dev/null +++ b/ethcore/types/src/ancestry_action.rs @@ -0,0 +1,27 @@ +// Copyright 2015-2018 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 . + +//! Actions on ancestry blocks when working on a new block. + +use ethereum_types::H256; + +#[derive(Debug, PartialEq, Eq, Clone)] +/// Actions on a live block's parent block. Only committed when the live block is committed. Those actions here must +/// respect the normal blockchain reorganization rules. +pub enum AncestryAction { + /// Mark an ancestry block as finalized. + MarkFinalized(H256), +} diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 83a1cc6557..18e0dde86a 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -46,6 +46,7 @@ pub mod state_diff; pub mod trace_filter; pub mod tree_route; pub mod verification_queue_info; +pub mod ancestry_action; /// Type for block number. pub type BlockNumber = u64; diff --git a/ethcore/types/src/tree_route.rs b/ethcore/types/src/tree_route.rs index b3fe431ab9..5d1bddd87b 100644 --- a/ethcore/types/src/tree_route.rs +++ b/ethcore/types/src/tree_route.rs @@ -27,4 +27,6 @@ pub struct TreeRoute { pub ancestor: H256, /// An index where best common ancestor would be. pub index: usize, + /// Whether it has finalized blocks from `from` (inclusive) to `ancestor` (exclusive). + pub is_from_route_finalized: bool, } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 54ee403d95..075a42d731 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -40,13 +40,35 @@ pub trait Header { fn number(&self) -> u64; } -/// a header with an associated score (difficulty in PoW terms) +/// A header with an associated score (difficulty in PoW terms) pub trait ScoredHeader: Header { + type Value; + /// Get the score of this header. - fn score(&self) -> &U256; + fn score(&self) -> &Self::Value; /// Set the score of this header. - fn set_score(&mut self, score: U256); + fn set_score(&mut self, score: Self::Value); +} + +/// A header with associated total score. +pub trait TotalScoredHeader: Header { + type Value; + + /// Get the total score of this header. + fn total_score(&self) -> Self::Value; +} + +/// A header with finalized information. +pub trait FinalizableHeader: Header { + /// Get whether this header is considered finalized, so that it will never be replaced in reorganization. + fn is_finalized(&self) -> bool; +} + +/// A header with metadata information. +pub trait WithMetadataHeader: Header { + /// Get the current header metadata. + fn metadata(&self) -> Option<&[u8]>; } /// A "live" block is one which is in the process of the transition. @@ -73,16 +95,36 @@ pub trait Transactions: LiveBlock { fn transactions(&self) -> &[Self::Transaction]; } +/// Trait for blocks which have finalized information. +pub trait Finalizable: LiveBlock { + /// Get whether the block is finalized. + fn is_finalized(&self) -> bool; + /// Mark the block as finalized. + fn mark_finalized(&mut self); +} + +/// A state machine with block metadata. +pub trait WithMetadata: LiveBlock { + /// Get the current live block metadata. + fn metadata(&self) -> Option<&[u8]>; + /// Set the current live block metadata. + fn set_metadata(&mut self, value: Option>); +} + /// Generalization of types surrounding blockchain-suitable state machines. pub trait Machine: for<'a> LocalizedMachine<'a> { /// The block header type. type Header: Header; /// The live block type. type LiveBlock: LiveBlock; + /// Block header with metadata information. + type ExtendedHeader: Header; /// A handle to a blockchain client for this machine. type EngineClient: ?Sized; /// A description of needed auxiliary data. type AuxiliaryRequest; + /// Actions taken on ancestry blocks when commiting a new block. + type AncestryAction; /// Errors which can occur when querying or interacting with the machine. type Error; -- GitLab From f9e64e0965febd95de513b1508f75fffc76169bf Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 16 May 2018 20:09:59 +0200 Subject: [PATCH 164/263] typo (#8640) --- parity/main.rs | 6 +++--- secret_store/src/acl_storage.rs | 2 +- secret_store/src/key_server_set.rs | 10 +++++----- secret_store/src/key_storage.rs | 2 +- secret_store/src/serialization.rs | 2 +- secret_store/src/traits.rs | 2 +- secret_store/src/types/all.rs | 2 +- secret_store/src/types/error.rs | 8 ++++---- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 03b04a8c82..06671cbfeb 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -54,15 +54,15 @@ fn latest_exe_path() -> Option { fn set_spec_name_override(spec_name: String) { if let Err(e) = create_dir_all(default_hypervisor_path()) - .and_then(|_| File::create(updates_path("spec_name_overide")) + .and_then(|_| File::create(updates_path("spec_name_override")) .and_then(|mut f| f.write_all(spec_name.as_bytes()))) { - warn!("Couldn't override chain spec: {} at {:?}", e, updates_path("spec_name_overide")); + warn!("Couldn't override chain spec: {} at {:?}", e, updates_path("spec_name_override")); } } fn take_spec_name_override() -> Option { - let p = updates_path("spec_name_overide"); + let p = updates_path("spec_name_override"); let r = File::open(p.clone()).ok() .and_then(|mut f| { let mut spec_name = String::new(); f.read_to_string(&mut spec_name).ok().map(|_| spec_name) }); let _ = remove_file(p); diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index b3427fa1b2..bc75cfec44 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -106,7 +106,7 @@ impl CachedContract { pub fn check(&mut self, requester: Address, document: &ServerKeyId) -> Result { if let Some(client) = self.client.get() { - // call contract to check accesss + // call contract to check access match self.contract_addr { Some(contract_address) => { let do_call = |data| client.call_contract(BlockId::Latest, contract_address, data); diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index d13017261c..8a0d786af9 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -271,7 +271,7 @@ impl CachedContract { pub fn update(&mut self, enacted: Vec, retracted: Vec) { if let Some(client) = self.client.get() { - // read new snapshot from reqistry (if something has chnaged) + // read new snapshot from registry (if something has changed) self.read_from_registry_if_required(&*client, enacted, retracted); // update number of confirmations (if there's future new set) @@ -371,7 +371,7 @@ impl CachedContract { None => { // no contract installed => empty snapshot // WARNING: after restart current_set will be reset to the set from configuration file - // even though we have reset to empty set here. We are not considerning this as an issue + // even though we have reset to empty set here. We are not considering this as an issue // because it is actually the issue of administrator. self.snapshot = Default::default(); self.future_new_set = None; @@ -540,7 +540,7 @@ fn update_number_of_confirmations H256, F2: Fn(H256) -> Option> // not enough confirmations => do nothing Some(_) => return, // if number of confirmations is None, then reorg has happened && we need to reset block - // (some more intelligent startegy is possible, but let's stick to simplest one) + // (some more intelligent strategy is possible, but let's stick to simplest one) None => { future_new_set.block = latest_block(); return; @@ -556,9 +556,9 @@ fn update_number_of_confirmations H256, F2: Fn(H256) -> Option> fn update_last_transaction_block(client: &Client, migration_id: &H256, previous_transaction: &mut Option) -> bool { let last_block = client.block_number(BlockId::Latest).unwrap_or_default(); match previous_transaction.as_ref() { - // no previous transaction => send immideately + // no previous transaction => send immediately None => (), - // previous transaction has been sent for other migration process => send immideately + // previous transaction has been sent for other migration process => send immediately Some(tx) if tx.migration_id != *migration_id => (), // if we have sent the same type of transaction recently => do nothing (hope it will be mined eventually) // if we have sent the same transaction some time ago => diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index 4f78bc338c..848e6bf2a5 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -108,7 +108,7 @@ pub struct SerializableDocumentKeyShareV0 { /// V1 of encrypted key share, as it is stored by key storage on the single key server. #[derive(Serialize, Deserialize)] struct SerializableDocumentKeyShareV1 { - /// Authore of the entry. + /// Author of the entry. pub author: SerializablePublic, /// Decryption threshold (at least threshold + 1 nodes are required to decrypt data). pub threshold: usize, diff --git a/secret_store/src/serialization.rs b/secret_store/src/serialization.rs index 42209e0de4..f3e9aa1d76 100644 --- a/secret_store/src/serialization.rs +++ b/secret_store/src/serialization.rs @@ -117,7 +117,7 @@ impl_bytes!(SerializableSignature, Signature, false, ()); /// Serializable shadow decryption result. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SerializableEncryptedDocumentKeyShadow { - /// Decrypted secret point. It is partially decrypted if shadow decrpytion was requested. + /// Decrypted secret point. It is partially decrypted if shadow decryption was requested. pub decrypted_secret: SerializablePublic, /// Shared common point. pub common_point: SerializablePublic, diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs index 04f2fa1294..704be1c254 100644 --- a/secret_store/src/traits.rs +++ b/secret_store/src/traits.rs @@ -94,7 +94,7 @@ pub trait MessageSigner: ServerKeyGenerator { /// Administrative sessions server. pub trait AdminSessionsServer { /// Change servers set so that nodes in new_servers_set became owners of shares for all keys. - /// And old nodes (i.e. cluste nodes except new_servers_set) have clear databases. + /// And old nodes (i.e. cluster nodes except new_servers_set) have clear databases. /// WARNING: newly generated keys will be distributed among all cluster nodes. So this session /// must be followed with cluster nodes change (either via contract, or config files). fn change_servers_set(&self, old_set_signature: RequestSignature, new_set_signature: RequestSignature, new_servers_set: BTreeSet) -> Result<(), Error>; diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index bfc58779a6..ab0aea1b13 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -94,7 +94,7 @@ pub struct ClusterConfiguration { /// Shadow decryption result. #[derive(Clone, Debug, PartialEq)] pub struct EncryptedDocumentKeyShadow { - /// Decrypted secret point. It is partially decrypted if shadow decrpytion was requested. + /// Decrypted secret point. It is partially decrypted if shadow decryption was requested. pub decrypted_secret: ethkey::Public, /// Shared common point. pub common_point: Option, diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs index 1fceb120e8..eae914ec86 100644 --- a/secret_store/src/types/error.rs +++ b/secret_store/src/types/error.rs @@ -60,7 +60,7 @@ pub enum Error { /// Document key with this ID is not yet stored. DocumentKeyIsNotFound, /// Consensus is temporary unreachable. Means that something is currently blocking us from either forming - /// consensus group (like disconnecting from too many nodes, which are AGREE to partticipate in consensus) + /// consensus group (like disconnecting from too many nodes, which are AGREE to participate in consensus) /// or from rejecting request (disconnecting from AccessDenied-nodes). ConsensusTemporaryUnreachable, /// Consensus is unreachable. It doesn't mean that it will ALWAYS remain unreachable, but right NOW we have @@ -78,9 +78,9 @@ pub enum Error { InsufficientRequesterData(String), /// Cryptographic error. EthKey(String), - /// I/O error has occured. + /// I/O error has occurred. Io(String), - /// Deserialization error has occured. + /// Deserialization error has occurred. Serde(String), /// Hyper error. Hyper(String), @@ -148,7 +148,7 @@ impl fmt::Display for Error { Error::DocumentKeyIsNotFound => write!(f, "Document key with this ID is not found"), Error::ConsensusUnreachable => write!(f, "Consensus unreachable"), Error::ConsensusTemporaryUnreachable => write!(f, "Consensus temporary unreachable"), - Error::AccessDenied => write!(f, "Access dened"), + Error::AccessDenied => write!(f, "Access denied"), Error::ExclusiveSessionActive => write!(f, "Exclusive session active"), Error::HasActiveSessions => write!(f, "Unable to start exclusive session"), Error::InsufficientRequesterData(ref e) => write!(f, "Insufficient requester data: {}", e), -- GitLab From 30ecd045fa2a1b7f001ca387965d5a296af61d7d Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 16 May 2018 22:00:33 +0200 Subject: [PATCH 165/263] Changelog for 1.10.4-stable and 1.11.1-beta (#8637) * Add changelog for 1.10.4 * Add changelog for 1.11.1 * Fix Typos --- CHANGELOG.md | 119 ++++++++++++++++++++++++++++++++++++++--- docs/CHANGELOG-1.10.md | 23 ++++++++ 2 files changed, 136 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f839802e7c..ee66149ed0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,22 @@ -## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-05-09) +## Parity [v1.11.1](https://github.com/paritytech/parity/releases/tag/v1.11.1) (2018-05-15) -This is the Parity 1.11.0-beta release! Hurray! +This is the Parity 1.11.1-beta release! Hurray! Notable changes in reversed alphabetical order: - TOOLING: **Whisper CLI** [#8201](https://github.com/paritytech/parity/pull/8201) - `whisper-cli` is a standalone tool to communicate with the Whisper protocol. - It provides functionality to specify `whisper-pool-size`, `port` and `address` to use. - - All whisper RPC APIs are enabled and can be directly acessed. + - All whisper RPC APIs are enabled and can be directly accessed. - JSON-RPC API: **Return error in case eth_call returns VM errors** [#8448](https://github.com/paritytech/parity/pull/8448) - This changes the behaviors of `eth_call` to respect VM errors if any. - In case of `REVERT`, it will also return the reverted return data in hex format. -- ENGINES: **Block reward contract** [#8419](https://github.com/paritytech/parity/pull/8419) +- ENGINES: **Block Reward Contract** [#8419](https://github.com/paritytech/parity/pull/8419) - The _AuRa_ PoA engine has now support for having a contract to calculate the block rewards. - The engine passes a list of benefactors and reward types to the contract which then returns a list of addresses and respective rewards. -- CORE: **Private transactions integration pr** [#6422](https://github.com/paritytech/parity/pull/6422) +- CORE: **Private Transactions** [#6422](https://github.com/paritytech/parity/pull/6422) - Parity now provides a private transactions system. - - Please, check out our wiki to get and [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). + - Please, check out our wiki to get an [overview and setup instructions](https://wiki.parity.io/Private-Transactions.html). - CORE: **New Transaction Queue implementation** [#8074](https://github.com/paritytech/parity/pull/8074) - Verification is now done in parallel. - Previous queue had `O(1)` time to get pending set, but `O(n^2)` insertion time. And obviously insertion/removal happens much more often than retrieving the pending set (only for propagation and pending block building) Currently we have `O(n * log(senders))` pending set time (with cache) and `O(tx_per_sender)` (usually within `log(tx_per_sender)`) insertion time. @@ -47,6 +47,113 @@ Notable changes in reversed alphabetical order: The full list of included changes: +- Backports ([#8624](https://github.com/paritytech/parity/pull/8624)) + - Trace precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity/pull/8486)) + - Trace precompiled contracts when the transfer value is not zero + - Add tests for precompiled CALL tracing + - Use byzantium test machine for the new test + - Add notes in comments on why we don't trace all precompiles + - Use is_transferred instead of transferred + - Return error if RLP size of transaction exceeds the limit ([#8473](https://github.com/paritytech/parity/pull/8473)) + - Return error if RLP size of transaction exceeds the limit + - Review comments fixed + - RLP check moved to verifier, corresponding pool test added + - Don't block sync when importing old blocks ([#8530](https://github.com/paritytech/parity/pull/8530)) + - Alter IO queueing. + - Don't require IoMessages to be Clone + - Ancient blocks imported via IoChannel. + - Get rid of private transactions io message. + - Get rid of deadlock and fix disconnected handler. + - Revert to old disconnect condition. + - Fix tests. + - Fix deadlock. + - Refactoring `ethcore-sync` - Fixing warp-sync barrier ([#8543](https://github.com/paritytech/parity/pull/8543)) + - Start dividing sync chain : first supplier method + - WIP - updated chain sync supplier + - Finish refactoring the Chain Sync Supplier + - Create Chain Sync Requester + - Add Propagator for Chain Sync + - Add the Chain Sync Handler + - Move tests from mod -> handler + - Move tests to propagator + - Refactor SyncRequester arguments + - Refactoring peer fork header handler + - Fix wrong highest block number in snapshot sync + - Small refactor... + - Address PR grumbles + - Retry failed CI job + - Fix tests + - PR Grumbles + - Handle socket address parsing errors ([#8545](https://github.com/paritytech/parity/pull/8545)) + - Fix packet count when talking with PAR2 peers ([#8555](https://github.com/paritytech/parity/pull/8555)) + - Support diferent packet counts in different protocol versions. + - Fix light timeouts and eclipse protection. + - Fix devp2p tests. + - Fix whisper-cli compilation. + - Fix compilation. + - Fix ethcore-sync tests. + - Revert "Fix light timeouts and eclipse protection." + - Increase timeouts. + - Add whisper CLI to the pipelines ([#8578](https://github.com/paritytech/parity/pull/8578)) + - Add whisper CLI to the pipelines + - Address todo, ref [#8579](https://github.com/paritytech/parity/pull/8579) + - Rename `whisper-cli binary` to `whisper` ([#8579](https://github.com/paritytech/parity/pull/8579)) + - Rename whisper-cli binary to whisper + - Fix tests + - Remove manually added text to the errors ([#8595](https://github.com/paritytech/parity/pull/8595)) + - Fix account list double 0x display ([#8596](https://github.com/paritytech/parity/pull/8596)) + - Remove unused self import + - Fix account list double 0x display + - Fix BlockReward contract "arithmetic operation overflow" ([#8611](https://github.com/paritytech/parity/pull/8611)) + - Fix BlockReward contract "arithmetic operation overflow" + - Add docs on how execute_as_system works + - Fix typo + - Rlp decode returns Result ([#8527](https://github.com/paritytech/parity/pull/8527)) + - Remove expect ([#8536](https://github.com/paritytech/parity/pull/8536)) + - Remove expect and propagate rlp::DecoderErrors as TrieErrors + - Decoding headers can fail ([#8570](https://github.com/paritytech/parity/pull/8570)) + - Rlp::decode returns Result + - Fix journaldb to handle rlp::decode Result + - Fix ethcore to work with rlp::decode returning Result + - Light client handles rlp::decode returning Result + - Fix tests in rlp_derive + - Fix tests + - Cleanup + - Cleanup + - Allow panic rather than breaking out of iterator + - Let decoding failures when reading from disk blow up + - Syntax + - Fix the trivial grumbles + - Fix failing tests + - Make Account::from_rlp return Result + - Syntx, sigh + - Temp-fix for decoding failures + - Header::decode returns Result + - Do not continue reading from the DB when a value could not be read + - Fix tests + - Handle header decoding in light_sync + - Handling header decoding errors + - Let the DecodeError bubble up unchanged + - Remove redundant error conversion + - Fix compiler warning ([#8590](https://github.com/paritytech/parity/pull/8590)) + - Attempt to fix intermittent test failures ([#8584](https://github.com/paritytech/parity/pull/8584)) + - Block_header can fail so return Result ([#8581](https://github.com/paritytech/parity/pull/8581)) + - Block_header can fail so return Result + - Restore previous return type based on feedback + - Fix failing doc tests running on non-code + - Block::decode() returns Result ([#8586](https://github.com/paritytech/parity/pull/8586)) + - Gitlab test script fixes ([#8573](https://github.com/paritytech/parity/pull/8573)) + - Exclude /docs from modified files. + - Ensure all references in the working tree are available + - Remove duplicated line from test script +- Bump beta to 1.11.1 ([#8627](https://github.com/paritytech/parity/pull/8627)) + +## Parity [v1.11.0](https://github.com/paritytech/parity/releases/tag/v1.11.0) (2018-05-09) + +This is the Parity 1.11.0-beta release! ~~Hurray!~~ This release has been pulled due to peering issues, please use 1.11.1-beta. + +The full list of included changes: + - Backports ([#8558](https://github.com/paritytech/parity/pull/8558)) - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) - Fetch logs by hash in blockchain database diff --git a/docs/CHANGELOG-1.10.md b/docs/CHANGELOG-1.10.md index 4db8f32bb6..a8c7ad20a7 100644 --- a/docs/CHANGELOG-1.10.md +++ b/docs/CHANGELOG-1.10.md @@ -1,3 +1,26 @@ +## Parity [v1.10.4](https://github.com/paritytech/parity/releases/tag/v1.10.4) (2018-05-15) + +Parity 1.10.4 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Backports ([#8623](https://github.com/paritytech/parity/pull/8623)) + - Fix account list double 0x display ([#8596](https://github.com/paritytech/parity/pull/8596)) + - Remove unused self import + - Fix account list double 0x display + - Trace precompiled contracts when the transfer value is not zero ([#8486](https://github.com/paritytech/parity/pull/8486)) + - Trace precompiled contracts when the transfer value is not zero + - Add tests for precompiled CALL tracing + - Use byzantium test machine for the new test + - Add notes in comments on why we don't trace all precompileds + - Use is_transferred instead of transferred + - Gitlab test script fixes ([#8573](https://github.com/paritytech/parity/pull/8573)) + - Exclude /docs from modified files. + - Ensure all references in the working tree are available + - Remove duplicated line from test script +- Bump stable to 1.10.4 ([#8626](https://github.com/paritytech/parity/pull/8626)) +- Allow stable snaps to be stable. ([#8582](https://github.com/paritytech/parity/pull/8582)) + ## Parity [v1.10.3](https://github.com/paritytech/parity/releases/tag/v1.10.3) (2018-05-08) Parity 1.10.3 marks the first stable release on the 1.10 track. Among others, it improves performance and stability. -- GitLab From 6ecc855c3433403e5d54910cdc6c44700d7b4ab7 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 16 May 2018 22:01:11 +0200 Subject: [PATCH 166/263] Don't open Browser post-install on Mac (#8641) Since we start parity with the UI disabled per default now, opening the browser post installation will show an annoying error message, confusing the user. This patch removes opening the browser to prevent that annoyance. fixes #8194 --- mac/post-install.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/mac/post-install.sh b/mac/post-install.sh index a364878d88..fc71ee1de6 100755 --- a/mac/post-install.sh +++ b/mac/post-install.sh @@ -3,6 +3,4 @@ test -f /usr/local/libexec/uninstall-parity.sh && /usr/local/libexec/uninstall-parity.sh || true killall -9 parity && sleep 5 su $USER -c "open /Applications/Parity\ Ethereum.app" -sleep 5 -su $USER -c "open http://127.0.0.1:8180/" exit 0 -- GitLab From cdbcfaa7de55731f4e1eb2613f72c980fba1e0f7 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 16 May 2018 22:01:55 +0200 Subject: [PATCH 167/263] Resumable warp-sync / Seed downloaded snapshots (#8544) * Start dividing sync chain : first supplier method * WIP - updated chain sync supplier * Finish refactoring the Chain Sync Supplier * Create Chain Sync Requester * Add Propagator for Chain Sync * Add the Chain Sync Handler * Move tests from mod -> handler * Move tests to propagator * Refactor SyncRequester arguments * Refactoring peer fork header handler * Fix wrong highest block number in snapshot sync * Small refactor... * Resume warp-sync downloaded chunks * Add comments * Refactoring the previous chunks import * Fix tests * Address PR grumbles * Fix not seeding current snapshot * Address PR Grumbles * Address PR grumble * Retry failed CI job * Update SnapshotService readiness check Fix restoration locking issue for previous chunks restoration * Fix tests * Fix tests * Fix test * Early abort importing previous chunks * PR Grumbles * Update Gitlab CI config * SyncState back to Waiting when Manifest peers disconnect * Move fix * Better fix * Revert GitLab CI changes * Fix Warning * Refactor resuming snapshots * Fix string construction * Revert "Refactor resuming snapshots" This reverts commit 75fd4b553a38e4a49dc5d6a878c70e830ff382eb. * Update informant log * Fix string construction * Refactor resuming snapshots * Fix informant * PR Grumbles * Update informant message : show chunks done * PR Grumbles * Fix * Fix Warning * PR Grumbles --- ethcore/src/snapshot/service.rs | 165 ++++++++++++++++--- ethcore/src/snapshot/tests/service.rs | 8 +- ethcore/src/snapshot/traits.rs | 3 + ethcore/sync/src/chain/handler.rs | 52 ++++-- ethcore/sync/src/chain/mod.rs | 104 +++++++----- ethcore/sync/src/chain/supplier.rs | 26 +-- ethcore/sync/src/snapshot.rs | 71 ++++++-- ethcore/sync/src/tests/snapshot.rs | 4 + ethcore/types/src/restoration_status.rs | 5 + parity/informant.rs | 23 ++- parity/snapshot.rs | 1 + rpc/src/v1/tests/helpers/snapshot_service.rs | 1 + 12 files changed, 361 insertions(+), 102 deletions(-) diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index c5b9123e10..17c362e044 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -17,8 +17,8 @@ //! Snapshot network service implementation. use std::collections::HashSet; -use std::io::ErrorKind; -use std::fs; +use std::io::{self, Read, ErrorKind}; +use std::fs::{self, File}; use std::path::PathBuf; use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; @@ -30,6 +30,7 @@ use blockchain::BlockChain; use client::{Client, ChainInfo, ClientIoMessage}; use engines::EthEngine; use error::Error; +use hash::keccak; use ids::BlockId; use io::IoChannel; @@ -270,8 +271,8 @@ impl Service { } } - // delete the temporary restoration dir if it does exist. - if let Err(e) = fs::remove_dir_all(service.restoration_dir()) { + // delete the temporary restoration DB dir if it does exist. + if let Err(e) = fs::remove_dir_all(service.restoration_db()) { if e.kind() != ErrorKind::NotFound { return Err(e.into()) } @@ -325,6 +326,13 @@ impl Service { dir } + // previous snapshot chunks path. + fn prev_chunks_dir(&self) -> PathBuf { + let mut dir = self.snapshot_root.clone(); + dir.push("prev_chunks"); + dir + } + // replace one the client's database with our own. fn replace_client_db(&self) -> Result<(), Error> { let our_db = self.restoration_db(); @@ -406,9 +414,26 @@ impl Service { /// Initialize the restoration synchronously. /// The recover flag indicates whether to recover the restored snapshot. pub fn init_restore(&self, manifest: ManifestData, recover: bool) -> Result<(), Error> { + let mut res = self.restoration.lock(); + let rest_dir = self.restoration_dir(); + let rest_db = self.restoration_db(); + let recovery_temp = self.temp_recovery_dir(); + let prev_chunks = self.prev_chunks_dir(); - let mut res = self.restoration.lock(); + // delete and restore the restoration dir. + if let Err(e) = fs::remove_dir_all(&prev_chunks) { + match e.kind() { + ErrorKind::NotFound => {}, + _ => return Err(e.into()), + } + } + + // Move the previous recovery temp directory + // to `prev_chunks` to be able to restart restoring + // with previously downloaded blocks + // This step is optional, so don't fail on error + fs::rename(&recovery_temp, &prev_chunks).ok(); self.state_chunks.store(0, Ordering::SeqCst); self.block_chunks.store(0, Ordering::SeqCst); @@ -424,29 +449,38 @@ impl Service { } } + *self.status.lock() = RestorationStatus::Initializing { + chunks_done: 0, + }; + fs::create_dir_all(&rest_dir)?; // make new restoration. let writer = match recover { - true => Some(LooseWriter::new(self.temp_recovery_dir())?), + true => Some(LooseWriter::new(recovery_temp)?), false => None }; let params = RestorationParams { - manifest: manifest, + manifest: manifest.clone(), pruning: self.pruning, - db: self.restoration_db_handler.open(&self.restoration_db())?, + db: self.restoration_db_handler.open(&rest_db)?, writer: writer, genesis: &self.genesis_block, - guard: Guard::new(rest_dir), + guard: Guard::new(rest_db), engine: &*self.engine, }; - let state_chunks = params.manifest.state_hashes.len(); - let block_chunks = params.manifest.block_hashes.len(); + let state_chunks = manifest.state_hashes.len(); + let block_chunks = manifest.block_hashes.len(); *res = Some(Restoration::new(params)?); + self.restoring_snapshot.store(true, Ordering::SeqCst); + + // Import previous chunks, continue if it fails + self.import_prev_chunks(&mut res, manifest).ok(); + *self.status.lock() = RestorationStatus::Ongoing { state_chunks: state_chunks as u32, block_chunks: block_chunks as u32, @@ -454,10 +488,65 @@ impl Service { block_chunks_done: self.block_chunks.load(Ordering::SeqCst) as u32, }; - self.restoring_snapshot.store(true, Ordering::SeqCst); Ok(()) } + /// Import the previous chunks into the current restoration + fn import_prev_chunks(&self, restoration: &mut Option, manifest: ManifestData) -> Result<(), Error> { + let prev_chunks = self.prev_chunks_dir(); + + // Restore previous snapshot chunks + let files = fs::read_dir(prev_chunks.as_path())?; + let mut num_temp_chunks = 0; + + for prev_chunk_file in files { + // Don't go over all the files if the restoration has been aborted + if !self.restoring_snapshot.load(Ordering::SeqCst) { + trace!(target:"snapshot", "Aborting importing previous chunks"); + return Ok(()); + } + // Import the chunk, don't fail and continue if one fails + match self.import_prev_chunk(restoration, &manifest, prev_chunk_file) { + Ok(true) => num_temp_chunks += 1, + Err(e) => trace!(target: "snapshot", "Error importing chunk: {:?}", e), + _ => (), + } + } + + trace!(target:"snapshot", "Imported {} previous chunks", num_temp_chunks); + + // Remove the prev temp directory + fs::remove_dir_all(&prev_chunks)?; + + Ok(()) + } + + /// Import a previous chunk at the given path. Returns whether the block was imported or not + fn import_prev_chunk(&self, restoration: &mut Option, manifest: &ManifestData, file: io::Result) -> Result { + let file = file?; + let path = file.path(); + + let mut file = File::open(path.clone())?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer)?; + + let hash = keccak(&buffer); + + let is_state = if manifest.block_hashes.contains(&hash) { + false + } else if manifest.state_hashes.contains(&hash) { + true + } else { + return Ok(false); + }; + + self.feed_chunk_with_restoration(restoration, hash, &buffer, is_state)?; + + trace!(target: "snapshot", "Fed chunk {:?}", hash); + + Ok(true) + } + // finalize the restoration. this accepts an already-locked // restoration as an argument -- so acquiring it again _will_ // lead to deadlock. @@ -499,12 +588,19 @@ impl Service { /// Feed a chunk of either kind. no-op if no restoration or status is wrong. fn feed_chunk(&self, hash: H256, chunk: &[u8], is_state: bool) -> Result<(), Error> { // TODO: be able to process block chunks and state chunks at same time? - let (result, db) = { - let mut restoration = self.restoration.lock(); + let mut restoration = self.restoration.lock(); + self.feed_chunk_with_restoration(&mut restoration, hash, chunk, is_state) + } + /// Feed a chunk with the Restoration + fn feed_chunk_with_restoration(&self, restoration: &mut Option, hash: H256, chunk: &[u8], is_state: bool) -> Result<(), Error> { + let (result, db) = { match self.status() { - RestorationStatus::Inactive | RestorationStatus::Failed => return Ok(()), - RestorationStatus::Ongoing { .. } => { + RestorationStatus::Inactive | RestorationStatus::Failed => { + trace!(target: "snapshot", "Tried to restore chunk {:x} while inactive or failed", hash); + return Ok(()); + }, + RestorationStatus::Ongoing { .. } | RestorationStatus::Initializing { .. } => { let (res, db) = { let rest = match *restoration { Some(ref mut r) => r, @@ -583,11 +679,41 @@ impl SnapshotService for Service { self.reader.read().as_ref().and_then(|r| r.chunk(hash).ok()) } + fn completed_chunks(&self) -> Option> { + let restoration = self.restoration.lock(); + + match *restoration { + Some(ref restoration) => { + let completed_chunks = restoration.manifest.block_hashes + .iter() + .filter(|h| !restoration.block_chunks_left.contains(h)) + .chain( + restoration.manifest.state_hashes + .iter() + .filter(|h| !restoration.state_chunks_left.contains(h)) + ) + .map(|h| *h) + .collect(); + + Some(completed_chunks) + }, + None => None, + } + } + fn status(&self) -> RestorationStatus { let mut cur_status = self.status.lock(); - if let RestorationStatus::Ongoing { ref mut state_chunks_done, ref mut block_chunks_done, .. } = *cur_status { - *state_chunks_done = self.state_chunks.load(Ordering::SeqCst) as u32; - *block_chunks_done = self.block_chunks.load(Ordering::SeqCst) as u32; + + match *cur_status { + RestorationStatus::Initializing { ref mut chunks_done } => { + *chunks_done = self.state_chunks.load(Ordering::SeqCst) as u32 + + self.block_chunks.load(Ordering::SeqCst) as u32; + } + RestorationStatus::Ongoing { ref mut state_chunks_done, ref mut block_chunks_done, .. } => { + *state_chunks_done = self.state_chunks.load(Ordering::SeqCst) as u32; + *block_chunks_done = self.block_chunks.load(Ordering::SeqCst) as u32; + }, + _ => (), } cur_status.clone() @@ -600,6 +726,7 @@ impl SnapshotService for Service { } fn abort_restore(&self) { + trace!(target: "snapshot", "Aborting restore"); self.restoring_snapshot.store(false, Ordering::SeqCst); *self.restoration.lock() = None; *self.status.lock() = RestorationStatus::Inactive; diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 3e3087f2bf..3fcb0addfa 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -130,12 +130,16 @@ fn guards_delete_folders() { service.init_restore(manifest.clone(), true).unwrap(); assert!(path.exists()); + // The `db` folder should have been deleted, + // while the `temp` one kept service.abort_restore(); - assert!(!path.exists()); + assert!(!path.join("db").exists()); + assert!(path.join("temp").exists()); service.init_restore(manifest.clone(), true).unwrap(); assert!(path.exists()); drop(service); - assert!(!path.exists()); + assert!(!path.join("db").exists()); + assert!(path.join("temp").exists()); } diff --git a/ethcore/src/snapshot/traits.rs b/ethcore/src/snapshot/traits.rs index a81c14f08d..2b6ee9df9f 100644 --- a/ethcore/src/snapshot/traits.rs +++ b/ethcore/src/snapshot/traits.rs @@ -30,6 +30,9 @@ pub trait SnapshotService : Sync + Send { /// `None` indicates warp sync isn't supported by the consensus engine. fn supported_versions(&self) -> Option<(u64, u64)>; + /// Returns a list of the completed chunks + fn completed_chunks(&self) -> Option>; + /// Get raw chunk for a given hash. fn chunk(&self, hash: H256) -> Option; diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index a55c0319b3..7668a64594 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -100,14 +100,27 @@ impl SyncHandler { } /// Called by peer when it is disconnecting - pub fn on_peer_aborting(sync: &mut ChainSync, io: &mut SyncIo, peer: PeerId) { - trace!(target: "sync", "== Disconnecting {}: {}", peer, io.peer_info(peer)); - sync.handshaking_peers.remove(&peer); - if sync.peers.contains_key(&peer) { - debug!(target: "sync", "Disconnected {}", peer); - sync.clear_peer_download(peer); - sync.peers.remove(&peer); - sync.active_peers.remove(&peer); + pub fn on_peer_aborting(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + trace!(target: "sync", "== Disconnecting {}: {}", peer_id, io.peer_info(peer_id)); + sync.handshaking_peers.remove(&peer_id); + if sync.peers.contains_key(&peer_id) { + debug!(target: "sync", "Disconnected {}", peer_id); + sync.clear_peer_download(peer_id); + sync.peers.remove(&peer_id); + sync.active_peers.remove(&peer_id); + + if sync.state == SyncState::SnapshotManifest { + // Check if we are asking other peers for + // the snapshot manifest as well. + // If not, return to initial state + let still_asking_manifest = sync.peers.iter() + .filter(|&(id, p)| sync.active_peers.contains(id) && p.asking == PeerAsking::SnapshotManifest) + .next().is_none(); + + if still_asking_manifest { + sync.state = ChainSync::get_init_state(sync.warp_sync, io.chain()); + } + } sync.continue_sync(io); } } @@ -320,6 +333,10 @@ impl SyncHandler { } fn on_peer_confirmed(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { + { + let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); + peer.confirmation = ForkConfirmation::Confirmed; + } sync.sync_peer(io, peer_id, false); } @@ -344,8 +361,8 @@ impl SyncHandler { } trace!(target: "sync", "{}: Confirmed peer", peer_id); - peer.confirmation = ForkConfirmation::Confirmed; if !io.chain_overlay().read().contains_key(&fork_number) { + trace!(target: "sync", "Inserting (fork) block {} header", fork_number); io.chain_overlay().write().insert(fork_number, header.to_vec()); } } @@ -560,6 +577,10 @@ impl SyncHandler { sync.continue_sync(io); return Ok(()); }, + RestorationStatus::Initializing { .. } => { + trace!(target: "warp", "{}: Snapshot restoration is initializing", peer_id); + return Ok(()); + } RestorationStatus::Ongoing { .. } => { trace!(target: "sync", "{}: Snapshot restoration is ongoing", peer_id); }, @@ -659,11 +680,16 @@ impl SyncHandler { // Let the current sync round complete first. sync.active_peers.insert(peer_id.clone()); debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); - if let Some((fork_block, _)) = sync.fork_block { - SyncRequester::request_fork_header(sync, io, peer_id, fork_block); - } else { - SyncHandler::on_peer_confirmed(sync, io, peer_id); + + match sync.fork_block { + Some((fork_block, _)) => { + SyncRequester::request_fork_header(sync, io, peer_id, fork_block); + }, + _ => { + SyncHandler::on_peer_confirmed(sync, io, peer_id); + } } + Ok(()) } diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 381936949b..5af2892549 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -245,9 +245,12 @@ pub struct SyncStatus { impl SyncStatus { /// Indicates if snapshot download is in progress pub fn is_snapshot_syncing(&self) -> bool { - self.state == SyncState::SnapshotManifest - || self.state == SyncState::SnapshotData - || self.state == SyncState::SnapshotWaiting + match self.state { + SyncState::SnapshotManifest | + SyncState::SnapshotData | + SyncState::SnapshotWaiting => true, + _ => false, + } } /// Returns max no of peers to display in informants @@ -643,7 +646,7 @@ impl ChainSync { } } - /// Resume downloading + /// Resume downloading fn continue_sync(&mut self, io: &mut SyncIo) { // Collect active peers that can sync let confirmed_peers: Vec<(PeerId, u8)> = self.peers.iter().filter_map(|(peer_id, peer)| @@ -751,26 +754,45 @@ impl ChainSync { } } - if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { - SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); - return; + // Only ask for old blocks if the peer has a higher difficulty + if force || higher_difficulty { + if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { + SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); + return; + } + } else { + trace!(target: "sync", "peer {} is not suitable for asking old blocks", peer_id); + self.deactivate_peer(io, peer_id); } }, SyncState::SnapshotData => { - if let RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } = io.snapshot_service().status() { - if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target: "sync", "Snapshot queue full, pausing sync"); - self.state = SyncState::SnapshotWaiting; + match io.snapshot_service().status() { + RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { + // Initialize the snapshot if not already done + self.snapshot.initialize(io.snapshot_service()); + if self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize > MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target: "sync", "Snapshot queue full, pausing sync"); + self.state = SyncState::SnapshotWaiting; + return; + } + }, + RestorationStatus::Initializing { .. } => { + trace!(target: "warp", "Snapshot is stil initializing."); return; - } + }, + _ => { + return; + }, } + if peer_snapshot_hash.is_some() && peer_snapshot_hash == self.snapshot.snapshot_hash() { self.clear_peer_download(peer_id); SyncRequester::request_snapshot_data(self, io, peer_id); } }, SyncState::SnapshotManifest | //already downloading from other peer - SyncState::Waiting | SyncState::SnapshotWaiting => () + SyncState::Waiting | + SyncState::SnapshotWaiting => () } } else { trace!(target: "sync", "Skipping peer {}, force={}, td={:?}, our td={}, state={:?}", peer_id, force, peer_difficulty, syncing_difficulty, self.state); @@ -861,10 +883,7 @@ impl ChainSync { packet.append(&chain.best_block_hash); packet.append(&chain.genesis_hash); if warp_protocol { - let manifest = match self.old_blocks.is_some() { - true => None, - false => io.snapshot_service().manifest(), - }; + let manifest = io.snapshot_service().manifest(); let block_number = manifest.as_ref().map_or(0, |m| m.block_number); let manifest_hash = manifest.map_or(H256::new(), |m| keccak(m.into_rlp())); packet.append(&manifest_hash); @@ -908,29 +927,36 @@ impl ChainSync { } fn check_resume(&mut self, io: &mut SyncIo) { - if self.state == SyncState::Waiting && !io.chain().queue_info().is_full() { - self.state = SyncState::Blocks; - self.continue_sync(io); - } else if self.state == SyncState::SnapshotWaiting { - match io.snapshot_service().status() { - RestorationStatus::Inactive => { - trace!(target:"sync", "Snapshot restoration is complete"); - self.restart(io); - }, - RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { - if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { - trace!(target:"sync", "Resuming snapshot sync"); - self.state = SyncState::SnapshotData; + match self.state { + SyncState::Waiting if !io.chain().queue_info().is_full() => { + self.state = SyncState::Blocks; + self.continue_sync(io); + }, + SyncState::SnapshotWaiting => { + match io.snapshot_service().status() { + RestorationStatus::Inactive => { + trace!(target:"sync", "Snapshot restoration is complete"); + self.restart(io); + }, + RestorationStatus::Initializing { .. } => { + trace!(target:"sync", "Snapshot restoration is initializing"); + }, + RestorationStatus::Ongoing { state_chunks_done, block_chunks_done, .. } => { + if !self.snapshot.is_complete() && self.snapshot.done_chunks() - (state_chunks_done + block_chunks_done) as usize <= MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD { + trace!(target:"sync", "Resuming snapshot sync"); + self.state = SyncState::SnapshotData; + self.continue_sync(io); + } + }, + RestorationStatus::Failed => { + trace!(target: "sync", "Snapshot restoration aborted"); + self.state = SyncState::WaitingPeers; + self.snapshot.clear(); self.continue_sync(io); - } - }, - RestorationStatus::Failed => { - trace!(target: "sync", "Snapshot restoration aborted"); - self.state = SyncState::WaitingPeers; - self.snapshot.clear(); - self.continue_sync(io); - }, - } + }, + } + }, + _ => (), } } diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs index 0bfb856982..e0245fdbcd 100644 --- a/ethcore/sync/src/chain/supplier.rs +++ b/ethcore/sync/src/chain/supplier.rs @@ -120,8 +120,9 @@ impl SyncSupplier { None => return Ok(Some((BLOCK_HEADERS_PACKET, RlpStream::new_list(0)))) //no such header, return nothing } } else { - trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, r.val_at::(0)?, max_headers, skip, reverse); - r.val_at(0)? + let number = r.val_at::(0)?; + trace!(target: "sync", "{} -> GetBlockHeaders (number: {}, max: {}, skip: {}, reverse:{})", peer_id, number, max_headers, skip, reverse); + number }; let mut number = if reverse { @@ -135,7 +136,10 @@ impl SyncSupplier { let inc = (skip + 1) as BlockNumber; let overlay = io.chain_overlay().read(); - while number <= last && count < max_count { + // We are checking the `overlay` as well since it's where the ForkBlock + // header is cached : so peers can confirm we are on the right fork, + // even if we are not synced until the fork block + while (number <= last || overlay.contains_key(&number)) && count < max_count { if let Some(hdr) = overlay.get(&number) { trace!(target: "sync", "{}: Returning cached fork header", peer_id); data.extend_from_slice(hdr); @@ -152,8 +156,7 @@ impl SyncSupplier { break; } number -= inc; - } - else { + } else { number += inc; } } @@ -237,20 +240,20 @@ impl SyncSupplier { /// Respond to GetSnapshotManifest request fn return_snapshot_manifest(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let count = r.item_count().unwrap_or(0); - trace!(target: "sync", "{} -> GetSnapshotManifest", peer_id); + trace!(target: "warp", "{} -> GetSnapshotManifest", peer_id); if count != 0 { - debug!(target: "sync", "Invalid GetSnapshotManifest request, ignoring."); + debug!(target: "warp", "Invalid GetSnapshotManifest request, ignoring."); return Ok(None); } let rlp = match io.snapshot_service().manifest() { Some(manifest) => { - trace!(target: "sync", "{} <- SnapshotManifest", peer_id); + trace!(target: "warp", "{} <- SnapshotManifest", peer_id); let mut rlp = RlpStream::new_list(1); rlp.append_raw(&manifest.into_rlp(), 1); rlp }, None => { - trace!(target: "sync", "{}: No manifest to return", peer_id); + trace!(target: "warp", "{}: No snapshot manifest to return", peer_id); RlpStream::new_list(0) } }; @@ -260,15 +263,16 @@ impl SyncSupplier { /// Respond to GetSnapshotData request fn return_snapshot_data(io: &SyncIo, r: &Rlp, peer_id: PeerId) -> RlpResponseResult { let hash: H256 = r.val_at(0)?; - trace!(target: "sync", "{} -> GetSnapshotData {:?}", peer_id, hash); + trace!(target: "warp", "{} -> GetSnapshotData {:?}", peer_id, hash); let rlp = match io.snapshot_service().chunk(hash) { Some(data) => { let mut rlp = RlpStream::new_list(1); - trace!(target: "sync", "{} <- SnapshotData", peer_id); + trace!(target: "warp", "{} <- SnapshotData", peer_id); rlp.append(&data); rlp }, None => { + trace!(target: "warp", "{}: No snapshot data to return", peer_id); RlpStream::new_list(0) } }; diff --git a/ethcore/sync/src/snapshot.rs b/ethcore/sync/src/snapshot.rs index 917e84c884..b603a2a007 100644 --- a/ethcore/sync/src/snapshot.rs +++ b/ethcore/sync/src/snapshot.rs @@ -14,10 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use hash::keccak; +use ethcore::snapshot::{ManifestData, SnapshotService}; use ethereum_types::H256; +use hash::keccak; +use rand::{thread_rng, Rng}; + use std::collections::HashSet; -use ethcore::snapshot::ManifestData; +use std::iter::FromIterator; #[derive(PartialEq, Eq, Debug)] pub enum ChunkType { @@ -32,6 +35,7 @@ pub struct Snapshot { completed_chunks: HashSet, snapshot_hash: Option, bad_hashes: HashSet, + initialized: bool, } impl Snapshot { @@ -44,7 +48,27 @@ impl Snapshot { completed_chunks: HashSet::new(), snapshot_hash: None, bad_hashes: HashSet::new(), + initialized: false, + } + } + + /// Sync the Snapshot completed chunks with the Snapshot Service + pub fn initialize(&mut self, snapshot_service: &SnapshotService) { + if self.initialized { + return; + } + + if let Some(completed_chunks) = snapshot_service.completed_chunks() { + self.completed_chunks = HashSet::from_iter(completed_chunks); } + + trace!( + target: "snapshot", + "Snapshot is now initialized with {} completed chunks.", + self.completed_chunks.len(), + ); + + self.initialized = true; } /// Clear everything. @@ -54,6 +78,7 @@ impl Snapshot { self.downloading_chunks.clear(); self.completed_chunks.clear(); self.snapshot_hash = None; + self.initialized = false; } /// Check if currently downloading a snapshot. @@ -89,18 +114,35 @@ impl Snapshot { Err(()) } - /// Find a chunk to download + /// Find a random chunk to download pub fn needed_chunk(&mut self) -> Option { - // check state chunks first - let chunk = self.pending_state_chunks.iter() - .chain(self.pending_block_chunks.iter()) - .find(|&h| !self.downloading_chunks.contains(h) && !self.completed_chunks.contains(h)) - .cloned(); + // Find all random chunks: first blocks, then state + let needed_chunks = { + let chunk_filter = |h| !self.downloading_chunks.contains(h) && !self.completed_chunks.contains(h); + + let needed_block_chunks = self.pending_block_chunks.iter() + .filter(|&h| chunk_filter(h)) + .map(|h| *h) + .collect::>(); + + // If no block chunks to download, get the state chunks + if needed_block_chunks.len() == 0 { + self.pending_state_chunks.iter() + .filter(|&h| chunk_filter(h)) + .map(|h| *h) + .collect::>() + } else { + needed_block_chunks + } + }; + + // Get a random chunk + let chunk = thread_rng().choose(&needed_chunks); if let Some(hash) = chunk { self.downloading_chunks.insert(hash.clone()); } - chunk + chunk.map(|h| *h) } pub fn clear_chunk_download(&mut self, hash: &H256) { @@ -185,8 +227,15 @@ mod test { let requested: Vec = (0..40).map(|_| snapshot.needed_chunk().unwrap()).collect(); assert!(snapshot.needed_chunk().is_none()); - assert_eq!(&requested[0..20], &manifest.state_hashes[..]); - assert_eq!(&requested[20..40], &manifest.block_hashes[..]); + + let requested_all_block_chunks = manifest.block_hashes.iter() + .all(|h| requested.iter().any(|rh| rh == h)); + assert!(requested_all_block_chunks); + + let requested_all_state_chunks = manifest.state_hashes.iter() + .all(|h| requested.iter().any(|rh| rh == h)); + assert!(requested_all_state_chunks); + assert_eq!(snapshot.downloading_chunks.len(), 40); assert_eq!(snapshot.validate_chunk(&state_chunks[4]), Ok(ChunkType::State(manifest.state_hashes[4].clone()))); diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index 804ebe9c53..864f3d4dc6 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -80,6 +80,10 @@ impl SnapshotService for TestSnapshotService { Some((1, 2)) } + fn completed_chunks(&self) -> Option> { + Some(vec![]) + } + fn chunk(&self, hash: H256) -> Option { self.chunks.get(&hash).cloned() } diff --git a/ethcore/types/src/restoration_status.rs b/ethcore/types/src/restoration_status.rs index 0cc7fccc08..51f5b8aa0a 100644 --- a/ethcore/types/src/restoration_status.rs +++ b/ethcore/types/src/restoration_status.rs @@ -21,6 +21,11 @@ pub enum RestorationStatus { /// No restoration. Inactive, + /// Restoration is initalizing + Initializing { + /// Number of chunks done/imported + chunks_done: u32, + }, /// Ongoing restoration. Ongoing { /// Total number of state chunks. diff --git a/parity/informant.rs b/parity/informant.rs index beeb258b52..a4d2727c35 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -278,15 +278,12 @@ impl Informant { } = full_report; let rpc_stats = self.rpc_stats.as_ref(); - - let (snapshot_sync, snapshot_current, snapshot_total) = self.snapshot.as_ref().map_or((false, 0, 0), |s| + let snapshot_sync = sync_info.as_ref().map_or(false, |s| s.snapshot_sync) && self.snapshot.as_ref().map_or(false, |s| match s.status() { - RestorationStatus::Ongoing { state_chunks, block_chunks, state_chunks_done, block_chunks_done } => - (true, state_chunks_done + block_chunks_done, state_chunks + block_chunks), - _ => (false, 0, 0), + RestorationStatus::Ongoing { .. } | RestorationStatus::Initializing { .. } => true, + _ => false, } ); - let snapshot_sync = snapshot_sync && sync_info.as_ref().map_or(false, |s| s.snapshot_sync); if !importing && !snapshot_sync && elapsed < Duration::from_secs(30) { return; } @@ -318,7 +315,19 @@ impl Informant { paint(Green.bold(), format!("{:5}", queue_info.unverified_queue_size)), paint(Green.bold(), format!("{:5}", queue_info.verified_queue_size)) ), - true => format!("Syncing snapshot {}/{}", snapshot_current, snapshot_total), + true => { + self.snapshot.as_ref().map_or(String::new(), |s| + match s.status() { + RestorationStatus::Ongoing { state_chunks, block_chunks, state_chunks_done, block_chunks_done } => { + format!("Syncing snapshot {}/{}", state_chunks_done + block_chunks_done, state_chunks + block_chunks) + }, + RestorationStatus::Initializing { chunks_done } => { + format!("Snapshot initializing ({} chunks restored)", chunks_done) + }, + _ => String::new(), + } + ) + }, }, false => String::new(), }, diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 423864679a..3c0dadedaa 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -122,6 +122,7 @@ fn restore_using(snapshot: Arc, reader: &R, match snapshot.status() { RestorationStatus::Ongoing { .. } => Err("Snapshot file is incomplete and missing chunks.".into()), + RestorationStatus::Initializing { .. } => Err("Snapshot restoration is still initializing.".into()), RestorationStatus::Failed => Err("Snapshot restoration failed.".into()), RestorationStatus::Inactive => { info!("Restoration complete."); diff --git a/rpc/src/v1/tests/helpers/snapshot_service.rs b/rpc/src/v1/tests/helpers/snapshot_service.rs index 25abab578e..099773ab52 100644 --- a/rpc/src/v1/tests/helpers/snapshot_service.rs +++ b/rpc/src/v1/tests/helpers/snapshot_service.rs @@ -43,6 +43,7 @@ impl TestSnapshotService { impl SnapshotService for TestSnapshotService { fn manifest(&self) -> Option { None } fn supported_versions(&self) -> Option<(u64, u64)> { None } + fn completed_chunks(&self) -> Option> { Some(vec![]) } fn chunk(&self, _hash: H256) -> Option { None } fn status(&self) -> RestorationStatus { self.status.lock().clone() } fn begin_restore(&self, _manifest: ManifestData) { } -- GitLab From d1934363e7c2c953f17cd451bea8476f46f52b82 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Thu, 17 May 2018 10:58:35 +0200 Subject: [PATCH 168/263] Fix not downloading old blocks (#8642) --- ethcore/src/client/client.rs | 62 +++++++++++++++++++++++------------- ethcore/sync/src/blocks.rs | 2 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 993ecdda21..5cfe8fce82 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -17,7 +17,7 @@ use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; use std::fmt; use std::str::FromStr; -use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; +use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Arc, Weak}; use std::time::{Instant, Duration}; @@ -210,6 +210,8 @@ pub struct Client { queue_transactions: IoChannelQueue, /// Ancient blocks import queue queue_ancient_blocks: IoChannelQueue, + /// Hashes of pending ancient block wainting to be included + pending_ancient_blocks: RwLock>, /// Consensus messages import queue queue_consensus_message: IoChannelQueue, @@ -433,6 +435,7 @@ impl Importer { let hash = header.hash(); let _import_lock = self.import_lock.lock(); + trace!(target: "client", "Trying to import old block #{}", header.number()); { trace_time!("import_old_block"); // verify the block, passing the chain for updating the epoch verifier. @@ -761,6 +764,7 @@ impl Client { notify: RwLock::new(Vec::new()), queue_transactions: IoChannelQueue::new(MAX_TX_QUEUE_SIZE), queue_ancient_blocks: IoChannelQueue::new(MAX_ANCIENT_BLOCKS_QUEUE_SIZE), + pending_ancient_blocks: RwLock::new(HashSet::new()), queue_consensus_message: IoChannelQueue::new(usize::max_value()), last_hashes: RwLock::new(VecDeque::new()), factories: factories, @@ -2008,7 +2012,7 @@ impl BlockChainClient for Client { impl IoClient for Client { fn queue_transactions(&self, transactions: Vec, peer_id: usize) { let len = transactions.len(); - self.queue_transactions.queue(&mut self.io_channel.lock(), len, move |client| { + self.queue_transactions.queue(&mut self.io_channel.lock(), move |client| { trace_time!("import_queued_transactions"); let txs: Vec = transactions @@ -2032,23 +2036,32 @@ impl IoClient for Client { { // check block order - if self.chain.read().is_known(&header.hash()) { + if self.chain.read().is_known(&hash) { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } - let status = self.block_status(BlockId::Hash(*header.parent_hash())); - if status == BlockStatus::Unknown || status == BlockStatus::Pending { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash()))); + + let parent_hash = *header.parent_hash(); + let parent_pending = self.pending_ancient_blocks.read().contains(&parent_hash); + let status = self.block_status(BlockId::Hash(parent_hash)); + if !parent_pending && (status == BlockStatus::Unknown || status == BlockStatus::Pending) { + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(parent_hash))); } } - match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), 1, move |client| { - client.importer.import_old_block( + self.pending_ancient_blocks.write().insert(hash); + + trace!(target: "client", "Queuing old block #{}", header.number()); + match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), move |client| { + let result = client.importer.import_old_block( &header, &block_bytes, &receipts_bytes, &**client.db.read(), &*client.chain.read() - ).map(|_| ()).unwrap_or_else(|e| { + ); + + client.pending_ancient_blocks.write().remove(&hash); + result.map(|_| ()).unwrap_or_else(|e| { error!(target: "client", "Error importing ancient block: {}", e); }); }) { @@ -2058,7 +2071,7 @@ impl IoClient for Client { } fn queue_consensus_message(&self, message: Bytes) { - match self.queue_consensus_message.queue(&mut self.io_channel.lock(), 1, move |client| { + match self.queue_consensus_message.queue(&mut self.io_channel.lock(), move |client| { if let Err(e) = client.engine().handle_message(&message) { debug!(target: "poa", "Invalid message received: {}", e); } @@ -2471,35 +2484,38 @@ impl fmt::Display for QueueError { /// Queue some items to be processed by IO client. struct IoChannelQueue { - currently_queued: Arc, + queue: Arc>>>, limit: usize, } impl IoChannelQueue { pub fn new(limit: usize) -> Self { IoChannelQueue { - currently_queued: Default::default(), + queue: Default::default(), limit, } } - pub fn queue(&self, channel: &mut IoChannel, count: usize, fun: F) -> Result<(), QueueError> where - F: Fn(&Client) + Send + Sync + 'static, + pub fn queue(&self, channel: &mut IoChannel, fun: F) -> Result<(), QueueError> + where F: Fn(&Client) + Send + Sync + 'static { - let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed); - ensure!(queue_size < self.limit, QueueError::Full(self.limit)); + { + let mut queue = self.queue.lock(); + let queue_size = queue.len(); + ensure!(queue_size < self.limit, QueueError::Full(self.limit)); - let currently_queued = self.currently_queued.clone(); + queue.push_back(Box::new(fun)); + } + + let queue = self.queue.clone(); let result = channel.send(ClientIoMessage::execute(move |client| { - currently_queued.fetch_sub(count, AtomicOrdering::SeqCst); - fun(client); + while let Some(fun) = queue.lock().pop_front() { + fun(client); + } })); match result { - Ok(_) => { - self.currently_queued.fetch_add(count, AtomicOrdering::SeqCst); - Ok(()) - }, + Ok(_) => Ok(()), Err(e) => Err(QueueError::Channel(e)), } } diff --git a/ethcore/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs index 321c783b4d..283f4ed610 100644 --- a/ethcore/sync/src/blocks.rs +++ b/ethcore/sync/src/blocks.rs @@ -266,7 +266,7 @@ impl BlockCollection { } } - /// Get a valid chain of blocks ordered in descending order and ready for importing into blockchain. + /// Get a valid chain of blocks ordered in ascending order and ready for importing into blockchain. pub fn drain(&mut self) -> Vec { if self.blocks.is_empty() || self.head.is_none() { return Vec::new(); -- GitLab From 6552256981589a3a80a1c6c253fb8418f9ded0e8 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 18 May 2018 08:04:25 +0200 Subject: [PATCH 169/263] Remove HostInfo::next_nonce (#8644) --- util/network-devp2p/src/host.rs | 12 +++++++----- util/network/src/lib.rs | 2 -- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 4cca2e6e5a..f3446845fb 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -210,6 +210,13 @@ pub struct HostInfo { pub public_endpoint: Option, } +impl HostInfo { + fn next_nonce(&mut self) -> H256 { + self.nonce = keccak(&self.nonce); + self.nonce + } +} + impl HostInfoTrait for HostInfo { fn id(&self) -> &NodeId { self.keys.public() @@ -219,11 +226,6 @@ impl HostInfoTrait for HostInfo { self.keys.secret() } - fn next_nonce(&mut self) -> H256 { - self.nonce = keccak(&self.nonce); - self.nonce - } - fn client_version(&self) -> &str { &self.config.client_version } diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 1327a9ad59..0137543fdd 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -332,8 +332,6 @@ pub trait HostInfo { fn id(&self) -> &NodeId; /// Returns secret key fn secret(&self) -> &Secret; - /// Increments and returns connection nonce. - fn next_nonce(&mut self) -> H256; /// Returns the client version. fn client_version(&self) -> &str; } -- GitLab From 9e719f088f37ec9af7a24403cbd7e8cbfd9a134e Mon Sep 17 00:00:00 2001 From: David Date: Sun, 20 May 2018 06:27:59 +0200 Subject: [PATCH 170/263] Remove the Keccak C library and use the pure Rust impl (#8657) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add license and readme * Use pure rust implementation * Bump version to 0.1.1 * Don't use C, prefer the pure Rust implementation * Add test for `write_keccak` * Bump version * Add benchmarks * Add benchmarks * Add keccak_256, keccak_512, keccak_256_unchecked and keccak_512_unchecked – mostly for compatibility with ethash * Remove failed git merge attempt from external git repo Cargo.lock updates * whitespace * Mark unsafe function unsafe * Unsafe calls in unsafe block * Document unsafety invariants * Revert unintended changes to Cargo.lock --- Cargo.lock | 53 +++++----- ethash/src/keccak.rs | 20 ++-- util/hash/Cargo.toml | 11 +- util/hash/benches/keccak_256.rs | 36 +++++++ util/hash/build.rs | 26 ----- util/hash/src/lib.rs | 55 +++++++--- util/hash/src/tinykeccak.c | 177 -------------------------------- 7 files changed, 119 insertions(+), 259 deletions(-) create mode 100644 util/hash/benches/keccak_256.rs delete mode 100644 util/hash/build.rs delete mode 100644 util/hash/src/tinykeccak.c diff --git a/Cargo.lock b/Cargo.lock index b4d6bd315f..e4c80310c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", "rlp_derive 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -487,7 +487,7 @@ version = "1.12.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -541,7 +541,7 @@ dependencies = [ "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "kvdb-rocksdb 0.1.0", @@ -633,7 +633,7 @@ dependencies = [ "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -685,7 +685,7 @@ dependencies = [ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", @@ -730,7 +730,7 @@ dependencies = [ "ethkey 0.3.0", "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -769,7 +769,7 @@ dependencies = [ "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", @@ -803,7 +803,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -851,7 +851,7 @@ dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -875,7 +875,7 @@ dependencies = [ "ethkey 0.3.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -900,7 +900,7 @@ dependencies = [ "ethkey 0.3.0", "evm 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unexpected 0.1.0", @@ -1021,7 +1021,7 @@ dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memory-cache 0.1.0", @@ -1345,7 +1345,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1454,9 +1454,8 @@ dependencies = [ [[package]] name = "keccak-hash" -version = "0.1.0" +version = "0.1.2" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1648,7 +1647,7 @@ dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "plain_hasher 0.1.0", "rlp 0.2.1", ] @@ -1987,7 +1986,7 @@ dependencies = [ "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb 0.1.0", "kvdb-rocksdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2051,7 +2050,7 @@ dependencies = [ "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2115,7 +2114,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2208,7 +2207,7 @@ dependencies = [ "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "macros 0.1.0", @@ -2244,7 +2243,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.12.0", @@ -2332,7 +2331,7 @@ dependencies = [ "ethcore-bytes 0.1.0", "ethcore-sync 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2440,7 +2439,7 @@ dependencies = [ "ethcore-logger 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memorydb 0.1.1", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2736,7 +2735,7 @@ dependencies = [ "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", ] [[package]] @@ -3472,7 +3471,7 @@ version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", ] @@ -3482,7 +3481,7 @@ version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "rlp 0.2.1", "trie-standardmap 0.1.0", ] @@ -3630,7 +3629,7 @@ dependencies = [ "ethcore-bytes 0.1.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", - "keccak-hash 0.1.0", + "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", "rlp 0.2.1", diff --git a/ethash/src/keccak.rs b/ethash/src/keccak.rs index 8ca4f54384..36fb173547 100644 --- a/ethash/src/keccak.rs +++ b/ethash/src/keccak.rs @@ -21,32 +21,36 @@ pub type H256 = [u8; 32]; pub mod keccak_512 { use super::hash; - pub use self::hash::keccak_512 as unchecked; + pub use self::hash::keccak_512_unchecked as unchecked; pub fn write(input: &[u8], output: &mut [u8]) { - unsafe { hash::keccak_512(output.as_mut_ptr(), output.len(), input.as_ptr(), input.len()) }; + hash::keccak_512(input, output); } pub fn inplace(input: &mut [u8]) { - // This is safe since `sha3_*` uses an internal buffer and copies the result to the output. This + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This // means that we can reuse the input buffer for both input and output. - unsafe { hash::keccak_512(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()) }; + unsafe { + hash::keccak_512_unchecked(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()); + } } } pub mod keccak_256 { use super::hash; - pub use self::hash::keccak_256 as unchecked; + pub use self::hash::keccak_256_unchecked as unchecked; #[allow(dead_code)] pub fn write(input: &[u8], output: &mut [u8]) { - unsafe { hash::keccak_256(output.as_mut_ptr(), output.len(), input.as_ptr(), input.len()) }; + hash::keccak_256(input, output); } pub fn inplace(input: &mut [u8]) { - // This is safe since `sha3_*` uses an internal buffer and copies the result to the output. This + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This // means that we can reuse the input buffer for both input and output. - unsafe { hash::keccak_256(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()) }; + unsafe { + hash::keccak_256_unchecked(input.as_mut_ptr(), input.len(), input.as_ptr(), input.len()); + } } } diff --git a/util/hash/Cargo.toml b/util/hash/Cargo.toml index da91cd733c..e136ada305 100644 --- a/util/hash/Cargo.toml +++ b/util/hash/Cargo.toml @@ -1,18 +1,15 @@ [package] description = "Rust bindings for tinykeccak C library" -homepage = "http://parity.io" +homepage = "https://github.com/paritytech/keccak-hash" +readme = "README.md" license = "GPL-3.0" name = "keccak-hash" -version = "0.1.0" +version = "0.1.2" authors = ["Parity Technologies "] -build = "build.rs" [dependencies] ethereum-types = "0.3" -tiny-keccak = "1.3" - -[build-dependencies] -cc = "1.0" +tiny-keccak = "1.4.1" [dev-dependencies] tempdir = "0.3" diff --git a/util/hash/benches/keccak_256.rs b/util/hash/benches/keccak_256.rs new file mode 100644 index 0000000000..8b398417d8 --- /dev/null +++ b/util/hash/benches/keccak_256.rs @@ -0,0 +1,36 @@ +#![feature(test)] + +extern crate test; +extern crate ethereum_types; +extern crate keccak_hash; + +use keccak_hash::{keccak, write_keccak}; +use test::Bencher; + +#[bench] +fn bench_keccak_256_with_empty_input(b: &mut Bencher) { + let empty = [0u8;0]; + b.bytes = empty.len() as u64; + b.iter(|| { + let _out = keccak(empty); + }) +} + +#[bench] +fn bench_keccak_256_with_typical_input(b: &mut Bencher) { + let data: Vec = From::from("some medum length string with important information"); + b.bytes = data.len() as u64; + b.iter(|| { + let _out = keccak(&data); + }) +} + +#[bench] +fn bench_keccak_256_with_large_input(b: &mut Bencher) { + // 4096 chars + let data: Vec = From::from("IGxcKBr1Qp7tuqtpSVhAbvt7UgWLEi7mCA6Wa185seLSIJLFS8K1aAFO9AwtO9b3n9SM3Qg136JMmy9Mj9gZ84IaUm8XioPtloabFDU5ZR1wvauJT6jNTkvBVBpUigIsyU7C1u3s99vKP64LpXqvo1hwItZKtISxmUAgzzjv5q14V4G9bkKAnmc4M5xixgLsDGZmnj6HcOMY3XRkWtxN3RscSKwPA0bfpgtz27ZVHplbXwloYRgRLpjRhZJc7sqO8RFnTHKasVkxVRcUoDBvWNJK27TbLvQQcfxETI2Q1H6c2cBAchi8unSiuxqy5rIvVxcl9rsmmRY4IXLEG9qKntUGbiIRLjEffIP9ODoWog0GbWLmMtfvtf24hWVwXz6Ap5oUAR0kLgb7HYIYrOwKjvfV25iEF7GW8cjhl8yowXx1zcgW4t6NJNqJlGzRKx8MvRWQXvHz8h8JxcHl7S64i6PAkxI9eCLXLvs8cpbEQQHt05Zu6GKm6IInjc9mSh52WFuGhgjbno69XzfkBufJs6c9tZuBf6ErVPj4UxmT82ajCruDusk79Tlvb8oQMLjoplQc1alQaLQwSsMac9iVp9MiE3PeYnTTepJ1V10tp79fciDAnNPJgPcRfDYv0REcSFgR9Q7yWhbpPpyBjO7HwOykDQVGtV0ZbDFrFRygLAXagAIkOPc9HDfcBNID1Q2MGk8ijVWMyvmGz1wzbpNfFcQaSOm8olhwoLyHUGvkyXegh44iNsPBUvSicNxTTDowtMqO5azleuWEjzxCobYbASDopvl6JeJjRtEBBO5YCQJiHsYjlXh9QR5Q543GsqhzRLgcHNRSZYLMZqDmIABXZi8VRNJMZyWXDRKHOGDmcHWe55uZomW6FnyU0uSRKxxz66K0JWfxuFzzxAR0vR4ZZCTemgDRQuDwL1loC3KUMjDpU13jUgoPc4UJUVfwQ4f4BUY3X51Cfw9FLw4oX39KoFoiCP2Z6z27gZUY1IlE59WoXGLj4KjTp4C16ZihG080gfDIWlXnDEk3VwBuBFyKWARB63sGLrGnn27b1gHWMaop6sPvkQgWxkEKIqsxDIvXLZJg2s23V8Gqtt0FeA7R3RCvBysF4jNjQ7NiQTIQWQZ8G9gO4mEsftolSZv6FlSpNeBKIIwYWSO2R6vkgeiz06euE9bwwnenOjwPNGTGk8WHIOZBJ1hIP0ejVU2i2ca9ON0phSAnewqjo5W3PtZf2Q7mDvp9imuVWoy4t8XcZq8I2Un9jVjes9Xi0FLN2t71vLFWLWZmGDzwXxpqEgkARS1WjtJoYXCBmRnXEPj6jQfwMZWKPYSIrmOogxMVoWvA8wrof6utfJna9JezyTnrBJSCuGTSNmwwAXRLoFYxF1RITyN8mI2KmHSfvLXBrbE6kmAkjsm4XJb6kria7oUQQ1gzJuCyB7oNHjZTBFNhNa7VeQ1s1xLOwZXLOAjZ4MDTYKnF7giGJGyswb5KQxkOV9orbuAu6pJsjtql6h1UD3BcNUkG3oz8kJNepbuCN3vNCJcZOX1VrQi0PWkDwyvECrQ2E1CgbU6GpWatpg2sCTpo9W62pCcWBK2FKUFWqU3qo2T7T1Mk2ZtM6hE9I8op0M7xlGE91Mn7ea6aq93MWp7nvFlBvbaMIoeU4MpDx0BeOSkROY03ZBJ0x7K8nJrNUhAtvxp17c9oFk0VxLiuRbAAcwDUormOmpVXZNIcqnap4twEVYaSIowfcNojyUSrFL5nPc8ZG93WgNNl9rpUPZhssVml3DvXghI80A9SW3QauzohTQAX2bkWelFBHnuG2LKrsJ8en51N6CkjcS5b87y1DVMZELcZ1n5s8PCAA1wyn7OSZlgw00GRzch1YwMoHzBBgIUtMO9HrMyuhgqIPJP7KcKbQkKhtvBXKplX8SCfSlOwUkLwHNKm3HYVE0uVfJ91NAsUrGoCOjYiXYpoRT8bjAPWTm6fDlTq2sbPOyTMoc4xRasmiOJ7B0PT6UxPzCPImM4100sPFxp7Kofv4okKZWTPKTefeYiPefI3jRgfDtEIP9E6a35LZD75lBNMXYlAqL3qlnheUQD1WQimFTHiDsW6bmURptNvtkMjEXzXzpWbnyxBskUGTvP2YQjtSAhWliDXkv6t1x71cYav7TQbqvbIzMRQQsguSGYMbs8YIC4DC9ep5reWAfanlTxcxksbEhQ7FGzXOvcufeGnDl2C85gWfryVzwN7kOZiSEktFMOQ1ngRC23y1fCOiHQVQJ2nLnaW7GILb9wkN1mBTRuHsOefRJST0TnRxcn4bBq4MIibIitVyjPRy7G5XvPEcL4pFaW1HCPGm6pUOEEwTer32JObNGCyTFB1BI2cRLJu5BHPjgG3mmb0gGkGlIfh8D2b2amogpivqEn2r9Y1KOKQ8ufJvG2mYfkevco9DuEZ9Nmzkm6XkCTZaFMNHqbfQaKqsEYK7i2N1KfkBct1leW2H9MQ9QO7AHCqXHK47b1kWVIm6pSJA1yV4funzCqXnIJCEURQgHiKf38YpN7ylLhe1J4UvSG3KeesZNeFFIZOEP9HZUSFMpnN1MOrwejojK0D4qzwucYWtXrTQ8I7UP5QhlijIsCKckUa9C1Osjrq8cgSclYNGt19wpy0onUbX1rOQBUlAAUJs4CyXNU0wmVUjw7tG1LUC8my4s9KZDUj4R5UcPz3VaZRrx1RqYu6YxjroJW70I1LyG4WEiQbOkCoLmaiWo9WzbUS2cErlOo2RPymlkWHxbNnZawX2Bc872ivRHSWqNpRHyuR5QewXmcyghH3EhESBAxTel5E2xuQXfLCEVK0kEk0Mj22KPsckKKyH7sVYC1F4YItQh5hj9Titb7KflQb9vnXQ44UHxY3zBhTQT5PSYv1Kv8HxXCsnpmhZCiBru16iX9oEB33icBVB2KKcZZEEKnCGPVxJlM9RTlyNyQmjHf7z4GeTDuMAUrsMO31WvgZBnWcAOtn6ulBTUCAaqxJiWqzlMx2FSANAlyAjAxqzmQjzPLvQRjskUnBFN3woKB1m2bSo2c5thwA1fKiPvN5LW8tl1rnfNy3rJ0GJpK8nZjkzHMztYrKYAe56pX4SvplpTyibTIiRXLyEVsmuByTHCZhO3fvGoFsav3ZuRhe9eAAWeqAh13eKDTcA0ufME3ZnmJheXEZ3OwrxnFjSf3U0clkWYVont3neh77ODKHhYnX0bOmnJJlr4RqFoLBitskY0kcGMKcZlaej21SENjDcFgaka3CfHbAH5vIFqnoX1JZrZPkQ65PZqQWImP79U3gXWKvz96lElyJZAFqn0Mbltllqw4MhlI766AvHraOmMsJoNvjv1QR7pCSnC0iX6nbqW1eVPaUSZDuZRtRIxfLA8HC9VbxufT2KZV3qG0l7wrZna5Di2MNcBE9uthuVLZcqp8vCmEhINDhRRlipR7tC2iRBHecS5WtxBCpbEm1y1kgNG5o60UKgAswxxuJ3RQ9Y49mPIApBMmp4LFpuKRfcrZb4UJnCfR3pNbQ70nnZ6Be2M7tuJUCoFfHrhqHXNz5A0uWMgxUS50c60zLl6QAELxHaCGba4WCMOHIo5nSKcUuYtDyDoDlrezALW5mZR4PRPRxnjrXxbJI14qrpymRReC3QgFDJp6sT5TLwvSHaavPlEbt2Eu0Kh5SXklGHXP9YuF3glGuJzSob3NakW1RXF5786U1MHhtJby64LyGWvNn4QXie3VjeL3QQu4C9crEAxSSiOJOfnL3DYIVOY4ipUkKFlF7Rp2q6gZazDvcUCp1cbcr7T7B4s22rXzjN7mHYWOyWuZGwlImeorY3aVKi7BaXbhgOFw6BUmIc1HeGFELHIEnPE9MwOjZam3LOm0rhBHlvJJZkXvJKmDUJrGlyqC5GtC5lDWLfXewyDWDqq7PY0atVQily5GWqib6wub6u6LZ3HZDNP8gK64Nf4kC259AE4V2hCohDnSsXAIoOkehwXyp6CkDT42NJb6sXHUv2N6cm292MiKA22PKWrwUGsan599KI2V67YRDfcfiB4ZHRDiSe62MBE0fGLIgXLIWw1xTWYbPQ9YAj3xovBvmewbJ1De4k6uS"); + b.bytes = data.len() as u64; + b.iter(|| { + let _out = keccak(&data); + }) +} \ No newline at end of file diff --git a/util/hash/build.rs b/util/hash/build.rs deleted file mode 100644 index eecb804f90..0000000000 --- a/util/hash/build.rs +++ /dev/null @@ -1,26 +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 . - - // build.rs - -// Bring in a dependency on an externally maintained `cc` package which manages -// invoking the C compiler. -extern crate cc; - -fn main() { - cc::Build::new().file("src/tinykeccak.c").compile("libtinykeccak.a"); -} - diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs index 526d22aeda..b75e095a68 100644 --- a/util/hash/src/lib.rs +++ b/util/hash/src/lib.rs @@ -18,7 +18,9 @@ extern crate ethereum_types; extern crate tiny_keccak; use std::io; +use std::slice; use tiny_keccak::Keccak; + pub use ethereum_types::H256; /// Get the KECCAK (i.e. Keccak) hash of the empty bytes string. @@ -30,12 +32,6 @@ pub const KECCAK_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x5 /// The KECCAK of the RLP encoding of empty list. pub const KECCAK_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47] ); -extern { - /// Hashes input. Returns -1 if either out or input does not exist. Otherwise returns 0. - pub fn keccak_256(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32; - /// Hashes input. Returns -1 if either out or input does not exist. Otherwise returns 0. - pub fn keccak_512(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32; -} pub fn keccak>(s: T) -> H256 { let mut result = [0u8; 32]; @@ -43,15 +39,30 @@ pub fn keccak>(s: T) -> H256 { H256(result) } -pub fn write_keccak>(s: T, dest: &mut [u8]) { - let input = s.as_ref(); - unsafe { - // we can safely ignore keccak_256 output, cause we know that both input - // and dest are properly allocated - keccak_256(dest.as_mut_ptr(), dest.len(), input.as_ptr(), input.len()); - } +pub unsafe fn keccak_256_unchecked(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) { + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This + // means that we can reuse the input buffer for both input and output. + Keccak::keccak256( + slice::from_raw_parts(input, inputlen), + slice::from_raw_parts_mut(out, outlen) + ); } +pub unsafe fn keccak_512_unchecked(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) { + // This is safe since `keccak_*` uses an internal buffer and copies the result to the output. This + // means that we can reuse the input buffer for both input and output. + Keccak::keccak512( + slice::from_raw_parts(input, inputlen), + slice::from_raw_parts_mut(out, outlen) + ); +} + +pub fn keccak_256(input: &[u8], mut output: &mut [u8]) { Keccak::keccak256(input, &mut output); } + +pub fn keccak_512(input: &[u8], mut output: &mut [u8]) { Keccak::keccak512(input, &mut output); } + +pub fn write_keccak>(s: T, dest: &mut [u8]) { Keccak::keccak256(s.as_ref(), dest); } + pub fn keccak_pipe(r: &mut io::BufRead, w: &mut io::Write) -> Result { let mut output = [0u8; 32]; let mut input = [0u8; 1024]; @@ -82,17 +93,33 @@ mod tests { use std::fs; use std::io::{Write, BufReader}; use self::tempdir::TempDir; - use super::{keccak, keccak_buffer, KECCAK_EMPTY}; + use super::{keccak, write_keccak, keccak_buffer, KECCAK_EMPTY}; #[test] fn keccak_empty() { assert_eq!(keccak([0u8; 0]), KECCAK_EMPTY); } + #[test] fn keccak_as() { assert_eq!(keccak([0x41u8; 32]), From::from("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8")); } + #[test] + fn write_keccak_with_content() { + let data: Vec = From::from("hello world"); + let expected = vec![ + 0x47, 0x17, 0x32, 0x85, 0xa8, 0xd7, 0x34, 0x1e, + 0x5e, 0x97, 0x2f, 0xc6, 0x77, 0x28, 0x63, 0x84, + 0xf8, 0x02, 0xf8, 0xef, 0x42, 0xa5, 0xec, 0x5f, + 0x03, 0xbb, 0xfa, 0x25, 0x4c, 0xb0, 0x1f, 0xad + ]; + let mut dest = [0u8;32]; + write_keccak(data, &mut dest); + + assert_eq!(dest, expected.as_ref()); + } + #[test] fn should_keccak_a_file() { // given diff --git a/util/hash/src/tinykeccak.c b/util/hash/src/tinykeccak.c deleted file mode 100644 index bfe172e5f6..0000000000 --- a/util/hash/src/tinykeccak.c +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include - -/** libkeccak-tiny - * - * A single-file implementation of SHA-3 and SHAKE. - * - * Implementor: David Leon Gil - * License: CC0, attribution kindly requested. Blame taken too, - * but not liability. - */ - -#define decshake(bits) \ - int shake##bits(uint8_t*, size_t, const uint8_t*, size_t); - -#define deckeccak(bits) \ - int keccak_##bits(uint8_t*, size_t, const uint8_t*, size_t); - -decshake(128) -decshake(256) -deckeccak(224) -deckeccak(256) -deckeccak(384) -deckeccak(512) - -/******** The Keccak-f[1600] permutation ********/ - -/*** Constants. ***/ -static const uint8_t rho[24] = \ - { 1, 3, 6, 10, 15, 21, - 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, - 62, 18, 39, 61, 20, 44}; -static const uint8_t pi[24] = \ - {10, 7, 11, 17, 18, 3, - 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, - 20, 14, 22, 9, 6, 1}; -static const uint64_t RC[24] = \ - {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, - 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, - 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, - 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, - 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, - 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; - -/*** Helper macros to unroll the permutation. ***/ -#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) -#define REPEAT6(e) e e e e e e -#define REPEAT24(e) REPEAT6(e e e e) -#define REPEAT5(e) e e e e e -#define FOR5(v, s, e) \ - v = 0; \ - REPEAT5(e; v += s;) - -/*** Keccak-f[1600] ***/ -static inline void keccakf(void* state) { - uint64_t* a = (uint64_t*)state; - uint64_t b[5] = {0}; - uint64_t t = 0; - uint8_t x, y; - int i; - - for (i = 0; i < 24; i++) { - // Theta - FOR5(x, 1, - b[x] = 0; - FOR5(y, 5, - b[x] ^= a[x + y]; )) - FOR5(x, 1, - FOR5(y, 5, - a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) - // Rho and pi - t = a[1]; - x = 0; - REPEAT24(b[0] = a[pi[x]]; - a[pi[x]] = rol(t, rho[x]); - t = b[0]; - x++; ) - // Chi - FOR5(y, - 5, - FOR5(x, 1, - b[x] = a[y + x];) - FOR5(x, 1, - a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) - // Iota - a[0] ^= RC[i]; - } -} - -/******** The FIPS202-defined functions. ********/ - -/*** Some helper macros. ***/ - -#define _(S) do { S } while (0) -#define FOR(i, ST, L, S) \ - _({size_t i; for (i = 0; i < L; i += ST) { S; }}) -#define mkapply_ds(NAME, S) \ - static inline void NAME(uint8_t* dst, \ - const uint8_t* src, \ - size_t len) { \ - FOR(i, 1, len, S); \ - } -#define mkapply_sd(NAME, S) \ - static inline void NAME(const uint8_t* src, \ - uint8_t* dst, \ - size_t len) { \ - FOR(i, 1, len, S); \ - } - -mkapply_ds(xorin, dst[i] ^= src[i]) // xorin -mkapply_sd(setout, dst[i] = src[i]) // setout - -#define P keccakf -#define Plen 200 - -// Fold P*F over the full blocks of an input. -#define foldP(I, L, F) \ - while (L >= rate) { \ - F(a, I, rate); \ - P(a); \ - I += rate; \ - L -= rate; \ - } - -/** The sponge-based hash construction. **/ -static inline int hash(uint8_t* out, size_t outlen, - const uint8_t* in, size_t inlen, - size_t rate, uint8_t delim) { - if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { - return -1; - } - uint8_t a[Plen] = {0}; - // Absorb input. - foldP(in, inlen, xorin); - // Xor in the DS and pad frame. - a[inlen] ^= delim; - a[rate - 1] ^= 0x80; - // Xor in the last block. - xorin(a, in, inlen); - // Apply P - P(a); - // Squeeze output. - foldP(out, outlen, setout); - setout(a, out, outlen); - memset(a, 0, 200); - return 0; -} - -/*** Helper macros to define SHA3 and SHAKE instances. ***/ -#define defshake(bits) \ - int shake##bits(uint8_t* out, size_t outlen, \ - const uint8_t* in, size_t inlen) { \ - return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ - } -#define defkeccak(bits) \ - int keccak_##bits(uint8_t* out, size_t outlen, \ - const uint8_t* in, size_t inlen) { \ - if (outlen > (bits/8)) { \ - return -1; \ - } \ - return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ - } - -/*** FIPS202 SHAKE VOFs ***/ -defshake(128) -defshake(256) - -/*** FIPS202 SHA3 FOFs ***/ -defkeccak(224) -defkeccak(256) -defkeccak(384) -defkeccak(512) - - - -- GitLab From 52f10242e2419cc31096904578e6c92e0e54e503 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 21 May 2018 15:33:47 +0800 Subject: [PATCH 171/263] updated tiny-keccak to 1.4.2 (#8669) --- Cargo.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4c80310c1..e2fa0a9db8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,7 +462,7 @@ dependencies = [ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -504,7 +504,7 @@ dependencies = [ "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -595,7 +595,7 @@ dependencies = [ "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -746,7 +746,7 @@ dependencies = [ "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -780,7 +780,7 @@ dependencies = [ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -814,7 +814,7 @@ dependencies = [ "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -955,7 +955,7 @@ dependencies = [ "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -995,7 +995,7 @@ dependencies = [ "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1458,7 +1458,7 @@ version = "0.1.2" dependencies = [ "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1776,7 +1776,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ring 0.12.1 (git+https://github.com/paritytech/ring)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2229,7 +2229,7 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "stats 0.1.0", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "transaction-pool 1.12.0", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2392,7 +2392,7 @@ dependencies = [ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3220,7 +3220,7 @@ dependencies = [ [[package]] name = "tiny-keccak" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4024,7 +4024,7 @@ dependencies = [ "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b" -"checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01" +"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" "checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" -- GitLab From 3c2f13f88b5fee3d485e91130d6b1a8bf1f66f52 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Tue, 22 May 2018 04:19:00 +0200 Subject: [PATCH 172/263] parity: improve cli help and logging (#8665) * parity: indicate disabling ancient blocks is not recommended * parity: display decimals for stats in informant --- parity/cli/mod.rs | 6 +++--- parity/informant.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index c7c484e2bd..34e3bf03a1 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -424,7 +424,7 @@ usage! { FLAG flag_no_ancient_blocks: (bool) = false, or |_| None, "--no-ancient-blocks", - "Disable downloading old blocks after snapshot restoration or warp sync.", + "Disable downloading old blocks after snapshot restoration or warp sync. Not recommended.", FLAG flag_no_serve_light: (bool) = false, or |c: &Config| c.network.as_ref()?.no_serve_light.clone(), "--no-serve-light", @@ -894,7 +894,7 @@ usage! { ["Legacy options"] FLAG flag_warp: (bool) = false, or |_| None, "--warp", - "Does nothing; warp sync is enabled by default.", + "Does nothing; warp sync is enabled by default. Use --no-warp to disable.", FLAG flag_dapps_apis_all: (bool) = false, or |_| None, "--dapps-apis-all", diff --git a/parity/informant.rs b/parity/informant.rs index a4d2727c35..e2f3960b67 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -303,13 +303,13 @@ impl Informant { paint(White.bold(), format!("{}", chain_info.best_block_hash)), if self.target.executes_transactions() { format!("{} blk/s {} tx/s {} Mgas/s", - paint(Yellow.bold(), format!("{:4}", (client_report.blocks_imported * 1000) as u64 / elapsed.as_milliseconds())), - paint(Yellow.bold(), format!("{:4}", (client_report.transactions_applied * 1000) as u64 / elapsed.as_milliseconds())), - paint(Yellow.bold(), format!("{:3}", (client_report.gas_processed / From::from(elapsed.as_milliseconds() * 1000)).low_u64())) + paint(Yellow.bold(), format!("{:5.2}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)), + paint(Yellow.bold(), format!("{:6.1}", (client_report.transactions_applied * 1000) as f64 / elapsed.as_milliseconds() as f64)), + paint(Yellow.bold(), format!("{:4}", (client_report.gas_processed / From::from(elapsed.as_milliseconds() * 1000)).low_u64())) ) } else { format!("{} hdr/s", - paint(Yellow.bold(), format!("{:4}", (client_report.blocks_imported * 1000) as u64 / elapsed.as_milliseconds())) + paint(Yellow.bold(), format!("{:6.1}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)) ) }, paint(Green.bold(), format!("{:5}", queue_info.unverified_queue_size)), @@ -350,8 +350,8 @@ impl Informant { Some(ref rpc_stats) => format!( "RPC: {} conn, {} req/s, {} µs", paint(Blue.bold(), format!("{:2}", rpc_stats.sessions())), - paint(Blue.bold(), format!("{:2}", rpc_stats.requests_rate())), - paint(Blue.bold(), format!("{:3}", rpc_stats.approximated_roundtrip())), + paint(Blue.bold(), format!("{:4}", rpc_stats.requests_rate())), + paint(Blue.bold(), format!("{:4}", rpc_stats.approximated_roundtrip())), ), _ => String::new(), }, -- GitLab From 3fde07b2e18f20453970ed2ab9c6f2df6cc717b1 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 22 May 2018 12:24:09 +0800 Subject: [PATCH 173/263] Refactor EIP150, EIP160 and EIP161 forks to be specified in CommonParams (#8614) * Allow post-homestead forks to be specified in CommonParams * Fix all json configs * Fix test in json crate * Fix test in ethcore * Fix all chain configs to use tabs Given we use tabs in .editorconfig and the majority of chain configs. This change is done in Emacs using `mark-whole-buffer` and `indent-region`. --- ...authority_round_block_reward_contract.json | 112 +- ethcore/res/ethereum/byzantium_test.json | 8 +- ethcore/res/ethereum/classic.json | 8 +- ethcore/res/ethereum/constantinople_test.json | 8 +- ethcore/res/ethereum/easthub.json | 174 +- ethcore/res/ethereum/eip150_test.json | 10 +- ethcore/res/ethereum/eip161_test.json | 10 +- ethcore/res/ethereum/ellaism.json | 144 +- ethcore/res/ethereum/expanse.json | 8 +- ethcore/res/ethereum/foundation.json | 8 +- ethcore/res/ethereum/frontier_like_test.json | 10 +- ethcore/res/ethereum/frontier_test.json | 10 +- ethcore/res/ethereum/homestead_test.json | 12 +- ethcore/res/ethereum/mcip3_test.json | 332 +- ethcore/res/ethereum/mcip6_byz.json | 318 +- ethcore/res/ethereum/morden.json | 8 +- ethcore/res/ethereum/musicoin.json | 324 +- ethcore/res/ethereum/olympic.json | 10 +- ethcore/res/ethereum/ropsten.json | 8 +- ethcore/res/ethereum/social.json | 17710 ++++++++-------- ethcore/res/ethereum/transition_test.json | 8 +- ethcore/src/machine.rs | 29 +- ethcore/src/spec/spec.rs | 29 +- json/src/spec/ethash.rs | 29 +- json/src/spec/params.rs | 15 + 25 files changed, 9663 insertions(+), 9679 deletions(-) diff --git a/ethcore/res/authority_round_block_reward_contract.json b/ethcore/res/authority_round_block_reward_contract.json index e008de117f..3195773123 100644 --- a/ethcore/res/authority_round_block_reward_contract.json +++ b/ethcore/res/authority_round_block_reward_contract.json @@ -1,61 +1,61 @@ { - "name": "TestAuthorityRoundBlockRewardContract", - "engine": { - "authorityRound": { - "params": { - "stepDuration": 1, - "startStep": 2, - "validators": { - "list": [ - "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e", - "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1" - ] + "name": "TestAuthorityRoundBlockRewardContract", + "engine": { + "authorityRound": { + "params": { + "stepDuration": 1, + "startStep": 2, + "validators": { + "list": [ + "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e", + "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1" + ] + }, + "immediateTransitions": true, + "emptyStepsTransition": "1", + "maximumEmptySteps": "2", + "blockRewardContractAddress": "0x0000000000000000000000000000000000000042" + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69", + "eip140Transition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0" + }, + "genesis": { + "seal": { + "authorityRound": { + "step": "0x0", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } }, - "immediateTransitions": true, - "emptyStepsTransition": "1", - "maximumEmptySteps": "2", - "blockRewardContractAddress": "0x0000000000000000000000000000000000000042" - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID" : "0x69", - "eip140Transition": "0x0", - "eip211Transition": "0x0", - "eip214Transition": "0x0", - "eip658Transition": "0x0" - }, - "genesis": { - "seal": { - "authorityRound": { - "step": "0x0", - "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x222222" }, - "difficulty": "0x20000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x222222" - }, - "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, - "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, - "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, - "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, - "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }, - "0000000000000000000000000000000000000042": { - "balance": "1", - "constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029" + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, + "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }, + "0000000000000000000000000000000000000042": { + "balance": "1", + "constructor": "6060604052341561000f57600080fd5b6102b88061001e6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f91c289814610046575b600080fd5b341561005157600080fd5b610086600480803590602001908201803590602001919091929080359060200190820180359060200191909192905050610125565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100cd5780820151818401526020810190506100b2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561010f5780820151818401526020810190506100f4565b5050505090500194505050505060405180910390f35b61012d610264565b610135610278565b61013d610278565b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018d57600080fd5b85859050888890501415156101a157600080fd5b878790506040518059106101b25750595b90808252806020026020018201604052509150600090505b815181101561021d5785858281811015156101e157fe5b9050602002013561ffff166103e80161ffff16828281518110151561020257fe5b906020019060200201818152505080806001019150506101ca565b878783828280806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050915090915093509350505094509492505050565b602060405190810160405280600081525090565b6020604051908101604052806000815250905600a165627a7a723058201da0f164e75517fb8baf51f030b904032cb748334938e7386f63025bfb23f3de0029" + } } - } } diff --git a/ethcore/res/ethereum/byzantium_test.json b/ethcore/res/ethereum/byzantium_test.json index 40c7e46599..90c92bbff5 100644 --- a/ethcore/res/ethereum/byzantium_test.json +++ b/ethcore/res/ethereum/byzantium_test.json @@ -8,10 +8,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "eip161abcTransition": "0x0", - "eip161dTransition": "0x0", "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": "0x0", "eip649Transition": "0x0" @@ -27,6 +23,10 @@ "networkID" : "0x1", "maxCodeSize": 24576, "maxCodeSizeTransition": "0x0", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", "eip98Transition": "0xffffffffffffffff", "eip140Transition": "0x0", "eip211Transition": "0x0", diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index a4c6fe9f22..928c056d66 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -9,13 +9,9 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": 1150000, - "eip150Transition": 2500000, - "eip160Transition": 3000000, "ecip1010PauseTransition": 3000000, "ecip1010ContinueTransition": 5000000, "ecip1017EraRounds": 5000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff", "bombDefuseTransition": 5900000 } } @@ -30,6 +26,10 @@ "chainID": "0x3d", "forkBlock": "0x1d4c00", "forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f", + "eip150Transition": 2500000, + "eip160Transition": 3000000, + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip155Transition": 3000000, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" diff --git a/ethcore/res/ethereum/constantinople_test.json b/ethcore/res/ethereum/constantinople_test.json index 7b137e86fa..155b06507d 100644 --- a/ethcore/res/ethereum/constantinople_test.json +++ b/ethcore/res/ethereum/constantinople_test.json @@ -8,10 +8,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "eip161abcTransition": "0x0", - "eip161dTransition": "0x0", "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": "0x0", "eip649Transition": "0x0" @@ -28,6 +24,10 @@ "maxCodeSize": 24576, "maxCodeSizeTransition": "0x0", "eip98Transition": "0xffffffffffffffff", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", "eip140Transition": "0x0", "eip210Transition": "0x0", "eip211Transition": "0x0", diff --git a/ethcore/res/ethereum/easthub.json b/ethcore/res/ethereum/easthub.json index ddc170d8a6..e7e1a6e708 100644 --- a/ethcore/res/ethereum/easthub.json +++ b/ethcore/res/ethereum/easthub.json @@ -1,89 +1,89 @@ { - "name": "Easthub", - "dataDir": "easthub", - "engine": { - "Ethash": { - "params": { - "minimumDifficulty": "0x020000", - "difficultyBoundDivisor": "0x0800", - "durationLimit": "0x0d", - "blockReward": "0x2B5E3AF16B1880000", - "homesteadTransition": "0x0", - "bombDefuseTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "ecip1017EraRounds": 5000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "registrar": "0x0000000000000000000000000000000000000000", - "accountStartNonce": "0x00", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID": "0x7", - "chainID": "0x7", - "eip155Transition": "0x0", - "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" - }, - "genesis": { - "seal": { - "ethereum": { - "nonce": "0x0000000000000042", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "difficulty": "0x0400000000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x323031382045617374636f696e2050726f6a656374", - "gasLimit": "0x1388" - }, - "nodes": [ - "enode://ca57e40edb95a08a81b85a91e91099a0aaab777ad329ea7f3f772bc0fd511a276a5d84944725d181ff80f8c7dc1034814bff25b9723b03363d48617fed4b15f0@13.125.109.174:30303", - "enode://57254e23a7e5fe1e081ee5d1b236e37735a120660daeb4bf1fec6943a82c915c5b6fad23eeb1a43a27c23f236e084e8051aaa28f7d4139149f844747facb62bb@18.217.39.51:30303", - "enode://ef248f327c73c0318f4d51a62270b0612f3c4a4fd04b77d04854dc355980e137708d1e48811bc91387b0d7eb85cf447d8bbc095404f39bb7064e76751bda9cd4@52.221.160.236:30303", - "enode://bf6f0e37dd733cf04f2b079c753d2dea7cc7c59d8637eff9a8e63e17d08e2bfc91229fbb2dff08fe6ee12e51c1b6f8ed969d7042b89d77029e7ea02b05e17be3@18.197.47.177:30303" - ], - "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "20c1252a8cb33a7a9a257b2a4cfeed8daf87c847": { - "balance": "100000000000000000000000000" - }, - "9dcd37c8e5aea3a0d37c5d0a2db683362d81febd": { - "balance": "100000000000000000000000000" - }, - "9eff080302333f44a60bfd8c33bd63015c6d921b": { - "balance": "100000000000000000000000000" - }, - "c1df2e5de98d5c41fec0642dc302971f5d3500bd": { - "balance": "100000000000000000000000000" - }, - "2e0fb67cd1d029cbaea4b74c361efcc06b3105fd": { - "balance": "100000000000000000000000000" - }, - "2b6425cc3cd90654f077889ef7262ac2f5846460": { - "balance": "100000000000000000000000000" - }, - "28562041230c6d575e233e4ed1b35c514884d964": { - "balance": "100000000000000000000000000" - }, - "16eb6896a5a83d39ac762d79d21f825f5f980d12": { - "balance": "100000000000000000000000000" - }, - "f09e3f1de27dd03a1ac0a021b2d9e45bde1b360c": { - "balance": "100000000000000000000000000" - }, - "2d87547819c6433f208ee3096161cdb2835a2333": { - "balance": "100000000000000000000000000" - } - } + "name": "Easthub", + "dataDir": "easthub", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x2B5E3AF16B1880000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "ecip1017EraRounds": 5000000 + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x0000000000000000000000000000000000000000", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x7", + "chainID": "0x7", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip155Transition": "0x0", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x0400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x323031382045617374636f696e2050726f6a656374", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://ca57e40edb95a08a81b85a91e91099a0aaab777ad329ea7f3f772bc0fd511a276a5d84944725d181ff80f8c7dc1034814bff25b9723b03363d48617fed4b15f0@13.125.109.174:30303", + "enode://57254e23a7e5fe1e081ee5d1b236e37735a120660daeb4bf1fec6943a82c915c5b6fad23eeb1a43a27c23f236e084e8051aaa28f7d4139149f844747facb62bb@18.217.39.51:30303", + "enode://ef248f327c73c0318f4d51a62270b0612f3c4a4fd04b77d04854dc355980e137708d1e48811bc91387b0d7eb85cf447d8bbc095404f39bb7064e76751bda9cd4@52.221.160.236:30303", + "enode://bf6f0e37dd733cf04f2b079c753d2dea7cc7c59d8637eff9a8e63e17d08e2bfc91229fbb2dff08fe6ee12e51c1b6f8ed969d7042b89d77029e7ea02b05e17be3@18.197.47.177:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "20c1252a8cb33a7a9a257b2a4cfeed8daf87c847": { + "balance": "100000000000000000000000000" + }, + "9dcd37c8e5aea3a0d37c5d0a2db683362d81febd": { + "balance": "100000000000000000000000000" + }, + "9eff080302333f44a60bfd8c33bd63015c6d921b": { + "balance": "100000000000000000000000000" + }, + "c1df2e5de98d5c41fec0642dc302971f5d3500bd": { + "balance": "100000000000000000000000000" + }, + "2e0fb67cd1d029cbaea4b74c361efcc06b3105fd": { + "balance": "100000000000000000000000000" + }, + "2b6425cc3cd90654f077889ef7262ac2f5846460": { + "balance": "100000000000000000000000000" + }, + "28562041230c6d575e233e4ed1b35c514884d964": { + "balance": "100000000000000000000000000" + }, + "16eb6896a5a83d39ac762d79d21f825f5f980d12": { + "balance": "100000000000000000000000000" + }, + "f09e3f1de27dd03a1ac0a021b2d9e45bde1b360c": { + "balance": "100000000000000000000000000" + }, + "2d87547819c6433f208ee3096161cdb2835a2333": { + "balance": "100000000000000000000000000" + } + } } diff --git a/ethcore/res/ethereum/eip150_test.json b/ethcore/res/ethereum/eip150_test.json index 60157c5716..baf9c1b7bf 100644 --- a/ethcore/res/ethereum/eip150_test.json +++ b/ethcore/res/ethereum/eip150_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x0" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x0", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffffff", "eip86Transition": "0x7fffffffffffffff", "eip155Transition": "0x7fffffffffffffff", diff --git a/ethcore/res/ethereum/eip161_test.json b/ethcore/res/ethereum/eip161_test.json index ac1c0a5d1e..079ce7d55a 100644 --- a/ethcore/res/ethereum/eip161_test.json +++ b/ethcore/res/ethereum/eip161_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "eip161abcTransition": "0x0", - "eip161dTransition": "0x0" + "homesteadTransition": "0x0" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", "eip98Transition": "0x7fffffffffffffff", "eip86Transition": "0x7fffffffffffffff", "eip155Transition": "0x7fffffffffffffff", diff --git a/ethcore/res/ethereum/ellaism.json b/ethcore/res/ethereum/ellaism.json index 96c2016e55..c3107bbe46 100644 --- a/ethcore/res/ethereum/ellaism.json +++ b/ethcore/res/ethereum/ellaism.json @@ -1,74 +1,74 @@ { - "name": "Ellaism", - "dataDir": "ellaism", - "engine": { - "Ethash": { - "params": { - "minimumDifficulty": "0x020000", - "difficultyBoundDivisor": "0x0800", - "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "bombDefuseTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "ecip1017EraRounds": 10000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff", - "eip100bTransition": 2000000 - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "registrar": "0x3bb2bb5c6c9c9b7f4EF430b47Dc7e026310042ea", - "accountStartNonce": "0x00", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID": "0x40", - "chainID": "0x40", - "eip155Transition": "0x0", - "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff", - "wasmActivationTransition": 2000000, - "eip140Transition": 2000000, - "eip211Transition": 2000000, - "eip214Transition": 2000000, - "eip658Transition": 2000000 - }, - "genesis": { - "seal": { - "ethereum": { - "nonce": "0x0000000000000040", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "difficulty": "0x40000000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0x1388" - }, - "nodes": [ - "enode://0d88e242aa0b01ee306ca43e956174677c96ec8eba4197f4d8be6fd7d4f2e57731e95d533b88229b66eb1a44399d870e99b7a4fe6547c8c80cdf00407a986e14@94.130.237.158:30303", - "enode://4be9e419d3efb0214faf3ef1794a0c33ebbd7633ece734a0a956faa166fefc496b2692a2a485adc66af805e461ba3e12f8d3941ec207e56bb9f3d3626787a705@94.130.237.158:60606", - "enode://834246cc2a7584df29ccdcf3b5366f118a0e291264980376769e809665a02c4caf0d68c43eecf8390dbeaf861823b05583807af0a62542a1f3f717046b958a76@45.77.106.33:30303", - "enode://d8059dcb137cb52b8960ca82613eeba1d121105572decd8f1d3ea22b09070645eeab548d2a3cd2914f206e1331c7870bd2bd5a231ebac6b3d4886ec3b8e627e5@173.212.216.105:30303", - "enode://9215ad77bd081e35013cb42a8ceadff9d8e94a78fcc680dff1752a54e7484badff0904e331c4b40a68be593782e55acfd800f076d22f9d2832e8483733ade149@213.14.82.125:30303", - "enode://5dd35866da95aea15211fb1f98684f6e8c4e355e6aa3cc17585680ed53fa164477b8c52cb6ca4b24ec4d80f3d48ff9212b53feb131d825c7945a3abaaf02d24d@178.79.189.58:60606", - "enode://6c585c18024eb902ca093278af73b04863ac904caabc39ac2920c23532307c572ad92afd828a990c980d272b1f26307f2409cc97aec3ff9fe866732cae49a8c2@144.217.163.224:31337", - "enode://edd90c4cc64528802ad52fd127d80b641ff80fd43fa5292fb111c8bd2914482dffee288fd1b0d26440c6b2c669b10a53cbcd37c895ba0d6194110e100a965b2d@188.166.179.159:30303", - "enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303" - ], - "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } }, - "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, - "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, - "0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } } - } + "name": "Ellaism", + "dataDir": "ellaism", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "ecip1017EraRounds": 10000000, + "eip100bTransition": 2000000 + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x3bb2bb5c6c9c9b7f4EF430b47Dc7e026310042ea", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x40", + "chainID": "0x40", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff", + "wasmActivationTransition": 2000000, + "eip140Transition": 2000000, + "eip211Transition": 2000000, + "eip214Transition": 2000000, + "eip658Transition": 2000000 + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000040", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x40000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://0d88e242aa0b01ee306ca43e956174677c96ec8eba4197f4d8be6fd7d4f2e57731e95d533b88229b66eb1a44399d870e99b7a4fe6547c8c80cdf00407a986e14@94.130.237.158:30303", + "enode://4be9e419d3efb0214faf3ef1794a0c33ebbd7633ece734a0a956faa166fefc496b2692a2a485adc66af805e461ba3e12f8d3941ec207e56bb9f3d3626787a705@94.130.237.158:60606", + "enode://834246cc2a7584df29ccdcf3b5366f118a0e291264980376769e809665a02c4caf0d68c43eecf8390dbeaf861823b05583807af0a62542a1f3f717046b958a76@45.77.106.33:30303", + "enode://d8059dcb137cb52b8960ca82613eeba1d121105572decd8f1d3ea22b09070645eeab548d2a3cd2914f206e1331c7870bd2bd5a231ebac6b3d4886ec3b8e627e5@173.212.216.105:30303", + "enode://9215ad77bd081e35013cb42a8ceadff9d8e94a78fcc680dff1752a54e7484badff0904e331c4b40a68be593782e55acfd800f076d22f9d2832e8483733ade149@213.14.82.125:30303", + "enode://5dd35866da95aea15211fb1f98684f6e8c4e355e6aa3cc17585680ed53fa164477b8c52cb6ca4b24ec4d80f3d48ff9212b53feb131d825c7945a3abaaf02d24d@178.79.189.58:60606", + "enode://6c585c18024eb902ca093278af73b04863ac904caabc39ac2920c23532307c572ad92afd828a990c980d272b1f26307f2409cc97aec3ff9fe866732cae49a8c2@144.217.163.224:31337", + "enode://edd90c4cc64528802ad52fd127d80b641ff80fd43fa5292fb111c8bd2914482dffee288fd1b0d26440c6b2c669b10a53cbcd37c895ba0d6194110e100a965b2d@188.166.179.159:30303", + "enode://9d960373335c1cc38ca696dea8f2893e2a071c8f21524f21e8aae22be032acc3b67797b1d21e866f9d832943ae7d9555b8466c6ab34f473d21e547114952df37@213.32.53.183:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } } + } } diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json index b9b734e313..2061231c60 100644 --- a/ethcore/res/ethereum/expanse.json +++ b/ethcore/res/ethereum/expanse.json @@ -13,10 +13,6 @@ "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", "bombDefuseTransition": "0x30d40", - "eip150Transition": "0x927C0", - "eip160Transition": "0x927C0", - "eip161abcTransition": "0x927C0", - "eip161dTransition": "0x927C0", "eip100bTransition": "0xC3500", "metropolisDifficultyIncrementDivisor": "0x1E", "eip649Transition": "0xC3500", @@ -37,6 +33,10 @@ "forkBlock": "0xDBBA0", "forkCanonHash": "0x8e7bed51e24f5174090408664ac476b90b5e1199a947af7442f1ac88263fc8c7", "subprotocolName": "exp", + "eip150Transition": "0x927C0", + "eip160Transition": "0x927C0", + "eip161abcTransition": "0x927C0", + "eip161dTransition": "0x927C0", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x927C0", diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 6658b5e522..b725c9f7c0 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -129,10 +129,6 @@ "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], - "eip150Transition": "0x259518", - "eip160Transition": 2675000, - "eip161abcTransition": 2675000, - "eip161dTransition": 2675000, "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": 4370000, "eip649Transition": 4370000 @@ -148,6 +144,10 @@ "networkID" : "0x1", "forkBlock": "0x1d4c00", "forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb", + "eip150Transition": "0x259518", + "eip160Transition": 2675000, + "eip161abcTransition": 2675000, + "eip161dTransition": 2675000, "eip155Transition": 2675000, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 6d2ea3693d..7eac5acbd0 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -127,11 +127,7 @@ "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" - ], - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + ] } } }, @@ -142,6 +138,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x7fffffffffffffff" diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index aae59cb071..7e52f6ecf9 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x7fffffffffffffff", - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x7fffffffffffffff" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x7fffffffffffffff" diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index c6d49b5455..817bf5ff57 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "homesteadTransition": "0x0", - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x0" } } }, @@ -24,7 +20,11 @@ "networkID" : "0x1", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", - "eip155Transition": "0x7fffffffffffffff" + "eip155Transition": "0x7fffffffffffffff", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/mcip3_test.json b/ethcore/res/ethereum/mcip3_test.json index d2e5ec8b6b..391a625730 100644 --- a/ethcore/res/ethereum/mcip3_test.json +++ b/ethcore/res/ethereum/mcip3_test.json @@ -1,168 +1,168 @@ { - "name":"MCIP3 Test", - "dataDir":"mcip3test", - "engine":{ - "Ethash":{ - "params":{ - "minimumDifficulty":"0x020000", - "difficultyBoundDivisor":"0x0800", - "durationLimit":"0x0d", - "homesteadTransition":"0x118c30", - "eip100bTransition":"0x7fffffffffffff", - "eip150Transition":"0x7fffffffffffff", - "eip160Transition":"0x7fffffffffffff", - "eip161abcTransition":"0x7fffffffffffff", - "eip161dTransition":"0x7fffffffffffff", - "eip649Transition":"0x7fffffffffffff", - "blockReward":"0x1105a0185b50a80000", - "mcip3Transition":"0x00", - "mcip3MinerReward":"0xd8d726b7177a80000", - "mcip3UbiReward":"0x2b5e3af16b1880000", - "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", - "mcip3DevReward":"0xc249fdd327780000", - "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" - } - } - }, - "params":{ - "gasLimitBoundDivisor":"0x0400", - "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", - "accountStartNonce":"0x00", - "maximumExtraDataSize":"0x20", - "minGasLimit":"0x1388", - "networkID":"0x76740b", - "forkBlock":"0x5b6", - "forkCanonHash":"0xa5e88ad9e34d113e264e307bc27e8471452c8fc13780324bb3abb96fd0558343", - "eip86Transition":"0x7fffffffffffff", - "eip98Transition":"0x7fffffffffffff", - "eip140Transition":"0x7fffffffffffff", - "eip155Transition":"0x7fffffffffffff", - "eip211Transition":"0x7fffffffffffff", - "eip214Transition":"0x7fffffffffffff", - "eip658Transition":"0x7fffffffffffff", - "maxCodeSize":"0x6000", - "maxCodeSizeTransition": "0x7fffffffffffff" - }, - "genesis":{ - "seal":{ - "ethereum":{ - "nonce":"0x000000000000002a", - "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" - } - }, - "difficulty":"0x3d0900", - "author":"0x0000000000000000000000000000000000000000", - "timestamp":"0x00", - "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData":"", - "gasLimit":"0x7a1200" - }, - "nodes":[ - "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", - "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", - "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", - "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", - "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", - "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303", - "enode://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", - "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", - "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" - ], - "accounts":{ - "0000000000000000000000000000000000000001":{ - "balance":"1", - "builtin":{ - "name":"ecrecover", - "pricing":{ - "linear":{ - "base":3000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000002":{ - "balance":"1", - "builtin":{ - "name":"sha256", - "pricing":{ - "linear":{ - "base":60, - "word":12 - } - } - } - }, - "0000000000000000000000000000000000000003":{ - "balance":"1", - "builtin":{ - "name":"ripemd160", - "pricing":{ - "linear":{ - "base":600, - "word":120 - } - } - } - }, - "0000000000000000000000000000000000000004":{ - "balance":"1", - "builtin":{ - "name":"identity", - "pricing":{ - "linear":{ - "base":15, - "word":3 - } - } - } - }, - "0000000000000000000000000000000000000005":{ - "builtin":{ - "name":"modexp", - "activate_at":"0x7fffffffffffff", - "pricing":{ - "modexp":{ - "divisor":20 - } - } - } - }, - "0000000000000000000000000000000000000006":{ - "builtin":{ - "name":"alt_bn128_add", - "activate_at":"0x7fffffffffffff", - "pricing":{ - "linear":{ - "base":500, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000007":{ - "builtin":{ - "name":"alt_bn128_mul", - "activate_at":"0x7fffffffffffff", - "pricing":{ - "linear":{ - "base":40000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000008":{ - "builtin":{ - "name":"alt_bn128_pairing", - "activate_at":"0x7fffffffffffff", - "pricing":{ - "alt_bn128_pairing":{ - "base":100000, - "pair":80000 - } - } - } - } - } + "name":"MCIP3 Test", + "dataDir":"mcip3test", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x020000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "homesteadTransition":"0x118c30", + "eip100bTransition":"0x7fffffffffffff", + "eip649Transition":"0x7fffffffffffff", + "blockReward":"0x1105a0185b50a80000", + "mcip3Transition":"0x00", + "mcip3MinerReward":"0xd8d726b7177a80000", + "mcip3UbiReward":"0x2b5e3af16b1880000", + "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", + "mcip3DevReward":"0xc249fdd327780000", + "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" + } + } + }, + "params":{ + "gasLimitBoundDivisor":"0x0400", + "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", + "accountStartNonce":"0x00", + "maximumExtraDataSize":"0x20", + "minGasLimit":"0x1388", + "networkID":"0x76740b", + "forkBlock":"0x5b6", + "forkCanonHash":"0xa5e88ad9e34d113e264e307bc27e8471452c8fc13780324bb3abb96fd0558343", + "eip150Transition":"0x7fffffffffffff", + "eip160Transition":"0x7fffffffffffff", + "eip161abcTransition":"0x7fffffffffffff", + "eip161dTransition":"0x7fffffffffffff", + "eip86Transition":"0x7fffffffffffff", + "eip98Transition":"0x7fffffffffffff", + "eip140Transition":"0x7fffffffffffff", + "eip155Transition":"0x7fffffffffffff", + "eip211Transition":"0x7fffffffffffff", + "eip214Transition":"0x7fffffffffffff", + "eip658Transition":"0x7fffffffffffff", + "maxCodeSize":"0x6000", + "maxCodeSizeTransition": "0x7fffffffffffff" + }, + "genesis":{ + "seal":{ + "ethereum":{ + "nonce":"0x000000000000002a", + "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty":"0x3d0900", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x00", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"", + "gasLimit":"0x7a1200" + }, + "nodes":[ + "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", + "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", + "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", + "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", + "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", + "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303", + "enode://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", + "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", + "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" + ], + "accounts":{ + "0000000000000000000000000000000000000001":{ + "balance":"1", + "builtin":{ + "name":"ecrecover", + "pricing":{ + "linear":{ + "base":3000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000002":{ + "balance":"1", + "builtin":{ + "name":"sha256", + "pricing":{ + "linear":{ + "base":60, + "word":12 + } + } + } + }, + "0000000000000000000000000000000000000003":{ + "balance":"1", + "builtin":{ + "name":"ripemd160", + "pricing":{ + "linear":{ + "base":600, + "word":120 + } + } + } + }, + "0000000000000000000000000000000000000004":{ + "balance":"1", + "builtin":{ + "name":"identity", + "pricing":{ + "linear":{ + "base":15, + "word":3 + } + } + } + }, + "0000000000000000000000000000000000000005":{ + "builtin":{ + "name":"modexp", + "activate_at":"0x7fffffffffffff", + "pricing":{ + "modexp":{ + "divisor":20 + } + } + } + }, + "0000000000000000000000000000000000000006":{ + "builtin":{ + "name":"alt_bn128_add", + "activate_at":"0x7fffffffffffff", + "pricing":{ + "linear":{ + "base":500, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000007":{ + "builtin":{ + "name":"alt_bn128_mul", + "activate_at":"0x7fffffffffffff", + "pricing":{ + "linear":{ + "base":40000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000008":{ + "builtin":{ + "name":"alt_bn128_pairing", + "activate_at":"0x7fffffffffffff", + "pricing":{ + "alt_bn128_pairing":{ + "base":100000, + "pair":80000 + } + } + } + } + } } diff --git a/ethcore/res/ethereum/mcip6_byz.json b/ethcore/res/ethereum/mcip6_byz.json index 8028e6b1bb..a12df7c711 100644 --- a/ethcore/res/ethereum/mcip6_byz.json +++ b/ethcore/res/ethereum/mcip6_byz.json @@ -1,161 +1,161 @@ { - "name":"Musicoin Byzantium Test", - "dataDir":"mcip6test", - "engine":{ - "Ethash":{ - "params":{ - "minimumDifficulty":"0x020000", - "difficultyBoundDivisor":"0x0800", - "durationLimit":"0x0d", - "homesteadTransition":"0x17", - "eip100bTransition":"0x2a", - "eip150Transition":"0x2a", - "eip160Transition":"0x7fffffffffffff", - "eip161abcTransition":"0x7fffffffffffff", - "eip161dTransition":"0x7fffffffffffff", - "eip649Transition":"0x2a", - "blockReward":"0x1105a0185b50a80000", - "mcip3Transition":"0x17", - "mcip3MinerReward":"0xd8d726b7177a80000", - "mcip3UbiReward":"0x2b5e3af16b1880000", - "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", - "mcip3DevReward":"0xc249fdd327780000", - "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" - } - } - }, - "params":{ - "gasLimitBoundDivisor":"0x0400", - "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", - "accountStartNonce":"0x00", - "maximumExtraDataSize":"0x20", - "minGasLimit":"0x1388", - "networkID":"0x76740c", - "forkBlock":"0x2b", - "forkCanonHash":"0x23c3171e864a5d513a3ef85e4cf86dac4cc36b89e5b8e63bf0ebcca68b9e43c9", - "eip86Transition":"0x7fffffffffffff", - "eip98Transition":"0x7fffffffffffff", - "eip140Transition":"0x2a", - "eip155Transition":"0x2a", - "eip211Transition":"0x2a", - "eip214Transition":"0x2a", - "eip658Transition":"0x2a", - "maxCodeSize":"0x6000", - "maxCodeSizeTransition": "0x7fffffffffffff" - }, - "genesis":{ - "seal":{ - "ethereum":{ - "nonce":"0x000000000000002a", - "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" - } - }, - "difficulty":"0x3d0900", - "author":"0x0000000000000000000000000000000000000000", - "timestamp":"0x00", - "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData":"", - "gasLimit":"0x7a1200" - }, - "nodes":[ - "enode://5ddc110733f6d34101973cdef3f9b43484159acf6f816d3b1ee92bc3c98ea453e857bb1207edf0ec0242008ab3a0f9f05eeaee99d47bd414c08a5bdf4847de13@176.9.3.148:30303", - "enode://38f074f4db8e64dfbaf87984bf290eef67772a901a7113d1b62f36216be152b8450c393d6fc562a5e38f04f99bc8f439a99010a230b1d92dc1df43bf0bd00615@176.9.3.148:30403" - ], - "accounts":{ - "0000000000000000000000000000000000000001":{ - "balance":"1", - "builtin":{ - "name":"ecrecover", - "pricing":{ - "linear":{ - "base":3000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000002":{ - "balance":"1", - "builtin":{ - "name":"sha256", - "pricing":{ - "linear":{ - "base":60, - "word":12 - } - } - } - }, - "0000000000000000000000000000000000000003":{ - "balance":"1", - "builtin":{ - "name":"ripemd160", - "pricing":{ - "linear":{ - "base":600, - "word":120 - } - } - } - }, - "0000000000000000000000000000000000000004":{ - "balance":"1", - "builtin":{ - "name":"identity", - "pricing":{ - "linear":{ - "base":15, - "word":3 - } - } - } - }, - "0000000000000000000000000000000000000005":{ - "builtin":{ - "name":"modexp", - "activate_at":"0x2a", - "pricing":{ - "modexp":{ - "divisor":20 - } - } - } - }, - "0000000000000000000000000000000000000006":{ - "builtin":{ - "name":"alt_bn128_add", - "activate_at":"0x2a", - "pricing":{ - "linear":{ - "base":500, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000007":{ - "builtin":{ - "name":"alt_bn128_mul", - "activate_at":"0x2a", - "pricing":{ - "linear":{ - "base":40000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000008":{ - "builtin":{ - "name":"alt_bn128_pairing", - "activate_at":"0x2a", - "pricing":{ - "alt_bn128_pairing":{ - "base":100000, - "pair":80000 - } - } - } - } - } + "name":"Musicoin Byzantium Test", + "dataDir":"mcip6test", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x020000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "homesteadTransition":"0x17", + "eip100bTransition":"0x2a", + "eip649Transition":"0x2a", + "blockReward":"0x1105a0185b50a80000", + "mcip3Transition":"0x17", + "mcip3MinerReward":"0xd8d726b7177a80000", + "mcip3UbiReward":"0x2b5e3af16b1880000", + "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", + "mcip3DevReward":"0xc249fdd327780000", + "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" + } + } + }, + "params":{ + "gasLimitBoundDivisor":"0x0400", + "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", + "accountStartNonce":"0x00", + "maximumExtraDataSize":"0x20", + "minGasLimit":"0x1388", + "networkID":"0x76740c", + "forkBlock":"0x2b", + "forkCanonHash":"0x23c3171e864a5d513a3ef85e4cf86dac4cc36b89e5b8e63bf0ebcca68b9e43c9", + "eip150Transition":"0x2a", + "eip160Transition":"0x7fffffffffffff", + "eip161abcTransition":"0x7fffffffffffff", + "eip161dTransition":"0x7fffffffffffff", + "eip86Transition":"0x7fffffffffffff", + "eip98Transition":"0x7fffffffffffff", + "eip140Transition":"0x2a", + "eip155Transition":"0x2a", + "eip211Transition":"0x2a", + "eip214Transition":"0x2a", + "eip658Transition":"0x2a", + "maxCodeSize":"0x6000", + "maxCodeSizeTransition": "0x7fffffffffffff" + }, + "genesis":{ + "seal":{ + "ethereum":{ + "nonce":"0x000000000000002a", + "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty":"0x3d0900", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x00", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"", + "gasLimit":"0x7a1200" + }, + "nodes":[ + "enode://5ddc110733f6d34101973cdef3f9b43484159acf6f816d3b1ee92bc3c98ea453e857bb1207edf0ec0242008ab3a0f9f05eeaee99d47bd414c08a5bdf4847de13@176.9.3.148:30303", + "enode://38f074f4db8e64dfbaf87984bf290eef67772a901a7113d1b62f36216be152b8450c393d6fc562a5e38f04f99bc8f439a99010a230b1d92dc1df43bf0bd00615@176.9.3.148:30403" + ], + "accounts":{ + "0000000000000000000000000000000000000001":{ + "balance":"1", + "builtin":{ + "name":"ecrecover", + "pricing":{ + "linear":{ + "base":3000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000002":{ + "balance":"1", + "builtin":{ + "name":"sha256", + "pricing":{ + "linear":{ + "base":60, + "word":12 + } + } + } + }, + "0000000000000000000000000000000000000003":{ + "balance":"1", + "builtin":{ + "name":"ripemd160", + "pricing":{ + "linear":{ + "base":600, + "word":120 + } + } + } + }, + "0000000000000000000000000000000000000004":{ + "balance":"1", + "builtin":{ + "name":"identity", + "pricing":{ + "linear":{ + "base":15, + "word":3 + } + } + } + }, + "0000000000000000000000000000000000000005":{ + "builtin":{ + "name":"modexp", + "activate_at":"0x2a", + "pricing":{ + "modexp":{ + "divisor":20 + } + } + } + }, + "0000000000000000000000000000000000000006":{ + "builtin":{ + "name":"alt_bn128_add", + "activate_at":"0x2a", + "pricing":{ + "linear":{ + "base":500, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000007":{ + "builtin":{ + "name":"alt_bn128_mul", + "activate_at":"0x2a", + "pricing":{ + "linear":{ + "base":40000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000008":{ + "builtin":{ + "name":"alt_bn128_pairing", + "activate_at":"0x2a", + "pricing":{ + "alt_bn128_pairing":{ + "base":100000, + "pair":80000 + } + } + } + } + } } diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index bca9919903..b61799c0c9 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -9,13 +9,9 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": 494000, - "eip150Transition": 1783000, - "eip160Transition": 1915000, "ecip1010PauseTransition": 1915000, "ecip1010ContinueTransition": 3415000, "ecip1017EraRounds": 2000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff", "bombDefuseTransition": 2300000 } } @@ -30,6 +26,10 @@ "chainID": "0x3e", "forkBlock": "0x1b34d8", "forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145", + "eip150Transition": 1783000, + "eip160Transition": 1915000, + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip155Transition": 1915000, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" diff --git a/ethcore/res/ethereum/musicoin.json b/ethcore/res/ethereum/musicoin.json index 6d5f6835bd..724f11478b 100644 --- a/ethcore/res/ethereum/musicoin.json +++ b/ethcore/res/ethereum/musicoin.json @@ -1,164 +1,164 @@ { - "name":"Musicoin", - "dataDir":"musicoin", - "engine":{ - "Ethash":{ - "params":{ - "minimumDifficulty":"0x020000", - "difficultyBoundDivisor":"0x0800", - "durationLimit":"0x0d", - "homesteadTransition":"0x118c30", - "eip100bTransition":"0x21e88e", - "eip150Transition":"0x21e88e", - "eip160Transition":"0x21e88e", - "eip161abcTransition":"0x21e88e", - "eip161dTransition":"0x21e88e", - "eip649Transition":"0x21e88e", - "blockReward":"0x1105a0185b50a80000", - "mcip3Transition":"0x124f81", - "mcip3MinerReward":"0xd8d726b7177a80000", - "mcip3UbiReward":"0x2b5e3af16b1880000", - "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", - "mcip3DevReward":"0xc249fdd327780000", - "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" - } - } - }, - "params":{ - "gasLimitBoundDivisor":"0x0400", - "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", - "accountStartNonce":"0x00", - "maximumExtraDataSize":"0x20", - "minGasLimit":"0x1388", - "networkID":"0x76740f", - "forkBlock":"0x1d8015", - "forkCanonHash":"0x380602acf82b629a0be6b5adb2b4a801e960a07dc8261bf196d21befdbb8f2f9", - "eip86Transition":"0x7fffffffffffff", - "eip98Transition":"0x7fffffffffffff", - "eip140Transition":"0x21e88e", - "eip155Transition":"0x21e88e", - "eip211Transition":"0x21e88e", - "eip214Transition":"0x21e88e", - "eip658Transition":"0x21e88e", - "maxCodeSize":"0x6000" - }, - "genesis":{ - "seal":{ - "ethereum":{ - "nonce":"0x000000000000002a", - "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" - } - }, - "difficulty":"0x3d0900", - "author":"0x0000000000000000000000000000000000000000", - "timestamp":"0x00", - "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData":"", - "gasLimit":"0x7a1200" - }, - "nodes":[ - "enode://09fcd36d553044c8b499b9b9e13a228ffd99572c513f77073d41f009717c464cd4399c0e665d6aff1590324254ee4e698b2b2533b1998dd04d896b9d6aff7895@35.185.67.35:30303", - "enode://89e51a34770a0badf8ea18c4c4d2c361cde707abd60031d99b1ab3010363e1898230a516ddb37d974af8d8db1b322779d7fe0caae0617bed4924d1b4968cf92b@35.231.48.142:30303", - "enode://b58c0c71f08864c0cf7fa9dea2c4cbefae5ae7a36cc30d286603b24982d25f3ccc056b589119324c51768fc2054b8c529ecf682e06e1e9980170b93ff194ed7a@132.148.132.9:30303", - "enode://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", - "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", - "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" - ], - "accounts":{ - "0000000000000000000000000000000000000001":{ - "balance":"1", - "builtin":{ - "name":"ecrecover", - "pricing":{ - "linear":{ - "base":3000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000002":{ - "balance":"1", - "builtin":{ - "name":"sha256", - "pricing":{ - "linear":{ - "base":60, - "word":12 - } - } - } - }, - "0000000000000000000000000000000000000003":{ - "balance":"1", - "builtin":{ - "name":"ripemd160", - "pricing":{ - "linear":{ - "base":600, - "word":120 - } - } - } - }, - "0000000000000000000000000000000000000004":{ - "balance":"1", - "builtin":{ - "name":"identity", - "pricing":{ - "linear":{ - "base":15, - "word":3 - } - } - } - }, - "0000000000000000000000000000000000000005":{ - "builtin":{ - "name":"modexp", - "activate_at":"0x21e88e", - "pricing":{ - "modexp":{ - "divisor":20 - } - } - } - }, - "0000000000000000000000000000000000000006":{ - "builtin":{ - "name":"alt_bn128_add", - "activate_at":"0x21e88e", - "pricing":{ - "linear":{ - "base":500, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000007":{ - "builtin":{ - "name":"alt_bn128_mul", - "activate_at":"0x21e88e", - "pricing":{ - "linear":{ - "base":40000, - "word":0 - } - } - } - }, - "0000000000000000000000000000000000000008":{ - "builtin":{ - "name":"alt_bn128_pairing", - "activate_at":"0x21e88e", - "pricing":{ - "alt_bn128_pairing":{ - "base":100000, - "pair":80000 - } - } - } - } - } + "name":"Musicoin", + "dataDir":"musicoin", + "engine":{ + "Ethash":{ + "params":{ + "minimumDifficulty":"0x020000", + "difficultyBoundDivisor":"0x0800", + "durationLimit":"0x0d", + "homesteadTransition":"0x118c30", + "eip100bTransition":"0x21e88e", + "eip649Transition":"0x21e88e", + "blockReward":"0x1105a0185b50a80000", + "mcip3Transition":"0x124f81", + "mcip3MinerReward":"0xd8d726b7177a80000", + "mcip3UbiReward":"0x2b5e3af16b1880000", + "mcip3UbiContract":"0x00efdd5883ec628983e9063c7d969fe268bbf310", + "mcip3DevReward":"0xc249fdd327780000", + "mcip3DevContract":"0x00756cf8159095948496617f5fb17ed95059f536" + } + } + }, + "params":{ + "gasLimitBoundDivisor":"0x0400", + "registrar":"0x5C271c4C9A67E7D73b7b3669d47504741354f21D", + "accountStartNonce":"0x00", + "maximumExtraDataSize":"0x20", + "minGasLimit":"0x1388", + "networkID":"0x76740f", + "forkBlock":"0x1d8015", + "forkCanonHash":"0x380602acf82b629a0be6b5adb2b4a801e960a07dc8261bf196d21befdbb8f2f9", + "eip150Transition":"0x21e88e", + "eip160Transition":"0x21e88e", + "eip161abcTransition":"0x21e88e", + "eip161dTransition":"0x21e88e", + "eip86Transition":"0x7fffffffffffff", + "eip98Transition":"0x7fffffffffffff", + "eip140Transition":"0x21e88e", + "eip155Transition":"0x21e88e", + "eip211Transition":"0x21e88e", + "eip214Transition":"0x21e88e", + "eip658Transition":"0x21e88e", + "maxCodeSize":"0x6000" + }, + "genesis":{ + "seal":{ + "ethereum":{ + "nonce":"0x000000000000002a", + "mixHash":"0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty":"0x3d0900", + "author":"0x0000000000000000000000000000000000000000", + "timestamp":"0x00", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData":"", + "gasLimit":"0x7a1200" + }, + "nodes":[ + "enode://09fcd36d553044c8b499b9b9e13a228ffd99572c513f77073d41f009717c464cd4399c0e665d6aff1590324254ee4e698b2b2533b1998dd04d896b9d6aff7895@35.185.67.35:30303", + "enode://89e51a34770a0badf8ea18c4c4d2c361cde707abd60031d99b1ab3010363e1898230a516ddb37d974af8d8db1b322779d7fe0caae0617bed4924d1b4968cf92b@35.231.48.142:30303", + "enode://b58c0c71f08864c0cf7fa9dea2c4cbefae5ae7a36cc30d286603b24982d25f3ccc056b589119324c51768fc2054b8c529ecf682e06e1e9980170b93ff194ed7a@132.148.132.9:30303", + "enode://d302f52c8789ad87ee528f1431a67f1aa646c9bec17babb4665dfb3d61de5b9119a70aa77b2147a5f28854092ba09769323c1c552a6ac6f6a34cbcf767e2d2fe@158.69.248.48:30303", + "enode://c72564bce8331ae298fb8ece113a456e3927d7e5989c2be3e445678b3600579f722410ef9bbfe339335d676af77343cb21b5b1703b7bebc32be85fce937a2220@191.252.185.71:30303", + "enode://e3ae4d25ee64791ff98bf17c37acf90933359f2505c00f65c84f6863231a32a94153cadb0a462e428f18f35ded6bd91cd91033d26576a28558c22678be9cfaee@5.63.158.137:35555" + ], + "accounts":{ + "0000000000000000000000000000000000000001":{ + "balance":"1", + "builtin":{ + "name":"ecrecover", + "pricing":{ + "linear":{ + "base":3000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000002":{ + "balance":"1", + "builtin":{ + "name":"sha256", + "pricing":{ + "linear":{ + "base":60, + "word":12 + } + } + } + }, + "0000000000000000000000000000000000000003":{ + "balance":"1", + "builtin":{ + "name":"ripemd160", + "pricing":{ + "linear":{ + "base":600, + "word":120 + } + } + } + }, + "0000000000000000000000000000000000000004":{ + "balance":"1", + "builtin":{ + "name":"identity", + "pricing":{ + "linear":{ + "base":15, + "word":3 + } + } + } + }, + "0000000000000000000000000000000000000005":{ + "builtin":{ + "name":"modexp", + "activate_at":"0x21e88e", + "pricing":{ + "modexp":{ + "divisor":20 + } + } + } + }, + "0000000000000000000000000000000000000006":{ + "builtin":{ + "name":"alt_bn128_add", + "activate_at":"0x21e88e", + "pricing":{ + "linear":{ + "base":500, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000007":{ + "builtin":{ + "name":"alt_bn128_mul", + "activate_at":"0x21e88e", + "pricing":{ + "linear":{ + "base":40000, + "word":0 + } + } + } + }, + "0000000000000000000000000000000000000008":{ + "builtin":{ + "name":"alt_bn128_pairing", + "activate_at":"0x21e88e", + "pricing":{ + "alt_bn128_pairing":{ + "base":100000, + "pair":80000 + } + } + } + } + } } diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index 6854f2b78a..3ae9baddf2 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -7,11 +7,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x08", "blockReward": "0x14D1120D7B160000", - "homesteadTransition": "0x7fffffffffffffff", - "eip150Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "homesteadTransition": "0x7fffffffffffffff" } } }, @@ -22,6 +18,10 @@ "maximumExtraDataSize": "0x0400", "minGasLimit": "125000", "networkID" : "0x0", + "eip150Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", "eip155Transition": "0x7fffffffffffffff" diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 065e336443..bddf5c0084 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -9,10 +9,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": 0, - "eip150Transition": 0, - "eip160Transition": 10, - "eip161abcTransition": 10, - "eip161dTransition": 10, "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": 1700000, "eip649Transition": 1700000 @@ -30,6 +26,10 @@ "forkCanonHash": "0x8033403e9fe5811a7b6d6b469905915de1c59207ce2172cbcf5d6ff14fa6a2eb", "maxCodeSize": 24576, "maxCodeSizeTransition": 10, + "eip150Transition": 0, + "eip160Transition": 10, + "eip161abcTransition": 10, + "eip161dTransition": 10, "eip155Transition": 10, "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff", diff --git a/ethcore/res/ethereum/social.json b/ethcore/res/ethereum/social.json index 87d1f2e4b1..52b442d088 100644 --- a/ethcore/res/ethereum/social.json +++ b/ethcore/res/ethereum/social.json @@ -1,8857 +1,8857 @@ { - "name": "Ethereum Social", - "dataDir": "social", - "engine": { - "Ethash": { - "params": { - "minimumDifficulty": "0x020000", - "difficultyBoundDivisor": "0x0800", - "durationLimit": "0x0d", - "blockReward": "0x2B5E3AF16B1880000", - "homesteadTransition": "0x0", - "bombDefuseTransition": "0x0", - "eip150Transition": "0x0", - "eip160Transition": "0x0", - "ecip1017EraRounds": 5000000, - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" - } - } - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "registrar": "0x0000000000000000000000000000000000000000", - "accountStartNonce": "0x00", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID": "0x1C", - "chainID": "0x1C", - "eip155Transition": "0x0", - "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" - }, - "genesis": { - "seal": { - "ethereum": { - "nonce": "0x0000000000000042", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "difficulty": "0x0400000000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x3230313820457468657265756d20536f6369616c2050726f6a656374", - "gasLimit": "0x1388" - }, - "nodes": [ - "enode://54d0824a268747046b6cabc7ee3afda48edba319f0d175e9e505aa9d425a1872b8b6f9ebf8f3b0a10dc7611a4c44ddec0fc691e5a5cde23e06fc4e4b3ff9dbef@13.125.185.147:30303", - "enode://7e150d47637177f675e20d663fc2500987f2149332caf23da522d92363be8a7880ef9150a6183e9031288a441e0457239474967a111eafce17e19a4288076ea9@18.219.40.235:30303", - "enode://6244c9d9cd288015d7ff165e90f3bb5649e34467e095a47c6d3c56e8fb8c849b3b4db683ff3c7ae8a654bbdc07ef12ee2fd7d72831ac213723281c1b0cc90599@13.250.220.98:30303", - "enode://e39f162b9f4b6ed6f098550f7867c2fb068fc66f362b3db0f45124c43ea18508f5ceef4e0e4de53d301e14a6f1683226aeb931d7401b4e83b5a583153ffdd7fd@52.57.98.157:30303", - "enode://54b4a117d66dc3aa93358dec1b31d4f38e72e4381b3e28a65ac6f1aaac3b304ebbe41d32cc864fa69a9a6815c34cf9b8965690dc174a5f72af14547b601b7924@222.239.255.71:30303", - "enode://851f14c5cc86cbc0a81acfcbe5dd99ad5c823435357219df736932c5f89ad4318f6973a553857a32d97a71793f5a35c062d46320be282aa0a80b06b9c6b624e4@13.125.232.71:30303" - ], - "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "ceed1c8254abaf069669fc6045e90482543d1f2e": { - "balance": "38000000000000000000000000" - }, - "6f22d7f8c38e0135e36be87e77fc8d4ae4b3d965": { - "balance": "38000000000000000000000000" - }, - "d016e982b7886302428d7c741392c658337513d2": { - "balance": "38000000000000000000000000" - }, - "defa96db5c8a41772bc56f68f95e307ff71a2c60": { - "balance": "38000000000000000000000000" - }, - "951ffd4253ffcf31b2895dd3f7f2a8a9bb2933e5": { - "balance": "38000000000000000000000000" - }, - "b7071dba21cfbe1b70abd7ddfd2f0f83d5d19a61": { - "balance": "38000000000000000000000000" - }, - "6ca420cd8d5407c61a9b14adcb38bee0f26e2848": { - "balance": "38000000000000000000000000" - }, - "b50d185b6cd04499a38afc0fcfcb59eaa74d0956": { - "balance": "38000000000000000000000000" - }, - "7ba8c49a444c117f2d2a50650b3f700d4ee659fe": { - "balance": "38000000000000000000000000" - }, - "83f9959ecc532dce071fcd0c62dc23cd571b689b": { - "balance": "38000000000000000000000000" - }, - "001327afce7ebb623a7d0f17b2ffc358fb863b5a": { - "balance": "9844198127334000000000" - }, - "0015ac7f8bb2a2c7d954fc2dbd4e20c0db5942a5": { - "balance": "1000000000000000000000000" - }, - "0021e69c041be2d28744b69361105ff51295da59": { - "balance": "1379639894000000000" - }, - "002cfd27bbb8164681b8762e71b2891beb127fdd": { - "balance": "25105286685000000000" - }, - "0033cf217bc765ccfc338869451588ce448fde65": { - "balance": "23425485280069000000000" - }, - "0048f1d1735979cd8ac9c0886088336b2d4a43a6": { - "balance": "10000000000000000000" - }, - "006a79cc154917cf204d8097728f290e29716d43": { - "balance": "20000000000000000000000" - }, - "007c8db36e4f649b14516dd78202670b671ba753": { - "balance": "1000000000000000000" - }, - "007d131b58388f251075a3c61020ce301106c5cf": { - "balance": "381079535880476000000000" - }, - "008e8fbffc2fdbefaa7e3be4f4a9160db826d05f": { - "balance": "10000000000000000000000" - }, - "0126d86b9814b0e78c4e01a3916bee6a7778145b": { - "balance": "10000000000000000000000" - }, - "012cb961297c837630251a173b7861e77724856d": { - "balance": "494562376059000000000" - }, - "0145886dfab5ef4f2def50a56b4a074cf5b18acf": { - "balance": "680585022951000000000" - }, - "0167918bab62aa2118cfa4d3eb80da0e71c71d8b": { - "balance": "122395119468000000000" - }, - "0182f7286ae9d4d6bc514d5175d14685d520bde7": { - "balance": "10000000000000000000000" - }, - "0184e9c8fe99d85100fe28a0e8877b14768b372a": { - "balance": "193295614762000000000" - }, - "019eff7dce7f31c2d4f7318da71d212cbf89d36e": { - "balance": "64004138198000000000" - }, - "01f3351ea66c352346244dbb79189066bed62fc5": { - "balance": "937056266523000000000" - }, - "0202ddd7f4f32bc575f7df24612f8aa9f9a7ae42": { - "balance": "106905151080000000000" - }, - "022b8c65e959cab71f56688b7073257b58bbef4a": { - "balance": "9682681149566000000000" - }, - "0245ff6382eb93ab1e8ed2e3c0bce7a1b9a9713d": { - "balance": "289000000000000000000" - }, - "025e117a69ca9244ed430732c11e550e3ee67577": { - "balance": "1861905310567000000000" - }, - "026e7457eeaeaec7898fdee1ad39be89e92733b3": { - "balance": "7529030978000000000" - }, - "028d2def8c54fcc77bf0191b183c0bc4570ec1c5": { - "balance": "9056720934000000000" - }, - "0291a087605b516e465134797b5459436d320e6a": { - "balance": "481100929805000000000" - }, - "02a4b18b3e13ec79307e712fba1867cbf7fb6155": { - "balance": "9000000000000000000" - }, - "02a812d4cebcac1a92ae470ade92fde7bead127d": { - "balance": "66793603497000000000" - }, - "02f718c94b2c8e8d62752f8632443504c1e4b6e2": { - "balance": "1000000000000000000000000" - }, - "030dab52b47b37505b72e5ca0985f65ead590816": { - "balance": "1376851176362000000000" - }, - "031c59846f75de1aefb0e8a95e0fb822fd06555b": { - "balance": "140978338628000000000" - }, - "031ee87c672d83ec73059c86a312a9e972142054": { - "balance": "96406273341000000000" - }, - "033182e860564cf695cb403c8c0f078053368d7d": { - "balance": "1504349255824000000000" - }, - "03788dc6528fa33a90e90e03295ae4b792d56644": { - "balance": "24356250426000000000" - }, - "037aae119047028157c5b3bc9d3d202b02cbce42": { - "balance": "105627739575000000000" - }, - "037d45b323cbc5cbac999c5001169646e690b94c": { - "balance": "2000000000000000000" - }, - "0390ba35c454a24519d845405a7e24df71250748": { - "balance": "1872501898509000000000" - }, - "03ab8c1e7f904db62437b16d28aeb539b2dee55e": { - "balance": "55000000000000000000000000" - }, - "03af4c69728a888fa26b1aefa439005989771fdf": { - "balance": "27704588237757000000000" - }, - "03b33fb19d165e5e33bcfbbfc009f418d71f30fb": { - "balance": "1999139000000000000" - }, - "03b34c79f8167a4e8be0f6133254d2b50cbd878d": { - "balance": "111065050160000000000" - }, - "03d7e8638b74ae44a2770287285489a95fa1ea11": { - "balance": "20000000000000000000000" - }, - "03d870bf719f03250c0dc5156a36751b3aa21f18": { - "balance": "981119649953000000000" - }, - "03de52c12b05fb8bcba3a1cfe02a0ad1bc9761d3": { - "balance": "362007990932000000000" - }, - "03e516db27b1abe008ffc57ced48f72f872d8b08": { - "balance": "3389116345657000000000" - }, - "03ef5ff863ee5f1167f38cdf316e4d52a242b750": { - "balance": "12395856876000000000" - }, - "03f27766760f2bd1cae1cb85ddf43ab59c871e47": { - "balance": "49000000000000000000" - }, - "03f4e1a8fb4eedc776f4835fcc85d0f236612f9c": { - "balance": "27210590272692000000000" - }, - "0404936ee04cc79cbb3aedfa33a53f94940f772c": { - "balance": "29919204637416000000000" - }, - "040501ffde9649be794b7d41643273ed6285ab39": { - "balance": "686000000000000000000" - }, - "040e449de680f69614120f0a2e894cde36e4adf1": { - "balance": "81993180085000000000" - }, - "041531e906dbdc70d89f5e255151d9865a059308": { - "balance": "2163418749315000000000" - }, - "041ad9f6bf970541e4ea8a14dde1e789d0fe4367": { - "balance": "44999979000000000000" - }, - "0446420c07cf73d2b3741b945c1cc8444b4ba6b6": { - "balance": "138749371512564000000000" - }, - "044c1a540b8ab286c218c2fa9d5bfbc2761e7626": { - "balance": "1" - }, - "04526b2c62911e78a939816aa4575fe30baa06c7": { - "balance": "2983093150081000000000" - }, - "04adf59f8a0ad3820a7972c6243202b3b0617fcf": { - "balance": "50000000000000000000" - }, - "04bbb42882a475eed58aae47fe530ed19c1cedaa": { - "balance": "278038763863000000000" - }, - "04cff7a7c2b9b0bf31c5ad4a5de8b0eade70aafc": { - "balance": "515406205244000000000" - }, - "04dcd325dc1fd37ff3c87da3b21c47ddfcc37cc2": { - "balance": "5831887315000000000" - }, - "04ec8d0b5157370f5a2671a2aa68ae486b7a7842": { - "balance": "10000000000000000000000" - }, - "04f50f2a6e89ee497a64c11baa90759a10a1247a": { - "balance": "25443071621949000000000" - }, - "0513a769ebef58ad3a4fd7011ddbe19799ff5600": { - "balance": "64369494797000000000" - }, - "0514c1151f356070ace281435f25c86b58280715": { - "balance": "38967380881301000000000" - }, - "052fda414fe1279c6276a237b07e1b4148a8cc77": { - "balance": "10000000000000000000000" - }, - "05431089cc62a987d0e99847e10a006233146f6d": { - "balance": "268977485219000000000" - }, - "054ed2f55028257212b996f9a3d34758d1d4ffd1": { - "balance": "100000000000000000000000" - }, - "05a68cc758560addde302baf814f2fdbe0ef2c2b": { - "balance": "10000000000000000000" - }, - "05c669d9ded79fe9e4e3718052bc7ca18a3205ab": { - "balance": "7347158140000000000" - }, - "05d77ce5c87477b05e90e829dafd8eb3a8c87823": { - "balance": "21191998933000000000" - }, - "05ef2894a2a1c6eb6c0a768d04ef5b573f357712": { - "balance": "20000000000000000000000" - }, - "0601011f80279190b96f641205c6a524a8ad5a28": { - "balance": "12025716447696000000000" - }, - "061a8acdb1a340ba7c550814831e27262708fc98": { - "balance": "234029764576000000000" - }, - "06219483e217c9ad479f76a95426f689ef4d5951": { - "balance": "1509408723551000000000" - }, - "062d0db8a650f2241f8a4295326a2570a7c771bb": { - "balance": "717459720227000000000" - }, - "0633ba746235d8fc8243751b1aa31646c299f262": { - "balance": "49000000000000000000" - }, - "06b6a5cadfe1fdc88015512e835d840e58ae4123": { - "balance": "1000000000000000000" - }, - "06d08fcbe96791514d900d2cb6c0f029d8d791d0": { - "balance": "19196168602258000000000" - }, - "06e5c0bad43a7011878b12a682abf01ccdfaa151": { - "balance": "30000000000000000000" - }, - "070656bb11ec36074d47c791c0b306394b703401": { - "balance": "1245216075291000000000" - }, - "070d84c938217163b60ed38e4937eea7158c03d9": { - "balance": "27507979787000000000" - }, - "07428c95ef3862026e54d3a963911cdc673dbcd9": { - "balance": "13792309994528000000000" - }, - "0781cb21df142ec5f67b956bf995f02f6f24985f": { - "balance": "224940990659000000000" - }, - "078c38c153b414cc4c12818fce2ea7ba09a34e51": { - "balance": "1410646136000000000" - }, - "07bfd0de7a9a1c927446aaf2d7ede55b471daa87": { - "balance": "77778844734000000000" - }, - "07d1ac83140188b8d7f4c8c607d0da22c5ba523f": { - "balance": "7713686418107000000000" - }, - "07d8ef8fc6dcde319a5af5b6cea18983bdc4c8fe": { - "balance": "3801361173000000000" - }, - "07dfab72dd3e44fcbb1ced625899bf20e0c52ffc": { - "balance": "154177778806000000000" - }, - "0817ce33d943e84c7b3261cc3e37b86b5d6d76ae": { - "balance": "90753785862000000000" - }, - "081be00a2ff62cbcb95a8eb020ac0efa33f93a42": { - "balance": "1027889807304000000000" - }, - "085ffdc6043b04653e51b1a34af20b609d158607": { - "balance": "3314058000000000" - }, - "0882c2228f5df24064bc37e8b7199199de308bb8": { - "balance": "98420617420000000000" - }, - "08918776e9a7136cedad5d0cee52f5d9dd833ece": { - "balance": "1263170315026000000000" - }, - "08bdbcff16919abc5e15fa68ece56eceef33f48d": { - "balance": "2552990000000000" - }, - "08fc8c7bd03fe1249266b233edfcf830693d0e10": { - "balance": "283490111768000000000" - }, - "090f79a4178b5180150444805f62c26cd21be897": { - "balance": "884195010282000000000" - }, - "0914a9dfc9d6ecc063a55e5320050112f305fe17": { - "balance": "15373898854941000000000" - }, - "091791ab5f8ab86f1d8f566ed221b268cbc55347": { - "balance": "2207516004000000000" - }, - "09529f8b1633ce4375451bb44b1025f6e5f9facd": { - "balance": "151697652792000000000" - }, - "09600bbb9d9b23661d269dbe1ed066d8e573b5e1": { - "balance": "802935104935000000000" - }, - "0964d2af1d5883fc0e0a77459f6a141824de7356": { - "balance": "9610980935058000000000" - }, - "097c731d1fc6792ac0f0ff92be4403c3749cc1dd": { - "balance": "165134479709000000000" - }, - "097f152b3f837d38ab1e8c0683d62f5a01d67902": { - "balance": "20000000000000000000000" - }, - "09a6772629ef0bf402ae6d27cd32e6eefb220a12": { - "balance": "20000000000000000000000" - }, - "09addb954d4e4b4e95e0c66d324115d609df5a99": { - "balance": "8435321515000000000" - }, - "09b2eb03e0fa321102196578eb40dcba3a46ec9c": { - "balance": "12723517962933000000000" - }, - "09ba0ed4dce470ba0bcb4d46b507c3b024b83070": { - "balance": "99999979000000000000" - }, - "09efbd6dfea375065be1b3a8f4541f024da21a34": { - "balance": "5870833623000000000" - }, - "0a24d4ae66edc7723bbb314e9b96dc7b9a31e813": { - "balance": "70000000000000000000" - }, - "0a3ee710909382f762648deff8ac7c8b30e2ce10": { - "balance": "407656462445000000000" - }, - "0a42b3145257154e76a97db8147c93be4cffd97b": { - "balance": "10000000000000000000000" - }, - "0a7cb6037f1eba5d19fe781335ecd37b7229c5f7": { - "balance": "74113322448000000000" - }, - "0a85d1bec4d44e309068b115abd517d3733fc56e": { - "balance": "14836218750000000000000" - }, - "0a891ba9ca7b99ecd815b1dcec9243dd4deff866": { - "balance": "178004857988000000000" - }, - "0ab69370b537d4ff5b45704fed293e46e3464f87": { - "balance": "1258876668246000000000" - }, - "0ab77a2e8ab9a3b659d1f1d37956c3607a0f9a60": { - "balance": "6283300817712000000000" - }, - "0abc7e8d52f5b0dcf1d4713e5fa4909102251dfb": { - "balance": "39307290577000000000" - }, - "0af2c0471c802d2e2b20aadf9dd4ec842d313ab0": { - "balance": "1529468143183000000000" - }, - "0b08c717bb3982fc8b92d5b3d30e5b41265a0d0f": { - "balance": "1184600154874000000000" - }, - "0b3f2aa9dc5b57b0469398d62f60a13774ec0e87": { - "balance": "132187640280004000000000" - }, - "0b3ffe85aa89e71a6e51e938c7265d2a7173061b": { - "balance": "2106793086824000000000" - }, - "0b468562e712d22b37e1a65f54b1fa825beebd1b": { - "balance": "15130906006000000000" - }, - "0b5333eb668dee29ebc0e335d74f33ffeaae9ac5": { - "balance": "125953133109000000000" - }, - "0b59a20107495e951b509187307782ca9dfa441f": { - "balance": "25000000000000000000" - }, - "0b8b7fb066601ea7744b81f6e1a21b8e489359cf": { - "balance": "101782000000000000000" - }, - "0bd7791097f79066d71ac0a2c94bce6628a63373": { - "balance": "44389955028000000000" - }, - "0be541af06e167206b5d1cbe08e8fb2b5ebc82cb": { - "balance": "9000000000000000000" - }, - "0bf178bba463f4f6c33e3d81b1a78d220f7b5d4b": { - "balance": "111784804790646000000000" - }, - "0c1f000249b1f1ac9e43c4f10e2da1cc2adf886f": { - "balance": "91251997635000000000" - }, - "0c74e46b115e19726997dd559d2b6ff1bfb79af6": { - "balance": "879229287149000000000" - }, - "0c7c1ec152c920a068c25626c22c4fae7f435536": { - "balance": "39849464104000000000" - }, - "0c85fbd7492d1ae87bf3d286c4750a34f1fd3121": { - "balance": "20000000000000000000000" - }, - "0c9fd6123e313f7d1f0cb25d99839102da08b2c5": { - "balance": "10000000000000000000000" - }, - "0cb051e3bdd9d96e667fbcc00a766d4f149f89e4": { - "balance": "1000000000000000000000" - }, - "0ce32bf6c433cbd26c6f09a1214db0374002784e": { - "balance": "3293279842000000000" - }, - "0ce6374ff04430e34edec8b6323feab2bccab92d": { - "balance": "93983447000000000" - }, - "0ce646412a1524c3f73edfd753c0ba3ee7338275": { - "balance": "10000000000000000000000" - }, - "0ced803e56eac3c99269ff7409d2d200d62d7c25": { - "balance": "49539379000000000" - }, - "0d1dc2be9f78ce2b2591e7f5b8af9dc778499bd5": { - "balance": "2235348003595000000000" - }, - "0d235583458a168e810275f907b5f87bebb2d1cf": { - "balance": "83106439283110000000000" - }, - "0d28fe6e8b7d4b8c90ef7c52b9656511ce5867f1": { - "balance": "1347248794799000000000" - }, - "0d5cbe0da660cbca831787efc45fecb20e06e02b": { - "balance": "297528508941000000000" - }, - "0d7a24f324176f6d793c3a2eb6c54d6ee47eca79": { - "balance": "25637813467000000000" - }, - "0da26a24e3650e84c52fedb36ef76225a8d9d259": { - "balance": "15467820321000000000" - }, - "0db7eaceaf3df21ebb49c56fa2d2e2c8e85dec52": { - "balance": "196000000000000000000" - }, - "0dde52823bd8fb2cb179e6d417c07ff285c31775": { - "balance": "347321514878000000000" - }, - "0df9585f1aa83189e0a813f5eac6e6e0b2bbb8d8": { - "balance": "2891430551000000000" - }, - "0e09af9368f05b476164953b7b9db60ac95248f0": { - "balance": "573644391203000000000" - }, - "0e18315dd2b663ce4859b5bed854403191452c2f": { - "balance": "24174325261000000000" - }, - "0e29bef5f4f66c38a0f05cca1e4938d57ff09c70": { - "balance": "10000000000000000000000" - }, - "0e443353b42e042ff5168e9b3c6de37070368223": { - "balance": "20000000000000000000000" - }, - "0e8cb6e439516b312158f169b546937b715db3f2": { - "balance": "8049136367000000000" - }, - "0e980fab23be601f3abec7b9a24e1335a5e765c8": { - "balance": "8301885845897000000000" - }, - "0ea63fef218ebf570a4ee62ef6ed712dbe623c44": { - "balance": "10000000000000000000000" - }, - "0eb60e3512336e4447ceeb8664ce0ecaa3eb0bdc": { - "balance": "41401696400000000000" - }, - "0edafc1058879a9568e711445b18ec4da31d2480": { - "balance": "10000000000000000000000" - }, - "0efce4565062b23b43dbc1e261463e363e4a5b4c": { - "balance": "10000000000000000000000" - }, - "0f08782c04bf7249ab08f4e251abc60aee792a96": { - "balance": "1380257622493000000000" - }, - "0f19bfe1eb24def828bf1be69791c63ba1de1263": { - "balance": "2223687184885000000000" - }, - "0f2171161eb9674218add261be61d18d86b846a6": { - "balance": "121000000000000000000" - }, - "0f42ef6c5690b6c95f8b8c9dbdc16f717c04852e": { - "balance": "81000000000000000000" - }, - "0f47f5063d321b34a0d800951bcdc3f53c07e32c": { - "balance": "5288516165000000000" - }, - "0f529a9beedb2c2a087a220f0013cea4f8454bfc": { - "balance": "114585457979000000000" - }, - "0f6751d10aaf855454a6e9e4241cfcae3b0ed732": { - "balance": "94160300063000000000" - }, - "0f6ed5a4c3ec100afcd59e9066ba7fcb63cfa6dc": { - "balance": "1000000000000000000" - }, - "0f77025519cc76c38e1cf0bd8721f4a5b9c814d4": { - "balance": "834620571043000000000" - }, - "0f773db2a1a96b775e4481575704f5f087b067e0": { - "balance": "554268361745000000000" - }, - "0fa0f73adbe82f8e09f8adbce15b051971e289c3": { - "balance": "11329911975000000000" - }, - "0fa6397d747d88a25d0c755b3be4eee0e3f68912": { - "balance": "31394936138000000000" - }, - "0fac8635a61bf7652d86725cc75c307949bd4f2a": { - "balance": "49000000000000000000" - }, - "0fb0ce787306ce13dcd614ab3d0e15d9772106ac": { - "balance": "50000000000000000000000" - }, - "0fb1d306d240360056f60f197dc7f68f732ac515": { - "balance": "20000000000000000000000" - }, - "0fe3571f498a6d945e123ac8ff6e3fed348d9432": { - "balance": "20000000000000000000000" - }, - "0ffd6b01ea9a7bd2576fe4a5838fe09e44c1639e": { - "balance": "100000000000000000000" - }, - "100bde3d73fda700369e78229127b58d2ade9177": { - "balance": "10000000000000000000000" - }, - "102028c7626970a28677bbdc7733484c8b14c2d2": { - "balance": "500000000000000000000000" - }, - "10245044be6a46ad41d4559129cb59e843379cf8": { - "balance": "857437279765000000000" - }, - "10417d0ff25c115b25915dd10ca57b16be497bf6": { - "balance": "10000000000000000000000" - }, - "10579870e6685ed7e97dd2c79a6dc3528bae968e": { - "balance": "5187866041491000000000" - }, - "109736465b4bbe31ea65ad01fc98f04498271e6c": { - "balance": "20000000000000000000000" - }, - "109c0535a4a86244c5094e99167d312a77657dd5": { - "balance": "138277702073000000000" - }, - "10aa08064689ee97d5f030a537f3cd4d8bbdaf74": { - "balance": "10000000000000000000000" - }, - "10d8bc8c3d3e2010e83009290586ad85b73321d1": { - "balance": "25000000000000000000" - }, - "10f22b82460252345753875555de2cebebe63a93": { - "balance": "765947730644000000000" - }, - "11111c3a2cfa55e52d6aacf533e1d412f8c8c01c": { - "balance": "4827254128275000000000" - }, - "11386103a0bf199db9504b617ccb3bbd780eb9fe": { - "balance": "10000000000000" - }, - "1156a129183e5bdfdf2bf7a70963285a979363a0": { - "balance": "10000000000000000000000" - }, - "11589cf70a6a4fbaac25224e2ddab222333f78e6": { - "balance": "49000000000000000000" - }, - "1162fabeb3eb1e4124179b00c4a1e01503023f54": { - "balance": "817145350625000000000" - }, - "116a7d140f4b7f9b4689063a8417ac07a32bae00": { - "balance": "106088220142108000000000" - }, - "116dc38ddb4b138b19ce6a51e5922c287da5c86b": { - "balance": "100000000000000000000" - }, - "1175f84f835a5ae40d49b8ca17e3e474c1eceef7": { - "balance": "1698584794716000000000" - }, - "119f822a796fee9c41a488949fcb14b589ffa628": { - "balance": "20000000000000000000000" - }, - "11a99f6019b6a53f5dc8cbd0c34f1ee75ced33b8": { - "balance": "102126982156000000000" - }, - "11b9324406068e8bf598d3a9ea59ef31c52f51fa": { - "balance": "6525925895203000000000" - }, - "11cb7be6869a10f5f9e8a47c6c92f729b083084b": { - "balance": "182959434323344000000000" - }, - "11d96a76166ec579e2b6cfa903f66da4af669351": { - "balance": "1000000000000000000000000" - }, - "11fcee55f78278df60f50096d45da1aafe72722d": { - "balance": "222859488179000000000" - }, - "120a1fc914718acd85bf92d9492330165d78075a": { - "balance": "3736627235906000000000" - }, - "12366136d83c77befdc30e04d4f5d808419f504f": { - "balance": "88008649003000000000" - }, - "12435af3f2f92ec43e8f2894be9c72fa932880fe": { - "balance": "1590548436852000000000" - }, - "124ff67125a00aed24e58b6d64ffa887a59b48a4": { - "balance": "20613022349070000000000" - }, - "1296f04910ebc89556ec7ab1b178fdbf14d0295c": { - "balance": "36000000000000000000" - }, - "1299f180e42bfaa1162d36110d29ab062e43e1c8": { - "balance": "321570118362000000000" - }, - "12abac62150c526866ec958cd0e3721b2c78d550": { - "balance": "51898545633262000000000" - }, - "12b345087cee385b9adccaaaa6741b767c82d7ea": { - "balance": "36000000000000000000" - }, - "12cd5e8c0c93f8e34b589b95954b719f54d1515b": { - "balance": "1000000000000000000" - }, - "12d262cdd25edc39b6fd9ae78184eb548e513927": { - "balance": "500976168000000000" - }, - "12d933448218629702c48547b3446b629ec65883": { - "balance": "2168010577395000000000" - }, - "13054aa42d3e119220ac359641c15f8b54bfffef": { - "balance": "24986834005530000000000" - }, - "130bda09f463a982199849ae617062a1d68f3a85": { - "balance": "154504844790000000000" - }, - "131a5da679863c05dc627d53634f2925ba0ce731": { - "balance": "10000000000000000000000" - }, - "1334f2752b5c21f681ba9e23a9fe95a85f8e05f1": { - "balance": "121000000000000000000" - }, - "13634512e2ae79fe3febb9e55e03b47bc350d7ba": { - "balance": "338331304738000000000" - }, - "136fae842aab625768bef9079ee1711e8c007d8f": { - "balance": "2759741687626000000000" - }, - "139fa969e8b74bee1f6113a362f15060ea998b15": { - "balance": "10000000000000000000000" - }, - "13c7e1d694bde6f8f6a31eb6c99f38dc739d61fe": { - "balance": "10901074773586000000000" - }, - "13c849944ad6ad12a46c46973d562bee8284f46d": { - "balance": "35114615504000000000" - }, - "13ec3aa8f4a427ecdecc7901060ccac9bea7a61e": { - "balance": "10000000000000000000000" - }, - "13f478c74acfd6897d13e602a8d362893f4fd038": { - "balance": "3521111850000000000" - }, - "14403970d0784a6458a7bf2584a53d14234e8860": { - "balance": "25000000000000000000" - }, - "14440bb7410337e34a064a92206075575f5362ee": { - "balance": "14918844868393000000000" - }, - "144a88e7a8af70b8bef5c4b70ee0cff771d0c252": { - "balance": "67961927542000000000" - }, - "146b79f474176a4b0069199b03669ab6467a4787": { - "balance": "122518123211000000000" - }, - "148893e7811c36c6bd1ada367681ab8327b3b2fa": { - "balance": "1313118418375000000000" - }, - "14900a17784e3b4d89d98b6cb31c74c685418b89": { - "balance": "131112181597000000000" - }, - "149a483758a98ffe28f7f25cfa17d7433f852ebe": { - "balance": "10000000000000000000000" - }, - "14a03c8e84f07c5596687a98d1e0b1859e9b34ac": { - "balance": "55000000000000000000000000" - }, - "14c7899cb34b5447d6363d4e8355113ebf4bcc66": { - "balance": "197554844582000000000" - }, - "14efa63ee285277c0f8e0d5cc22193e17984e11b": { - "balance": "106221254735000000000" - }, - "151c6099b3fb5b18e0e36a3335dff186dcd2904d": { - "balance": "4304311254087000000000" - }, - "1525dce233a971eb1387f130fdf0e5bf3455723b": { - "balance": "45004174531000000000" - }, - "15271904676f2bc2511294e500152d05ea9acc85": { - "balance": "9300898622566000000000" - }, - "1556ba42ea69d72c1d0faf802906645268e36aac": { - "balance": "171939212653000000000" - }, - "156558fb71ff986953d899c9916a121fd047675c": { - "balance": "290926338537000000000" - }, - "156fbf32614aac2cf462952ec1a3f141f797316e": { - "balance": "6084388860000000000" - }, - "15b9497d6bde8017baf3c29e12430e05a47efbf4": { - "balance": "206126229839000000000" - }, - "15d532e828bdcaf1246696d679a2eb66a154db5d": { - "balance": "69656571015000000000" - }, - "15e26a60cfaf23dfd9bbb999a30904d11b6ddd05": { - "balance": "9839303178835000000000" - }, - "15f3be2f11ee3b19472cc3d171931f050d8629a2": { - "balance": "13572825921000000000" - }, - "16254bed335420e5f793de2295b0081ac41a08d1": { - "balance": "144000000000000000000" - }, - "163aa91bc2ad588116141d48fcbd943985455cac": { - "balance": "618250979557000000000" - }, - "164cff4b9341d536b8aaf2d1dd0e3ed35ecb1db7": { - "balance": "671554639913000000000" - }, - "164d2a9a63868ac25bfe26ecba446d7ce256c351": { - "balance": "7233638188261000000000" - }, - "164e759b64d3ee0a23ec3030f50a1b454a6ec15b": { - "balance": "12281161499000000000" - }, - "165d4a0f23c016b8064adf0dcf7e31bc06350777": { - "balance": "256757922324741000000000" - }, - "166b862954dacddc3333aba4edbe523d693df858": { - "balance": "123677971414000000000" - }, - "16858eb1a6f0e7ff01b91aa9c92d0a433a5f767c": { - "balance": "500000000000000000000000" - }, - "168909a1c2a43cff1fe4faeac32a609c25fbd1e8": { - "balance": "62258808044224000000000" - }, - "16987ad8e10dda7f9e5d95c0f0ee36f46b10e168": { - "balance": "10000000000000000000000" - }, - "16b5dffce79573300a6514ace5f2e844d26fc64e": { - "balance": "5576805697087000000000" - }, - "16e01370a93befe24f6ae6076cd04c84cd3515b1": { - "balance": "1922179181578000000000" - }, - "16fbafd4fc871c7589e63062133793ab244c2019": { - "balance": "2865030627000000000" - }, - "16fdf76180796c6e4335eaa2842775b2e4a22e0b": { - "balance": "20000000000000000000000" - }, - "17081d4d6ebb9f4b163e181a59c2102c99fce6bd": { - "balance": "490625378000000000000" - }, - "17218ff455aa87b29ad4c4f7ba21e9c6f74fc97a": { - "balance": "1607392037652000000000" - }, - "1725bce47f3700f4646efb343f950e2e8ba66607": { - "balance": "58472967071000000000" - }, - "172c5f71aabf072507664471ebaa435779d74a32": { - "balance": "16000000000000000000" - }, - "173a065f351ee0513cfebfe9b950fd2c641fc8cc": { - "balance": "25000000000000000000" - }, - "174e1793c96cefb584ae0a67fff85c65065dafc5": { - "balance": "50221000010000000000" - }, - "1794bc4d622d514f95da5404358ed404b3f59aa3": { - "balance": "36000000000000000000" - }, - "179839d61e7c7a0382fe08e0573bcfbe42a108ca": { - "balance": "203299791419000000000" - }, - "179eb30b5b28a961eac70a919d26ca96e6472166": { - "balance": "55000000000000000000000000" - }, - "17be72168606fb5d27761157e48fc14789f84634": { - "balance": "311205588354000000000" - }, - "17cefb6611033759b8755197b983de2d7e98315e": { - "balance": "10000000000000000000000" - }, - "17e07cc7d89bcd1708b1f05ab6e1252c629d71cc": { - "balance": "903234908997000000000" - }, - "1811be559b657685c2f163122479101c404325b0": { - "balance": "10060694170000000000" - }, - "181417a4883c429ef26a4baeb48e70d4f00278b4": { - "balance": "4621446218088000000000" - }, - "181d345cd6b5f518bdab8d40f5d4896a725b3f3d": { - "balance": "114349561983000000000" - }, - "184625e544aa31552d2911023a892f739df84be7": { - "balance": "5303698708000000000" - }, - "185e4f6eee203ca3c089baa1e643ff1aab7cc8f4": { - "balance": "33969718257699000000000" - }, - "188e4a1a7b23ff35ec90b7bf7561db9e3c0f53bb": { - "balance": "394325508701000000000" - }, - "18a4dbf513be132f9ecfd69e3eb683d710e28c4b": { - "balance": "5997985132329000000000" - }, - "18c9298f62635ef47d0ef215b8a693af60829c27": { - "balance": "100000000000000000000" - }, - "18e7e2ee0c86bc1ba3595fee3d40257776fe8172": { - "balance": "185584626033000000000" - }, - "196575e74499b741877793f8c8facf2f3b1ddb8f": { - "balance": "30318381929000000000" - }, - "196df33f2d3ed473e6e07650419969f4a39fd03b": { - "balance": "15442864665000000000" - }, - "1975c5293ec9c72a28e6cc74173cdfd8de682fea": { - "balance": "103624886552134000000000" - }, - "19832cd1b2fc4138c8d9291a0f404d3c4326b48f": { - "balance": "4732362673000000000" - }, - "198705f46f31c7ca22f5b88fab210bc5b0c7647c": { - "balance": "548940869737000000000" - }, - "19a5a213e6abfee29f17e871222cbe9ac45322c8": { - "balance": "10000000000000000000000" - }, - "19ab9a7a4e9f9c08c9b4295c406b78389a864ba7": { - "balance": "369299839157000000000" - }, - "19f19f5f01b3f6a1c4f645dc7e3992b1196ccb7a": { - "balance": "97759406000000000000" - }, - "1a11a0b0081522e60e16f154e093ac2e005d24ee": { - "balance": "88024675252000000000" - }, - "1a27309b0c09be2234fd64afdbcfb099f8e2e7cd": { - "balance": "10000000000000000000000" - }, - "1a3d61754974bea23503a61ef0fe584b7b6e6cf3": { - "balance": "326950210355000000000" - }, - "1a49bbde1457a8d4c247606b206ac8d4d389da5a": { - "balance": "402438941516000000000" - }, - "1a7a4b41be64fff3a31eb6166db59741e073d0f7": { - "balance": "250000000000000000000" - }, - "1a8d282e82c606e992f69ce618ba634d98bf2683": { - "balance": "20000000000000000000000" - }, - "1aa0ba27662816e5e3d79e223cc18f5dfef089cf": { - "balance": "187581622694000000000" - }, - "1acab416a1d3e8caa65faca378c79aaf2065b851": { - "balance": "1000000000000000000" - }, - "1acd37af3f87da1dff743dfcb97038d178b1dc4f": { - "balance": "708034481300000000000" - }, - "1ad8f036022c3e5258455d6aa05fb4be5dd121b1": { - "balance": "42957064709000000000" - }, - "1aee811e06c579c21fbcc3b53d2dcf9d5f24808e": { - "balance": "52480060284048000000000" - }, - "1b03b7a4e9908c3531618f49f8d050ba6afb4de6": { - "balance": "28410489187000000000" - }, - "1b073d026e93de51db34d5a8e19047784c277ea1": { - "balance": "20579129628026000000000" - }, - "1b0b87e414bc8fe4920fe104b6de7d17db3a1a19": { - "balance": "10720000000000000000" - }, - "1b411c692c80948e59cd805a0f8574dd67519288": { - "balance": "5416615538000000000" - }, - "1b8d57e995749618c7bb3e60194ac6fc57e9b3eb": { - "balance": "10000000000000000000000" - }, - "1b913efde1255516346b40ae2a48ebf62251682d": { - "balance": "100000000000000000000" - }, - "1ba7276c133f93d43db2f2caddec08e0167eaf15": { - "balance": "82559173174000000000" - }, - "1ba919f7742160cabf2756eb6eae67b92530f3f3": { - "balance": "1102304139883000000000" - }, - "1bb20857de494694fe15bd11f8cac1218435fbc0": { - "balance": "10221322567000000000" - }, - "1bb5c5e81d451f03e899852edc8556a9f7aac5df": { - "balance": "18781017696028000000000" - }, - "1be3507349ed07d3e7902951d490f560a75e96be": { - "balance": "660691718918000000000" - }, - "1bf1c0b2e6f64b612f35f2bf98d894b13dda9bf7": { - "balance": "3050161851140000000000" - }, - "1bfd3c2ba6a537e97cedd542cd554a5050963d54": { - "balance": "20000000000000000000000" - }, - "1c4af5003f9e7223f4141107d21640e4a85a4827": { - "balance": "612390629874000000000" - }, - "1c6a94810bd0afcf79ceea11afe86c34f6813211": { - "balance": "10000000000000000000000" - }, - "1c7e277460191c886cb1647173d27122c2146252": { - "balance": "209062806527000000000" - }, - "1c818ffa9caa61d512fa5d7d6e566f3ae37d5434": { - "balance": "454897845316000000000" - }, - "1c9599d5f8e5eaf8f68d35d52132e15a153f6d3c": { - "balance": "36000000000000000000" - }, - "1c95ab5229fd08c638a1728c022f09291b8dc55d": { - "balance": "20000000000000000000000" - }, - "1c962808c175ee5e5e365483d066c8ea95993700": { - "balance": "1362779746855000000000" - }, - "1cafad295b2188f10192c8a32440931f7e3554e4": { - "balance": "36000000000000000000" - }, - "1cdc2899ec563d79569d1ba776bc03cff331e786": { - "balance": "572163587827000000000" - }, - "1ce0042e7b4f13589f5f8490836dc63e0ca60c3c": { - "balance": "25000000000000000000" - }, - "1ce62051fd7801d294bf31a7b44cd87510e8b545": { - "balance": "2008112411284000000000" - }, - "1cf20f30cd901b2e5fef3f948289dafaaabaa77d": { - "balance": "1444000000000000000000" - }, - "1d449764d38b7a4ac848f49e2dc99df02dfd8a53": { - "balance": "48215693645000000000" - }, - "1d635125c494b1137ca5f15ac95dd6d93c3a9546": { - "balance": "10000000000000000000000" - }, - "1d85a61353c3e0b6d34e105e35c8c7833b6a1e35": { - "balance": "16000000000000000000" - }, - "1d969134ee156c41c98c3721c5dbb092c0b581a6": { - "balance": "64000000000000000000" - }, - "1da12434596a9c318dab854f06d404fe61f0a69d": { - "balance": "16675185416000000000" - }, - "1db0d23fb63681958a66e716e99df3e0b848fd12": { - "balance": "1103581911968000000000" - }, - "1dc628820da657f07ab5eb887d5f512378b5b61f": { - "balance": "6272287019755000000000" - }, - "1e05cba75b0dd379037940352e0073564957b7d9": { - "balance": "12453446342664000000000" - }, - "1e13f037a92ab6f19c4484ae3301b3ac6f48575d": { - "balance": "106244918916000000000" - }, - "1e167bc07f094915c00e7aa4c43b607ed2c998b9": { - "balance": "1000000000000000000" - }, - "1e1f9409bf92c3ef59aa2fd82dce55cd90e23f19": { - "balance": "99139000000000000" - }, - "1e4dfea7871d941e72a161022b62fdb01818c86d": { - "balance": "81000000000000000000" - }, - "1e5d0b525228167334e94314a201388bba08153b": { - "balance": "1138044078759000000000" - }, - "1e6633290c9898abf5fcac54396de770164edc5a": { - "balance": "25052055674000000000" - }, - "1e76296584058670ea80fe9a39d8f457c03747c5": { - "balance": "10000000000000000000000" - }, - "1e88b2c8dcd289929e51a15c636d0b0f3b035569": { - "balance": "87357600832000000000" - }, - "1eb59a1732a159a91a9371650943840e0eb61174": { - "balance": "20542821429000000000" - }, - "1ee077bdef6d45d491602342cee008cd1e2912e3": { - "balance": "10000000000000000000000" - }, - "1f1ebf2f80afced68424cb7b0b966fdf42d508a4": { - "balance": "1460082126494000000000" - }, - "1f3d4a903bd32a537efae19592f5516698c95a20": { - "balance": "10000000000000000000000" - }, - "1f6431696efc6f1ab98dcc2ef0e8553da697e6f1": { - "balance": "20000000000000000000000" - }, - "1f657552b745acbdf731f2ad107d6362480abc88": { - "balance": "162042599568000000000" - }, - "1f699a7682c1266291a3f49e19cac0846470abf5": { - "balance": "712268213248000000000" - }, - "1f7a332dabb00851705274c59187817d859cb9a4": { - "balance": "199999999160000000000000" - }, - "1f7c333047e168f5d3408c42a4919bd44b8f7961": { - "balance": "3918096658000000000" - }, - "1f8226f7a4525b9f3cd4da3acc1bb34529f8d28a": { - "balance": "3530829464000000000" - }, - "1f8b6fcea9e0991ad0b0b25dc65748518a28713f": { - "balance": "142069368416000000000" - }, - "1fa3de6913e4de78cc4828e246554785950c3c8e": { - "balance": "178437291360000000000" - }, - "1faa75d57fd597d2b58d2ac6f65bc2bd5946911f": { - "balance": "13092024644362000000000" - }, - "1faf1721dba3266cde1e04a7e9c789bdabdd930d": { - "balance": "862698523071976000000000" - }, - "1fb861559361701fca1df6ab4ef4d2fb9d2d7e13": { - "balance": "100000000000000000000" - }, - "20154d678cdde9ca1c0acb94726f26617a4da0d8": { - "balance": "2288800561677000000000" - }, - "202484a46ca9d54d0d456bc38e2a74ec5f469349": { - "balance": "50178714107336000000000" - }, - "20324278018b4d8e0c49e0fd1be35d3494079165": { - "balance": "484082383314000000000" - }, - "2033ef68ef6297e9229bb73e6486330543aa3eb7": { - "balance": "51260669473000000000" - }, - "20b1e0ab7b9d62a314946b55a5775f24ae3cfa00": { - "balance": "1540424185584000000000" - }, - "20b61f2eb5e18b1e8568d18235918f9e2f596c32": { - "balance": "10000000000000000000000" - }, - "20ed8ca39dd148edf22e03b8021af32cecadd42a": { - "balance": "20000000000000000000000" - }, - "20fd5feb799fbb021ba262d28332b4dda8f44a2c": { - "balance": "7607475714434000000000" - }, - "215ab8aad1c8960838225294d086f0786c2dd796": { - "balance": "19929201327000000000" - }, - "21681cda53aa1a4cfb3e3ea645c8eeaecfc3ba4f": { - "balance": "10000000000000000000000" - }, - "217b75eaf2c0be12108120ba56ddb709e1885324": { - "balance": "36000000000000000000" - }, - "21be1d75b93e96017f088f1ca64ba7076c8edf07": { - "balance": "150798073752000000000" - }, - "21ccdbe0216b486cb39c94ed13767aa061c75ce9": { - "balance": "11070639373000000000" - }, - "21f2289f2d274bddd7928622fffdf3850d42d383": { - "balance": "268859368544000000000" - }, - "21f54f92a7d9a91915e1751ceb02cb8e3ed3d622": { - "balance": "10000000000000000000000" - }, - "2202c70ec23f4605394d69944edd9f90e488eb61": { - "balance": "9000000000000000000" - }, - "220e2253e1ab9ec348cc28d38bae4cb2d5d9cf8f": { - "balance": "116100821631000000000" - }, - "22328e434957107884854999e666ad0710187e3b": { - "balance": "233364805270000000000" - }, - "22851c0487d119ee3f150010515358d6ff14807a": { - "balance": "104464221701684000000000" - }, - "22a38000f5eca29001e387b52c18fb6030683fac": { - "balance": "55000000000000000000000000" - }, - "22b655a19810307750ed1b6b093da10a863d4fe2": { - "balance": "11840799203605000000000" - }, - "22cc48cf48e8ee207bc08411240f913a4e594529": { - "balance": "10000000000000000000000" - }, - "22d6ea6cb8a9206285ccddd3b6d0d1471ba66f17": { - "balance": "64000000000000000000" - }, - "22e2f41b31a0c69472a1a02d419886539b7b6197": { - "balance": "39885451304000000000" - }, - "22e962f91d01480d027ee0060030f529a7a64c8f": { - "balance": "93285203531000000000" - }, - "22f169328fb1104b386ad7fa69f0c7bf3e9a7d3b": { - "balance": "63366769386000000000" - }, - "22f35f5e0e7a8405714de66a5875c7ef84ec4891": { - "balance": "60944382032000000000" - }, - "23041bdc8d371dc29ffc890f19317dabeef12634": { - "balance": "402327389857000000000" - }, - "230eff5e8595f418686737ae671f1f1d225080a5": { - "balance": "114574598112000000000" - }, - "2331e1756d9800800fc9b54ee6e43e1150b6e58b": { - "balance": "44594796226000000000" - }, - "233a72b132e4ab1d3884274d4402d1a2a6399f0b": { - "balance": "1372148909093000000000" - }, - "2369d9dbbfd0f8aa8a3d84d8f2aea840a0cdf760": { - "balance": "500000000000000000000000" - }, - "23754e5cef31ab60aa97a0c8f9ccb4f2969f2d6c": { - "balance": "24764775861000000000" - }, - "2387973589fb07a8c1ec92492c0b8ba9ab5e52a2": { - "balance": "11642113696681000000000" - }, - "23950cd6f23912758ebe9d412166e27994fe6ec2": { - "balance": "100000000000000000000" - }, - "23b383e11573f3ca9be84e1e11694f58a432324b": { - "balance": "206558238838000000000" - }, - "23c329bb641fa51122ea476e3bc614f5d4f9cf00": { - "balance": "35908627324000000000" - }, - "23cb9f997c39853486adfc1a8b029874d1a6af15": { - "balance": "1400984459856000000000" - }, - "23ee14215c531f6ff1baef2c74b1754306f4532d": { - "balance": "10000000000000000000000" - }, - "23f641f765cf15665b6c28d77229d3b2a58fd857": { - "balance": "266570948120000000000" - }, - "23febb49d9541360b9d099377df16b5630dfbb52": { - "balance": "228513797641000000000" - }, - "24082040652a09cbed6504f3dd6491e0ee9d2bff": { - "balance": "91160839809000000000" - }, - "240d3edf4aaf42e99d366ca36d82c370271b8e8d": { - "balance": "65535355843947000000000" - }, - "242b63ebf47678f17c176d5d4a670e46e66a823c": { - "balance": "469668185647000000000" - }, - "2433612fb939236a87a97261ff7b3bc7b754afb1": { - "balance": "20000000000000000000000" - }, - "246bb03a3fab572b3c64fc23b03dfda42b7ea34c": { - "balance": "936364046000000000" - }, - "246c510dfaf5b49bc0fe01c8256d3879c1b5f89a": { - "balance": "100000000000000000000000" - }, - "24bf4d255bd3db4e33bff1effd73b5aa61ae1ac2": { - "balance": "302436106595000000000" - }, - "24c0378e1a02113c6f0c9f0f2f68167051735111": { - "balance": "36000000000000000000" - }, - "24cf04b7450a0fac4283fa6fcfef6215274b273e": { - "balance": "83714002622000000000" - }, - "24f5f8e7d6a23b55c95fcdc1300de05f9d2abd83": { - "balance": "20000000000000000000000" - }, - "25204bfb27a08dbdee826ad6d9c3398ec6d14fe1": { - "balance": "5929256591480000000000" - }, - "253d95911b4174805d13706b449879413b1672be": { - "balance": "37012901440000000000" - }, - "256065f7e919c508b68957b1d2c9120d29181e12": { - "balance": "25000000000000000000" - }, - "25624542c14c2ecb9a0fe7daec9ac5af16868ee7": { - "balance": "16000000000000000000" - }, - "256d05b6de445179e504a6c94ce1253ae159e19a": { - "balance": "12048598744001000000000" - }, - "256d37fc8980a969063b1f7e7fda8b87d4210da6": { - "balance": "107293553721000000000" - }, - "2588af91a0e8f3ba3ab636781bb84e263acd1f52": { - "balance": "8910000000000000000" - }, - "259774584d4fcae1d84f5997c00beee8a380e46c": { - "balance": "1140713354605000000000" - }, - "25bda1418853a22eb6a5380e8a2862d2a74949bc": { - "balance": "10000000000000000000000" - }, - "25cafdab7f79f7b95d55b4c2dda1f4080aa74d64": { - "balance": "2525573681000000000" - }, - "25cca69b41bb51c51b387c47ece83f30b9a78daa": { - "balance": "163449631440000000000" - }, - "25ce9dabd0a72b02e0056931155ba99c94cbc837": { - "balance": "230073284349000000000" - }, - "25d9d1785c96acddd926b3ed52987ff74f9083f6": { - "balance": "780460361789000000000" - }, - "25e56bd3e1461f27db4eb0cce8bb5ca1574401f8": { - "balance": "1001937531200000000000" - }, - "25fa2162d5c86cda10e4be42c14a24329e455ad8": { - "balance": "50000000000000000000000" - }, - "260a932a23b344056acb8e676714ffac0a13ad2b": { - "balance": "2000000000000000" - }, - "2622efe8836095fcf48d9c8019f48c8320d6e0f2": { - "balance": "5451866545636000000000" - }, - "262447c4d8826ed23ea25e9703a11b4ad3ae9388": { - "balance": "33992454005000000000" - }, - "263eee3badb9b0dd13579c09361806503705a1de": { - "balance": "1134831344000000000" - }, - "266f4c232ebc946c46979cd90d70868380e186d8": { - "balance": "20000000000000000000000" - }, - "267dfe6fa918686942f5e1d19d5fa615f6f2086d": { - "balance": "3569373363935000000000" - }, - "268ad2272c2b71243a7391020a600fd8dfa42d45": { - "balance": "122768017414906000000000" - }, - "269e4f43be9865f05a277933c2fbb466659ada7f": { - "balance": "22064992930948000000000" - }, - "26ae161c20acb26a320fbfbd60c97335cda28bca": { - "balance": "170710653621000000000" - }, - "26b4da905780fb0c5c3e7e5315989fed3aeef135": { - "balance": "20000000000000000000000" - }, - "2704312aa5a4202f14fa3b08e587e4f0ef13accf": { - "balance": "124259630994000000000" - }, - "2704e4b0e8df0c1f298843109ae3bb26c29a22c4": { - "balance": "3155521256785000000000" - }, - "2709347d12251c01aac6455108c6bebe72f0af2d": { - "balance": "220898650215000000000" - }, - "270a32b41dde877463d2106ea4f4529557a5e1d3": { - "balance": "10000000000000000000000" - }, - "2738b3746d6bda9bd72858eaa76f8b5ce7a88c8c": { - "balance": "10000000000000000000000" - }, - "27593d2271aced83e81034e8dd603d098238320c": { - "balance": "20000000000000000000000" - }, - "2771ba4b5944bb12d74b1888255c60e0db215fd2": { - "balance": "412946979808000000000" - }, - "27780086136ea3e97d264584d819dcb2176d7544": { - "balance": "292224348060000000000" - }, - "278936fff8afb553043f038c39fe93906bdb1f4f": { - "balance": "1448466441752000000000" - }, - "27aa0d45d3506f8446816e0e2e9675d46285f6e0": { - "balance": "20000000000000000000000" - }, - "27e655dcc5728b97b3b03fb2796c561090dced1a": { - "balance": "9841344000000000" - }, - "27eb0529279f7a71e50efb70bb1767cbe1ffa4ce": { - "balance": "10000000000000000000000" - }, - "27f564956c837d7949739f419d6ac99deb33d790": { - "balance": "1505247707018000000000" - }, - "280f5618a23c41ac8c60d8bef585aa1cc628a67d": { - "balance": "1316618646306000000000" - }, - "28167a591d66ae52ab22a990954a46e1555c8098": { - "balance": "1000000000000000000000000" - }, - "28257eeb8d20f2fe5f73b0ff2eca3214e30ece4f": { - "balance": "95924728584000000000" - }, - "2827abfc49828db0370b0e3f79de448d46af534e": { - "balance": "769862008499000000000" - }, - "2832b92434e3c922206c2408442bc8274606cbd9": { - "balance": "103421320914027000000000" - }, - "2854f190a38e9b9c04cf499259c6577a68b0b5ed": { - "balance": "144000000000000000000" - }, - "288923bd91be164496e5378ee484f0e4c6c16ed6": { - "balance": "10137243270703000000000" - }, - "2897ff80794153edb721801fb91c6d8373c965f4": { - "balance": "10000000000000000000000" - }, - "28aa06e2290010374097aa2f87a67556d8d68083": { - "balance": "84783245638916000000000" - }, - "28b04ec8eb18b0c6a384f9d92cfb44d1d43ecb51": { - "balance": "14364248730194000000000" - }, - "28db0c000cad3a524bb68dfdd74ffd47b42fb13a": { - "balance": "43586590410000000000" - }, - "28ecd4c5fe98cff66a5b8423f4a27cba9634e2d0": { - "balance": "56106658052000000000" - }, - "2930822031420731f09dce572554a8b8c1eaa09b": { - "balance": "1170839742000000000" - }, - "295154c4522d7bcb2e24b7de9c543dcd1c5f51d9": { - "balance": "179028680906000000000" - }, - "296be4ef7402b00d7af673c1770a50162d7ab602": { - "balance": "8206640005889000000000" - }, - "297b84150756fa89101dd59750a7beb36fb8785c": { - "balance": "1168894124400000000000" - }, - "297cfb72cd1b8b2808fd1b25cdcf7d8de279ad96": { - "balance": "500000000000000000000000" - }, - "29cec0eca9f8508a1ba192a90bb6dee18c40745a": { - "balance": "260217025084000000000" - }, - "29d8f7e72bfa297f17fdce9cf8f4a398f547e200": { - "balance": "307787433251000000000" - }, - "29e14b01c59ba894dd090382fb193ea441164b90": { - "balance": "229028661439000000000" - }, - "29ed634e165084b720e446d28893dbeecd6a7018": { - "balance": "226530464200000000000" - }, - "2a0f8136d43248233f652fe579ef3bd2281dde24": { - "balance": "4007544428000000000" - }, - "2a10204a0c7c9f7701e33c1b71c9427ea16e2e45": { - "balance": "50000000000000000000000" - }, - "2a319ee7a9dbe5b832beae324290f7df6d66f516": { - "balance": "28127560161000000000" - }, - "2a50bfda2b06a9fb28c73f14aaff4f7ef865db65": { - "balance": "10483823413828000000000" - }, - "2a7b7feb145c331cb385b9fcb9555859c16820f6": { - "balance": "1017182951264000000000" - }, - "2ae076c36b18a60f1e3c05d434276a1e16f3f838": { - "balance": "10000000000000000000000" - }, - "2ae2e51ea2ee6a848acde342db2bf6eac927e5af": { - "balance": "494279795271000000000" - }, - "2afd69fac54c167e7ca9d8198a8de386f3acee50": { - "balance": "227162683047000000000" - }, - "2b08018d6e65a7b74ddb5ce1af99976a484b9f50": { - "balance": "16000000000000000000" - }, - "2b0c1d629ad2958ab91e31f351a91219fdbca39e": { - "balance": "113239399820000000000" - }, - "2b2bb67fe9e44165d2108676579a9437c760da30": { - "balance": "20000000000000000000000" - }, - "2b2c99e88e938d1f1416a408a7d0041a605bce16": { - "balance": "6118539729000000000" - }, - "2b5c97b6402ac189e14bbca3e7759319ca8a9222": { - "balance": "10000000000000000000000" - }, - "2b813339c7f818f578b45f17c41c7e931c7828e2": { - "balance": "842834712955000000000" - }, - "2ba6fc21f743968d51f80113aadfc0fdfe8499ed": { - "balance": "309973507270000000000" - }, - "2bb75b272b279cb54498f12b6805261af643c8b1": { - "balance": "1426727673809000000000" - }, - "2bdac062364abd9cf67ba7de214a2cceb0511033": { - "balance": "1090525272063000000000" - }, - "2bea658caa805241aa921f48c8f10cb49e16ffae": { - "balance": "1295499213027000000000" - }, - "2befe7e34299a7c1ad53fc9988ce77e2d9fab20b": { - "balance": "4326342236300000000000" - }, - "2bf466a83cd44aaf0f627606a1c954fd31deb782": { - "balance": "1388986370166000000000" - }, - "2c016a23890e9633fc17b0a8d328ec1ec7ee0113": { - "balance": "92483174342000000000" - }, - "2c45a87a63cc5c8c102d12b83bd9a3501ee41995": { - "balance": "394657687589000000000" - }, - "2c600a596368405e584f3b869f7fabef4ce54aa4": { - "balance": "9879984853585000000000" - }, - "2c7032da8b7816e16095735aee43d1c3f1c43acb": { - "balance": "10000000000000000000" - }, - "2c7275511fe06ee86663b3a618497168b35b0cdf": { - "balance": "10000000000000000000000" - }, - "2ca4074843e9519265447c0dd9ac84ddc2033c1a": { - "balance": "179612279567000000000" - }, - "2cac03ba2c45a6c8186bdceb095b7c5feced3114": { - "balance": "2022060470376000000000" - }, - "2cb8c2cd506b2d7b4cac88ce63230022d412c62d": { - "balance": "211378154058000000000" - }, - "2cd27561cf37ec229982dd592c71d1aab9c2d7d8": { - "balance": "42189968284000000000" - }, - "2cd2e85310a4fbb7f296c3d0d1cee07b191239eb": { - "balance": "1940327317417000000000" - }, - "2ceca4501c5f2194518b411def28985e84d42913": { - "balance": "25000000000000000000" - }, - "2cf7abd42394634689aa2a36d263a6345116b7df": { - "balance": "3553167226295000000000" - }, - "2cf88f29356c166df8383d3312cea10397e25150": { - "balance": "76961677759000000000" - }, - "2d0b62fe49592752cfebaa19003a60b8b39b1cb9": { - "balance": "10277397502735000000000" - }, - "2d2051887107bbd8ed45b405b9be6974a13172d9": { - "balance": "1928781992000000000" - }, - "2d2c9525e2811f4d1016c042f476faf23274aa31": { - "balance": "1000000000000000000000000" - }, - "2d2ef9e1c7a6b66d9a2994adb3ac4a9921408e69": { - "balance": "10000000000000000000" - }, - "2d3bcd18e5c97ddbf1cd28ab37eabe070e9a04d1": { - "balance": "323879852538000000000" - }, - "2d3e60496d0092a4efc665389a916be1a9f8b378": { - "balance": "161958437779000000000" - }, - "2d3fb0ae9b17d3a57d23549ae5500fbb163de25d": { - "balance": "25000000000000000000" - }, - "2d8106dbee6f728c0ff11887690a6370a7d9f5a5": { - "balance": "3102418708000000000" - }, - "2da48eeb788686811ac8270ef3baf0159fc47446": { - "balance": "252187695395000000000" - }, - "2da9d2a6f0b92651a36b05c5e9d2a717c6e166de": { - "balance": "500000000000000000000000" - }, - "2dad81b23d8447190259119019c04a4ef61ab91f": { - "balance": "53428719965000000000" - }, - "2db1faf35901e272aee74a2469a278fdaa6e6e18": { - "balance": "100000000000000000000000" - }, - "2dbae8e1ad37384ca5ff0b4470d3dbc73559841c": { - "balance": "10000000000000000000000" - }, - "2ddf9e23945c181b8592d7965e782068b4c38b37": { - "balance": "100000000000000000" - }, - "2def05d1f2abbaa193a219b87e5319c7ecd48dea": { - "balance": "51359946957000000000" - }, - "2dfd221f96a21e41ffe4dca67b15cd352fe9637e": { - "balance": "36000000000000000000" - }, - "2e1371fcfea9d8dc8e692897a91753400caa9c3a": { - "balance": "5199902650733000000000" - }, - "2e2e04945adbfaeec698ea0f5275f1ad5ffd3d5b": { - "balance": "42034514567000000000" - }, - "2e41f865cfbcf8b89f848405e04de9114087f4ff": { - "balance": "44875730962000000000" - }, - "2e530254768ce94db0ef1204ede0e12b3558e7eb": { - "balance": "14319506377747000000000" - }, - "2e5c43868f45de268967fb22f3f4107da401510d": { - "balance": "20000000000000000000000" - }, - "2e5d2e117d2ba9af9697ec023a4d10b5a2436902": { - "balance": "16000000000000000000" - }, - "2e6000778fb225ddb3e1a2f297d56774e85d9c9d": { - "balance": "10000000000000000000000" - }, - "2eb64b8ab13f0d7823158217d15ba310ed3d0e58": { - "balance": "58724606000000000" - }, - "2ec3973ff33a06d355ad4e8f73b657af8a5ed8e9": { - "balance": "1165606294808000000000" - }, - "2ed4362ea5edf510e210af733089b294f87e8f67": { - "balance": "427561040806000000000" - }, - "2ed8788f1c31b508e37079098a7337bff77b49cc": { - "balance": "10000000000000000000000" - }, - "2edbbe1e2ea482920c76a4ff4c14602b4d37c955": { - "balance": "294409476945451000000000" - }, - "2edcba2bd76128750c8aa00f832c62db30aa7868": { - "balance": "25000000000000000000" - }, - "2ee5abcc0d0d51d4b18947b5aaaa95d037be4e2c": { - "balance": "20000000000000000000000" - }, - "2f058187ef141c06c7c87da86cc1953d2fcf70fa": { - "balance": "9000000000000000000" - }, - "2f16b101da9986a18f4b0d30a26557860338c4e0": { - "balance": "254907899725000000000" - }, - "2f4363df2c61273d230071286bb0157dfefee2cc": { - "balance": "64000000000000000000" - }, - "2f6099a8cb7bc3713b87dab20994d8dc09342003": { - "balance": "1902400000000000000000" - }, - "2f7b3902ce56f74adb0f83cc7d3a99df440cca1c": { - "balance": "825246221388000000000" - }, - "2f7d0298ff6a363375b7eecfe754fca0963c8a1b": { - "balance": "101000000000000000000" - }, - "2fb7c16232b3b1f2e3a676d6d5c93ae6fe5cb14e": { - "balance": "1000000000000000000" - }, - "2fbd5ccc716d2f510d10ec84def3fa69e49f46ca": { - "balance": "1000000000000000000" - }, - "2fd84376be11772e5d072cd74c96b0d9a49c27fb": { - "balance": "1000000000000000000" - }, - "2fdab070e20e2c8923a24c196bec72c33ff0f220": { - "balance": "64000000000000000000" - }, - "3003e6007f69902a0f5e4b4e6d0468277897fc70": { - "balance": "1501210602075000000000" - }, - "30095e6a4ccd1ac2014c3d1d98dce003d775708e": { - "balance": "500000000000000000000000" - }, - "300e47e0fa556371f6c882eb98423be44de7c239": { - "balance": "9108837665958000000000" - }, - "3011231224920b62bcfcbf0aed4fde35dd0a4bdb": { - "balance": "374689586073000000000" - }, - "304be24debce62e70943efddd20457d34e85ab40": { - "balance": "81000000000000000000" - }, - "30912555bb14023e9b7c90aa2314721918cdf1f9": { - "balance": "10000000000000000000000" - }, - "309a94ca7b44bc84a7909ee2b93ed1c94eaf75a1": { - "balance": "39000000000000" - }, - "30bcc93965fa36bbaabcd781326e42227c4e1a51": { - "balance": "10000000000000000000000" - }, - "30c71fed91d24bff69f286ff8f0c6c02a21736a8": { - "balance": "409782329653000000000" - }, - "30cbaf4103757013fd8fb71c44a985939e212b86": { - "balance": "7424807960947000000000" - }, - "30dd59e66093d0bfd87b09c5f6588b9857e9a6f7": { - "balance": "26123006239871345154" - }, - "30f692235f254b02f583d5b515f4701a35c7f692": { - "balance": "148184457997000000000" - }, - "310763019a24a927ce42b00604ee664ca53ff6d0": { - "balance": "393757908273000000000" - }, - "3118a5d4d06ca8b7c8835f4860e6973228000ee2": { - "balance": "56188713212579000000000" - }, - "311adec5bfcaed44680691cc644ee120a484aa05": { - "balance": "169000000000000000000" - }, - "3124e387aa7023995643344c782dac84b9d8c7d4": { - "balance": "1393596696367000000000" - }, - "31379702391cb5a737db3f3ffc336bd03aaa181f": { - "balance": "10000000000000000000000" - }, - "3145606c3ccbaf337610185ffac14ac4f0583c0b": { - "balance": "196454968572000000000" - }, - "315e11501d2c57a62af1631fc2662d4d8745401e": { - "balance": "225000000000000000000" - }, - "31a785ad3eea177c59fb575cad0b44f9a48a12e9": { - "balance": "38039017162416000000000" - }, - "31ae64035e95c1205bf957afb5e1636df00dea3d": { - "balance": "1718600907000000000" - }, - "31c0bb22fd2e9d22984f248a16ec3ed9ad834517": { - "balance": "5982762676000000000" - }, - "31e73a3b5451ebe1163571e9e0567c425bbbfb83": { - "balance": "10000000000000000000000" - }, - "322543c74039ef61fd051021b5e6f16b54bc7c1c": { - "balance": "101346282441000000000" - }, - "3233c7ed11c25bfc41d506c3ae0daf5a3c7c1278": { - "balance": "20000000000000000000" - }, - "325dae17b5225f6734a02c677d43fd126bea89b7": { - "balance": "365067246683000000000" - }, - "326ce8166a4094b93c15557f50f2b1d47811e72c": { - "balance": "16641460224765000000000" - }, - "32cf76046ae48b609524b1a6203eb6296d04853d": { - "balance": "1094839482061000000000" - }, - "33456a28f36aa240262cf95b78b4ac2cd8aa77f6": { - "balance": "3077123488326000000000" - }, - "3348bce2ef90ffd6a59ef5079e1af84b2dd604a7": { - "balance": "9000000000000000000" - }, - "334e5f0ae77dcd3d32dfc2c4ec6ab5e2826dc4b1": { - "balance": "3176777762079000000000" - }, - "335775e19200cd0305e529bc4cdf7295a47cb2d3": { - "balance": "2945631571804000000000" - }, - "336ba81ea6ec4f0da38c1a1761ed3d97fd3ca28c": { - "balance": "3587379203826000000000" - }, - "339191e03e9d5a08ae7b58f4c860235a0721b5a1": { - "balance": "2732237722000000000" - }, - "3399bf9f94c5488c89450257b39fdf3ec8c7f413": { - "balance": "477423805836000000000" - }, - "33cb8556a6c6c867e1be7de591cb22c1b7e9824e": { - "balance": "62293494164000000000" - }, - "33ed633804f39367078e830328dd223254be3366": { - "balance": "22842013797896000000000" - }, - "3409025dce86ad441a5a80f30ce03768d37e40bc": { - "balance": "1381667933000000000" - }, - "34153174cd4d3f1eaed7438638d302f6414d5965": { - "balance": "50000000000000000000000" - }, - "343c6b82b13f0dc82d4269e2c806d2d58e6dde35": { - "balance": "9546969736042000000000" - }, - "346089ea81f7dcb79caf2444df34bd6ee78be4bb": { - "balance": "4344080889000000000" - }, - "34984a8f96dbbfd1f977826a4c2187482559a2e4": { - "balance": "25000000000000000000" - }, - "34a5cce96d2211feb04472260c4cd368bda8432e": { - "balance": "1240050112677000000000" - }, - "34c026a39e44955d1051e8669f9cc58a027455c1": { - "balance": "20000000000000000000000" - }, - "34d730652f4aa002a9f39a47212ca3bc47506b8b": { - "balance": "418050617956000000000" - }, - "34e1d8c8a32ce0f6378abb9bd05ea1f9bfdc5782": { - "balance": "20000000000000000000000" - }, - "350b228870445141f4417ea5dba4f009d693b96c": { - "balance": "76995849736776000000000" - }, - "350eaec708d5d862831aa31be2c37b2fdcef97c6": { - "balance": "258753545822704000000000" - }, - "351fc1f25e88b4ccf090266ebb408593418d8fde": { - "balance": "10000000000000000000000" - }, - "3523ac7a6e79162bb8400bf161cb59389432aa51": { - "balance": "436606776923000000000" - }, - "354d490095e79a29bda2fa11823328450f14333b": { - "balance": "50000000000000000000" - }, - "355a555a36e319e76042e62875a15e1db3012b86": { - "balance": "20000000000000000000000" - }, - "3568840d0a26f39248ab088653ede831f150ce29": { - "balance": "16000000000000000000" - }, - "357096b9c1c7c8d51b682ed3c43d150f55629ff2": { - "balance": "900090781248000000000" - }, - "3588c47ba9204b672c456ee9b5c1ae70f3c738ac": { - "balance": "10000000000000000000000" - }, - "3591edeb9c036e871b4fc6fb3ae6d42e0c0d7203": { - "balance": "1000000000000000000" - }, - "359d92e3e8757a4a97187a96d408c0c11f5c7eb9": { - "balance": "22330509101591000000000" - }, - "35aac2a948f316ba93ed111ac127e29ee9a3adb0": { - "balance": "364387817746000000000" - }, - "35b20459a7daa5f44ae423fd4a1b451ea5090b09": { - "balance": "20000000000000000000000" - }, - "35cdaa84c1f3bc2673bc0c60222c133bae0d3db1": { - "balance": "15234182435000000000" - }, - "35d554233ca690130aaa43501e121a208c657226": { - "balance": "10000000000000000000000" - }, - "35ed399940ece44d01ac873b9c0d3212e659a97e": { - "balance": "55000000000000000000000000" - }, - "35f164612afc2d678bb770f317085ae68cce19bc": { - "balance": "693763596328000000000" - }, - "3601b36cb475101d0d0976a8de9d38e5f3483a08": { - "balance": "1000021000000000000" - }, - "361368bc42c8daf365bce9f9ff3b611373d7b690": { - "balance": "21658400518000000000" - }, - "361bc43be077a269e3e37c11e91479017c47f847": { - "balance": "268900383140000000000" - }, - "363c7a2203f6f93287de091bde3c87eb6800e7a7": { - "balance": "20874859005000000000" - }, - "365dc06856dc6ef35b75b1d4eabb00a7220f4fb5": { - "balance": "30000000000000000000" - }, - "3660e246bce68e2b6e4a802681f188587d2c1c99": { - "balance": "55000000000000000000000000" - }, - "366868ef8e193d7e649ee970d476e6774d5ff1ac": { - "balance": "2544456626840000000000" - }, - "366f7f762887cfb2d09cefa4a5108cf390bdeb41": { - "balance": "26837527714000000000" - }, - "36759f9c92a016b940424404de6548632c8721b1": { - "balance": "1033159825798000000000" - }, - "36a939be88508646709d36841110015bf7cedd90": { - "balance": "144000000000000000000" - }, - "36adca6635db6b00d28a250228532fe560127efb": { - "balance": "3370820618318000000000" - }, - "36bfaed8099ee9f216193ade26d21656c98ce4b5": { - "balance": "1353728563832000000000" - }, - "36df854d0123e271529a8767d1cded4e7b5f31d6": { - "balance": "10000000000000000000000" - }, - "36f59989a902cd10725ff7fe2cab1689aa4e9326": { - "balance": "20000000000000000000000" - }, - "370d6999ae70e781c81d12dc259ea304183b01eb": { - "balance": "45563989086590000000000" - }, - "370e8af59a64a3171b422913921a1e2f982dd512": { - "balance": "170263356254000000000" - }, - "372e01083072214134018f50bde3c8ac4f6e071d": { - "balance": "1400474252324000000000" - }, - "37410fda52f94185d824258ad5f3c9ad9a331257": { - "balance": "11830521097085000000000" - }, - "3752b7e1628275522cd693307787b9564501d959": { - "balance": "67839627078000000000" - }, - "3776f82701c384ce6cbf6a8fea40772cb882b66d": { - "balance": "50000000000000000000000" - }, - "379f63e538168925ba6313f9a6a3b6e7f0e8ed52": { - "balance": "292876625446000000000" - }, - "37a24c1a8080ab429a136c5582782b276eaa931f": { - "balance": "6099055841000000000" - }, - "37abbeaf24b5e6264c87633734852e243d377010": { - "balance": "1051360014489000000000" - }, - "37c50cecab8fe9dcd81aaede95050d27c53f4d45": { - "balance": "106051638566000000000" - }, - "37f82962c3097f0cd9ff605db66e792025a540cb": { - "balance": "10000000000000000000000" - }, - "382ba1e6c53cd7b9c360ef894962d281d557561f": { - "balance": "216789631461000000000" - }, - "38309b458993916efc1ac8b0b5d41302fec21095": { - "balance": "999139000000000000" - }, - "3847f25956a97a32caac059fd9e4cdc105756e25": { - "balance": "876497264905000000000" - }, - "384fe5f399638d277d4fb93f26d527497939287a": { - "balance": "280035151914000000000" - }, - "388335d8b92b445b1b19a3107547bb6ca7c0763c": { - "balance": "167140942784000000000" - }, - "3894a1e65973a542101caa4dc01e9553a5521d63": { - "balance": "34262479791000000000" - }, - "38a0e019c6120a19acaf0e651dd8338982cdaab1": { - "balance": "153843170492000000000" - }, - "38d4bdb10819a7d4ae9a32f4abb82402dff319b5": { - "balance": "1471131830647000000000" - }, - "38e56a55e2ac8320a480562f4a7cea9220306ee3": { - "balance": "907464312139000000000" - }, - "38f18123f3643e03d24ad759afbefc90ed923a2a": { - "balance": "943729130798000000000" - }, - "38f764c861def6d5d65e5ec099536f4cfcc3af55": { - "balance": "20000000000000000000000" - }, - "391e12b51fc85fb879a72fa746ca06c7a5659e6c": { - "balance": "9000000000000000000" - }, - "392342dc7b475c3975877a41622be0fed8e386be": { - "balance": "218719857770000000000" - }, - "3944cc960b8f1993ad841629a79e53d0535a88c8": { - "balance": "210571656485000000000" - }, - "396219864b8cfb0ffb3c675690ccd7026424ad4b": { - "balance": "138984508746000000000" - }, - "396403f26b388150b4876485b124a49845101464": { - "balance": "10000000000000000000000" - }, - "396f1e0f9e7ee86d1b2159ab8f9353677d12d340": { - "balance": "121000000000000000000" - }, - "397cc9f6254d56c721c767e41628a9078bea878c": { - "balance": "225000000000000000000" - }, - "39878b0c7049fb179aba0015279eff6cc3136816": { - "balance": "33962071375000000000" - }, - "3a06b58d0cceee5b091fe6aeb0fc0db5774e9395": { - "balance": "272033811720000000000" - }, - "3a3330e0152d86c5aa1d9bdfe9e1697645d3377e": { - "balance": "2165107207206000000000" - }, - "3a3bb8ed3130e09fbdfc21db3571d4711fc92d60": { - "balance": "885484658836000000000" - }, - "3a4ac96c489c864765cb1997a0084ba745b67a87": { - "balance": "1257436384863000000000" - }, - "3a69e1c351978ced418cea6cee019f220bcb065f": { - "balance": "579242822216000000000" - }, - "3a76a23d81929bed05ef7e1982d32b456e62aa7c": { - "balance": "1027078338792000000000" - }, - "3a7beadd1e11d0e3326c0dcd0f670530612931a5": { - "balance": "20633069818937000000000" - }, - "3a867c44d0dd06517a82ad467d0aefd7f11ce729": { - "balance": "12323708574000000000" - }, - "3a969ae486215e24c7ab89e38929562e2f85d923": { - "balance": "18955477335000000000" - }, - "3ab81366d898a8b798afb08a4b722ab0eb883652": { - "balance": "1220090012596000000000" - }, - "3ac1e14ed5929d382f6488c5444e717373ed29ba": { - "balance": "2030543873000000000" - }, - "3accf4b8ef20e4fea983f13f99ab257a5f9e988d": { - "balance": "156030342415000000000" - }, - "3ad38fa6e3c078025794e213d9dcc5aa397050c2": { - "balance": "36561766773000000000" - }, - "3adef81b2c861ae39c418d55be99aee2306e29fc": { - "balance": "15752410974000000000" - }, - "3b21ff4d5801d3976643899f195fbfd1b72a50b3": { - "balance": "8971221745646000000000" - }, - "3b2f2635dd428ac0b5873088a9a81800f09d6e02": { - "balance": "56922872447000000000" - }, - "3b39919c7bc8d0afec792288c56ab7f4934dc7d2": { - "balance": "1678237240464000000000" - }, - "3b468d9d5546810aa837c29ccb8349548b0e8170": { - "balance": "1100000000000000000" - }, - "3b83d1b651f117f1559a19b04ef408619c2dc4a7": { - "balance": "53628552066000000000" - }, - "3b9a72201bb1e8e678e36129cb1570e3ac99270e": { - "balance": "25000000000000000000" - }, - "3bcab1535b04a0a3fbb673bc41fedaa80bf7901c": { - "balance": "1526488015042000000000" - }, - "3bed42c3d0c49ffac87b9d482f6338fdc9e3880e": { - "balance": "26189771073000000000" - }, - "3bf736b57f0ae47f3714a6bb852090a543b9d367": { - "balance": "652395174320000000000" - }, - "3bfd481651956105ed909eeb98be404ec5ae77e9": { - "balance": "177520143473000000000" - }, - "3c0a12a327545b5f8b7b5c1f7a1ec6a341ec9578": { - "balance": "4184342789398000000000" - }, - "3c132698d59927fe08cba433a41d08acc96c0edd": { - "balance": "151913899135971000000000" - }, - "3c27bd92c4be1a19974ec773bd20b13afe582c9f": { - "balance": "10000000000000000000000" - }, - "3c2ad171573a608286f1fa3f5ef9e6099823983e": { - "balance": "3240802189194000000000" - }, - "3c4b5e808b9fb8baab1144b981b6cd53e216fcdd": { - "balance": "61214114118619000000000" - }, - "3c4cfc6ead044819ceb41c1c64ceda1a228af801": { - "balance": "9000000000000000000" - }, - "3c553afd45535f7c2a70c701d00890e607b96ffe": { - "balance": "2678827200938000000000" - }, - "3c620d55268c55b6deea3b7dc7f59dbe93b6e141": { - "balance": "55494311990000000000" - }, - "3c9b204db23b902d4295e6aba3405917efd59449": { - "balance": "55543672571000000000" - }, - "3cf233b7730a175d05a861318b7bb917bb5bee06": { - "balance": "1867187351033000000000" - }, - "3d292272992397ed5f27d5202da693128d023d35": { - "balance": "79770828413000000000" - }, - "3d353cfe84e9a93aef90547fbeb6e4b4bef83069": { - "balance": "36000000000000000000" - }, - "3d54da4ddd0621822a114581ecd15572e6488be9": { - "balance": "1623867132383000000000" - }, - "3d62ddc67d366fb055eaf92c936a6e7df5085454": { - "balance": "124933526793000000000" - }, - "3d754df1151b9b62a6ed48b477225121c29af063": { - "balance": "50000000000000000000000" - }, - "3d79d1ebd5224ffdc13e27924ab7f9f8e3452ec9": { - "balance": "520163228474000000000" - }, - "3d84fd9785a6bd3148847038c6f1e135042a892e": { - "balance": "10000000000000000000000" - }, - "3d9574c3860f30bcb42523a0cbb08aa7dd83e733": { - "balance": "15259904884000000000" - }, - "3da809a5911ccc77f892034049a97a9022c35e7d": { - "balance": "1415009021101000000000" - }, - "3db9a6c6ab3d0cf6d3bd7e04bdad39b4d419ab13": { - "balance": "9999781764000000000" - }, - "3dc7367c3218f88de8867c425f89102d2f2056f4": { - "balance": "10000000000000000000000" - }, - "3dd273dedb28824d1309c7d60a0744a6b6353e79": { - "balance": "9000000000000000000" - }, - "3dd6b25eb91dd2f3468e0786e8beb465abe7f515": { - "balance": "275172962210000000000" - }, - "3e0d14f83b304136311a33bbac2720c0cd66f117": { - "balance": "3390479675000000000" - }, - "3e15e947ee76f52f0f2a7d84da7c4ab060eb5cbf": { - "balance": "6751398714759000000000" - }, - "3e1b5469e1da4ec27537513f4df3f1a338a7dc2d": { - "balance": "161899580000000000000" - }, - "3e3329bcc90e47e4dabb5c93572b18b5e0efa024": { - "balance": "10000000000000000000000" - }, - "3e5a585ad0f34d78899433edaed574af052616f0": { - "balance": "910225655353000000000" - }, - "3e6be9615713bb06198bf354ef434a9db649699b": { - "balance": "783525278181000000000" - }, - "3e7c7c082f2f99b1ad579400a2e93586a24ed992": { - "balance": "159035553843000000000" - }, - "3e86ea5713f90022c0914fcc25e97c39487eb957": { - "balance": "101867287023438000000000" - }, - "3e9dabab6e50a696edfba6bcd44230d087c8d04c": { - "balance": "3315882414579000000000" - }, - "3ed956f86fe78223c86e164e4f372c9a0bf4a279": { - "balance": "119959915220000000000" - }, - "3ee87e776fb12e9c894e36fd5a61daa984e8a5cb": { - "balance": "50000000000000000000" - }, - "3ef1c8f294443f776a794563ce7569a8fe4d5d20": { - "balance": "25000000000000000000" - }, - "3ef6a396d6611df6c79ec1e6ad6bbd253917fbe9": { - "balance": "10000000000000000000000" - }, - "3ef727346fc631ae6473e9a36e2e5e54df696195": { - "balance": "121000000000000000000" - }, - "3efdcf2c0998637cb82d2b5fc24f27162578d207": { - "balance": "1054861112990000000000" - }, - "3f2cb2335e2bc07744175c497e2f437e87c2a146": { - "balance": "48999979000000000000" - }, - "3f4d16663a4f76ade93eb8bd6ca8fe2158e24322": { - "balance": "237117597268000000000" - }, - "3f7c5e6aea7f3f74d764df50f0fc1aa758fc99a7": { - "balance": "63372222562060000000000" - }, - "3f92239fdb41c6ec228252248c2db3f23675e275": { - "balance": "28538064487000000000" - }, - "3f9610454b621c04f00f01f4d54046502edb21fb": { - "balance": "16000000000000000000" - }, - "3fcfb30cbfe53c0c43f58c28386d9a6e5b49f7cd": { - "balance": "79080579219000000000" - }, - "3fda0c9a3d3f0000635376f064481d05d1b930bb": { - "balance": "10599947385000000000" - }, - "3ffce0475430de0bd9b09a412e404bc63aa28eea": { - "balance": "10000000000000000000000" - }, - "3ffe7583b568448ded5183e1544bca0d283680d2": { - "balance": "1076944549283000000000" - }, - "4003a137e577351a4ad7e42d1fc2d2cf1f906b6f": { - "balance": "25000000000000000000" - }, - "40215fc4c6300d8d8179383d9028fd2d909c6cc4": { - "balance": "3941346079000000000" - }, - "4027d7bbfa5d12c1ab9d08933a1659ae8dd023ee": { - "balance": "1156537386462000000000" - }, - "4039439c960070394dbda457726d97121c7b3669": { - "balance": "4444061364102000000000" - }, - "405978c24a12d930ada6163a44fc4a70c16569e1": { - "balance": "707298643296000000000" - }, - "405d2c1b55ba3f67c8634456b99c19092b407a10": { - "balance": "1462185951849000000000" - }, - "405ddfcf45005cf5a0ee1bfa605a7346a0167945": { - "balance": "88775535985000000000" - }, - "405f72a6940acf5d36a29498075f2d0d7a75bc22": { - "balance": "402796678569000000000" - }, - "407253b005ae97857f812fc60d441e5367b4bac8": { - "balance": "1484147810895000000000" - }, - "4091e1fb1c7af51a64c201d6a0c8f0183dfb7ca5": { - "balance": "10000000000000000000000" - }, - "40950bad9580d4b111955da7d3f9ada26dd9f05a": { - "balance": "500000000000000000000000" - }, - "409a28106192cae7a76c6aa8add0f73dcd63d2c0": { - "balance": "214832616721000000000" - }, - "409d5b872b059aea9a773e854f9a17ed2d5c2ef3": { - "balance": "64000000000000000000" - }, - "40a6e3c753b04c42fcf89cc30df8f50418caecb8": { - "balance": "754228409494000000000" - }, - "40e5ce1e18c78d6c792f46ed6246bfb31bcdb6af": { - "balance": "500000000000000000000000" - }, - "4121692a14554ddca1ca662fb577d7152d4fa7d0": { - "balance": "49000000000000000000" - }, - "412acb10c8ca937ddd64cf0d413b1dd34760f72b": { - "balance": "6073360870000000000" - }, - "4166a5c94d5ae48ced410f950d40656182bf8990": { - "balance": "55000000000000000000000000" - }, - "41752b7d0d3ee58a6b69d8ba721c0894ff701237": { - "balance": "585556720807000000000" - }, - "417c86d6bf734e99892a15294230771bbfd7e1e1": { - "balance": "38233258264000000000" - }, - "418414498f7361b29428c54732e1f49fb394f813": { - "balance": "2063786326155000000000" - }, - "41a424dcbff6bf31686f5c936e00d21e8a4e0f78": { - "balance": "33554754580438000000000" - }, - "41a893429d5f8487c1866b87779155d4bfe33198": { - "balance": "20000000000000000000000" - }, - "41bbedd607fa576d130305486824cd2871bf6b05": { - "balance": "649728993301000000000" - }, - "41ee42c1fb1bcdc9c7a97a199fdcf9b63623521a": { - "balance": "7906012418597000000000" - }, - "41feffaf56d1712af6965fa6eee1b06bd624e7b8": { - "balance": "49000000000000000000" - }, - "42107e765e77ea76b3d6069d3775bc3aef7d692c": { - "balance": "25320783684183000000000" - }, - "421f4dab3240e15a1c78e3ce8642de9b578b8e4a": { - "balance": "832511242936000000000" - }, - "4246c52c3601541a873d4bbaafedf28b9bad5b73": { - "balance": "10000000000000000000" - }, - "424efe1ba28bb1aeedc38a3a5135547d0fe80751": { - "balance": "25622294162729000000000" - }, - "424fb0a3ec325bf42e7edbef7e450f2ffd1cf318": { - "balance": "20000000000000000000000" - }, - "42714c04d17f6c29029daf7f50d1cbad6590cfad": { - "balance": "271755674161000000000" - }, - "42b66e9123d304b70fef3dbcfe8587fd6189b5c4": { - "balance": "1030481609000000000" - }, - "42dacbc412b829cb304ffbc316b3f81b379bfc80": { - "balance": "304208485736000000000" - }, - "42e3d9832c8b6cdea39c97525570391803dee276": { - "balance": "2581020833000000000" - }, - "42f757898f95c1b46f64a4a6b7f86ab03022d672": { - "balance": "100000000000000000000" - }, - "42f7956fd659e00d3be2f3d1d4f3ed187aef04d6": { - "balance": "50000000000000000000000" - }, - "43160b2bc00f7f8f7fc806e2f6e2ffdc62b3a651": { - "balance": "1000000000000000000000000" - }, - "431b77cdd067003eeed26c1aee32f67fb94f7092": { - "balance": "902514849986000000000" - }, - "434e44583786e354731bca250d94ef0d8860a538": { - "balance": "1187789683866000000000" - }, - "434f1b9b193c88bf58685124aac0167fe69f9014": { - "balance": "500000000000000000000000" - }, - "43535982688844fa703cb9bd5723790cab364049": { - "balance": "100000000000000000000000" - }, - "43559f405590592c254e427fa25f03e774d8defd": { - "balance": "6913200000000000000" - }, - "435c08c481d59308a64afec0d6f936321bb120bf": { - "balance": "9005920819593000000000" - }, - "43629748a92b846f21f637aac5103412fbabb9a6": { - "balance": "1177513692845000000000" - }, - "43650b37552882d225ccc977aa2b7a86a4ca9bb1": { - "balance": "16000000000000000000" - }, - "4385de394371d26a45f18e8b3842effd015027bf": { - "balance": "187331693412000000000" - }, - "4386ff9648fe420503c9a36fe7b97c079de3b770": { - "balance": "2714401478778000000000" - }, - "43b370c4457cf39a3be86cc00c2b27614ca6e638": { - "balance": "8316429850934000000000" - }, - "43c464ea740172fe6f4f09974106fd24029837b9": { - "balance": "129643160399000000000" - }, - "43ddd2d33dcb7e578f4e59ad6b9c61a24c793aa8": { - "balance": "500000000000000000000000" - }, - "43e0f8065eb7faf3bbd13bc7c5d5d8f5ff1bdac3": { - "balance": "4454324716300000000000" - }, - "43e96cd065d7934b246d0fec8cd2dc6b36d56d7a": { - "balance": "81721481452000000000" - }, - "43e99acabfbdc6cafee3afb12fa7ed1345370b2d": { - "balance": "4595292398872000000000" - }, - "43fae764c7555b859b93d2126edfa59cfbf298b5": { - "balance": "105746805109558000000000" - }, - "44052eb938c02776b5240f38ec99f5ef51ef0d87": { - "balance": "38446396949881000000000" - }, - "440fc7621cc17f121f0bdf2a68c5be2c3af4fd3b": { - "balance": "1026958147051000000000" - }, - "4440ccbc77249a4d891d9ab5a5f2026b17aff7c7": { - "balance": "10000000000000000000000" - }, - "447f3f702c13a3fbdc8675c6285702b5aa2b66bc": { - "balance": "1089533398014000000000" - }, - "448f152be153fdb0497403f70e37d876946a5021": { - "balance": "614429461682000000000" - }, - "44a1e3a044f5d1fb00f4beb3772a3ee08d8b7093": { - "balance": "1000000000000000000" - }, - "4515edc7154bedd7143b69a04c4e738f8aa4ab18": { - "balance": "10000000000000000000000" - }, - "4572148fe5ea9d4795e1f1ed93097aac1d70991c": { - "balance": "2873782218000000000" - }, - "457581f223b8eacd757abb292613e317d6f59305": { - "balance": "3582446780073000000000" - }, - "45b450961882850f7038d5cdcd2a8fa2dc4b5469": { - "balance": "20000000000000000000000" - }, - "45bdfdf3840d4341503cd7fc87e4b66f6179e5fe": { - "balance": "10000000000000000000000" - }, - "45dd9baa87b3c94df66308d8ed4f3a5bb65c3dcb": { - "balance": "25000000000000000000" - }, - "45de332b8ee95d886cf11b99291b46f46c1ddd45": { - "balance": "36000000000000000000" - }, - "45e06afdbc70288a2cc55bccc4fb2d8195aea028": { - "balance": "790360485306000000000" - }, - "45fce5fd1acb2bc5507723c897cb340437e39735": { - "balance": "100000000000000000000" - }, - "46045cddd940d80596826ce5354489b3047663bb": { - "balance": "100000000000000000000000" - }, - "4610286f8a2649dcfbc6d91735745f418a6abc75": { - "balance": "10000000000000000000000" - }, - "4615905ecc6f7df0ccb7b86a3e1d3770adb2f874": { - "balance": "1000000000000000" - }, - "46256e00ff927d54b0ca139ddccac2148784273b": { - "balance": "10000000000000000000000" - }, - "465e40e7d129ad310fc60ff0f17c0f968611118f": { - "balance": "677971225649000000000" - }, - "4664a920f7fe9b0d78a665e1a4aeb95f287d6059": { - "balance": "20000000000000000000000" - }, - "46679de1c6143138fd9c44ff05853a52371915ff": { - "balance": "363627463229000000000" - }, - "467cdc210ae48ba99740d37ee79fa57c4216bc81": { - "balance": "10000000000000000000000" - }, - "468053d193debb88735571acb24b764f2676272e": { - "balance": "49000000000000000000" - }, - "46826d1f1418abbe4e7b9236d643e5b57a0f0208": { - "balance": "37752144164916000000000" - }, - "468df2ea57972ddeb88d470a5f3c2c0e2284ac17": { - "balance": "757320434551000000000" - }, - "4695ad5b686520ee8426d24b50ff7a5f0d703443": { - "balance": "2851082366000000000" - }, - "46a149bc8ec2b85fdf938f753a6c53777dcca2b1": { - "balance": "10123698633000000000" - }, - "46c081440f760a21b74c2499bdda13aef8245930": { - "balance": "180752319265000000000" - }, - "46e615324f6e4fb242f9bfecffc0c802ba7733c9": { - "balance": "10000000000000000000000" - }, - "46eb54f09dbdaaf3b97a1f79a3d82ee2e902b3b8": { - "balance": "3430510380318000000000" - }, - "46ebb24b04919ec0164f0bafcebca2309f2d3035": { - "balance": "129155832233000000000" - }, - "4701f9fe78111011f820fe28c47522e601655678": { - "balance": "9000000000000000000" - }, - "473f44e2c1d5d7aa53cf7041d7ad19a0d9eaf1d8": { - "balance": "162679637505000000000" - }, - "474f8bf4d03a7efa4d190905ce062eea7c75118c": { - "balance": "1259904506149000000000" - }, - "47598330e862a4f7cbda8be74ac10cd5d370a55e": { - "balance": "291763101699000000000" - }, - "476455d48fc858a06bd7854fcf1bd60bcfde9ed3": { - "balance": "10000000000000000000000" - }, - "476826d58192ad822f4686311d6c6d4d4f66ee5f": { - "balance": "453184657722000000000" - }, - "47a231eb3fdbc24f2d008f06228624b2a45ae5fa": { - "balance": "1000000000000000000" - }, - "4805f4c0eb1c83c436118ec9148019e5fc1962e3": { - "balance": "1311161626928000000000" - }, - "4809f373cdd56c8481ba3bce5a401d55a7e50a50": { - "balance": "2284845194349000000000" - }, - "4839bf9ad56873abd5695057bf71972806cde827": { - "balance": "42264923611000000000" - }, - "486dba2a47decabc9a85d1d64d74687983ab273b": { - "balance": "49000000000000000000" - }, - "4877993f5ecf02451f8d4591594cb2f30dcf9f26": { - "balance": "100000000000000000000" - }, - "489723e325f609e27be14528c4111fb3eec13f7c": { - "balance": "2489030141000000000" - }, - "48b710d16e9da736b773453089d69cc6ede116b5": { - "balance": "26651593216000000000" - }, - "491088e1e4b5c3d65870f2deef9be6ec3dc6c7c7": { - "balance": "1446809481953000000000" - }, - "49174451320ad2e14cb2b05ecdd251b75ace3038": { - "balance": "15533380764616000000000" - }, - "4956ead915594b621131b2fc2dbbb49ba43c5559": { - "balance": "1175638488000000000" - }, - "4973a0d32147ba89f525a18f989518dcfce93b0e": { - "balance": "522848489444000000000" - }, - "498c6f9063705054fae07260d4176c3d55a97650": { - "balance": "732941433000000000" - }, - "49991f68f2a76bd1cffa3e9721be36f3fd8351b8": { - "balance": "17742568700019000000000" - }, - "499a8af194e0040f349e893937fe3858f8267fca": { - "balance": "80704784160862000000000" - }, - "49bcbb7b263febf54f8ff498525bac8e7241f966": { - "balance": "603044032468000000000" - }, - "49bd72773656c4e1a4d16284aea2fb05546d2b31": { - "balance": "1896607093054000000000" - }, - "49bf80fcdefebe8cd4830ba09e46ccd7231c8e6f": { - "balance": "10000000000000000000" - }, - "49c9d82dea78f14b1c52efc0196b67f508f7859b": { - "balance": "2313040051399000000000" - }, - "4a2daeacf0468d137e3bc464d6d5fa3893a9136b": { - "balance": "10000000000000000000000" - }, - "4a6c428f245e8d9115b34764bab17eb86ac472be": { - "balance": "10000000000000000000000" - }, - "4a6e8d037acf1960dbbf14e7a02fec0ac656f9c1": { - "balance": "6516295825438000000000" - }, - "4a7e7fc3c72f2f9b92bf0dcd5297cfb19f077d7c": { - "balance": "99426213999999999" - }, - "4aaa6817a5000bb7596e000135b3051c5931e7c5": { - "balance": "102884105546478000000000" - }, - "4abcdc3d7d3d314a163da92aee53a56b87313a2e": { - "balance": "44402243657000000000" - }, - "4ac9385ade2377b061f4211b392ed6a6e7fb83cc": { - "balance": "1000000000000000000" - }, - "4ac96e1e26cb66ff788ed8c62db811d7b4fdbc74": { - "balance": "68476115774000000000" - }, - "4b10c247caf33fb872d9bf86572424410aa86752": { - "balance": "337915294240000000000" - }, - "4b23ffff1894df49005c7afc0828880924571299": { - "balance": "169848767272000000000" - }, - "4b486895caf3a0b5afa198df744de7082eec8666": { - "balance": "1672587376054000000000" - }, - "4b98fc960610573be456c0e1e319f4f863bf9095": { - "balance": "259382246718303000000000" - }, - "4bc0cc483be20223f40ed6deef63dd9645c216c4": { - "balance": "4322684620000000000" - }, - "4bf4a046afdd4ec9d0e50730ff6ded5ef2327442": { - "balance": "70601389160000000000" - }, - "4c0149058e2e74f7c900e6d6e5fa12eea882c5e0": { - "balance": "2017399852886000000000" - }, - "4c17a3997fb70599794d01a33a27a6d5b52b6f01": { - "balance": "469002093209000000000" - }, - "4c4559e7b32340dce112cf7a021ced1b113f6dd9": { - "balance": "25000000000000000000" - }, - "4c4f02b3f232b8ce8485d425639271510cd0486f": { - "balance": "68828038140000000000" - }, - "4c52ec56142bb6e8c8830e5c17b01b5165915f3c": { - "balance": "321766233041000000000" - }, - "4c58defa57875e709ca039a54a2be5aed6672f6d": { - "balance": "121000000000000000000" - }, - "4c5a886ab90b6bac68677a7eb92a06bf33ff2930": { - "balance": "236899852150000000000" - }, - "4c60539363edbd812334a54543c40ecab8af2ac8": { - "balance": "3281904094699000000000" - }, - "4c76897d0d5d39195354194710c5e7f99bef63d1": { - "balance": "10232271258305000000000" - }, - "4ca3c03780c20a64f3b5ebb75669982a71ee8a71": { - "balance": "377172198976000000000" - }, - "4caf77eefe062a6f053a464171bc75254b47f52b": { - "balance": "20000000000000000000000" - }, - "4cb7d7ce805e56f6e47e94cd755b6d97f8f996a0": { - "balance": "120998866000000000000" - }, - "4cd34f8f3299d3b7aaee180baa0b432369e1b3d6": { - "balance": "197088135242000000000" - }, - "4cd7aaa5415d809f405f520e4c0319a6029b981b": { - "balance": "686627368232000000000" - }, - "4d01067555f1ef63883f25c562b07168f79fa80d": { - "balance": "17547055698000000000" - }, - "4d2cb4c1da53e227b08c0a269402e9243a13f08d": { - "balance": "324000000000000000000" - }, - "4d38bb5f48ec37b751d16de32a4896fbda479ce1": { - "balance": "802530078718000000000" - }, - "4db3e76e2f68896cecc9826e10a5e09df0352c28": { - "balance": "555180306924000000000" - }, - "4dc8730d9f032d33dc493bcd3c6375b38f41afff": { - "balance": "5726933881000000000" - }, - "4ddde96556f5185a13617f01ebd9102800bc9e9c": { - "balance": "1181822708402000000000" - }, - "4df9359cb204bf649668ff8086a7f5e24709083c": { - "balance": "262998978400000000000" - }, - "4e0a1a3dff0d33c418758263664b490140da9e01": { - "balance": "100000000000000000000" - }, - "4e0dd6d8de5caa3a3bf9fdd6f2d7b30618623cc0": { - "balance": "10000000000000000000" - }, - "4e11af85d184b7f5e56d6b54a99198e4a5594b38": { - "balance": "76658631121000000000" - }, - "4e314349abc52c686d47dc771ebc8040966be386": { - "balance": "632341985941000000000" - }, - "4e3fb09c35375106bece137dbe0e5491e872871b": { - "balance": "153648535396000000000" - }, - "4e4f0d606f7065bfb1545e60b5e684ae1934e055": { - "balance": "48998635468000000000" - }, - "4e50957aa6c91c548075add8ec625b74c0973abd": { - "balance": "1000000000000000000" - }, - "4e5c6efa76493f0e9422582016aac50539ae60d9": { - "balance": "2078967343000000000" - }, - "4e70bbcb50c4e875fd573dcb694908abf3b30b37": { - "balance": "20000000000000000000000" - }, - "4e7f5670a7dd168a0803e53b8bf72f4db280e3ae": { - "balance": "1658463113665000000000" - }, - "4edaf859990a10977bf378df45b32f93422c84b4": { - "balance": "121000000000000000000" - }, - "4ef41923a1a426772832d3c267adbd84e5994edd": { - "balance": "5432615017384000000000" - }, - "4f11a70d80f36f46ed0c2a5fff1a39b711f3bae5": { - "balance": "8415785077000000000" - }, - "4f159095afcc75b8f5cfc90c9d07a0d77ac8ed69": { - "balance": "25000000000000000000" - }, - "4f2652322736cc18b24af582d4022fe329a9dfb7": { - "balance": "9000000000000000000" - }, - "4f328173f352f3dfdca0ff5e3185f26de77c6f75": { - "balance": "10722917874680000000000" - }, - "4f47a62aba6ea049fc0e92d8afbe1682472d98bf": { - "balance": "10000000000000000000000" - }, - "4f4c3e89f1474fe0f20125fae97db0054e9e14e0": { - "balance": "50203638983000000000" - }, - "4f5ac8dfe79c366010eb340c6135fbee56f781d8": { - "balance": "50000000000000000000000" - }, - "4f672cbd373183d77d8bd791096c6ebb82fa9a2a": { - "balance": "978111227765000000000" - }, - "4fb179c9c88decaa9b21d8fc165889b8b5c56706": { - "balance": "24750205150000000000" - }, - "4fbcf391c765b244b321875d6ab4381c44d0747a": { - "balance": "99999580000000000000" - }, - "4fc979b38b981fca67dfa96c6a38a17816d00013": { - "balance": "1088876196468000000000" - }, - "4fdfdd1832b114b4404aae23305c346beee14e1d": { - "balance": "278724179057000000000" - }, - "4feffb1836029cd0e9b8f4aa94b35ae3982fa770": { - "balance": "1674590934924000000000" - }, - "50045745a859f8fce8a2becf2c2b883b3723b2c8": { - "balance": "169000000000000000000" - }, - "5028bde29fe88e03e3de069b3907fa9df551c379": { - "balance": "196000000000000000000" - }, - "507096ed771fa8a1d004ee5377c01506df461b32": { - "balance": "2669205000000000" - }, - "50788574a0967580fdaddc4758f834d8978455f6": { - "balance": "1648581593000000000" - }, - "508d8e8f338ca98d3c09f0f15fd9e7baa80701e8": { - "balance": "16000000000000000000" - }, - "50a4dc916845172b83764a6c8b4b00d6d02d41d3": { - "balance": "3020744393592000000000" - }, - "50da06418780c220ced4898af0b1fca533f73cca": { - "balance": "36486700700823000000000" - }, - "50fb6fd8432a66219e754234e9eea1dabcc07676": { - "balance": "489500000000000000" - }, - "5104bb1b831902333732dd25209afee810dfb4fe": { - "balance": "1333614132000000000" - }, - "513963743ec6ec9dc91abf356b807ebad64df221": { - "balance": "1508002412172000000000" - }, - "51397ca69d36e515a58882a04266179843727304": { - "balance": "941648956414000000000" - }, - "514a58f2b36c2cf1b6293c36360cf658d8af30ed": { - "balance": "1233397704089000000000" - }, - "514fe0cdb3de692cab9f2ef2fd774244df71be66": { - "balance": "9670444445882000000000" - }, - "51583128081fd800d9550144afebdf3fe88149cb": { - "balance": "231190355520000000000" - }, - "517384fe92391187d0e65747a17bfaadf967c331": { - "balance": "1943121865489000000000" - }, - "51aebfaa26a54071cfe6c2d8f81157ec313984ad": { - "balance": "1422225031261000000000" - }, - "51d4f1205b272e491e94fe21f0341465f14141fc": { - "balance": "552384783614000000000" - }, - "51de598faa85276bb26a68b135028755304b6700": { - "balance": "2068484560002000000000" - }, - "51e08e0304f08ef768c80ca149da4721fcf482b0": { - "balance": "194629207228000000000" - }, - "51fa3da695e24f602952a71966f37ac3596a94a4": { - "balance": "17008166261720000000000" - }, - "520b22776b1befd3064636da0dd251afe569ef13": { - "balance": "18538137781909000000000" - }, - "52219a1e1aa82b78b971088c30583a3bbe675c8e": { - "balance": "411959222637000000000" - }, - "5252b8a0688096523498cb5c1f42bcd1f61923d7": { - "balance": "1863936864000000000" - }, - "5259154e1a5a809b2e3dab80372124cebbfd56e2": { - "balance": "110000000000000" - }, - "5264f2de516835e549710bfe34ef03b08b8557dd": { - "balance": "1216000000000000000000" - }, - "52b17fae7e9cac447f026db71dba4034a1d53174": { - "balance": "99001631977000000000" - }, - "52b3363ae882a99354faeb76733d0fa2cbb89787": { - "balance": "102517584327000000000" - }, - "52bee7fb24a7fc1f34cf0874ec2f06c5fe847cb1": { - "balance": "54443400591000000000" - }, - "52d1f12d391c7a2f3b52939a61a20da5f85eecc3": { - "balance": "2707175772061000000000" - }, - "52f27099483589e883e7eb789896de39c61e46da": { - "balance": "358944977251000000000" - }, - "52f3b715b678de95d1befb292de14c70f89f5e03": { - "balance": "2989868434000000000" - }, - "53259780569f6dd6753c1da1d53d0b155c5b30d2": { - "balance": "200489122590000000000" - }, - "532e4908e8297c90d75d2280b432b469aaafa2ac": { - "balance": "20000000000000000" - }, - "5334d1e399feacabc9648cebcd93172db95d43be": { - "balance": "25000000000000000000" - }, - "5341665addfb5e367f7a7d35de95b87a0cceb3a9": { - "balance": "60544291695000000000" - }, - "535a39a854ed1c2f0afbc5944f1ee0e2e68cf65a": { - "balance": "2141913781000000000" - }, - "536515c0c08988ee69da1d75f18c706f6b9bf7a3": { - "balance": "169000000000000000000" - }, - "5387a1ce4cd2ef4f90075c15dc3c0744948ec356": { - "balance": "50000000000000000000000" - }, - "539a30ee5724978010990718bb8b0dd25f89fd15": { - "balance": "1306896514000000000" - }, - "53a5f87dfb17149b8c2934a2a9d519ace4ac9724": { - "balance": "4569449510000000000" - }, - "53b24fb36e72c22eb830dc93857a8188b03397a9": { - "balance": "64000000000000000000" - }, - "53cc35b3daf4b8e1982e0e63d0bc68d7252e7fcc": { - "balance": "68213426853658000000000" - }, - "53e1f85147e000ae1ff6a5910407395e388c683c": { - "balance": "20000000000000000000000" - }, - "541f43ff66ed5eb1a1ea0ae3f86355ecff665274": { - "balance": "49562725831000000000" - }, - "5428a31f736c0d2b3c4e80baefb75a76ed44d3f7": { - "balance": "10000000000000000000000" - }, - "542f732aec0873bf531f6941828b6f0ed0611106": { - "balance": "8407722276000000000" - }, - "54300b6a77b95545373b2bba73e60f37c31eb1c6": { - "balance": "1581215621996000000000" - }, - "5434bd65a492a4d14d3b97eb49f6e491350ef73c": { - "balance": "484000000000000000000" - }, - "5444a1735913eeac177d947ef38de7cd6bdfc0a6": { - "balance": "1000000000000000000000000" - }, - "544ffeab53bdc59ef8edaff0042b03c2ea123615": { - "balance": "10000000000000000000000" - }, - "54613713df6c5b89c3012a7835651f25cdac8331": { - "balance": "98684037547000000000" - }, - "5471fb39b4e48c118f855492830ad9e2eaa68179": { - "balance": "91791250228000000000" - }, - "5472591efd048dd60a4d6afdb549e95a65578b0a": { - "balance": "50000000000000000000000" - }, - "547b4c1ae70567fd77a896dc05eb536f502ac8a4": { - "balance": "14037444012000000000" - }, - "547fa9f6f86a2939f9144aacb74e0af60d434535": { - "balance": "428416957729000000000" - }, - "54841d6a478cb9b6e717a9de35577a1a4a504b0d": { - "balance": "144000000000000000000" - }, - "549157e5b1c92a88a0eef335b1bcf4d162482017": { - "balance": "21019502942000000000" - }, - "5492757c55c72ac5946b21514ee16c5065ecde7b": { - "balance": "10446737491000000000" - }, - "54984a41eeaa8e710e4e5b8a7f68c96057b7df3a": { - "balance": "10000000000000000000000" - }, - "549a3717a1bca3f38d24655197c3ccef1e8c273e": { - "balance": "4416133255000000000" - }, - "54b047fbe004191cd02f31163d29bd61ccfaadf7": { - "balance": "52649445905000000000" - }, - "54b125d8b260386633b756056b7d7e78e7071715": { - "balance": "10000000000000000000000" - }, - "54ffad1ae76ab45c4218ced27e49bf2745b2a2e7": { - "balance": "1426474871178000000000" - }, - "550b28968bae36f4e99780c6d7deb54c158be6d8": { - "balance": "10000000000000000000" - }, - "55117923e8393dbf233c0f10819e7de75569962c": { - "balance": "470094520022000000000" - }, - "554a2471e6ecf2320da545d559c40b8b622465ab": { - "balance": "4052895973949000000000" - }, - "55607b39da9480ed8f54d74d0818ab8798136589": { - "balance": "13704276648975000000000" - }, - "5561cbe99fd775f5d0f05903fd62ba4877b3319d": { - "balance": "1007596371374000000000" - }, - "559ba7ab58670d4a0b118bbf6aed7f6fdb276594": { - "balance": "3127762973000000000" - }, - "55b0bc444f2a5952a98f216f61cf07382da1e156": { - "balance": "18683409750727000000000" - }, - "55c0a02dc68123aca7ee0c9cd073ead50b16406e": { - "balance": "99999999580000000000000" - }, - "55c47d593952afd637050c5758a921a204f23fc6": { - "balance": "1615608723958000000000" - }, - "55c6855b3970e5a550f0c75d5727329476406d91": { - "balance": "600705012673000000000" - }, - "55eadbe33899f53138d0fb204f42e272f447cfd6": { - "balance": "1671128311341000000000" - }, - "55fa59fa0fbba06b7184ea78868d438176eb96eb": { - "balance": "1553000000000000000000" - }, - "560a11493b5a0ec28589e80276fe975ee26c6a3e": { - "balance": "10000000000000000000000" - }, - "560fbb31d83bf6dc49e5fb15bd582d70c49fd273": { - "balance": "46015432815000000000" - }, - "5620e17ccf094b1be1a93f6f3388fb96e3a90165": { - "balance": "484000000000000000000" - }, - "5633512298cf74f4d2b8663e6f291e9e25436e7f": { - "balance": "10026444446000000000" - }, - "564423f92b8841b3b1f8bdba443067b580916e65": { - "balance": "465451550122000000000" - }, - "56730e1d11a84970355c43ac7659f2f4786dadcd": { - "balance": "20000000000000000000000" - }, - "5678851984add045f3d054623c198dfd4665d54e": { - "balance": "227651903234000000000" - }, - "569cf18b4bcb99e3f3d27235f2c4c0d8d160af03": { - "balance": "4124979731000000000" - }, - "56ac5f2c3486a9ce744a71599ab89a606e7464a7": { - "balance": "9000000000000000000" - }, - "56bc5936a6ea37c1d0839bf64bcec0d366840ace": { - "balance": "14741201469670000000000" - }, - "56bf62e0135e903525cc46b0a3cce33f4a16880a": { - "balance": "534970476270000000000" - }, - "56da0781a80a0abf5dcda4da35861e9de601bfbb": { - "balance": "166898390441000000000" - }, - "56db15729e52d615a744a04f8a59d63e3b9f735b": { - "balance": "10000000000000000000000" - }, - "56e32ed78e7f5be6b00c28847efe7b3589cdae1a": { - "balance": "1046236086484000000000" - }, - "570f7a08150e0088178276f8116bc4103f885903": { - "balance": "1124393518440000000000" - }, - "57147fdd9b52ef53b4ebd4b5712d29da83f99374": { - "balance": "39000000000000" - }, - "57395fb355fe51f1b32c1baa4e9ee0fc2b8fe05c": { - "balance": "7701013675397000000000" - }, - "5752f0f11ed12bb1d5041b0cee4ddd500cd8806f": { - "balance": "151337200533000000000" - }, - "575907d73ad5ad4980a2037efbd20860afc67ad9": { - "balance": "3568754158000000000000" - }, - "576acb4c0bccc89903ad285ac08c70fde514aaf2": { - "balance": "25000000000000000000" - }, - "5784cb8a17cfb5392c4aeec2edbd173849ca6ee3": { - "balance": "15804767597000000000" - }, - "579234645eb857a3ca51230b3a02b964f8efa2f6": { - "balance": "20576922380000000000" - }, - "57989f9fa52b4c0502e7d0c3caac0c37a0b20516": { - "balance": "462711082812000000000" - }, - "57a55c376ea03c22e21c797d83e2fb039508ad3c": { - "balance": "10000000000000000000" - }, - "57d1612ea1fddacf088b62f625ad8cd49d7517cd": { - "balance": "18001023230648000000000" - }, - "5811590907050746b897efe65fea7b65710e1a2c": { - "balance": "310984892882000000000" - }, - "582ffd8c43966aa8ad3c6cecdfc18eddc56fe5c0": { - "balance": "69136214255000000000" - }, - "583b90b3c4d00b9ddf101efbce75bb811d969fe2": { - "balance": "7839200298177000000000" - }, - "5841fee8b1965141e51b8c146b6af00f6a879a8c": { - "balance": "1210322907244000000000" - }, - "5847a576f7799ba1a35e36906b2c2a5aadeb99b1": { - "balance": "183765768447000000000" - }, - "586dea7ada0a54150f5afcf54198db473ed046a2": { - "balance": "7123598380000000000" - }, - "586f545062ec7dc0ffc213eacd59af80660df570": { - "balance": "10000000000000000000000" - }, - "587187488758f67912bd5bb8a5be787a73d97ee3": { - "balance": "702757402654000000000" - }, - "58be0a3482dc3411571f047f4128387049cb9798": { - "balance": "1000000000000000000" - }, - "58d546e2ae82efc4d8efc887ac6fd30f7eb5dac6": { - "balance": "1486717153455000000000" - }, - "58e7010e6b8d97a556c0e7f0d90151224ebf674e": { - "balance": "20000000000000000000000" - }, - "58f991b3b12d29f09ff4cc2c6e83d576e95b1f59": { - "balance": "25000000000000000000" - }, - "5923a65a796934e69081715657e8dfec8874e40d": { - "balance": "10000000000000000000000" - }, - "593b7c43073b8954355ed76020ff3780dd6ae783": { - "balance": "1403468567787000000000" - }, - "5947f1dbd79a622bcc3fa64b19f9b6eda164dcce": { - "balance": "50000000000000000000" - }, - "596311e2fc09ae1eaee57900f2ca188afd5e68a6": { - "balance": "448723397560091000000000" - }, - "597a3adac4607d457c90817220f67eb4abcf129f": { - "balance": "18000240000000000000" - }, - "598201a9bcff0a773e9323338a8a094e9d9b3999": { - "balance": "74904485722481000000000" - }, - "599e93031704c2ce36308f44d4ff8166e71ae516": { - "balance": "100000000000000000000" - }, - "59af0178699f9f3d8f0ea645dda75356119a6e2e": { - "balance": "152462578058000000000" - }, - "59b0c06e40475cd75728797add9c69c3fdb17b4e": { - "balance": "23147237210000000000" - }, - "59b79577f183b9d39c2b458646a26b2fd6ed806e": { - "balance": "4244859516807000000000" - }, - "5a03b51d67a9c660258ebc030120d5d1d4f687c5": { - "balance": "4451691855300000000000" - }, - "5a0d03dff6754963c757eb15a3339ac6c4ba6196": { - "balance": "215126489934000000000" - }, - "5a34ab3937854e407a8739fa14574d3d20e30d6f": { - "balance": "1375979293937000000000" - }, - "5a352fbeb2fd78bbe0268b0efd34f68d401e2769": { - "balance": "27929247671418000000000" - }, - "5a47c2ca4c0fad7e2fc7bbdf5f2356d68843c564": { - "balance": "3218227936000000000" - }, - "5a538adb2c7f6a80634b0ec20ec5152ff6bb4d5f": { - "balance": "10000000000000000000000" - }, - "5a8fe770c221072a7cba79ae7759cae0185adde7": { - "balance": "11913943233694000000000" - }, - "5aafe1efac688583d7facb09d3e569d58fb5a357": { - "balance": "4713219466825000000000" - }, - "5ab68d762750d5185138187db7751c9f71db5836": { - "balance": "500000000000000000000000" - }, - "5acab69851959dd5a6f0673ef757009ed36dfa3b": { - "balance": "974443209942000000000" - }, - "5ad9f2ab11b5e59b756404395f350aad6019d7a7": { - "balance": "54151179981663000000000" - }, - "5b1dc013ba1a28235cc70e785a00eff8808faef6": { - "balance": "516289257133000000000" - }, - "5b1eeb44ef61c7f35482503b7041162bec9b1e32": { - "balance": "125493885394000000000" - }, - "5b3db31996bca4625d22330686128ec234270206": { - "balance": "362316593128000000000" - }, - "5b401fc9ff3be7cdf5f0df870843bbef94f43285": { - "balance": "1373804724122000000000" - }, - "5b47ba296069041f25768e61be14437b8a469e81": { - "balance": "3152706392234000000000" - }, - "5b5030b5057c0457c190489c5d709d7dbdddee8f": { - "balance": "1154404278000000000" - }, - "5b5a4a782d37154a307868cd79bec9cb2a8f0161": { - "balance": "100277816425153000000000" - }, - "5b5e0b6b7cc27b06456ba4c7816ac4e89e1e26a3": { - "balance": "1023749119000000000" - }, - "5b638e4b6dfdb6928b07586e63d5879dce69a1f8": { - "balance": "1000000000000000000000000" - }, - "5b7be81d6ff5228a2b8c2913deea3f86823f1dee": { - "balance": "36000000000000000000" - }, - "5b7c4804bc2b8c72f3112b73d44b59c0711f83cf": { - "balance": "6803857604000000000" - }, - "5ba26d941544d07100744d8ffd6595a8eb7770bc": { - "balance": "583051897662000000000" - }, - "5bd58fc88733632b63d4f26893bc5c08fb60e2ad": { - "balance": "3480620567502000000000" - }, - "5bd85b5f0ecad08133fceb486c43998e537b3451": { - "balance": "484263880245000000000" - }, - "5c12639a5ab107f9e580cbd2278568dde10758d6": { - "balance": "101293252434000000000" - }, - "5c5522df05d6c6d960394c4762599e74247ab102": { - "balance": "149088856773000000000" - }, - "5c722f3ac94421f95389756af9cd97d0eaa6b696": { - "balance": "1435349483553000000000" - }, - "5c7b14ce51abf629bb0953ee4e2d9d87fc86eb4d": { - "balance": "10000000000000000000000" - }, - "5c8b215403da4e7912c1a1704a949087e091b111": { - "balance": "1440961256910000000000" - }, - "5cab313964f6730888e4158234bbd4806db0286e": { - "balance": "32284637230203000000000" - }, - "5cd736bf65c99469490d0523b10a658178cab10b": { - "balance": "99740204082000000000" - }, - "5ce91ef7ae254b2bd6d910cbf0d380814200811b": { - "balance": "50000000000000000000000" - }, - "5d15fc3a0ba8b3d87b80f9bbf972320112c644f9": { - "balance": "64000000000000000000" - }, - "5d2ccc795b19df400f21f24c0dca4d0e9e898093": { - "balance": "10000000000000000000000" - }, - "5d879b8b31af1e400cf53eb7170f82583190b96f": { - "balance": "93765337844000000000" - }, - "5d8dd54178b68bb36e1963d47d29c123864fd0ef": { - "balance": "20000000000000000000000" - }, - "5da1653bbe8353134edfff6158211ad7ee21dbef": { - "balance": "1491149937915000000000" - }, - "5da733ef41a7bdc0cf7975f83ed24604fbb4d40b": { - "balance": "10343699901151000000000" - }, - "5ddf5d7306f7c603b8d3ff993f03906dca14cd8b": { - "balance": "862558469755000000000" - }, - "5de87ec54e2160c7c2a8eff2d859414737501ae2": { - "balance": "21579321171000000000" - }, - "5df1b805b1361c1f39ca844aebe5ecee8a8d06b2": { - "balance": "411820472746000000000" - }, - "5df86b0a183b5e7f702e4da582ce9a8116a05f61": { - "balance": "256000000000000000000" - }, - "5e22359e20dc14be6930c6c1ce5a0c81c039cac7": { - "balance": "10000000000000000000" - }, - "5e2d38a06f33c784303abf2012f9af12622d9e5a": { - "balance": "10000000000000000000000" - }, - "5e479e616585e7fa84bd6f7465d394a1c0302be7": { - "balance": "10000000000000000000000" - }, - "5e4a55027a0d372f6da042b7f73720b143347d9c": { - "balance": "16175516772000000000" - }, - "5e52e86eda3e05f96e353d7e3f0ee90f08864f84": { - "balance": "21255916842000000000" - }, - "5e91c4d3a21c9dfac2c0994ed8890c78d58626d5": { - "balance": "325349462011000000000" - }, - "5ea797b18caba45d5504e57b80b12f5f5ae630aa": { - "balance": "7805696321000000000" - }, - "5eaec8815e859c34dba88cfe7b7fe28572c964ba": { - "balance": "145852682588000000000" - }, - "5eb974b5716fc4712d431bec7fbb2c49057a7b84": { - "balance": "4890681156035000000000" - }, - "5ee5f8407dedbac839f509419051106219458006": { - "balance": "3042761975468000000000" - }, - "5ef782abb28d1ca889ceb3039eef98713effbf32": { - "balance": "40915083108000000000" - }, - "5f23b88f06430c42570ac3fa33b1c7503b388a3c": { - "balance": "2376070180325000000000" - }, - "5f2b1641c0f2605b090039851aacf297e35632ef": { - "balance": "141615261000000000" - }, - "5f44cc8083340e644d19d3debc84dc14a0cbc53f": { - "balance": "291829106275000000000" - }, - "5f633f89adcc70e9da0b66611a5da108b4b221cd": { - "balance": "50835573000000000" - }, - "5f94ef8e9612b03a5c6ffcf423ada9a19a40818f": { - "balance": "102566595099430000000000" - }, - "5fae1977b76a5e899b384f572e4d94855f9cb52f": { - "balance": "773616125740000000000" - }, - "5fbd22cb3de462c794e523fd1ce36f230cc84b83": { - "balance": "1009995132839000000000" - }, - "5fd91676bc95bd6b5e69db8b9216dc83ed9dddaa": { - "balance": "1000000000000000000" - }, - "5fdda8f5271a08cf1b830faa497019d75fa9d231": { - "balance": "4149626365000000000" - }, - "5fdea351c5eccedf2394fb54437b149ae423ecf3": { - "balance": "100000000000000000000000" - }, - "5fe70ee123cb2e03c768138b2f71c1e1ea75ad17": { - "balance": "1074496282650000000000" - }, - "5fec9df797214459f85a040a559b186ee9161c88": { - "balance": "205282872821268000000000" - }, - "60037df7e4092466656a6b9571437fc4600c66e3": { - "balance": "1000000000000000000000000" - }, - "6009a0bcf531640a5a7f1664a69fe0f64b564ede": { - "balance": "50170000000000000000" - }, - "601668d8b678c95ec5ef98d9d2624decbdd52e9b": { - "balance": "23592727870000000000" - }, - "6027bafcd0ade24fda8c345dcbc812d59df74bf7": { - "balance": "10000000000000000000000" - }, - "6029514f24825c1fadc68cf8614951de5d53268f": { - "balance": "1389262963614000000000" - }, - "606de6db14272a314d778cf0e67913b7fabea45c": { - "balance": "144000000000000000000" - }, - "6074f20675f975ae2c081930cae8f299710f0bba": { - "balance": "10000000000000000000000" - }, - "60850fa9e09d414af3690e4b5daefb1b906b0d20": { - "balance": "10000000000000000000000" - }, - "60ad0b6239dda5df7ac0f0ca941684cf20ae0fd8": { - "balance": "81000000000000000000" - }, - "60d6136e6db631be45fefb9667c3dfa69e9d6054": { - "balance": "651902184266000000000" - }, - "60d733dedec6886908520ba57cab8c9d5c2d7f7a": { - "balance": "555461746642000000000" - }, - "61202238aea4010d115c5c64322ad790576cee43": { - "balance": "10465801848035000000000" - }, - "6142d92b61111657de4b2d65698a3621411e3adc": { - "balance": "100000000000000000000" - }, - "61879bc1a022d9cac8b7d57c8f528065beb10bb2": { - "balance": "72766025231000000000" - }, - "618b15c9a60ad89e7fc28afc79bbf7f28d4998cf": { - "balance": "444855210015000000000" - }, - "61c1169e8ba43ee6b919e5be2eac19542eb913b4": { - "balance": "500000000000000000000000" - }, - "61f1cd6efce17f5458325f022f363fd9772d8f20": { - "balance": "19704989598372000000000" - }, - "61f7d39211a0af2e226d8cbc95fb673168653b0a": { - "balance": "484884476279000000000" - }, - "621aa67f09e6506efb2fd141f080fb1d96693a57": { - "balance": "1694451603196000000000" - }, - "62332fa5127b98bd2a627a0ac22d3a1bdb418efd": { - "balance": "926882233406000000000" - }, - "624a465696ad409586a2e67d84750ba50a971fee": { - "balance": "25000000000000000000" - }, - "624d866f0d61bdefc3ec2210bfe36b6d51018f9c": { - "balance": "199592183194000000000" - }, - "6255d6d3b49443891661b209056d530ecd63bcca": { - "balance": "10000000000000000000000" - }, - "626c484055e6739d46e2ff25190c8b3a4af3fe0f": { - "balance": "1485276462321000000000" - }, - "62865e637d723393ab9654d6439db7fb5abf8803": { - "balance": "10000000000000000000000" - }, - "628a47761d5ce755de88444aaf6d7736b911672f": { - "balance": "18625552918216000000000" - }, - "62df6a38e8b15a1c4f4a7aa7c1736c612f54a0e4": { - "balance": "16468111299582000000000" - }, - "631d7916ddbb5f7c469f8ba07cd48e377560319d": { - "balance": "2493487426430000000000" - }, - "632754f5afcae7dc36d9286cfcd91c14abf0f7bd": { - "balance": "1424933496931000000000" - }, - "635788343997ea9f145c508b0cd2ed36e180f46d": { - "balance": "143040938538000000000" - }, - "636973e7dbda9e3042a8c03e25696d0faf27f025": { - "balance": "5491869128148000000000" - }, - "63707efa26d34d7ceadf4e6439324e7bde0ebc3f": { - "balance": "1000000000000000000" - }, - "637d92494f7872d397340c9b5183dce354c8c43b": { - "balance": "724687404033000000000" - }, - "63b9c2e6762a431752f7669b8bbedae9f37120b3": { - "balance": "1360967549741000000000" - }, - "63bd281d8c4d1279519237a2b68f2a73c228f7e1": { - "balance": "217457311664000000000" - }, - "63c0eb8c9a0019e36ec9a731b4bd947271a5bed0": { - "balance": "36693488147419103230" - }, - "63c6362eff56de328a29b7e9d32ced28f3602b6b": { - "balance": "148335309448000000000" - }, - "63c979c787a7b037693cadfeda738ae33178c009": { - "balance": "81000000000000000000" - }, - "63d4621d91906215d32f6fbcee1ac48bd773f630": { - "balance": "1006939236069000000000" - }, - "63ff99fec1cbd2f6e83c0e6de3c0ea4b7c7e1398": { - "balance": "1201300688980000000000" - }, - "640ffd856e48528b05d5ef1e60348048ce291960": { - "balance": "20000000000000000000000" - }, - "641c25f7c380e2745c81a268384a029b2e2be0cf": { - "balance": "635133477665000000000" - }, - "6427792a164bbeab45f6c3acf17c76f721b90e81": { - "balance": "10000000000000000000000" - }, - "6437986b4c545af9c4a5ee96371a5807275e9221": { - "balance": "2951152516627000000000" - }, - "64460d09d1bc5c425d62bef5969eb0c5916963c3": { - "balance": "1680000000000000000" - }, - "646381f92216b97abbd86ca100a773eebdf7545b": { - "balance": "211234535515000000000" - }, - "649f73d1cafeb3ab0631432f04c9d08b9f438c22": { - "balance": "248900746448000000000" - }, - "64a239be45a92df83bb85b25f8ed7de5d82313b9": { - "balance": "100000000000000000000000" - }, - "64a3d97f82e3d42eea78bbcee31a95d33767b055": { - "balance": "2511466286000000000" - }, - "64ad579975888f455217e0f801e371900d9814c9": { - "balance": "7118859416319000000000" - }, - "64af5edbfec8adea679951662c08a781175688bb": { - "balance": "822966999709000000000" - }, - "64b7f2c22c20a59c07cb0dd7f8f692153c68f3f8": { - "balance": "20000000000000000000000" - }, - "64bc17e28d468b7b8368ee8a8375710d21c3ac5d": { - "balance": "875002262415000000000" - }, - "64d17aa662e56061cebb3c2e2421e637163e8dd3": { - "balance": "363241251465000000000" - }, - "64d714ec3145308e8f939bab7591b0773038b886": { - "balance": "338231954012000000000" - }, - "65199fc9ba95434382c108b44ac553534a9a3670": { - "balance": "2537340957145000000000" - }, - "6527c67c29e47833dc2440570596023318a7bd99": { - "balance": "555434226832000000000" - }, - "654b9d299077c90768c5ca6635e5802e8099f51a": { - "balance": "119004827465000000000" - }, - "655908513607cc38de35351ff3738b201bbf39d4": { - "balance": "652902936029000000000" - }, - "656ad16063b2d397788c231e537384ece94eb0d2": { - "balance": "63116382606000000000" - }, - "656e622970b8829a7cfe24f5b82696c7777683ba": { - "balance": "20390269890405000000000" - }, - "6583a6ff4dfcf447e3b163a61b0d5cb84ceee375": { - "balance": "3858529344000000000" - }, - "658d2b7e8a6517256efafd74321757d5c384a2b9": { - "balance": "221114751567000000000" - }, - "65920758857ee5b27b0f31487ccc3c5d6986df3a": { - "balance": "16272975796000000000" - }, - "659d60d67a07774ecc5cfea9e56809bec024d639": { - "balance": "20000000000000000000000" - }, - "65a1a3f968bab5fc1f097b8e297099a3d34ef45a": { - "balance": "16000000000000000000" - }, - "65b5e3163d20b2a6fc75c0219b7f97d83479a26d": { - "balance": "1716459529041000000000" - }, - "65c9bc3b8b0ce7c4d16b35abe1a5c285a59f672e": { - "balance": "20000000000000000000000" - }, - "65d5b458d9b1a9659c1125d20d970d5e6c29dc3e": { - "balance": "20000000000000000000000" - }, - "65e75bb8ade25eb7975ea12b9afdb17ac21063b3": { - "balance": "2270407774714000000000" - }, - "65ed78d0c4ef1150e8765b24b210f056e079cd59": { - "balance": "500000000000000000000000" - }, - "664ee5e334b8378928becfbf5d5e51daaf001125": { - "balance": "860160259186000000000" - }, - "6679bdb26adc179d046607d49f4b10c65d8a40d1": { - "balance": "436794739763000000000" - }, - "6680fe9d6eda3ab9fc4ac1ac933339b533eb682b": { - "balance": "551296206326000000000" - }, - "66a1249501cc5076b040bbb165ce032ace216ea2": { - "balance": "36000000000000000000" - }, - "66a475d014c2f976704bfb93ce78dbabbfc5e072": { - "balance": "1140135640169000000000" - }, - "66ae43d92e8fb2231fee8c72d720ff90cdd267ff": { - "balance": "796696150339000000000" - }, - "66b7e0c810d6959afa8210f6ca67e3e40bd24eb9": { - "balance": "16000000000000000000" - }, - "66bf8be16f33b111b2a425743bb7ebcdfbb35034": { - "balance": "538590591000000000" - }, - "66d2eaf7fe10900d93eab17823ebfde5486aa2b7": { - "balance": "121000000000000000000" - }, - "66e525bb01b3ede1a4a105bb6087ec8a76200616": { - "balance": "1506610219207000000000" - }, - "67291e0df83d6e9f1386e87a1792d7d147341df9": { - "balance": "272330177662000000000" - }, - "6730b27b62e064b9d63df3bcbb8c4bbb0e500afe": { - "balance": "331282968154000000000" - }, - "67318617bfe19b739fac9a126fd129223db52498": { - "balance": "12699924981000000000" - }, - "674dd0b036c91f3a83288af44897b4ceb2e15a12": { - "balance": "4352791270187000000000" - }, - "6751bffd04be55c86692994fed06694cb78b62ff": { - "balance": "26049487516000000000" - }, - "6768d99a0cdcd7bb7c7d0aeee466d6bdc7208bbc": { - "balance": "309909685000000000000" - }, - "677ba2de3e5c68a4c354c9e3129ed1c41025312b": { - "balance": "127426274611000000000" - }, - "67b83745856551f1878027843be20e1473191944": { - "balance": "185757248875000000000" - }, - "68170edcfaf2c6df4e6542b2856ad33e9e2d6623": { - "balance": "4003453949471000000000" - }, - "684ae403d9a08e4f4f971cfedf81094074daa77f": { - "balance": "25139713925794000000000" - }, - "684f3b8a749c002aa434bad6af7a3e2579c69315": { - "balance": "16000000000000000000" - }, - "68538a9e8246be5a5c5ea315cb325344062cf8c4": { - "balance": "14009193210480000000000" - }, - "68935ff3a3a3b6ef16ae7df58cee50b157658dd2": { - "balance": "20000000000000000000000" - }, - "689f508256ea64f5dbd6bb77f1ce1bdaf36d7152": { - "balance": "10000000000000000000000" - }, - "68a3e6e7c191a8c1add988bfbbb9b51d4f36f521": { - "balance": "10000000000000000000000" - }, - "68a74ff2a5577321f854b56d3834a55d3c41bd94": { - "balance": "88873831171000000000" - }, - "68e6da521bde13cf4e4f423a78fda2f69b3d1c2a": { - "balance": "538392460838000000000" - }, - "68ecd5cf8cf8d9704fafc36d8da53930afeb0553": { - "balance": "1090923641219767000000000" - }, - "68fd0b8e000bd2788be6cb10fc0496fe2cbe155d": { - "balance": "32853847745000000000" - }, - "6904045feb5ef94e096894b863d314ff8a0f206b": { - "balance": "9892165615000000000" - }, - "690fbae5153849bb20797af7b8dea66a728a06c3": { - "balance": "6082107223716000000000" - }, - "693d909842877d017e0f102e37a55024517dd0ae": { - "balance": "20000000000000000000000" - }, - "694cd00fac9cded484ef2cfcd44faf161354f288": { - "balance": "3049716150137000000000" - }, - "6964c3c2c7bc719ec94a51bc4bf412e137d2b4e9": { - "balance": "1000000000000000000000000" - }, - "69a5c692516940bebad8efaa2243a8fbdf2ade62": { - "balance": "2803346939929000000000" - }, - "69f566c44802b0140f5e1c9234f46006773c03d4": { - "balance": "20000000000000000000000" - }, - "6a17eef3a6bd407260f52067592226448182cdc3": { - "balance": "1116509364305000000000" - }, - "6a200e99a0f50aab32fa7373c7880817c81f472a": { - "balance": "1836680122795000000000" - }, - "6a2a29f5f441876816dd17856051040787f48a64": { - "balance": "1131603204000000000" - }, - "6a3f855c7dceb75d0de7fa18fbc2f40c81b76756": { - "balance": "32267494586000000000" - }, - "6a46af653b938643e781cc4a0edcf5357852fd21": { - "balance": "1140718780752000000000" - }, - "6a4b2e5b45da0d70621ce71f165a11078a1745e2": { - "balance": "3768326643000000000" - }, - "6a530c813595a5b7776cced05a865dedcb110d94": { - "balance": "270559347097000000000" - }, - "6a6e3e82f98ce891f47721770301dbe2652a9e25": { - "balance": "10000000000000000000000" - }, - "6a828d6f2f7f68bde4a12608024020e593540010": { - "balance": "7531817000000000" - }, - "6aaddd1f4ff6b4d414c87271619b826ead27f09f": { - "balance": "64000000000000000000" - }, - "6ae6bce1e2865ade0d02eff9899ea3767b5511cd": { - "balance": "6893781798524000000000" - }, - "6b04e7c6a837d218fd3322b87a267fdd979358ef": { - "balance": "302679180175000000000" - }, - "6b2210b8536803b134e69c5046904acafef48cdd": { - "balance": "47823456459000000000" - }, - "6b2da6f36c2e7f61cabd7580480065360c995c93": { - "balance": "55000000000000000000000000" - }, - "6b3401986f2be7ae5a4ec160b8f96b2a651fce73": { - "balance": "16000000000000000000" - }, - "6b3847774e99dec307dcf5bf5adba49df4a9f145": { - "balance": "43276069579000000000" - }, - "6b57f2d9d95cac67fd2f70c0911d48c7f09de072": { - "balance": "1000000000000000000" - }, - "6b65d736a8ca89ec8508b52e4aca5166f9703732": { - "balance": "766421968820000000000" - }, - "6bcc55d897829e98fc3f3ac8beb331e59c33b942": { - "balance": "318115956882000000000" - }, - "6bd76e7af1775b88743d5f53ede0ce846d3d7ced": { - "balance": "139548017482371000000000" - }, - "6bd7cca99acf6eed5842417c2327c642df5473fd": { - "balance": "3321731000000000" - }, - "6bf72c4d39d6700181954a8d386c3df216634412": { - "balance": "12742769034078000000000" - }, - "6bfd3aedeac7c6ec086c0a4ec29d2d0f5bd69bc5": { - "balance": "50000000000000000000000" - }, - "6c025962810a6fb8374af5e07d7fcd631d10b1ce": { - "balance": "674126722005000000000" - }, - "6c1b72df836f410038af9e020fa2ff2ead398ef4": { - "balance": "1851293017364000000000" - }, - "6c1fddb4254ff46b3750de322ebb7d6238c0a606": { - "balance": "9977629348276000000000" - }, - "6c37069a361c5c72355bb5a56879dd0a9735a237": { - "balance": "1062230154063000000000" - }, - "6cb166eeca248a234c971b2a864a7b3fdbe5a737": { - "balance": "390222992865000000000" - }, - "6cb797289059cadcfa77eab0365e6bf1ae12df46": { - "balance": "100000000000000000000" - }, - "6cc787e6bb4f484828b080330667b93953e7a3c9": { - "balance": "16106440380234000000000" - }, - "6cdf7b334fb2ef8115198d475d431eeb7d88df77": { - "balance": "1940904395351000000000" - }, - "6ced85b035b787e9e427d0904aaf96e011417310": { - "balance": "103417697874000000000" - }, - "6d6e09acc07f388cbab99e53959f75e9ad8f07bc": { - "balance": "1305917678000000000" - }, - "6da91b02f512f412d374392247a9aaa853e9dd59": { - "balance": "2300525907893000000000" - }, - "6de5d70481cd40db468f64227228cdd362ad9980": { - "balance": "10447389944082000000000" - }, - "6dea87255c9ebfa63f017209046e894ecbbc03b7": { - "balance": "1527216854064000000000" - }, - "6df6f6b9953c2f2a8ce5985e19dd6835ae2c566c": { - "balance": "6539856530000000000" - }, - "6e013c83cac111a38fbbf8d47778fda0d3af25d5": { - "balance": "12139181929380000000000" - }, - "6e18a484f402fd433a5ac4dee5a4b8bf6f22db47": { - "balance": "23215906572368000000000" - }, - "6e4fd058e4dcd502c2015f83f3677f680ec58110": { - "balance": "480059342014000000000" - }, - "6e501ac7357fc758caf5dff6c29a995c806a1a7f": { - "balance": "1573491311733000000000" - }, - "6e6912f9fc21dfba736055e6ccef074dd62dcc59": { - "balance": "256000000000000000000" - }, - "6e869c68511c1458f4fbed9a4c5296fe961eb47e": { - "balance": "68488423994541000000000" - }, - "6ea6827b377b3d3ecf7c7628ed8daad7fd8eab1e": { - "balance": "188825714738000000000" - }, - "6eb9237738339fcaad3763466509f23efd0c5054": { - "balance": "48417242786000000000" - }, - "6eb92a61390f9d9ecdac80a8833aa801c3926b13": { - "balance": "1412936326723000000000" - }, - "6ecb93f18153ef2d2a552286ea3b7436f1f8168c": { - "balance": "20272577229669000000000" - }, - "6ee087c04cf16f4768c783a548686448fd125914": { - "balance": "1397039628538000000000" - }, - "6efbae7a34c71233329d0bb4cbec45274824ebf4": { - "balance": "8910000000000000000" - }, - "6efcd6776f287c25a6eb3cf71018adc282eeab6d": { - "balance": "1310659853178000000000" - }, - "6f9ca805ddaaea5205e85778dedb2eff4a5aaa75": { - "balance": "2585733757016000000000" - }, - "6fbbea927469f4d18942ce0aade164828fe23a2a": { - "balance": "4671857880000000000" - }, - "6fbe9df6c42151c453502960d99170445dd3ac0a": { - "balance": "20060296562115000000000" - }, - "6fed121fb310431f1659e637f35f4c878a7256c7": { - "balance": "55170085399000000000" - }, - "6ff2dd5373bd72966ef48d3183c60d74a6549cb9": { - "balance": "24103445361000000000" - }, - "703a490c4783776da244384c964897491aed3711": { - "balance": "2001677632732000000000" - }, - "704dcd2d9f75f0bbfb73f2fe58bcbf4508374381": { - "balance": "439603954369000000000" - }, - "70859a14f33b8ab873fa5781a4af1ce40dff65c0": { - "balance": "10000000000000000000000" - }, - "70b9cdfa5f6d41c60e1c0d3f544f569c9b340ea2": { - "balance": "198355566698000000000" - }, - "70d0ee793e28e320b34267ef2df69050fca0a9e0": { - "balance": "8010660534227000000000" - }, - "70dc7e5951752c22a0e3c50e8e7b1f7af4971d51": { - "balance": "3991137321749000000000" - }, - "71057f5afbed7d82c92d50790e3797fd7395d036": { - "balance": "49000000000000000000" - }, - "7109a3b3d5d6af49693549728691099d696ce016": { - "balance": "4119694297000000000" - }, - "712231a5161745fa1b33c7b0f6e8c767e1de4f81": { - "balance": "1353809351914000000000" - }, - "712aa38999c0be211654e5c84f59e3b2e018f597": { - "balance": "160199774000000000000" - }, - "713229fc94a86b71a5bd1ea6498b9373e3f3c549": { - "balance": "98289185940000000000" - }, - "715de29a0b6f467b94d4a90dc767ad52d0fb3b9e": { - "balance": "948824982990000000000" - }, - "71776853ac97ce04b008c9a7b64156a3cafc52a4": { - "balance": "608309596513759000000000" - }, - "7189f6dcfe64e1ddbfb5e51fd5f3174bc636dd0e": { - "balance": "5674608906899000000000" - }, - "718a4da87464caf6e83ca374d5ef9255b8f7cc3e": { - "balance": "761891873568000000000" - }, - "71bc447761cdb68915cc2288b4929fdc0adce02d": { - "balance": "10000000000000000000" - }, - "71d78531896642069b725bf82fc385789c63217c": { - "balance": "33103960195000000000" - }, - "71e328deeafbb1724051d1062609c43eef56ecdf": { - "balance": "493550967964000000000" - }, - "71ed0310fb51b86a61794aea17a3c792dd301e3c": { - "balance": "3234918634449000000000" - }, - "71fa264f58041e41cfe36e8f8d4e0cb22ab71925": { - "balance": "5558941960000000000" - }, - "72059c57d0fc05bc02ba54ebea6cefd1efbeadf1": { - "balance": "4458278271443000000000" - }, - "720847a28916a532bcab33e1fcbde5d1c4d820bc": { - "balance": "1392418942284000000000" - }, - "723cd2b5b836b0ee8481d37b9c51b5f3f1beddd2": { - "balance": "1856420455522000000000" - }, - "72430c6664d23c7051b0e99912fa54dfadcfdeff": { - "balance": "102078926010505000000000" - }, - "72652c4320dda25348f15c0ecfeb4b3b3ceeb7c8": { - "balance": "307639955659000000000" - }, - "7288bd1b9f4c068dd5df9bcd6fec1ccecd240195": { - "balance": "80161087899000000000" - }, - "7299cb8a288abe8e1a22c11b53a903acb7db5827": { - "balance": "752198565719000000000" - }, - "72f6bc0c3ae437756c099e02e9c084febedc5569": { - "balance": "696294297587000000000" - }, - "730e5907b344c80e0a6115723a90a23e3635192f": { - "balance": "6056082041729000000000" - }, - "732e97b992e4f8a53034cf29cf11aacba7452261": { - "balance": "100000000000000000000000" - }, - "7339df65ce293b3d501647a04c83819099f0bd38": { - "balance": "706500983417000000000" - }, - "73482f8135ca2231db5e0e034a235a9d244a8656": { - "balance": "1143989148865000000000" - }, - "73769e43058d30a530048e5a2bea7e9333534e93": { - "balance": "113542901996000000000" - }, - "73bb9e6f1709fbb7964df7b3cc0f9170c3152f38": { - "balance": "1639793026701000000000" - }, - "73e261da7978764044ee916f88bf66680952607f": { - "balance": "100000000000000000000" - }, - "740154120c4f41c50b0aaa0636a2000ff1e870ad": { - "balance": "10000000000000000000000" - }, - "741fe2a1537284b70e97e3ff659eedfd7fc5b1b6": { - "balance": "75911502037000000000" - }, - "7420bb277d834763e4429db9bf37f053f71ab769": { - "balance": "3100160195046000000000" - }, - "74281371c3b569c774da6bab686e7d7a45d4dc4c": { - "balance": "25666397941223000000000" - }, - "7428d261b5418652c5ab248d6abc3d2af25d904a": { - "balance": "56252809397000000000" - }, - "742c876433297f5a8fd4a25f75ee9a607726bd3c": { - "balance": "4132793019677000000000" - }, - "74302036cf52e11aa3f32a371bb4992e2bdc3f39": { - "balance": "19557661364000000000" - }, - "7445c657c24d014f3a9dddc3e446868bc2dbd13e": { - "balance": "10000000000000000000000" - }, - "744b8fa69d2542be3557267edaeaf2cfa8a9e991": { - "balance": "16000000000000000000" - }, - "74728999963524e7cc1736abcb4deac630142c44": { - "balance": "37000250991000000000" - }, - "74926cbdacd0e871cad0d926c8e17cb2c00475b9": { - "balance": "20000000000000000000000" - }, - "749e115a9e675bb15af5e1c04f81fede07c40120": { - "balance": "440913547154000000000" - }, - "74b7e01acf825898544d6c1b61e53356be759c56": { - "balance": "25000000000000000000" - }, - "74c5fcf875e2e9b726a7cf6e176dc2f7eb84c200": { - "balance": "59208835472000000000" - }, - "74f44579859e4a7944dda7bd810088e116ae9910": { - "balance": "1038454108527000000000" - }, - "750b1e2955ba05c1fc8a1f9dbb1624ed11587edd": { - "balance": "9545712605000000000" - }, - "75375129cff2a051f656b91f868325c3b35ee1ae": { - "balance": "25000000000000000000" - }, - "753ca28fbd89081382a996fe938da7e6c3ae6cfd": { - "balance": "156582454263000000000" - }, - "753d91c04e554680cc32a97c1abc96280e8263ee": { - "balance": "725101425969000000000" - }, - "754e5b5d64c267e83fd4804d112725531cf5abe9": { - "balance": "83276113115000000000" - }, - "7588a96a2bc65569a6c124c4a4acc55863a8ab78": { - "balance": "24062602342000000000" - }, - "759075dc3a6b9d2499a74bc57e346c9ed7ff834e": { - "balance": "225000000000000000000" - }, - "7591d6fa043801fe12462e11d9e33a53f438c073": { - "balance": "1863874274000000000" - }, - "75bda5bdf6aa749bbd62b6107941a7dd9ce3880a": { - "balance": "36000000000000000000" - }, - "75c2d3a99f144c4b9962b49be9d0a81b203906e8": { - "balance": "9000000000000000000" - }, - "75f587a69a97eb4d1c4c4078418d5fa85dff6f94": { - "balance": "10000000000000000000000" - }, - "75f67649605f49d98d866102ea2d6881ead9bea0": { - "balance": "814929108418000000000" - }, - "7602abce0f510b6ca471fd8d734e21a2591886f6": { - "balance": "50000000001006000000000" - }, - "7629b788160531b0be28bf445bf305fbe2c514d2": { - "balance": "23022256366212000000000" - }, - "762aed2e3aa2293e69dc2110b1fc6c806ae799a5": { - "balance": "10000000000000000000000" - }, - "7637b89130bc3f87e90c618fd02d6dd27179101d": { - "balance": "77765738300000000000" - }, - "765136022facade53e7a95c0c7aa510787e674d5": { - "balance": "1478178932688000000000" - }, - "765274015a308a9e6b1f264e5bac592d267f2f7b": { - "balance": "3058788819393000000000" - }, - "765cbc0a89fd727a2c1a6b055139faee53f11330": { - "balance": "500000000000000000000000" - }, - "768bb6d4b190c18a0946d92073ee446d68d98a6f": { - "balance": "144000000000000000000" - }, - "76ae8079894c760f2850c02cf5a0d7bb41e5864d": { - "balance": "156059816821000000000" - }, - "76af4103a231b1302d314c486a0ba524d0427899": { - "balance": "10000000000000000000000" - }, - "76b6394cd02ddf761e981b6a6ce1654c0e575443": { - "balance": "1078304803757000000000" - }, - "76db33eafeaf965dcf15d5460b64a48b37285259": { - "balance": "1000000000000000000" - }, - "76e5721c0a39d41274f84cb572039967a07e9beb": { - "balance": "156298167226000000000" - }, - "76e6ca6ef145d2711ab27f82376a065cc6f62a29": { - "balance": "100000000000000000" - }, - "7705d637cf9f6ceaa452deaca7ccc581beb5fa34": { - "balance": "36254762908065000000000" - }, - "7706c80af4eb372e168501eedfe7bda6dc942243": { - "balance": "50000000000000000000000" - }, - "771493da92c9fc6c6b39a4071ae70d99f6a588d3": { - "balance": "2000677471360000000000" - }, - "7719206286f26144c0f20b5e1c35cf4495271152": { - "balance": "1380480863056000000000" - }, - "771adcba1409fa2df6db19d9f784abc81a7bbf36": { - "balance": "15416381820915000000000" - }, - "772f7baa80a852e05b2fb3903a36061da132b2d8": { - "balance": "121000000000000000000" - }, - "7731a4175eee5077e2ede48878e6e2a18fce0f9e": { - "balance": "10000000000000000000000" - }, - "77385deeba01e3cd7a63e13d6048011020f56724": { - "balance": "57204247488000000000" - }, - "776808e7688432755b9e91a838410d29e532c624": { - "balance": "120318608715941000000000" - }, - "776d1b406f63082b80e250c4a0073fa0d83b9090": { - "balance": "243779839900000000000" - }, - "779848a59036ee3cd23b93ff6d53620d874f0bee": { - "balance": "82228810849000000000" - }, - "77d02a031274bd4ed2a16f3cc29d94e755142036": { - "balance": "408567696646000000000" - }, - "77d609a407aa0d126d58090b8d635f5ab7a02d6d": { - "balance": "776754055755000000000" - }, - "77dec41e116301dbd6e542f139816bfd9bf6d154": { - "balance": "16335989583000000000" - }, - "780398b42f81167731a8ef6a8bd1d14942b83267": { - "balance": "25000000000000000000" - }, - "780a645d59027e7b0670d9565898dc00704cbe5f": { - "balance": "20000000000000000000000" - }, - "78182a7711c773f306ec42ce6da3e983cd49b00b": { - "balance": "580861257254000000000" - }, - "7822622f07fec12995c4bb8eb32d62aa7f00be05": { - "balance": "5018461926846000000000" - }, - "786410c679101c0ebf06fb4f36102368121f3c8b": { - "balance": "16098386724761000000000" - }, - "787d5476038ab0a09b846645285ada23ffd7318c": { - "balance": "492047430907000000000" - }, - "788e9e27ed979d1e7aefadda798f69df1de1d1bd": { - "balance": "30965301214000000000" - }, - "78ab2d2dfaf5d2580ed89c970e771572bc91d3be": { - "balance": "36000000000000000000" - }, - "78ab7ac6f379ff084a7acf4a1a31fe2e5a6834c0": { - "balance": "107332516726000000000" - }, - "78aba95da37385c736ef93d0ca8318baf6c5ff3e": { - "balance": "9000000000000000000" - }, - "78cecbd82229dc91a530bd555c9e45125e2a6bc7": { - "balance": "28474069251604000000000" - }, - "78d4df90990248f3ac67e492a0a1e3f4ee455507": { - "balance": "10000000000000000000" - }, - "78f6de3768abc604c49b10d798e0656948cd334e": { - "balance": "9000000000000000000" - }, - "7909aca95ed899743de222e56c231f9bed1b518a": { - "balance": "5355599376491000000000" - }, - "79193e660b4431e8aca9c821b7daa88064e33750": { - "balance": "100000000000000000000000" - }, - "792487caa23b0d9b9998002810cf29439f7190bb": { - "balance": "4828579961131000000000" - }, - "793f56adea51063243a9633ecc1d1e620a91f327": { - "balance": "926742377449000000000" - }, - "796d187077c1d7591583436ae64d10a641490ca5": { - "balance": "242664407084091000000000" - }, - "79a6b7fad3b5a655679450ca82818ec2d6f58688": { - "balance": "1400472715109000000000" - }, - "79acf627e67cedf48297c26fd135973bff6c57da": { - "balance": "444598475759000000000" - }, - "79ae0dda1964ff0191b98d28c9b52a79dc9ab078": { - "balance": "325908985422000000000" - }, - "79e71dcc52fa1b28226c519f715faa3cf63cfb09": { - "balance": "497898493594000000000" - }, - "79e98193ff8770f26af824734bbb1c2ce8197b6f": { - "balance": "10000000000000000000000" - }, - "79ff3d790d52c58b7317a415278e9058915d5241": { - "balance": "48502649691864000000000" - }, - "7a0b02d16d26e8f31e57106bbdad308f513d436c": { - "balance": "841000000000000000000" - }, - "7a1d422352ec7e6ca46131728e4b71f20ed84e2f": { - "balance": "50496873413000000000" - }, - "7a2a3fbe27e33df867ba8800788995d7662c046b": { - "balance": "100000000000000000000000" - }, - "7a629c4783079cd55633661d2b02e6706b45cf8e": { - "balance": "50000000000000000000000" - }, - "7a62d8875f53e54b775ee2f67f7e2ec137bf724f": { - "balance": "25000000000000000000" - }, - "7a67285fd883d36ea3107aa3fe7727c68a99eb2d": { - "balance": "254787158217000000000" - }, - "7a90fbec48492473d54b0fad128ceda94ea66100": { - "balance": "313715004199000000000" - }, - "7a9e11463d84a08140d698972e32e66bacf7a7c9": { - "balance": "3602603216258000000000" - }, - "7ac4f33e1b93ef0f9c15014e06da24904ef4419e": { - "balance": "101000000000000000" - }, - "7ae082ad247275fd5a9e77b127cee5693784e9e1": { - "balance": "1921957343533000000000" - }, - "7b27e070ca4158d13f8333b34842d4c28b678c92": { - "balance": "10000000000000000000000" - }, - "7b2e34374921e4dc10fd9cfc670a40f5d092da1b": { - "balance": "2098457950503000000000" - }, - "7b54c6c8041c8b09240de1ff06e0d3d2d8d877e0": { - "balance": "944752036841000000000" - }, - "7b5aecb798d8f4f5a04bdaef909e09a35bde8d47": { - "balance": "21975115049000000000" - }, - "7b88a7ef9201966bd1ca634779c3b7f40c22f0d7": { - "balance": "64344833519732000000000" - }, - "7b8c22ddc5c7e59e571587d7c776fa50e65f4845": { - "balance": "225108110445000000000" - }, - "7bb4d8a169f72432494ac362eeab005ce1e02d81": { - "balance": "2098993419448000000000" - }, - "7bbaaa6690698e749d095447bdd27207c0caee43": { - "balance": "490069993631000000000" - }, - "7bbf27f92f9f726381d4f68b21ed86af8f792d04": { - "balance": "806346082666000000000" - }, - "7bc6f172fd78953c3456c571ac8394756715d5fd": { - "balance": "81000000000000000000" - }, - "7bcca29b477730ee8f219a5d1bca24415c7a4625": { - "balance": "36273885000000000000" - }, - "7bd296e1cb29ad87ed28b0ed18440ee686b157e0": { - "balance": "35964679698000000000" - }, - "7bde6d49a1af34a5a9dac0b9007e9a5583c65ebd": { - "balance": "1041474566346000000000" - }, - "7bea6240f245e649563253fa4c1da39b12625da7": { - "balance": "100000000000000000000" - }, - "7bf096396c56f27f9c39c4056ee6cfcb0db44bc6": { - "balance": "407261849111000000000" - }, - "7c3b58d3ba283bd9b1580832e9d014eff48bff7f": { - "balance": "7074518779349000000000" - }, - "7c5a56c45f23c353ff9f6f71ec86c9a6a1a0ca67": { - "balance": "11277879639596900000000" - }, - "7c783ac9b07bc6576835635f37e7e3c137055c8c": { - "balance": "16253676225000000000" - }, - "7ca2fbc0a0d1370e95048a21a300eac4d6056df3": { - "balance": "2772084065617000000000" - }, - "7cbe95802a20eb765f9fcff0a068859cc35d2660": { - "balance": "255153842674000000000" - }, - "7d004fb3a6a81c00fd2872e8079ad2912841b0e0": { - "balance": "642630220843000000000" - }, - "7d30c788d4ea18849ebae1173373c8915ffd7a35": { - "balance": "61062263242000000000" - }, - "7d39324f5ff62e849b0f0f46ab8ee396fbd85581": { - "balance": "100000000000000000000000" - }, - "7db0ce6c04537417dca1dd3415a5bf213edc2028": { - "balance": "30393443462000000000" - }, - "7dcfaa795586c92f1ce7d5c7b10608fe6a773fe4": { - "balance": "183173395920000000000" - }, - "7ddd111cfdc3133f59b82568e3deefc3cf10b0d0": { - "balance": "5622149283840000000000" - }, - "7de81daaa7ed5cbf4d379cdd26ae353cbd5a2489": { - "balance": "10000000000000000000000" - }, - "7e0a11af993a41626c5564f719442c0dfd608ec5": { - "balance": "1532083534600000000000" - }, - "7e34971b187047e7f7980650630b936eedc11023": { - "balance": "10000000000000000000000" - }, - "7e5214e16851b33c4a4d29e5a06929461d3d9555": { - "balance": "371790231197000000000" - }, - "7e52ae9c7e4b888015a3a5af7a91444510aa18e2": { - "balance": "109879329128000000000" - }, - "7e69b383671f96b7abc2d1fed8b61477b87a58dd": { - "balance": "10000000000000000000000" - }, - "7e733b1fcadc9a20dc038fba74e236af0b5a39b3": { - "balance": "43583614302000000000" - }, - "7eadcf955c90040668fb0f75a61f687e4e41f314": { - "balance": "332201682206000000000" - }, - "7eb51f3ead1dd0f5384c199ad5518ec55f77d35c": { - "balance": "38487884822000000000" - }, - "7ee73c0d64caf46f47f439969060092ecafdecd9": { - "balance": "15063618320000000000" - }, - "7ee8e4c6742a4c6d8efbfacc4d56119bc6c74ea4": { - "balance": "31882319329000000000" - }, - "7f16d981521c06347db8324da38b25eab3cee23c": { - "balance": "400000000000000" - }, - "7f6ff7db81a26fe78dd80636f0b178c669344393": { - "balance": "10000000000000000" - }, - "7f792b094c0b96d6819823cf21bc0c402fc27bf9": { - "balance": "50000000000000000000000" - }, - "7f84ae97c21cc45a7e56603ddf97449d803fb246": { - "balance": "81000000000000000000" - }, - "7f89c2b9daba034841f19ae843cfb6cd6f75b1d7": { - "balance": "20000000000000000000000" - }, - "7fb18f8b0e1fd1ed8c863a66226082bdc0429ee6": { - "balance": "11465417544634000000000" - }, - "7fb4e30579c64efe981d0057204e5bd8770a1f87": { - "balance": "249801873762000000000" - }, - "7fcc4de10e837d98691acc52732e1568c890304a": { - "balance": "1000000000000000000" - }, - "7fcc77798cd50345b2784a78b81a25dd4c1e64ab": { - "balance": "2676882485895000000000" - }, - "7fe33e773a02b995278ff595d55a0741813b19d4": { - "balance": "5788279057355000000000" - }, - "7ff32b13d531ceef500ca6c6806ffc0773639264": { - "balance": "1000000000000000" - }, - "801380158ef8f24316bdceaa00eb89c3d886707e": { - "balance": "35627521347898000000000" - }, - "804fdccdc8603858d15dec88666437505b2a106a": { - "balance": "14607090269617000000000" - }, - "807915567eed99bb9146354a32409812b9490d70": { - "balance": "1083142734057000000000" - }, - "8092ceeb2be5b271f4c156d85fe14977e919c7e0": { - "balance": "761607160308000000000" - }, - "80962bf961d0d713395dbe00379a6e207b425a76": { - "balance": "524215754483000000000" - }, - "80a9787124075c8cd44b9c8674967a54445e2354": { - "balance": "7600078997429000000000" - }, - "80aacd59dd76bf443c47ca02976178af8453f23a": { - "balance": "411856023767000000000" - }, - "80db788f7fbd7613f0fff66c21389eedbbd4bd35": { - "balance": "956888725645000000000" - }, - "80e449a70e3c7707d6441ae8863a44aee2d7f3f2": { - "balance": "16260784762856000000000" - }, - "811a2c3d0ba4e1c36a848495585da824ec3a7620": { - "balance": "36000000000000000000" - }, - "812a3c55234d5849a854ad76891c34ee90c8a0e3": { - "balance": "703378980438000000000" - }, - "814b4b5eb67afb8d1a60e3d240fe804bb752f632": { - "balance": "17578964576000000000" - }, - "817025619f37838470b90d0a25af2c02de80dae6": { - "balance": "96000000000000000000" - }, - "817233a104d87cac34d9c90243aebd7f68e0a9ea": { - "balance": "510051038684000000000" - }, - "818be95c0c13c3018b4084ea177556705e84c1f5": { - "balance": "332239667000000000" - }, - "819618c19a4a490b821f8156c5633749ea782ca2": { - "balance": "10000000000000000000000" - }, - "81a80d26b70626e07e8747bc1569dd2855834f7c": { - "balance": "521696417321000000000" - }, - "81b2fb0db882bf2538cf8788bae1ad850cef3bab": { - "balance": "102457067052000000000" - }, - "81d4c3bf72837b21203b2a4f90bf42fda10acf48": { - "balance": "10000000000000000000000" - }, - "81df59e5d7b9a2db5463b53be83b4d7c7673d163": { - "balance": "887372337013000000000" - }, - "81ef38d074e0aa9ad618deaab01bcd135301fb67": { - "balance": "24072930558567000000000" - }, - "81f3a4c5291f13f8f97a067a6ed744a686331eaf": { - "balance": "56612148225000000000" - }, - "820610d0ddd3e9f3893f7cc13f32b1ad0d169f81": { - "balance": "50000000000000000000" - }, - "822d6388145e96cdeb2900420a0e0436e940b670": { - "balance": "20000000000000000000000" - }, - "82323b748fdee9f18e34aefc4ddebd4993ac6293": { - "balance": "112752706047881000000000" - }, - "82324995b36f4ff15be3559ccee14742d5b4c75a": { - "balance": "1184047304377000000000" - }, - "8235bfba0bf0fb664271ebe534616456a78852ce": { - "balance": "6804584686000000000" - }, - "824df7b17a61392f88f7e3067f8c261abb48806b": { - "balance": "144857897574000000000" - }, - "82555a7aebfc95a01a3773aa5370394cadef0302": { - "balance": "40069354268401000000000" - }, - "82831d451b8f92fbf6a763adb708010a3e66bb60": { - "balance": "8750983992240000000000" - }, - "8294176178418f46bb18440cc87a07cf40c1669d": { - "balance": "4439783816461000000000" - }, - "82a1c733c3c937ba0a1a49481e4d1f6226157d2a": { - "balance": "50000000000000000000000" - }, - "82ad0b5dc23bc763da0352f5983efceeaee6ea08": { - "balance": "171723633433000000000" - }, - "82b4a3d16655fd71f4020e6a562592a621ff6e1c": { - "balance": "190211621484000000000" - }, - "8357d5a016a00aa5e3ef05d3ce210826adf4c501": { - "balance": "10000000000000000" - }, - "836c41d7f9e72131eff839b7d510fd0ed412f939": { - "balance": "15575572364757000000000" - }, - "8377fff2b0eb03393543ddf5ffae90b3311af5d3": { - "balance": "2058810049054000000000" - }, - "838859e6fd751539a88d00581b0e19bc98c37e47": { - "balance": "338264241636000000000" - }, - "838da0414211392b644e73541e51e9f0fba26615": { - "balance": "20000000000000000000000" - }, - "83958896a43d23ef4ba01bdf6757c36105985096": { - "balance": "9000000000000000000" - }, - "83b88314b606df40d5e716df488980bc64125b46": { - "balance": "10985538717083000000000" - }, - "83bf53fa162e1d85751be0bc6f46e8ec881392e2": { - "balance": "1497107276676000000000" - }, - "83d7c52608b445e18fb1e28dc6198908d66bb6d8": { - "balance": "265446362740000000000" - }, - "83ee8ebaed62092d2116de6b4e90778454e8dfc4": { - "balance": "1000000000000000000000000" - }, - "8402fe573658250f50fbe111596ce35ea9ec01ca": { - "balance": "3479737676000000000" - }, - "8412b877e708a7d5db2a38d9b0f4f23d12231f63": { - "balance": "9225027744855000000000" - }, - "8418dcc09fe052febf2946ee22bcc8c53d548eb6": { - "balance": "3000000000000000" - }, - "84199f54ef96bda5e14f60aa1723e811f755d3bb": { - "balance": "129197612052433000000000" - }, - "841b1400f97ecd2ca008e7b4f5a95274bc3e99dc": { - "balance": "2095180906854000000000" - }, - "844177191a120d2dc4be9169ddbc3b5430e9e238": { - "balance": "3620793599287000000000" - }, - "84578fcffc73be7d65bfa81b0cdafd26885bafbc": { - "balance": "37592478429000000000" - }, - "8460acb05c6c476ca26495aec7224c2bf90996fc": { - "balance": "8999580000000000000" - }, - "84696cdb9f018d3e7bf453efdc174e1a586e9c25": { - "balance": "118007806297016000000000" - }, - "846a8a91d2890000d1e995fc1663cf5b7c22211c": { - "balance": "27266838638307000000000" - }, - "846b5ef52d5f7ccc17d9c7e5f49db807908c63f3": { - "balance": "375423381758000000000" - }, - "847409e5d6ed2c4e54ff97f2ed58217ac5fc3d68": { - "balance": "23972870617025000000000" - }, - "84bf432c967540caafb8bf49cdc9983e8953a18a": { - "balance": "453476687224000000000" - }, - "84eba1bb76f7a3f6d2b9052d068cc6c48d449d76": { - "balance": "17655334922000000000" - }, - "851245ef1637a07578241b3c35acf215908e1898": { - "balance": "1269389304110000000000" - }, - "853708e974fd4810655d9cd19fc8dbfd3d5e1e36": { - "balance": "18000534000000000000" - }, - "8547989af8c99a3432038a03d3fb30a054d90413": { - "balance": "10000000000000000000000" - }, - "854ba39bac4c7bf619804b6773fe43bc71f3255d": { - "balance": "15999580000000000000" - }, - "85636f3e113cbe1d1bbd1b3a23e9e98edbcb94f2": { - "balance": "1199038399611000000000" - }, - "857167896b859394babf897c4c6fa57b3a057117": { - "balance": "921057404898000000000" - }, - "85799226a1474371ca76f05597a1e3835c17e7d7": { - "balance": "562141544946000000000" - }, - "85a2221cbbb47e8b74fc2617d6087a98f47e2738": { - "balance": "10000000000000000000000" - }, - "85be0bd55fb9143ff17387914a82d0a2650224c4": { - "balance": "4038654147145000000000" - }, - "85c5ff0e4956ef0fb662a2cbf6a86325a53dac8a": { - "balance": "28690160424000000000" - }, - "85caff4ec0e1719ad963e97c1c02828683070370": { - "balance": "2022427900763000000000" - }, - "8630cc2780fee566f172ed0437264c45421ce675": { - "balance": "669721278148000000000" - }, - "8633d245c5f1b63403e3d7828dc197ce1cfafc0f": { - "balance": "10000000000000000000000" - }, - "867ccceae3192a27751d870ae13b1d3d2c3584dc": { - "balance": "1491436265909000000000" - }, - "868bed241f77983ff4a7a8d0bf121299b6b2248b": { - "balance": "5600000000000000000" - }, - "868ddd283a76a26c8bbb9761df3ca647bea267e2": { - "balance": "9000000000000000000" - }, - "8696e546f96f6e51f405905e095902db8bb90118": { - "balance": "533558981421000000000" - }, - "86ac0eae4e4c20cb7019325f4dbebad053f92213": { - "balance": "697960117764000000000" - }, - "86bef47f9d2cd7526495454eb4d1737510696a5f": { - "balance": "2938307902381000000000" - }, - "86ddd4e3f444b395be8b2b2b75c35c78877fefb7": { - "balance": "15615434748526000000000" - }, - "86f115ed19a32aba4f98270b8ad45820abbc4653": { - "balance": "151868798605000000000" - }, - "870f19e7ee358de61ad0fd3c7710441156d68f66": { - "balance": "674715936435000000000" - }, - "87141a2d3857fb8a328ef8e7b503ed965294c85d": { - "balance": "1609607183158000000000" - }, - "87257783d866af25a7a71b46ea6c2bd1e9ab9596": { - "balance": "64000000000000000000" - }, - "87298979a9a0dbc272b0e15b7e5f2e42639c9912": { - "balance": "722087160930000000000" - }, - "8757b784015f88d072229176cabefa358a0e95a4": { - "balance": "204003337866000000000" - }, - "8760e60a56c5b8b61276634a571400023f08e3ac": { - "balance": "1000000000000000000" - }, - "877e54ea7e8ab03bb8e2b842dadab16bf4ae0a4c": { - "balance": "341020957932000000000" - }, - "87919285fc5d98169bbd073cebb1b3a564264dd8": { - "balance": "579080463078000000000" - }, - "87c39cfaa9c82d84119f306e6a233a3abfbb0ad1": { - "balance": "121753433796000000000" - }, - "87d479659a472af7c8ea78a3c658605f8c40bec6": { - "balance": "20000000000000000000000" - }, - "87d933ad6fba603950da9d245b9387880e6d9def": { - "balance": "1087642723520000000000" - }, - "87ec448309024bb1b756116b81652ea518cf353d": { - "balance": "344562808694000000000" - }, - "87fbbe010837f8907cc01a5bbd967f402a216488": { - "balance": "185411503628000000000" - }, - "8805a3c529bef4d19a6491f3b7d7b1b7232bb93d": { - "balance": "264150205918000000000" - }, - "880ec9548864fcd51f711ab731d847260ed0e3d5": { - "balance": "723225945994000000000" - }, - "8818d160b56b18e196871a6c7ccf02112dc13342": { - "balance": "2857439182291000000000" - }, - "8836e25baa08c19a9b0155c57072582b49f7dbef": { - "balance": "5468425690148000000000" - }, - "885b6303d06142accf2ddddbbdd4a9379d1cd124": { - "balance": "11853214736000000000" - }, - "88656958d9cd758d71546ba52c4ea646b658c84c": { - "balance": "10000000000000000000000" - }, - "88740acdf9ab5711d015391fe8cf4a7c70a0bc86": { - "balance": "510027156671000000000" - }, - "8874966976d776c3154261afa802692afedf3d3d": { - "balance": "305634301700000000000" - }, - "88aea53c727d7a5dd8a416e49faba1c4f741f01a": { - "balance": "15358334295959000000000" - }, - "88b67d05997ae3852259ca638a00ce9b9e7e4a61": { - "balance": "278125551806452000000000" - }, - "88d730e074a102048008de81d3adcba831335736": { - "balance": "5984576042159000000000" - }, - "88da27b1f0a604a87fdedd9ea51087a331179cb4": { - "balance": "10000000000000000000000" - }, - "88efaa91dab9671f5c903e69aa6ca4d9a04b5ddb": { - "balance": "1996126782729000000000" - }, - "89a9d702f64f14fae4d1a69717744dd700208d9a": { - "balance": "251686323241000000000" - }, - "89ac81571265bebbf9d3c09e9459fd1ba7fb1297": { - "balance": "162368080974000000000" - }, - "89c75c4f0ce41d283587beba1a3e3efab05ca6ad": { - "balance": "16000000000000000000" - }, - "89d44cb81cc5a1bdf4d573c4954ee641f3cb91d1": { - "balance": "97965629614355000000000" - }, - "89e2fef4f7b7c255b36afa81cf4033b22de3db25": { - "balance": "7278615226888000000000" - }, - "89fe5d3cb5283c7b87daf6103bb568f92a230631": { - "balance": "64000000000000000000" - }, - "8a07242231f4a654aeea65b857d1519385a18065": { - "balance": "20000000000000000000000" - }, - "8a5a415f0fe2a8329e14628493d11ca20d4e482a": { - "balance": "157274758238000000000" - }, - "8a6ce9f270fe3ec33a013be9e5b1ef823c0dab53": { - "balance": "20672772672000000000" - }, - "8a6fe4fa2f86f879ec9b2bf643beeb0876da46d4": { - "balance": "1041983771868000000000" - }, - "8a765ff2b429dcdf59b65a34c4bb41798dfb5886": { - "balance": "355487172996000000000" - }, - "8a9b9b65a3d443a6e4dcf696a64983f3b625774f": { - "balance": "3185351572575000000000" - }, - "8ab1f5443cf9149773b9ddb69de3e6ea047ae38f": { - "balance": "161619949415000000000" - }, - "8abeacee0078e07fb417277e8bf15dcc2cdb9fa7": { - "balance": "144000000000000000000" - }, - "8ac0d9e0e77aa4ada4080604f2118b3a5a0f8102": { - "balance": "100000000000000000" - }, - "8adae0dc99300f60d31bfa619ec83d45b48ea22b": { - "balance": "697262590215000000000" - }, - "8aef59e59a27a8662043f1a4abcaf945a5e3fafc": { - "balance": "26780431538000000000" - }, - "8b3386f32e2d77526c223ee8bb95b7dd111ced92": { - "balance": "2179932854210000000000" - }, - "8b34d5e457ef6451bb7f5ecc93c80678a30e3194": { - "balance": "31492358338840000000000" - }, - "8b47e07f192c33bd7d298bae717dfcd68a8097ae": { - "balance": "1000000000000000000000000" - }, - "8b55bff4b281f6a24ab428d66b91f9bab06f7b96": { - "balance": "1596248680941000000000" - }, - "8b576b1e2391f22193bb4f91bec5f2a8aec02af7": { - "balance": "29660301836269000000000" - }, - "8b9097b762c7bc38a487974f3551fea697087553": { - "balance": "260887123991000000000" - }, - "8b92c50e1c39466f900a578edb20a49356c4fe24": { - "balance": "35654824979000000000" - }, - "8ba3933337108841a997accf0b5735e005373f53": { - "balance": "574965182000000000" - }, - "8ba3eeb2d1b27e021ed6bf5827280807f32c7897": { - "balance": "64000000000000000000" - }, - "8bb23a5b8c48ec5bde84f39b463559b7c048c853": { - "balance": "16186405874000000000" - }, - "8be0b6ab14e15b46905335d07df03726fb1df0e8": { - "balance": "500000000000000000000000" - }, - "8bfc53af1ae6931f47ad7f7ed2f807f70fddb24e": { - "balance": "20000000000000000000" - }, - "8c0599df87df142d3aea37d50c975c1813ecb642": { - "balance": "871085782287000000000" - }, - "8c2deeeaf095be075a2646ed7b8764d3665acf14": { - "balance": "10000000000000000000000" - }, - "8c3e7381b0598356ff81e860faf25390ae7de9d9": { - "balance": "36000000000000000000" - }, - "8c5671a6f4610ddbd05a5139659c7190f54117b5": { - "balance": "50000000000000000000000" - }, - "8c60582c4e4e60da665b4a5a2d18f514ded6c49d": { - "balance": "16806447782991000000000" - }, - "8c8464ea6b17687eec36ef04966d59c7c91fa092": { - "balance": "1872124465602000000000" - }, - "8c85c5a318cc0227576adba3e91dce6adc73f6a2": { - "balance": "52479305517000000000" - }, - "8c8f3796a2942a2298d14ff1a9e3264e9f63f2bd": { - "balance": "10000000000000000000000" - }, - "8cec1886f2cc71b09ca32a1cf77a280ae3a6a9fe": { - "balance": "500000000000000000000000" - }, - "8d0b26d57eb52a62814d7876d64c8274f4371464": { - "balance": "20794037603000000000" - }, - "8d40b92e41f3cfec06e767d64b4dafc5612133b6": { - "balance": "25000000000000000000" - }, - "8d41ea1cfb70d0ef1f6572fd72a6b417739ac7dc": { - "balance": "738777348304000000000" - }, - "8d4eb54646f9d14882fc8ebb0ef15f6056d1afbb": { - "balance": "1003867239086000000000" - }, - "8d51ab29ccd190bfe12bcd94a651e9f49a003253": { - "balance": "442251355663000000000" - }, - "8d6c0c8e4ca47626115433b39feb939014b8738f": { - "balance": "119828137027000000000" - }, - "8d7acd92d664a485625bb9884e7cac9cc6077f41": { - "balance": "1381910232084000000000" - }, - "8d7ee7a9c1c263ba8061f54dcf62d9f8420e2008": { - "balance": "20000000000000000000000" - }, - "8d941c5d0c6e2b8e2934c9f80f8a63e2fb5868ef": { - "balance": "116443644149000000000" - }, - "8da0dc43ed3ccefb18f21aa13f3fa42c13e540a6": { - "balance": "516000000000000000000" - }, - "8dab4500316475e8fc3bb6494be09f549dedf026": { - "balance": "2736245677000000000" - }, - "8db39a95f4e63bde0bd8c02e386122ce2c57a30f": { - "balance": "12577347153000000000" - }, - "8dc718b49fb68584d9472490743f9be1b0ad683b": { - "balance": "50000000000000000000000" - }, - "8dd05e26224aa8a6deb0904b6d3bbb34d268e901": { - "balance": "613146658282863000000000" - }, - "8dda0e7ddde515480ef08cf90a1eb4e78f50a2c4": { - "balance": "19265526663314000000000" - }, - "8dedad1511c11798c338334dde7be967de96e9b2": { - "balance": "50000000000000000000000" - }, - "8df63c04f18a854d7bb397bca3e2ba19202e9da1": { - "balance": "1479940547081000000000" - }, - "8dfd7edb7d28e8b3df1faab70a8ef9e3b923d998": { - "balance": "10000000000000000000000" - }, - "8e2c3af057e931b5f82e83873b336a7f68e7eb03": { - "balance": "27138009123000000000" - }, - "8e2f4eaddd60468bdc09d47f65839b96f50596ef": { - "balance": "970529157231000000000" - }, - "8e750010c88ba99d75b0b5943c716d6fc0d01802": { - "balance": "42271114987000000000" - }, - "8e889d47f3307a18490e53f2108dc31b14d6300e": { - "balance": "115722965933000000000" - }, - "8e9e1953c82217ba56365e7a9c54b1ded73914bd": { - "balance": "6248835752208000000000" - }, - "8ec980d3066cb6afa793577cf88ccb46ce8d13f2": { - "balance": "100000000000000000000000" - }, - "8ef324c861de7e042c445776bcc8ac026533bc15": { - "balance": "1869634994148000000000" - }, - "8efd14464465e50af087a80a5fbe652445de373d": { - "balance": "1157403424927000000000" - }, - "8f1b57304406fd8b2eb5dabcbd322e326dd873f5": { - "balance": "194188733254000000000" - }, - "8f36ffd921e12083e374335d3cc43fcfeeadfa46": { - "balance": "100000000000000000000000" - }, - "8f813b88e6e125eab71a63455f326322ef505501": { - "balance": "19087691927734000000000" - }, - "8f83892d4d2892cd57828fde2318610a54b14498": { - "balance": "22833507983000000000" - }, - "8f89c1bcba85757cf1718d5b9eb007e27e5195ab": { - "balance": "2241600478705000000000" - }, - "8f927ab63df4c2ce46f1ea35bc875a0c006d2d4f": { - "balance": "327487123409000000000" - }, - "8fc3c231df0f93a84bbe348aff12ab576284d70f": { - "balance": "25000000000000000000" - }, - "8ffa089b07ed1388a5d1a428daf54d9591e734e6": { - "balance": "1347580402248000000000" - }, - "90040e00f585f8be44c82597037fde452472e741": { - "balance": "2746884591879000000000" - }, - "9034eb46aad2a76bdb812c981565d4701dc10718": { - "balance": "10000000000000000000" - }, - "904ca1ac2381702bd18472b175262a8928cde5f1": { - "balance": "304421909590000000000" - }, - "90502c1123692c3b86e99b328d07fae473d4a283": { - "balance": "227491252462000000000" - }, - "9052ca7e9623c1bbe3568668673d6d252b56a764": { - "balance": "35268091378000000000" - }, - "9093d12d8410193293e1fda0cca98a43b85b91a8": { - "balance": "6829489147119000000000" - }, - "909ba8cdc707c12ba577dcd8ed1df1c02a7ce2ef": { - "balance": "60524108169000000000" - }, - "90a2cc3aa73495531691e027a8c02783cea7941d": { - "balance": "65263780625000000000" - }, - "90d7c82615f151953a8d71a68096cee4d428619c": { - "balance": "298774379499000000000" - }, - "90e02deb31d98b9c85fcaa7876eb5ec51d721dd4": { - "balance": "2000000000000000000" - }, - "90e538746bbfc6181514338a608181a3c4286d1d": { - "balance": "6069511690189000000000" - }, - "9106dddc1b693e7dcb85f1dc13563d6c7c9d8a6e": { - "balance": "1977000091291000000000" - }, - "910d1e0d3f71054835ee0d4cd87054dd7add3e38": { - "balance": "40104690362000000000" - }, - "912e2349b791fe702692a6c1ccbf6f0f06b826db": { - "balance": "6305336897000000000" - }, - "9144cc61c01eb819e654b46730620c230da9e936": { - "balance": "144000000000000000000" - }, - "91478d4c15d9ba02816456030915be08fa3aa208": { - "balance": "200078339107000000000" - }, - "9160c466b5f9020b0ab1c0ff497bf0345598ec90": { - "balance": "17705350930000000000" - }, - "919025625787101c572d8340ead1444a96593424": { - "balance": "2418027749789000000000" - }, - "91926323868c65f91b6d74c85c07279610651ede": { - "balance": "538073886450000000000" - }, - "91950cd6e2dd99e024854b65c09c5a7476777a21": { - "balance": "11629505934425000000000" - }, - "91ae8d74c26d3dcc291db208fc0783347fcc197f": { - "balance": "7604593786920000000000" - }, - "91b9ac26869abc9eb3090f1d8140eabe97f41001": { - "balance": "25000000000000000000" - }, - "91c349651afb604f9b00a08e097e02c0964e148a": { - "balance": "117290771022000000000" - }, - "91ddc95cadeb6dcf6ebbdb3300a29699ac8ded39": { - "balance": "20000000000000000000000" - }, - "91ebbd36714cc069f8ce46f3e0eda5504fdd3aa2": { - "balance": "203944728497000000000" - }, - "91f2765125b84923bd506a719d72b0c1de030e32": { - "balance": "452269960816000000000" - }, - "91f2e54a9d61ef52a33d150da50d5a8f2ebcd6bf": { - "balance": "242321058694000000000" - }, - "920dc90d11e087a0d8912c1d43db102e9ba4f43e": { - "balance": "20000000000000000000000" - }, - "922ff522cf7f3ce0bab9312132df51704caa755b": { - "balance": "1414824682473000000000" - }, - "9251449b0f757ef62f63c2774eb63ba15bf3712b": { - "balance": "102688517037000000000" - }, - "926255c17386720fdc1701747a2f024475063d4a": { - "balance": "25000000000000000000" - }, - "92808a38ffc5a339b1ab6b0b472f9975718d4a07": { - "balance": "500000000000000000000000" - }, - "9286c4497e820845341e3b9127813c1b7c884830": { - "balance": "101241387488275000000000" - }, - "9298e1df6730e91e9892d19f7ce18a3db9b5d2a1": { - "balance": "169000000000000000000" - }, - "92d98aed335c29402a43ba96c610251bed97308b": { - "balance": "3032350763000000000" - }, - "9319153f24814a81d920c60cbee9b5f2f275fac0": { - "balance": "56619610984000000000" - }, - "9347532d6396bc0b86bcd34eb80facd4c3690684": { - "balance": "258912194626000000000" - }, - "93487691d71e6248d88f06b1fbaee58b6fe34615": { - "balance": "1593901704394000000000" - }, - "9375154a7f19783b26ae1c9e48f114e1cfd1307a": { - "balance": "9000000000000000000" - }, - "9377947e0db688bb09c9ca3838ca2197fb262a1e": { - "balance": "323993393587000000000" - }, - "939ca9030b28d356dc1b071169f98b0728a9aef3": { - "balance": "218900305967000000000" - }, - "93b71636b8332515c2af031aac7a8805de716a62": { - "balance": "1640174743698000000000" - }, - "93bca153afd427b0c3c1de4a5584610e4a6595b7": { - "balance": "654782426410000000000" - }, - "93cb3b73fee80cedacf5197f8b4ac8f18f0d0184": { - "balance": "100000000000000000000" - }, - "940fcd215bab373d1b736e354f2def501244885a": { - "balance": "13133641534585000000000" - }, - "943f4bc76f20580b6546b6aff2800448f82cfdc0": { - "balance": "1927982550280000000000" - }, - "946ddb5c46fb13010b9c7ec56e4055b4f3e24b4a": { - "balance": "1410000000000000000" - }, - "947961dc367226f78d722361d5821cced52db01b": { - "balance": "115598797369000000000" - }, - "948eab3ffe44d5f1f381de2c8cadcb311c25df2a": { - "balance": "870664355820000000000" - }, - "94bf674593378243fb6b811f331f77561efb4106": { - "balance": "226539311455000000000" - }, - "94ce082887dd6324d7dcfa6cae17b653be021b25": { - "balance": "420000000000000000000" - }, - "94e2aaa4b5e2b36a12f866c96e3382a1150a97b4": { - "balance": "7344059136611000000000" - }, - "94ea5b1cdceb3f1a9d5ecacb6ac8dd2db9a461d7": { - "balance": "1951787237292000000000" - }, - "95218633176c0fe2f32fb55ad3df9f387e63aed1": { - "balance": "99999999580000000000000" - }, - "9543cb22853a46cce3aadc60e46cbddbd3fcf593": { - "balance": "2806074281914000000000" - }, - "958842c5389656d156aab05ac1731a20656716ff": { - "balance": "391064461038000000000" - }, - "958fd9bbc96531a00adc5c484d06dc61ccd717b6": { - "balance": "8021794447667000000000" - }, - "9593ce72919cb0648ddacc58af233d942963e2e6": { - "balance": "32322940730755000000000" - }, - "95a8e371af9128c97c9d4d7c4d58f5f75f2d07d4": { - "balance": "49000000000000000000" - }, - "95b9a9ad563a4c1ff7b6ebcf5fabcf5dbdb4a6a3": { - "balance": "10000000000000000000000" - }, - "95ef5fac6aa3ab1b4a87246fa800cfceff43dec7": { - "balance": "119666779022000000000" - }, - "961a3aa8015cd520de43bd47d81f5194ee4dfdc2": { - "balance": "248589901007000000000" - }, - "962bad39df25d64ee1c6b4ae9c14a18d316bfc06": { - "balance": "2404608291000000000" - }, - "96392119198c4b644c64284c9a75f61210a6292d": { - "balance": "1000000000000000000" - }, - "963c82319380587eeba0bd7b07eb63ea7042984b": { - "balance": "1480123630618000000000" - }, - "963e05fb6245ec11d67ed80e9feba6e2c0a8b4ae": { - "balance": "276053287417000000000" - }, - "964452b86b0d1d4b34aa881509a99e7b631d4a85": { - "balance": "64000000000000000000" - }, - "9644a2af2ff70eb43584a4351bfbe027c42ba3f9": { - "balance": "500000000000000000000000" - }, - "96572a017489450f2dfc0e31928576acd3bc6808": { - "balance": "1140183097730000000000" - }, - "9686bfcc0dc3de20604eb77787d0dba818cc5016": { - "balance": "10593448987804000000000" - }, - "96879780764b4433589d26573fc221f5218f1877": { - "balance": "154136576560000000000" - }, - "96ac1e62c95e33dbbd4f6ed389007e16c00b205e": { - "balance": "4130528000000000" - }, - "96ba703df3a8a6dc3c5d6be02cbf6a4afa2d1650": { - "balance": "2885298549532000000000" - }, - "96d516ded110f1d7e0290716689fd1b7964d9d42": { - "balance": "40665675241000000000" - }, - "96d75950c9354cec6084ba11058dd52d00fdb1f2": { - "balance": "903158106646000000000" - }, - "96f362c59c72fa1d39ae3ec37a7b715d2dd23679": { - "balance": "110000000000000000" - }, - "97115f7544cb05009b3fad2f0c2817f3ee77dd4d": { - "balance": "10000000000000000000000" - }, - "971cbaeafd4b0fdbad24fab946051b8949efaebf": { - "balance": "8462381628000000000" - }, - "971e195e980b4fd4db8d279c80968ca1bd390edd": { - "balance": "10000000000000000000" - }, - "9722648970c455929d621546fddbff27c49acd3c": { - "balance": "70337427969000000000" - }, - "9772027a4ea991eb9eb5ae6b8f34d750a917538b": { - "balance": "148918416138000000000" - }, - "97797e3919aa35567b9eb1224be87f96c6c2e1b4": { - "balance": "973342196399000000000" - }, - "9780a9c86160e27f627179535c3d3f23b6b29917": { - "balance": "10000000000000000000000" - }, - "97a85f4e3f53aa066825de15f1d0e25d4189b037": { - "balance": "2435764858719000000000" - }, - "97f46465e99910539bd3593c16a572e159bac87d": { - "balance": "25000000000000000000" - }, - "9882505fcb54ca2d2f4f79b03f0a5ead61936979": { - "balance": "249999580000000000000" - }, - "9898e969629502a891b758efecc9fdc5ada7d32c": { - "balance": "20000000000000000000000" - }, - "98a52d325e28ca9b4474846c7e4c07a223440fab": { - "balance": "418260286015000000000" - }, - "98a9b2f7d1ba7838e3242b5e4cbf1f2897aa4bc5": { - "balance": "500000000000000000000000" - }, - "98b8308c37a2f6cc1bb382dba2ba95a3c5ca2834": { - "balance": "10000000000000000000000" - }, - "98bf0170a61f98ab0710a68810bf152b7f6c56fd": { - "balance": "2279761566089000000000" - }, - "98c8a323a0022bd147a466fa1ac867977e12eb92": { - "balance": "10000000000000000000000" - }, - "98cd102caf0866ba0a74604b01f54049503905d6": { - "balance": "34739921273310000000000" - }, - "98d7e89c2765aaac224d4015aa277fef208953c3": { - "balance": "1291811952000000000" - }, - "98fe96bfd1e10fb60b343e512b15e955aefc0778": { - "balance": "464922897623000000000" - }, - "99064a57d693e45559a1a910c9ef7d46cce0e703": { - "balance": "8969733492948000000000" - }, - "991ea5429b91a8bfc4352a1d93304dc463be5b90": { - "balance": "149367286734000000000" - }, - "9921d405fada890fee6bf76acc39141fd34e5d2b": { - "balance": "5021308706457000000000" - }, - "9938d357d3d5dcc6f6fc7fb47a98405c0ab6830e": { - "balance": "516293591974000000000" - }, - "994f4e6521a3a5752359308b9f6b2722922c60b1": { - "balance": "23993133615000000000" - }, - "995a6a1c38f037b3a9f0a2e915b8fc0efdea082a": { - "balance": "1403498530728000000000" - }, - "99709e57748a7da6556b1670ba4f15c45aef4689": { - "balance": "36000000000000000000" - }, - "99789f65655c6f917d575169f4ba8192440e659a": { - "balance": "393071814319000000000" - }, - "998f66cbde2693603fa109ad7aaa8bc42a8765a9": { - "balance": "49000000000000000000" - }, - "99afd42a58af31daa54ad9ba35b06954330107ba": { - "balance": "25000000000000000000" - }, - "99b6a9ff2b2ac9ac0361af007aba107695ff5fad": { - "balance": "12860157225353000000000" - }, - "99d16a5955d43723ed8e2b1a642f8f1195f38b64": { - "balance": "62907829047000000000" - }, - "99df609926ca536ed3be80e35dbaecc42ae67f2f": { - "balance": "316809833612000000000" - }, - "99f3faf97a36fabea7306979b30b08fa70110e29": { - "balance": "173292373556000000000" - }, - "9a26110067b473e3bdc0fc32951b39596c967a56": { - "balance": "78192198764000000000" - }, - "9a3a8eff6fb82377da6c17ba658dca87ca0dfe26": { - "balance": "50000000000000000000000" - }, - "9a3b06257088ef8c17410a8f2d63392edb9b55ce": { - "balance": "239567000000000" - }, - "9a426842301802866cca0ef89794d928d3e8f843": { - "balance": "776173297821000000000" - }, - "9a5f2c0a6d41131d9aacdb4f8c274958cbdd377e": { - "balance": "441954000000000000000" - }, - "9a6893023ac6f34b493d33e4dc63ef697169a58d": { - "balance": "439689418527000000000" - }, - "9a86eefd848acafcbd9960003e90b22162b15ef9": { - "balance": "294190908093575000000000" - }, - "9aa711f3e4eb67d2f6405b5ee6290a014d203a72": { - "balance": "9101556549634000000000" - }, - "9abf9ccf6abb8d55ede458d2d12a279d0a823944": { - "balance": "17609693072000000000" - }, - "9ac1909b983c754f0800559174025c0f0baa9d31": { - "balance": "80921948093000000000" - }, - "9ad62cd855d629e1ddab632874a6dc2b812f2348": { - "balance": "2068118534000000000" - }, - "9afc2c33aa2c9a42600abb18aedaefa433326122": { - "balance": "2485353229354000000000" - }, - "9b18d230b221a99c74877d4a1dbdee2214c7d60c": { - "balance": "4024172228743000000000" - }, - "9b18e27788c9d59053072032a480569e142595a0": { - "balance": "110789164888000000000" - }, - "9b4535b23af0b8e5f488a6f318ff6badf71d16c1": { - "balance": "84756740661000000000" - }, - "9b5e7cf43aece7b38ea2af6d08bebe2d3b926840": { - "balance": "262771268227000000000" - }, - "9b77dac92fedd0ad3eb4326d4fafe0f4315a8844": { - "balance": "3616321626000000000" - }, - "9b8f6f223641f9b1bab319dd1e88c49fd411a765": { - "balance": "2054417462086000000000" - }, - "9b9f94861d80365464912e5c7213403405a6cd8d": { - "balance": "2367093088000000000" - }, - "9ba24397002929e6239848596b67b18a8dea1eef": { - "balance": "5000000000000000000" - }, - "9ba99736c5ac468d6b644e39b8d515c39151f51d": { - "balance": "311900650761999999999" - }, - "9bf2d4ff366e1bb2313ae9a93ccca75d6bc0d232": { - "balance": "764870206925000000000" - }, - "9bfce7dbfc9ae62d450e862261d1e21e68bac92c": { - "balance": "1000000000000000000000" - }, - "9c003e74b62f192a864045d678639580c672fc22": { - "balance": "50000000000000000000000" - }, - "9c128bd2c0c96b896db6c0f398e908c98302809e": { - "balance": "3251059363800000000000" - }, - "9c255daa89ee16f32fc0ab1ed8e22db39342e6ca": { - "balance": "37695843594589000000000" - }, - "9c32e714bcb601a56a8a4e6b3f7bcd9e1c7a1b54": { - "balance": "50000000000000000000" - }, - "9c503e087b04a540ed87056c9371d591afa72df2": { - "balance": "64229084991000000000" - }, - "9c54297dd3527cbbb8ca8c305291b89bfb7ab39d": { - "balance": "61682466962052000000000" - }, - "9c55bb1db3b2bb06e605a66ced9ea2ac95718205": { - "balance": "16512365324000000000" - }, - "9c59dbc48b9cf53fe668784e89d30493da9995b3": { - "balance": "50000000000000000000000" - }, - "9c61b58aa760265f7fd1b9e749df70122ea81175": { - "balance": "50590272373000000000" - }, - "9c6c7eaf4bec0566a7bf8acd30e10311a963267c": { - "balance": "999999999580000000000000" - }, - "9c91dd4006f9d01d8caf5f5fb4f2c4f35ee63ffc": { - "balance": "175730980227000000000" - }, - "9c99275f5dee14b426302b1a47a8488c16432f2b": { - "balance": "2000000000000000000" - }, - "9ccf7b23528d062da63f6af3e26531b775c83c52": { - "balance": "928373869120000000000" - }, - "9cd21c30ccbc1087c9b351395fdea17ad669cc2e": { - "balance": "529762292313000000000" - }, - "9cfee47d6f24880af7b281cc00e1fc58e0a4a718": { - "balance": "198888257958000000000" - }, - "9d08251f7d4cfd66d15c17e1ea6bae5c795e290b": { - "balance": "813841349140000000000" - }, - "9d5411490ce89359bfbacf9f9957ebfbbc18debb": { - "balance": "22263187467000000000" - }, - "9d61e1dfaa7d0e0c5f5d733a24a1883c4e201f3d": { - "balance": "144000000000000000000" - }, - "9d754d94a15ab6d738e511fe4c775ee6d20a53ee": { - "balance": "20000000000000000000000" - }, - "9daccedf104fdcc3c39f2961ddfa1c64eb632476": { - "balance": "1237093270947000000000" - }, - "9dad4968c0e44aa729fc5732f3ee903c6799637b": { - "balance": "838788687517000000000" - }, - "9db73ca677bacbb622f44fe90b53ee1d9f0c2009": { - "balance": "472858335000000000" - }, - "9dbcb5026e0f444a33197da240856f108db14ff0": { - "balance": "10000000000000000000000" - }, - "9dc46cf729187ceed8001c4ab14fa4fc21c35f32": { - "balance": "3320792646995000000000" - }, - "9dd895c1bdac2ed9864134aaa8c543473ee5f19b": { - "balance": "1430620966869000000000" - }, - "9de2687242cbf9fb94fee0ad873acc7494ebd2bf": { - "balance": "20000000000000000000000" - }, - "9deec036282717aac93ad5cc1b6d4a5354e85c2e": { - "balance": "2048627955362000000000" - }, - "9df8dc66395aeae9b4c831b4d63bdf48db08811a": { - "balance": "215874670561486000000000" - }, - "9e1fe68a70abd8ab517878b03961da8564b43eb5": { - "balance": "67908329894526000000000" - }, - "9e33293006982abc668e199aab20260b9b754463": { - "balance": "49000000000000000000" - }, - "9e65616282a0baf89469a58915fd8fdbed210e3f": { - "balance": "829209872657000000000" - }, - "9e7b7b522834dd7e83ff2bb6b6e4cd2972330899": { - "balance": "500000000000000000000000" - }, - "9ed134b3a8feccb4056b2e511cea9a8ec58a3e77": { - "balance": "18787546978390000000000" - }, - "9edcf477687a9dee79341ed5d89d576c9a854c2d": { - "balance": "500449025554000000000" - }, - "9eeb06d4b532118afa013a01c9e89216fe0475ae": { - "balance": "1823939486758000000000" - }, - "9ef20a338e85044922f08f3648355e834874d551": { - "balance": "50000000000000000000000" - }, - "9f0855f9cc429fd3590c6ad05bb66a9e038efdca": { - "balance": "8017999878252000000000" - }, - "9f3befcc1884d16b65ae429228d26fffc146c8dc": { - "balance": "1016482445089000000000" - }, - "9f4571748463eee19e59ff9bd734a62a66613850": { - "balance": "20000000000000000000000" - }, - "9f51de282745f77b8e531e1de0b7c14e3369ba54": { - "balance": "1010657089383000000000" - }, - "9f6527175a2b581cc79f2a68c35202e0a7f2af20": { - "balance": "216495522463000000000" - }, - "9f70204d1194f539c042a8b0f9a88b0a03bbcd8b": { - "balance": "10000000000000000000000" - }, - "9f70e44704049633110ecd444f9540e241b50783": { - "balance": "9139000000000000" - }, - "9f73fea741e8506ba7acb477745dab1cfab8366e": { - "balance": "4461472359634000000000" - }, - "9f88d33d26c90e74c39c9676b8b580d21bbad124": { - "balance": "54437240781000000000" - }, - "9fa47455be14ad2eecce495281ed0eea926ec6a6": { - "balance": "10000000000000000000000" - }, - "9fbb15b595d154754a2ae77c77283db9d4e9f27b": { - "balance": "6195722646556000000000" - }, - "9fc480ab1823a59fd6130c3948980f95ac99f1d2": { - "balance": "24101151540000000000" - }, - "9fe5f054165fbf1943b1b02c01063f04e0c3890b": { - "balance": "1000000000000000000" - }, - "9fe7d3d5976e7b8b5ad6baa15ceae96c43c60fea": { - "balance": "55000000000000000000000000" - }, - "9ff116ea0e219814970cf0030932f5ce2cd9a56f": { - "balance": "36000000000000000000" - }, - "a01f6c36193839bc3a31e6d0792324771040fc05": { - "balance": "48298750000000000000" - }, - "a0264706d668522b737bbdbe949ce3e5a60fe314": { - "balance": "1423066922869000000000" - }, - "a02b13bb3b13027045ffb9b44bc7380a942e8ebb": { - "balance": "86845430807181000000000" - }, - "a03d246a931c3d422e5d2bf90f64975923a93643": { - "balance": "5834171660287000000000" - }, - "a046caaee59425ea1040867c62a6fcda11652a23": { - "balance": "83087966538000000000" - }, - "a04b57b2dd8b2082c53517d956f5909d25e14b69": { - "balance": "4518538234851000000000" - }, - "a074ef9e0ffe15619103e3de490f5813be53dcbb": { - "balance": "4568113810000000000" - }, - "a07bae42b44c085067de16e7d9846db529059acf": { - "balance": "4000000000000000000" - }, - "a08530e5fb7e569102b2c226aa5e53dc74483e4e": { - "balance": "2325665286793000000000" - }, - "a095a2c666f4f3203a2714fb04867c13c2add4be": { - "balance": "14768043990000000000" - }, - "a0a967418a3fcb3ee3827a08efa851347c528a60": { - "balance": "20000000000000000000000" - }, - "a0bb293071e07418ecb2fefc073136569ebd1736": { - "balance": "25871128320000000000" - }, - "a0c6c220a53b7dc790f7a5b462a106245c761f70": { - "balance": "1000000000000000000000000" - }, - "a0f06c86c49b248f4835bff405b620d12ec80d07": { - "balance": "484572382390000000000" - }, - "a10bc9f4d05678b26c4ffd2d92ab358163020b61": { - "balance": "10000000000000000000000" - }, - "a10c1197f7bc96639d01a652df73e49c669165dc": { - "balance": "1205859101575000000000" - }, - "a1221b2001f85f71e0655551e300ce115284b8dd": { - "balance": "1376698025177000000000" - }, - "a13fce836d65124fe5bcfa2d817ab2a043acbcf8": { - "balance": "55000000000000000000000000" - }, - "a15f1f609f7464906e0eb9d5e1d26468b90d9198": { - "balance": "16000000000000000000" - }, - "a1617dcf3acda60737e5ca9e4d0ecd82a98ef667": { - "balance": "500000000000000000000000" - }, - "a165c5f151d0daab905ba4a6d1fe5d5114fd7686": { - "balance": "41039049526000000000" - }, - "a17d5bed36c1059561e184a8a90a38ce955b92e4": { - "balance": "10000000000000000000000" - }, - "a18efb4e0950e7ac95970cd4591dacc286241246": { - "balance": "12403188476000000000" - }, - "a191fa6be64f2f6d2b4a7fb5a586416a605552c6": { - "balance": "60340281461000000000" - }, - "a194c15518cefbe94edbef3a2421586b51f7e1f6": { - "balance": "4153525550636000000000" - }, - "a1d0e41aacf83fc62fbecf35f8e873f8d734ecaf": { - "balance": "9000000000000000000" - }, - "a1ddd1f615ed483ef895e341f3266b6891f9b59c": { - "balance": "180411786335000000000" - }, - "a1f4d1e03114707a56ef9069bc20c6094e810d34": { - "balance": "51949145435222000000000" - }, - "a1fe101a65616cd03e3af03092be63434b7bf203": { - "balance": "1005401878265000000000" - }, - "a25a8225ce67c54048737601eac5e0d063c2fa17": { - "balance": "272038848571000000000" - }, - "a2714999233bcaff7294fa3e3b64c63ad45a928b": { - "balance": "14560781294000000000" - }, - "a28db3f7fb1771a3d77dfb19b54f88fd55b15c8c": { - "balance": "8000940572576000000000" - }, - "a290101bfe5fbc73146c4ec3ab5266c043eb701c": { - "balance": "1397563244603000000000" - }, - "a2924cfbcd37d0b321d6abbe57c645f9ce32340e": { - "balance": "200000000000000000" - }, - "a2a26c34f3d950c795fc965f6b1df3990e111403": { - "balance": "34525064429023000000000" - }, - "a2a2855851711bfc051c1f298821ae89e4c872c5": { - "balance": "491025000000000" - }, - "a2b956dd6f1934a4a44a026a18ac345ddabe42d5": { - "balance": "20096625821563000000000" - }, - "a2b9a118a79be81711d95485aa12e3efe78ca256": { - "balance": "10451051632647000000000" - }, - "a2bcf08ddd1778b30ea7882518148edfba2d9b20": { - "balance": "347033754668000000000" - }, - "a2bd489ec4790f4145f8a9a95c9c829c5c020146": { - "balance": "100311110878000000000" - }, - "a2ee35300ddf6a2491ec0e1848f8b56defafd7fe": { - "balance": "500000000000000000000000" - }, - "a31adf082ffd212df18d5a84b105a937e83b1b1a": { - "balance": "7124891785000000000" - }, - "a32c944e6c5fe186794b88d6bcbf51c47bea55ab": { - "balance": "732129357042000000000" - }, - "a33105d543f5d2b1220d4e1ecfdcf85699324dad": { - "balance": "74798779358000000000" - }, - "a3330c73e2d79355a14e570da1ec2e80f8048c69": { - "balance": "10000000000000000000000" - }, - "a3580034590e3052b9de5abd635e514ec5ba8694": { - "balance": "10000000000000000000000" - }, - "a360d8e2519dc6d7793cc371d91ad6add75e3314": { - "balance": "192622260840000000000" - }, - "a36b9b8b2adb20fb4a84d3025bf2e35baa8b7fef": { - "balance": "20000000000000000000000" - }, - "a3771b191237bef48339aa77ad5357f6227b358c": { - "balance": "512633055119000000000" - }, - "a3892bfd25705387cfb4eeb6d21089753c22e3e2": { - "balance": "258136912825000000000" - }, - "a38c793775ebfc7330b4331fe2dc848abb862b73": { - "balance": "1193250172232000000000" - }, - "a39417002ab94845541aded4a614a5a04af8187b": { - "balance": "1185722898000000000" - }, - "a3a79a9f929b54075de43689adb665ef914812ca": { - "balance": "100000000000000000000" - }, - "a3b59ea3d366f818ca09980846ac533d4685c121": { - "balance": "59734700360000000000" - }, - "a3c7b7c594a64225922e02039669e4d0b43fc458": { - "balance": "11779233750000000000" - }, - "a3cc39a68184e51f6445d3ba681a55f4157d4383": { - "balance": "10000000000000000000" - }, - "a3d414d9f210f7b77f90790ce09f6128abe50adc": { - "balance": "10000000000000000000000" - }, - "a3dfda16e5ae534ac100f56741b77b6f86786615": { - "balance": "9000000000000000000" - }, - "a3f79b9d1fc9d6dbaaef49d48fa9c9fb5a822536": { - "balance": "108910000000000000000" - }, - "a3f87414bc9e6f01c2fbde966fc8fb6edbf58c29": { - "balance": "441000000000000000000" - }, - "a3fa3f58c802d9a9690de760716275f14449045a": { - "balance": "437227558095000000000" - }, - "a417ec5a9749064a6521ca2bf9d05f208eeaed54": { - "balance": "959205202638000000000" - }, - "a484d5b883d2b99b81b7bef27e307957ecb64b15": { - "balance": "126491152120000000000" - }, - "a488cd48258e57d66f44e73a60c121f963cb29f5": { - "balance": "20000000000000000000000" - }, - "a488e3b5096e964b21cdeba12ab423f391765b6d": { - "balance": "1712050478592000000000" - }, - "a49dba65f28909e9bd2ce5675bd091f498c6c5db": { - "balance": "216802821062000000000" - }, - "a49eb6a791022c1324facc23d8813f9954d1c639": { - "balance": "287438914902000000000" - }, - "a4cc080a5c4649f511b5844a8e0b031927e13a87": { - "balance": "20333578449000000000" - }, - "a4d2624ac5e027f72edaa625ef22134217203b5d": { - "balance": "1000000000000000000" - }, - "a4d30e35c9617eafeda82866c96c3ce6bf14400e": { - "balance": "1223254927978000000000" - }, - "a4deae7355bd2e1d57eefa56600601b8b475a501": { - "balance": "36000000000000000000" - }, - "a4ff3b5abfe4e50adad16d01aaf62c3d4cdb5260": { - "balance": "20000000000000000000000" - }, - "a502b109869ef07451576bf0e13ab294e1f236b9": { - "balance": "94843398055000000000" - }, - "a517a3b5e4324197902e16f8a29e47335cf39c11": { - "balance": "100000000000000000000" - }, - "a51e101088da23c82907e3e2c65a058f0454b131": { - "balance": "196000000000000000000" - }, - "a52bcff6a7e2e70cd714058bc30a16138fe39899": { - "balance": "30429750204000000000" - }, - "a544e84c2bc4b17859d06f136b6e377e4e398b22": { - "balance": "143977568178000000000" - }, - "a54ddacbc17a98b9fb6292aab3d92f4c5753fd0a": { - "balance": "100583192014000000000" - }, - "a557754f6637a19c1a48cb9bf58c1fe897acf434": { - "balance": "2087038692036000000000" - }, - "a56649205d9ea247b49e03dacbed6c78c21beb4a": { - "balance": "5046177099585000000000" - }, - "a568136446ee6b3bf62a20238db3b11397a065f2": { - "balance": "11652249158033000000000" - }, - "a56a7865b526e315a9eb41f4847485c7e0c952fd": { - "balance": "50000000000000000000000" - }, - "a56bab2a9aac9d08a7bc9265864a80089b68570d": { - "balance": "37138466291329000000000" - }, - "a5965a601c5df7765cd70e5dad27dd23da67ac99": { - "balance": "10000000000000000" - }, - "a5a3161c44c34c441784b7df795067760b0ee569": { - "balance": "35053289069000000000" - }, - "a5c245cf843e691956007b94e259b437a4e6b7e3": { - "balance": "18749166170000000000" - }, - "a5d7de961c3b991dc78f2d6c0448fa6225116d3f": { - "balance": "1574510758868000000000" - }, - "a5f47d2081ef728808786128549a28a5662e92a8": { - "balance": "1750000000000000000" - }, - "a610c90f5b7e5f33044956ba431a3887de1c969f": { - "balance": "25000000000000000000" - }, - "a61c1919bc3f3181dc94e2230d35574cfc972d78": { - "balance": "8990565120000000000" - }, - "a62f1aabd91cbc0112e796d1ec3727fcd26fa293": { - "balance": "1311277302001000000000" - }, - "a64fff0bb32e32f81a541c393982bc59fa183b1e": { - "balance": "8291357610655000000000" - }, - "a673dae555d367b8d4a784274577a1884615b9d9": { - "balance": "27416452091330000000000" - }, - "a6c780b585355d84d9d3c13be5bd05374588e240": { - "balance": "913657165911000000000" - }, - "a6cc1f6f51862c2798adaa1d266988022005a71a": { - "balance": "284500645805000000000" - }, - "a6d9c82784fa20dcf28266d047db441cfeb8855b": { - "balance": "10000000000000000000000" - }, - "a6dae08f99e4fb57b066a645a259d8e4f7ac2bc8": { - "balance": "9044922773690000000000" - }, - "a6f49f36f8d10a796bc2afc9e069cb0c76004ddd": { - "balance": "128555691078000000000" - }, - "a721ce1c294a0f1957ebf9be20b0fffcf90111ad": { - "balance": "3392103457630000000000" - }, - "a72b82c33bd3d6060e8a04392d236775d48ec3ae": { - "balance": "1434465940701000000000" - }, - "a7344654f2a1a44b3774e236f130dff8a4721e82": { - "balance": "100000000000000000000000" - }, - "a748cced92a87066db8b29f931fb92e827488a9e": { - "balance": "5487679824758000000000" - }, - "a78dcb2bcbec2d0a60661e1715c9a95c9d573a68": { - "balance": "346798292989000000000" - }, - "a7a6c0505e7090e0b2c21394877f91c50be6b45f": { - "balance": "4125233658872000000000" - }, - "a7dcdd9b9785a44a2dd4c5eeeb863ac1feae0f66": { - "balance": "10000000000000000000000" - }, - "a8013e9dca1bd38975748de2fb6cb3af5cae74d9": { - "balance": "10000000000000000000000" - }, - "a807bf78b15c15cd9e8edcf586849db716fedbb1": { - "balance": "1458293606310000000000" - }, - "a83410ff00fb4b913dd0ea2003b38c5c3247350a": { - "balance": "2876442029807000000000" - }, - "a848f61298a409e77a03900712017572f35a3319": { - "balance": "2783106133600000000000" - }, - "a85bb81d0dc57f824a763814759fd93fe3020569": { - "balance": "4558027813744000000000" - }, - "a860611cd098ce98974313030d9f6f462bb274d4": { - "balance": "961594154368000000000" - }, - "a8799eeff72929ee6cbfb5b0c02985cd4841be3c": { - "balance": "500000000000000000000000" - }, - "a8c29b9b1349fac0be9a65873e1911b7439c9a63": { - "balance": "1264035560749000000000" - }, - "a8c321024a3c015d881efca33bd1b2c1788b379e": { - "balance": "528752788000000000" - }, - "a8d02e8925ed48f4274d8bee62253dc0d4f2989c": { - "balance": "209083880937000000000" - }, - "a8d2bde2ccd6bad67ee1b9550c9310accb37cd79": { - "balance": "49000000000000000000" - }, - "a8d61abc6a403adc183aeb74c83e4221fd28ee1e": { - "balance": "50000000000000000000" - }, - "a8eb6aa5a0c5b6d9260a202dc76ab674d9a5f3b9": { - "balance": "1041257515142000000000" - }, - "a8efc57efc776dcaaf4003a8cfa63f215ab0284d": { - "balance": "166144142685000000000" - }, - "a8faba86d87678294e311cfa7f8cbeb6f9d8a499": { - "balance": "124541781000000000" - }, - "a912e02f8eab0cb620316129875f919455201117": { - "balance": "6454482105955000000000" - }, - "a929ac95281d1a77a3eda3b5ac90a761ef03ff16": { - "balance": "1074305309650000000000" - }, - "a92a4e40519003813f5574397ce328d046f75802": { - "balance": "9188437500000000000" - }, - "a93850ba8fff3bd18ab259f87c58bbce84165fff": { - "balance": "39018890852058000000000" - }, - "a9843660a17c2d972246028cb8045472abdd346d": { - "balance": "1052681604185000000000" - }, - "a9866c6271733971e46df3c9bb27b3d3c513c166": { - "balance": "200000000000000000000" - }, - "a9b1299c0c064e766f9f29f4301a78c6e4931fcd": { - "balance": "267785134400000000000" - }, - "a9bc33b9c99dd5a3967387c1e99766f9bc74d591": { - "balance": "65356157048000000000" - }, - "a9ccf1cd2f816b15182997e3207d9a681bf21b06": { - "balance": "17521053440000000000" - }, - "a9e54bd9826f853f65e0be1ec0bb9c28f95e0eea": { - "balance": "6260000000000000000000" - }, - "a9ef563c872342f49817a903a5725b504d455ea9": { - "balance": "50134015139000000000000" - }, - "aa0d69c7e1382cd16c527a3fee48db19c38e1398": { - "balance": "142562301500000000000" - }, - "aa12abcc3ab373d07bf560fd200652c8580fd967": { - "balance": "5509242259903000000000" - }, - "aa1d6b968b3f8046a94f128864bfc612fc2e2700": { - "balance": "489179780895000000000" - }, - "aa20b8559d6dd1543e8c528775ae4b04c6242471": { - "balance": "169000000000000000000" - }, - "aa227e9d6074a60ecd43e1cc24092ee58560374c": { - "balance": "596190898010000000000" - }, - "aa7b660fec7b05968ba656eae9a8aaef4481720e": { - "balance": "674642002744000000000" - }, - "aa9e04077d44d288978a3a3ab0d7c251c0447a4c": { - "balance": "10000000000000000000000" - }, - "aaaac1e72955e9d67625cf8bed73fa643fb1cc1a": { - "balance": "9781187987000000000" - }, - "aab46c0c2db4e330834081f97678906252746f97": { - "balance": "16440184245000000000" - }, - "aade5358c52b8aa5ad8ff285c6b297e86f49fa0f": { - "balance": "982846000000000" - }, - "aaedb3fa2cf0ebca0ef4a121a28a406264ccc900": { - "balance": "100000000000000000000000" - }, - "aaf30bf76362a03450aefaf5bd68d28b84eb4962": { - "balance": "509106199370000000000" - }, - "aafbaaa6b6369e986ba72b196bd5f08cc458e344": { - "balance": "216372214000000000" - }, - "abb03c888d61c9102827a1dc0950145beb9d96b3": { - "balance": "144000000000000000000" - }, - "abc6dc937d7703a6b0c83659a328cde0d5008e32": { - "balance": "4052429106341000000000" - }, - "abd3910139a97cb92dc09a8a0352575bcc9ebed3": { - "balance": "24028359215749000000000" - }, - "abdc3953ef293c98989802063f8cb55e0e506432": { - "balance": "64000000000000000000" - }, - "abf1a47c582bc87d36e47cfce24e0ad249f42e73": { - "balance": "71947491720909000000000" - }, - "ac0b6e7aadfb5ffafd5cb3ef3620ebb0691cc3fe": { - "balance": "10000000000000000000000" - }, - "ac1a182607046b56e7a4bbab87cc1182874f79ef": { - "balance": "453499500178000000000" - }, - "ac251b311f781ad7a43d01b0b4b20fe891004e7e": { - "balance": "304621378298000000000" - }, - "ac258cec5ef49f96612d659f66dd4e6ea88e3c87": { - "balance": "255185373455000000000" - }, - "ac4000d9ad080740ef4a2ebe4a3075877bea277e": { - "balance": "10000000000000000000000" - }, - "ac7445c09372f15259fd852cc458783d6140c0db": { - "balance": "10000000000000000000000" - }, - "ac8d29dc05ea6c2f5409a76abe04321bf9381f32": { - "balance": "22464474197854000000000" - }, - "accd52b63822d8cb5117d9deb56596e072462614": { - "balance": "20000000000000000000000" - }, - "ace63a86a2ddfc79f677344e93dc0c4750b8fdcf": { - "balance": "1355066360964000000000" - }, - "ace83deb83fa8d319979658592b75ed13bdf97c7": { - "balance": "20000000000000000000000" - }, - "acf91515df16b21f1e5f5474dbefe596e4929b96": { - "balance": "1153047238967000000000" - }, - "ad04381f7ba89220e8fcd7e200f98a476683a904": { - "balance": "2000000000000000000" - }, - "ad22225bf225d8f705f93bdcda8d301180ea28dd": { - "balance": "1272512717188000000000" - }, - "ad3f74034ff5ca89f97b2585edf12376820307ab": { - "balance": "12303261515593000000000" - }, - "ad43a3527ad2b9445417cb73cbcb42965a5f469c": { - "balance": "67607364133000000000" - }, - "ad61cf9bf560bd5da75d55738477bd9aa25fb0b8": { - "balance": "4358939446693000000000" - }, - "ad649e8a3e1436e0604b0b8c9b1a5f1c09e06d7c": { - "balance": "344000000000000000000" - }, - "ad6b584813814db4c72c4c7eb31447d224074b46": { - "balance": "18445595367000000000" - }, - "ad7d404afc67c0e457fd3ce142cd30b506408683": { - "balance": "48218702840000000000" - }, - "adaf4d39b6806d132128ac438c2862c0a1650cff": { - "balance": "500000000000000000000000" - }, - "adda124baed2e1fdc1acc7b4a048eab0cd249212": { - "balance": "1074765673925000000000" - }, - "adef437c429d90a350b99750d4b72bc8538c5f98": { - "balance": "931901903135000000000" - }, - "adf826a0ea7dc4322d26e9d8c54c4180c1827216": { - "balance": "323567723315099000000000" - }, - "ae01d8b1668f8bfe6e225bd9bc746f7e839ac0d8": { - "balance": "321211880744000000000" - }, - "ae17de3ae6127022e53ebcf9e08457174cdee0e9": { - "balance": "3817903000000000" - }, - "ae243b0186793eddc6ebbb1a2c1f0b1cd574b07c": { - "balance": "9000000000000000000" - }, - "ae3ae1d41dfb16e19a1817b3639cd4300fd166c1": { - "balance": "55437674845679000000000" - }, - "ae506999882d4c6f05cc7979c342c0ce559a8df0": { - "balance": "1391755905401000000000" - }, - "ae524cee5aa23025d6ad185ccab75a6974335d53": { - "balance": "797132751509000000000" - }, - "ae5a55075d0541f179b085152bfc8c72c74abe23": { - "balance": "589408139567000000000" - }, - "ae63d02b18b464f0bbab4de943766bdc7ba2926d": { - "balance": "300261019201000000000" - }, - "aed8ffb86a49c09ae3a83e93d9045851434a9f0c": { - "balance": "1031991707237000000000" - }, - "aee18a9a2ccdf6025d61005827753ce4f510f7e8": { - "balance": "1818639022863000000000" - }, - "aee67910c514fa63a228769d5e15ca40bc4b26c2": { - "balance": "5688989238568000000000" - }, - "aef744eb2ec682dca128dc3149afcf881e367121": { - "balance": "818801643225000000000" - }, - "af04430b3e40e746127623532353a0f177a88fe3": { - "balance": "100000000000000000000000" - }, - "af181833edb15c9b2ee2329dcf1845b977361b7d": { - "balance": "93228805338000000000" - }, - "af30db29765b4fda6f075af96e8acd5046b099c4": { - "balance": "1000000000000000000" - }, - "af31fd30cfb10f1b0a12c2e7dd7ca56bdf517745": { - "balance": "36000000000000000000" - }, - "af70d6820e1d26194b0a9965b55254a287b162f3": { - "balance": "87593999609754000000000" - }, - "af96a573fa86c07389a71db797bea689419b23ca": { - "balance": "36000000000000000000" - }, - "afa4c5b674934e31a9aa5e3e723d85060d51c4d0": { - "balance": "10000000000000000000000" - }, - "afa6e4b4060c2e5969c2329d13cc42924412efde": { - "balance": "127502378589556000000000" - }, - "aff2308ac607f85392f4c8a6a043af67b7b849cd": { - "balance": "11130371831000000000" - }, - "b00ea9c459105b650def1e8569c85fa01837454d": { - "balance": "94928352162000000000" - }, - "b02a7d16ea8663c88416e6f64eaf57787d230be3": { - "balance": "17215604601000000000" - }, - "b03f4e9aa5c352cb1cec953d1123c2f22cd94b5b": { - "balance": "206022552274000000000" - }, - "b051459b91d253c5e8251a5a68282c291833466a": { - "balance": "297127749975000000000" - }, - "b055bdc874ca5a7d2f4bcbc51f1cfc3671b55f72": { - "balance": "1421913523478000000000" - }, - "b06156b99b891b756262c5b40db9bbe39fddc77f": { - "balance": "49000000000000000000" - }, - "b076893b9841d2775ec8883f05b74f1e5aec327c": { - "balance": "22591055478000000000" - }, - "b095de644af3c9f960f67502da6ac5eb050a158e": { - "balance": "4958067562725000000000" - }, - "b0a1f794cf70422395f74395abc9a7d0b271846c": { - "balance": "812057322000000000" - }, - "b0d36e0f426a99416425689c657fc6d64ad698ca": { - "balance": "1157727077158000000000" - }, - "b0f35fa554d6ed657bf3996cc027d045c3971fcc": { - "balance": "64000000000000000000" - }, - "b0f76b4c9afdfe35c41d588265642da60f1b97d1": { - "balance": "1000000000000000000000000" - }, - "b0f76b4c9afdfe35c41d588265b42da60f1b97d1": { - "balance": "2028311808491377000000000" - }, - "b1445842d56c56bc532d2f33ab9b93509c732a3b": { - "balance": "13522982470164000000000" - }, - "b156bafe05973bc839c4f115be847bbde8a67cb1": { - "balance": "10000000000000000000000" - }, - "b182e4d318893dc1c4c585195dbde52a84ed4ffd": { - "balance": "329498977335000000000" - }, - "b18f506e77df4db80ca57cefeaca4f1010f78f50": { - "balance": "956339304078000000000" - }, - "b1b6f617b110dd79c8fd77e729584d1fdfa9aa09": { - "balance": "16000000000000000000" - }, - "b1bba36e2d9e272e0131f4bae09bcfd92e0a63db": { - "balance": "64000000000000000000" - }, - "b2285651e57ae0ff27c619207cceacd20884d152": { - "balance": "1345938295122000000000" - }, - "b2419a93732d0d324daf7707fac3782a77b0dff8": { - "balance": "625000000000000000000" - }, - "b27206e9f2ac430841fb8da69b49d505f1558b8b": { - "balance": "29507819229000000000" - }, - "b2801fe902c7bbc987ba12ecae98765c99980fef": { - "balance": "240016083000000000" - }, - "b2843d5215ceb761e78f281402a1660c3abadf5b": { - "balance": "3335539720927000000000" - }, - "b2a22e6a04a2ce3287da3b8b6eed4ea1f18f05dd": { - "balance": "99999978999999999999" - }, - "b2d55a061fc6f90d2a05e0cbd26ffe0a1c3321c2": { - "balance": "1000000000000000000" - }, - "b326aec1cd523948ffec2fd1e8f21bd2b4308f40": { - "balance": "913000000000000000" - }, - "b32abc82b251e2d310ea7588cae4ad4acb657cd9": { - "balance": "26946233911000000000" - }, - "b36924d578973aec05ce7ab556d7ed00004949ca": { - "balance": "393041705867000000000" - }, - "b37482114c83e857c730588d7d959d300b8142da": { - "balance": "29429544454000000000" - }, - "b39998bade135ac6ccadff41cd709e161d01aa60": { - "balance": "26272579375000000000" - }, - "b3a995ee94f1d63d12f10cea5ab3d596c7c6f284": { - "balance": "64000000000000000000" - }, - "b3bf35e936fdbb7d0bbeeb1cf076f243855ed477": { - "balance": "754081187934000000000" - }, - "b3c2ac85b99abed4a2a52b5f96a2c98040d16022": { - "balance": "50000000000000000000000" - }, - "b3d1a2c0ab2d8987446d74f49e357adf5bf15986": { - "balance": "10000000000000000000000" - }, - "b3fbcd24c8394a5d2b7fe877f18681a109a404e5": { - "balance": "2558689648423000000000" - }, - "b4110f4e38405adfc054e55ff73c55842db8e2cd": { - "balance": "129000000000000000000" - }, - "b417f4681fdd4e53cfdf8550e3d326dbb0a557ec": { - "balance": "1000000000000000000" - }, - "b422970fb8799d83642b7ff715fc941d69e86053": { - "balance": "81000000000000000000" - }, - "b4237be71920497715826eae8d85c26cb3c111a8": { - "balance": "10499979000000000000" - }, - "b431839de4b21dfb44150cfc6ed00ea430a81687": { - "balance": "26839560174813000000000" - }, - "b43a0d6399c7d1be943c4b45838156a47c88f909": { - "balance": "10000000000000000000" - }, - "b44ec608b95d0d51105ce5f4b48de5dd72f346fd": { - "balance": "448125120000000000" - }, - "b47f63e14f6de6c3413b2be95a725e367ac18fb6": { - "balance": "500000000000000000000000" - }, - "b48071cd1b15f45028e9dec2237f14f10b7aedf9": { - "balance": "38042711385000000000" - }, - "b4b874b323b560aa0e4811ca574bd48b65b3fc72": { - "balance": "18063913676592000000000" - }, - "b4e4d4af0667f8158cf817bf1bc3eada08a551ca": { - "balance": "2149067370317000000000" - }, - "b4ecd625ffe470ee1fa1d97832e42ddf3f9ddf6a": { - "balance": "1181738860120000000000" - }, - "b53f380ce92787c1db461524290e8fcede552fe7": { - "balance": "12640674931821000000000" - }, - "b547e04ab8a44d3cae38704356f1f59408457b67": { - "balance": "286604155735000000000" - }, - "b562e4010a0a5fd0906a4cd9f47fc28f6f51e210": { - "balance": "1000000000000000000000000" - }, - "b584de7b38a2a2e3d9ff9c055b309ca56e5da5a9": { - "balance": "237896887904000000000" - }, - "b5c1129961c4a43673324aaedb8296f5ade82516": { - "balance": "4213058948283000000000" - }, - "b5da6711c72bf27c87923aed4a39349b4192e6b4": { - "balance": "55180742586465000000000" - }, - "b5eac5e7e03b9d31e40393e16e956cd588cb7566": { - "balance": "4508019435556000000000" - }, - "b5fd46ee4e02946dca3485439f98bdab290c82b7": { - "balance": "108321600045000000000" - }, - "b5ff2a3caef6ec30365f4f0ecbecbdeec1cacbba": { - "balance": "979696597242000000000" - }, - "b609d05242f7c13a4ae4036f6da9c0bae18dd70c": { - "balance": "229121731278000000000" - }, - "b611156a2f87fb45c431a5cf5740ded90c2dc542": { - "balance": "401783365700000000000" - }, - "b61c7623144afbd0f6cf44c951e4219ef8096119": { - "balance": "36000000000000000000" - }, - "b61cbe0e58ff6fa4c810ad03c759c79d9ff052a5": { - "balance": "1034495371371000000000" - }, - "b622bb67e95a03f58dc9aecf82c217e86f2cf7c3": { - "balance": "500000000000000000000000" - }, - "b62a50be3ce0e7cf8f61991daf8fa7e23775141e": { - "balance": "1000000000000000000" - }, - "b63cbff6b1747ad5cda101d5f919ce81dd67e363": { - "balance": "2570089937000000000000" - }, - "b65e80551a8687c9cef2d852949177c0e3b56e51": { - "balance": "100000000000000000000" - }, - "b68126ebbcb5ab9b0371b62597a38d5c1685b0df": { - "balance": "671140851028000000000" - }, - "b69f5830c371cad5a74ae823eb8892d153ef3c23": { - "balance": "18446744063709551616" - }, - "b6b4468c4db64e0b85cddc251d02f32fffcd1f7c": { - "balance": "10308006217291000000000" - }, - "b6c129312505e571148dbe69833d30550efc12c9": { - "balance": "5105834767567000000000" - }, - "b6cee8ef00b8674a9a96447e4511b30d6564ff67": { - "balance": "667754569888000000000" - }, - "b70f805aeba260d44f0730f0a9dec60f2b4f54a1": { - "balance": "2751303297000000000" - }, - "b71a901dc4b6c6463f7d221f868677bcadbcc680": { - "balance": "169000000000000000000" - }, - "b7385bd8f8257331f4c7a87c7a23724f615cff8e": { - "balance": "196000000000000000000" - }, - "b755692bc027e30730dc1d0e0b2a883830a84115": { - "balance": "30713083153428000000000" - }, - "b765305dda3c1e069a7a022ec127ff2140d0a820": { - "balance": "603122990932000000000" - }, - "b77403a4c56ffc7715b4bfdfe4b054336aeca466": { - "balance": "130840969728386000000000" - }, - "b78b2f6dc731d7d84b7eea151805f9208a1d0cf0": { - "balance": "142084687500000000000" - }, - "b792a0fd762c002a7585cfdefd36cf7ffb42fc05": { - "balance": "10000000000000000000000" - }, - "b7ccd7164aa7fb871726d9d043a8f8f890068c0f": { - "balance": "1170997140237000000000" - }, - "b801f49018317caf30f310dbe116f4e876184874": { - "balance": "50000000000000000000000" - }, - "b81ca2bc63cb4008cebdda3ce8f4eaba322efca6": { - "balance": "4678481047354000000000" - }, - "b82e3d50bf8c5b471c525ec8dd37b06688ed6178": { - "balance": "1202448975553000000000" - }, - "b841162a7a8876296f10794d8847d8095426aa54": { - "balance": "73500210754000000000" - }, - "b8421d375c3f954e22b6fd304235dd7c43b68bd0": { - "balance": "6499782706009000000000" - }, - "b859b76d77eb604728093c61fcabe6f9d22433b0": { - "balance": "196000000000000000000" - }, - "b86536268ace9be93a1db2012d6e3e59023ef2cb": { - "balance": "52878034904067000000000" - }, - "b87e1ac4fc423ab37e10ffd221df8056537b1d03": { - "balance": "119159824674000000000" - }, - "b8825a99806c5a968423e69d22f2b61a2f0ae9e4": { - "balance": "999999999580000000000000" - }, - "b8835acaf63e0e5d41fb743eb0f954040a38d381": { - "balance": "64000000000000000000" - }, - "b8844c74b227781d4b3fafd32e39ff6fa9857f77": { - "balance": "490694157000000000" - }, - "b8962e8bcbcf0f69144f8fcd2ec3ae8e54c05034": { - "balance": "1425313342735000000000" - }, - "b898b4ece8e0eea375f6eb85615652cc5c221593": { - "balance": "2284038029169000000000" - }, - "b8a949bfd9751c29c4cd547cca2e584d8dac4e12": { - "balance": "50000000000000000000000" - }, - "b8ad5ce2ae781e2d245919c15bbbc992185e5ada": { - "balance": "733786526623000000000" - }, - "b8cb6a9bc5a52b9cfce26869e627b2af0ff5ed4a": { - "balance": "98364826821577000000000" - }, - "b8cf6aac7b9028649f0d55a57b61640d70cef120": { - "balance": "104799890645000000000" - }, - "b8e827b5d1e10a3944039adb1a3dd7ff6949145c": { - "balance": "172413427060000000000" - }, - "b8f6d7f33ee5755ba56647ab8fc9ca27b8aba677": { - "balance": "1430769696978000000000" - }, - "b9221177e2b09725bc95f08c72c17c42887eea62": { - "balance": "1212779749827000000000" - }, - "b936e0d83cde9bb810b85ad58eb5ff0fa9c11654": { - "balance": "4999580000000000000" - }, - "b961d435c457e205fdbed5442c8614ecfd59616c": { - "balance": "27847452621284000000000" - }, - "b969e9d89f32002cd4f90ef5907bebbbdca6fe6a": { - "balance": "12455448454838000000000" - }, - "b981c9137cfca5389f0123927852278d2d7ff618": { - "balance": "92180707865000000000" - }, - "b98abf0fe91b0d3a16c6ed37aea446baea33fd23": { - "balance": "560454425563614000000000" - }, - "b99ab4e6ae277b9fb04537adbb781e8390b490ad": { - "balance": "32814665223319000000000" - }, - "b99d0a433d7994743dd675894c18ed03164436e1": { - "balance": "16000000000000000000" - }, - "b9d8b6f0a505d217709bb9327f3b9b3f84813e00": { - "balance": "81000000000000000000" - }, - "b9dbd64e3c8e6ad84c9c67c66e678c06ea7bcb91": { - "balance": "1161140466507000000000" - }, - "ba361f7a6dff16a96f957c63e08267dec8f9ecf7": { - "balance": "2170060167590000000000" - }, - "ba47f4136f74b566f62ba373651332b59e74e1db": { - "balance": "906249296535000000000" - }, - "ba5287cf15de91daeaea2465da4d4c1a14dea716": { - "balance": "98978398162000000000" - }, - "ba77d056d52f84e740579aa527792f826591c858": { - "balance": "50000000000000000000000" - }, - "ba895406774ced5fd2e759b58f9ffaed5e04fb14": { - "balance": "10000000000000000000000" - }, - "ba96fab21a4926fd1137558ae996b52ec14538a6": { - "balance": "10000000000000000000000" - }, - "baacc247801eddbf152fd6ec39d659f265935743": { - "balance": "2661902597584000000000" - }, - "bab2eb9fab8e699a958699b15ddc7ada5428d33a": { - "balance": "27006404153000000000" - }, - "babeacd7933c817472875c86bf126e6d11886f8c": { - "balance": "2461234517292000000000" - }, - "baf7021d4d754d4478d3c3624c2376e3f1d4ee5e": { - "balance": "1352066301857000000000" - }, - "bb0760bd1da973d8f70dd0caa6cadfcfd8199231": { - "balance": "177674700430000000000" - }, - "bb278c6a52eebd0b8950e9b78ba211453ccb1b6a": { - "balance": "25000000000000000000" - }, - "bb327e5f260b2dfe25fb180c2d3f4b63211c1dee": { - "balance": "7694972715000000000" - }, - "bb643e768ab20c135e7df3f400284cf04c40a6f7": { - "balance": "385756449779000000000" - }, - "bb73d1d1c289b4953d0033b52d9d2d0d92573d22": { - "balance": "11000000000000000000" - }, - "bb89936d562b19e4c599826ce7cd0c60cb02b512": { - "balance": "725910446589000000000" - }, - "bbc509b7999b0e94534477b98ec8927cba879677": { - "balance": "20000000000000000000000" - }, - "bbcfa9ab62f4eab14d6a1b09c1aa554dae113183": { - "balance": "589417352665000000000" - }, - "bbe78301134249b52b74d73ee3855e7e3d288a40": { - "balance": "4456159000000000" - }, - "bbe7bb4c4f1b506b58f7e3334e6c89011cf2d6a7": { - "balance": "3889127030000000000" - }, - "bc016690596e077273465d1728d18553b185654c": { - "balance": "185932953686000000000" - }, - "bc16b2ab9c7ab309249f93b496b75c6a7392cb10": { - "balance": "5000000000000000000" - }, - "bc254e5405b154b98abb5fe5508d3e7c98663f4e": { - "balance": "144000000000000000000" - }, - "bc258aeb0f18150d3ca253c6bb04f63d657d99ac": { - "balance": "6011905701701000000000" - }, - "bc2620b5ebac12a88b287b625fa5b336568e7869": { - "balance": "534886892259000000000" - }, - "bc318687cfaae2be4c5ece4a18bb9252486a19d0": { - "balance": "147226513970000000000" - }, - "bc32dd123fcc2ef0dc36484c3ab1bae5d9890761": { - "balance": "16000000000000000000" - }, - "bc5c5151be06aaf6180bc9c1058b181a5a30366e": { - "balance": "113865120384000000000" - }, - "bc66241ca430dc31a3e2f44dedba868e16b9a6a1": { - "balance": "50000000000000000000000" - }, - "bc7c371af0688b1c409f4b07662609a1c9efd120": { - "balance": "20000000000000000000000" - }, - "bc9454f7efc86e25d18a8e8b6e230de42a51d967": { - "balance": "148103676062000000000" - }, - "bc9d5456b975bf0b95c161c3355e4ceb28898fd9": { - "balance": "28083912047000000000" - }, - "bce0b47bf13e4517c53bbbe6e51544b99f3147f6": { - "balance": "919711480389000000000" - }, - "bce2d1ec7c41b426f72b352f5f2b7da3edac4157": { - "balance": "908085365725000000000" - }, - "bcf0756789a57f16206dd78bf6e1322ba9b9b85b": { - "balance": "110888224252000000000" - }, - "bd0bc4a0730f9f55a2f65f62662c7553db52238e": { - "balance": "8440290043000000000" - }, - "bd29fda37c2581a3f040c77eead3143cff24a346": { - "balance": "126022762542000000000" - }, - "bd4c1270322a26a1b825040b239008a447c31918": { - "balance": "727012140904000000000" - }, - "bd6a3da2db66dc9fa26fa2b63b14003d26ef91d0": { - "balance": "5492112771780000000000" - }, - "bd80fcccac60078fcf09f5bddd8a25a92fb9cfdf": { - "balance": "10000000000000000000" - }, - "bd92dc94b6e81a3da5dc3ae6bd80782622658196": { - "balance": "10000000000000000000000" - }, - "bdb35c2c595fe7a2864ebe20dd56d6ddaf9d447c": { - "balance": "4346566125000000000" - }, - "bded4718cbad2150c9b6df9ee7356e0f5c713cea": { - "balance": "311694803600000000000" - }, - "be1804630ecd95ac411b935566cecc5a24c6f18a": { - "balance": "85033246331000000000" - }, - "be2318ad50b0a85b95870a81dce5c31029636159": { - "balance": "5185298019030000000000" - }, - "be3de52fc1119f02f4707f353c040b7c4222d847": { - "balance": "25267399461000000000" - }, - "be4feae01d429c872601ae84dfae8fddc3372686": { - "balance": "20000000000000000000000" - }, - "be7c09d704d16e4b2c9e19cc8c07808bb335f926": { - "balance": "25000000000000000000" - }, - "be873a9525899bdad5e4376b0115950e534dea2f": { - "balance": "404116929377000000000" - }, - "be891b1680ad835aab1ac05a30c0813306cf20f2": { - "balance": "144000000000000000000" - }, - "be8ed2d85a5e3f83c6105db1a1f304e9f174bfce": { - "balance": "50000000000000000000" - }, - "beb1cd80c2f8fabc27ee3a3b2a15e35fa52e7879": { - "balance": "11539095431000000000" - }, - "beb67375e46950830906bf281209be133075452f": { - "balance": "1305262446956000000000" - }, - "bebe54437722c6000bc6a8843f159538a2abf613": { - "balance": "41042548942568000000000" - }, - "bef2a05e283ae948efa9b0e3a6ab5d26a57f1de0": { - "balance": "180614450853000000000" - }, - "bf03950f265a4182b4402703723a0311158eef4f": { - "balance": "158997402149000000000" - }, - "bf06393654baa1ad15c2e717e06dbaa61834c214": { - "balance": "34409427774000000000" - }, - "bf2b867313a44bd04aceaa644771d1e95317c881": { - "balance": "10000000000000000000000" - }, - "bf350ccad91a2a2aff4cf27a291323a297a78009": { - "balance": "124593326152000000000" - }, - "bf3d86edfcf52733e91a9c59be606a95bd921885": { - "balance": "20000000000000000000000" - }, - "bf5b21d5e339752b33b180064d0e6047338650a5": { - "balance": "1000000000000000000" - }, - "bf64c2715db8f353600a45b9264e1f22a40ef8c1": { - "balance": "2952972677360000000000" - }, - "bfaff32c8b04a61658ff94f94e4687232b8d2d7a": { - "balance": "1117691379350000000000" - }, - "bfb00182321502e0729d9a0862ec1df1b3e2208e": { - "balance": "500000000000000000000000" - }, - "bfcdfc9f60610f0ca279ca2c89b9af831332aece": { - "balance": "1431082635308000000000" - }, - "bfe14356e86f6b2ad470bc77d250517c8dc03d15": { - "balance": "310115085185000000000" - }, - "c008bd3fb881da9dca4cadcc56b1d99c56db9abd": { - "balance": "12899598792000000000" - }, - "c01efea456d30360a78ee10c790d46bcb889ee61": { - "balance": "103203021492000000000" - }, - "c03d622627bba7d5db1a9f699924e9d5ff5640f2": { - "balance": "95102233308870000000000" - }, - "c0465ed806ce7ee730e5b6eb7b86a754bfd196a9": { - "balance": "1654379359619000000000" - }, - "c061c5b0d0ce7af95ded1805abb23f743e13c455": { - "balance": "500000000000000000000000" - }, - "c074f2024f79cf8d7aab2d858dd110fc2ee89d41": { - "balance": "18382732686000000000" - }, - "c085147a76d0336b4bd6e7d5b60d394bfd3c6f42": { - "balance": "3236912707535000000000" - }, - "c089416d2d679cb2abf44251de227d0a08fa1206": { - "balance": "497124416350000000000" - }, - "c09d8cfd85989397dc723f2df821dbfb2c0c39b3": { - "balance": "833485701262000000000" - }, - "c0aaf130e3b67250d9775d62e7cd3963daf0a627": { - "balance": "1249947125780000000000" - }, - "c0aebdb5c2e8c5ff9870535c738bfe892c9365dd": { - "balance": "360097616959000000000" - }, - "c0db5680ba88052652bfd5a617c4e8a5be188077": { - "balance": "509051625766000000000" - }, - "c0ee350e5e09a2daeff332a66a6e117fad102112": { - "balance": "10000000000000000000000" - }, - "c12c0a3fd42501f8772e4ad5d262eef3f0bc4701": { - "balance": "120398848512531000000000" - }, - "c135b48c7fd11670bbfba923b28767d21d7923ea": { - "balance": "20000000000000000000" - }, - "c1397c66b7f150c0062b0e87c981c107d771b109": { - "balance": "87751498250000000000" - }, - "c1507ee435cf506fc5d8e4cb62515f2ea0f3a7ae": { - "balance": "4935384099000000000" - }, - "c150d185e2cf203054a6e328b72d8c35bfbbcc33": { - "balance": "21044148271000000000" - }, - "c163098f8b8f0736862274860b3842cf14bd2288": { - "balance": "119025568966000000000" - }, - "c1687fbbc7d504b73fe3e71af440b3dec0da88b2": { - "balance": "229520711528000000000" - }, - "c172bf224080d448261b3b66453074b28628daf7": { - "balance": "7903438287958000000000" - }, - "c18e9bc05dfee2a39fe2b6778a24a48d5bf0f141": { - "balance": "500000000000000000000000" - }, - "c198fec4069c95300d34b9c7109d7441b8e62745": { - "balance": "50000000000000000" - }, - "c1b4134f4757d19a687d05bd7087872b5625405f": { - "balance": "20000000000000000000000" - }, - "c1b43ca2af534ac6bcad8f23c30c07ba07e7e8fb": { - "balance": "194999622000000000000" - }, - "c1c2249507d2dcaf4a9103fcea2cfb47aa4957f7": { - "balance": "571416394325000000000" - }, - "c1e90af40fb64427aeb79a13607debbae9270b52": { - "balance": "50000000000000000000" - }, - "c1ffc8938f3412d19d428b8450f17fd394ae539a": { - "balance": "36000000000000000000" - }, - "c20013e25ae53d0d41bf365aa767822bbbe70936": { - "balance": "10000000000000000000000" - }, - "c20e9eadffa5529ce58a39f5898f39906dcd4b78": { - "balance": "757301065305000000000" - }, - "c211fc2623d51846d26952628d140643efa5156c": { - "balance": "865384323985000000000" - }, - "c2546c312570b30ad2ed05edb13b6469494c5b92": { - "balance": "5000000000000000000" - }, - "c25b2280ed0f835538f8ffd9dfc08a3b853f1ccf": { - "balance": "1000000000000000000" - }, - "c260e43b89a7a4e84bcc4c21dc43d4b5e6923f3a": { - "balance": "1000000000000000000" - }, - "c26aeef0e1f382c88bbdb1eb8c01afa7f58218ce": { - "balance": "79774757760000000000" - }, - "c27dd2645254bc30b6cf7bf418803b02ac808b5e": { - "balance": "4419594173874000000000" - }, - "c2b4f6cf92d6d63a20034e409a358df1803159b8": { - "balance": "1630820442000000000" - }, - "c2ba4a7ea6ca2d17231fb17ebd5dd2dfc0964de4": { - "balance": "221662324727000000000" - }, - "c2bc18f24b8097208a8b2418c444ea58beb94281": { - "balance": "1766754009521000000000" - }, - "c2c028dd17f8a89b9131b7daaeae9cb1dddf86e7": { - "balance": "10000000000000000000000" - }, - "c2ed78a0cb850c12ce8e6ff3873e8c18ffc9f4b9": { - "balance": "1017518755567000000000" - }, - "c2fd7296210b7013d476205d2517d51b21c9e76c": { - "balance": "500000000000000000000000" - }, - "c3041d3d650ff6ac3e35b60371b6798360727651": { - "balance": "1011071365226000000000" - }, - "c328ab9ce1fddd5623e0383828714a7e3ff12eff": { - "balance": "285042661579000000000" - }, - "c34ab008ddddf376dd866cccae4a4d6eb88403e2": { - "balance": "2798642711076000000000" - }, - "c3511391c4515cf8f27e9bc0f777a02a4125c8b1": { - "balance": "20000000000000000000000" - }, - "c36916a9fdf656bb1a8c2f7fb752a3489020f6ff": { - "balance": "689483152953000000000" - }, - "c37598a388d6f4e8e046923265ee9256456e40ab": { - "balance": "62865106394696000000000" - }, - "c38813db256eb221a7142d042b81ba2babab2c31": { - "balance": "98477603778000000000" - }, - "c3acd30f0bc3146fc2cab8d54904f98289021374": { - "balance": "17820000000000000000" - }, - "c3ede34dc1cd995fda1c5cb6e9ffd0c0da080587": { - "balance": "1080428143758000000000" - }, - "c3f04dffe2be55a1d6cdaa78e5c09a79d0477e7b": { - "balance": "59747493842929000000000" - }, - "c3f09f681cfb57d3cabc547dc32a71d2a6585c1a": { - "balance": "1757648436173000000000" - }, - "c3f3bb6444d853614f18c04a3c81f7d26e62e96a": { - "balance": "9022830778000000000" - }, - "c3fe4534327a2fc4144e2d3d3392f7b78d2aabc5": { - "balance": "1759225739027000000000" - }, - "c424f5be9490ec7f0f1e2debc3f72bd83e35f587": { - "balance": "1774372626989000000000" - }, - "c434f64eb937207f80e9a02d2f77ca34bfc63aa2": { - "balance": "960850858644000000000" - }, - "c438b6fa5801a4b8dea450530d975f174cdd47ef": { - "balance": "64000000000000000000" - }, - "c446effb984ff3e5ed92280e7b3dcdb1284230b3": { - "balance": "503490303680000000000" - }, - "c453ae9f94253ebdb871e9dac19056b13d1747a3": { - "balance": "1621494076559000000000" - }, - "c4a473b5e3a6bfb51f963d4dcf109bddedf4fb43": { - "balance": "104273242373000000000" - }, - "c4b8058e9e5416e526ea16e37f29dc221d28a003": { - "balance": "1833513486496000000000" - }, - "c4c09f4bbae0ee06f2a52ff0ef0de1978b5305e9": { - "balance": "20000000000000000000000" - }, - "c4c5981f5ac0a9a3701663b887c4aaac3a3a4d1d": { - "balance": "1411640000000000" - }, - "c4f7a493d16aab4d18e88e530e75e3095a3439ee": { - "balance": "191606419322000000000" - }, - "c5259c18bbd8b0485ca83d069d5ac235b28f24ea": { - "balance": "1276479076242000000000" - }, - "c526ef1124c7d0549b117e7b7463539a24209290": { - "balance": "9106523141000000000" - }, - "c5278b9eeff2221604f30f002c307ca2882fba97": { - "balance": "20875716591000000000" - }, - "c527ca73562846de9fca1649fe5144e5068a2f6e": { - "balance": "25000000000000000000" - }, - "c52a960c5df55169ed5d5cb0109a576321ab82fa": { - "balance": "1097338876493000000000" - }, - "c533ab799e5a04e0ba4e4780d632e0044262d216": { - "balance": "200529941482000000000" - }, - "c5389e3ee2f043ac2b6481f254440a97a9cf3bdb": { - "balance": "84047554571000000000" - }, - "c5594292b324c1d63f797c588a589c895c680ed0": { - "balance": "334298857161000000000" - }, - "c55d7ae4f29d857182d5f1ac2a78cbf35a694dc2": { - "balance": "500000000000000000000000" - }, - "c55ead0ece8fcfbecc573666c0170228e089aefb": { - "balance": "438775082956000000000" - }, - "c55f7d73491cdba391b631581029de32755a09b8": { - "balance": "1340000000000000000" - }, - "c56cb4e8308d6462eded0bbc74965ee135e23e11": { - "balance": "568187503785000000000" - }, - "c5b0c5f840f579536d5977a77262458d72ef1490": { - "balance": "5880686297881000000000" - }, - "c5b129c764daac8bfbf023646b9306d817a8ebdd": { - "balance": "10000000000000000000000" - }, - "c5bba43db949e2ed3de3036caf7a6e42558b1ef2": { - "balance": "763947031151000000000" - }, - "c5d57171e5b9cbafaba7d2c13cca3ec9d81bda49": { - "balance": "25000000000000000000" - }, - "c604e6c539c857ae9e60ca20d1906308ba431892": { - "balance": "100000000000000000000" - }, - "c607bdc5ad2f189e9356edb4d7975c7ba9300836": { - "balance": "55828814399000000000" - }, - "c60b0d2341ecada6c3faf1efcc9027125d99e17a": { - "balance": "121000000000000000000" - }, - "c61e1b993c3fd91a1023ba5b92d06a0aa539d92c": { - "balance": "23863993763643000000000" - }, - "c624656ee5298786cb3d0de045b0ac089c5341d6": { - "balance": "2210389938000000000" - }, - "c6573a023d6f4b5e151f266af4ec0045df0d1518": { - "balance": "52505006485983000000000" - }, - "c66b1d84c42018b16dbc4777409bf50a49febba9": { - "balance": "9078953000000000" - }, - "c69e4de93457f251b1e0879b5250b26e57839fec": { - "balance": "500000000000000000000000" - }, - "c6c51205c9f0bcaea05dce8e47e91d94a3f63c2a": { - "balance": "2720612321571000000000" - }, - "c6d237e0936c4714e701823aadb368fdc471451d": { - "balance": "541700595551000000000" - }, - "c6dcac15739872089cb3d23287e8cd546487ecf2": { - "balance": "1023857245227000000000" - }, - "c6f40b81a5860dece34305f53570be61cdf9a8fa": { - "balance": "20000000000000000000000" - }, - "c7147a95cc4f6bedce6292e8f95539caf550e9d6": { - "balance": "20000000000000000000000" - }, - "c7185b1a680d8b0893065d8213de54375d086420": { - "balance": "11564622085000000000" - }, - "c71b3876613c928197aadf3dd7888db3665f28f0": { - "balance": "112276274428000000000" - }, - "c72200bb380db62a3fd741713d332be77bc1a4ed": { - "balance": "6962060809000000000" - }, - "c7345cd5a7eafc9d7ebdc17d674f83e23336538c": { - "balance": "4425703195684000000000" - }, - "c734f9dc3ee2d857ac826b101129eb77a4a22256": { - "balance": "100000000000000000000" - }, - "c736fa9550b73f4a4ca0ac1cd94bf6f42ccbb11b": { - "balance": "449139000000000000" - }, - "c74128ea37f5d1ee016086a38e470bb332eb5270": { - "balance": "40479951869000000000" - }, - "c7647ec91e823cfe57e8a3433ddafd7b4f675b80": { - "balance": "307102062000000000000" - }, - "c76d49334ce25f5fc62841e5a87d4e03ab3edd9f": { - "balance": "109999979000000000000" - }, - "c771093ed5c4df518536b76e013e8142ecc3f9ed": { - "balance": "5247752820195000000000" - }, - "c780dfb4cdcba4dc89245a8be8a93de1a3e82d3c": { - "balance": "205580199482642000000000" - }, - "c79c6c3a0a46052f723a26b1f107a332474df3a1": { - "balance": "50370325181000000000" - }, - "c7a4e02d2c0f00fa56662cc9f323cabeff82759f": { - "balance": "1163435680762000000000" - }, - "c7c0632cff11812130c30163c83746839a625f95": { - "balance": "10000000000000000000000" - }, - "c82238664bedfa8ded51e91969a39f13a8262a37": { - "balance": "10000000000000000000000" - }, - "c877d228c350ec0d8d97802e7d874d3130171813": { - "balance": "199845203467946000000000" - }, - "c88b8a2e498fee366a1290a575a7f09da12ea8b2": { - "balance": "50895598476000000000" - }, - "c8bbd0e52b11ae6a20adc5f6bbe4d34d7440e8ca": { - "balance": "114566193776000000000" - }, - "c8ca2bd1bef02b505f0333996bcb6bf730648390": { - "balance": "1177250974576000000000" - }, - "c92c3358910418fdb3950e1a378af7246553ae38": { - "balance": "81000000000000000000" - }, - "c9325c9b6d2af226bc5ae1cc975e00cc11274cd1": { - "balance": "2927587698197000000000" - }, - "c95ae8dbc8bb075e7dcb2b2c6d9411bedf26244e": { - "balance": "931878010706000000000" - }, - "c98fc33c1d980052d75fee8b34d08796734b6a4d": { - "balance": "8671327034000000000" - }, - "c99fba8321d16cb19c55703b407c54ed106dcdc4": { - "balance": "20000000000000000000000" - }, - "c9a0da2a3be799e751738e61b9cc376eb06e2b00": { - "balance": "50000000000000000000000" - }, - "c9afc551058c32e89bc2d6704d0d00e92f5ef6d7": { - "balance": "11135553563900000000000" - }, - "c9bfa2ad4b3e9c624255c6ede116421b04487d65": { - "balance": "105514983171000000000" - }, - "c9e4b61d8ddeee339e31ba088efb5d608c3464a5": { - "balance": "20000000000000000000000" - }, - "c9e9090d9f95f401c87c7240f3bf88ca9b540f8b": { - "balance": "553735838243000000000" - }, - "c9fd40bb35284e3d7f0dd3b43a1d9e958f7c86e0": { - "balance": "50480449695128000000000" - }, - "ca038c7c9e66531ad79e4d67b42d7920b7f05c26": { - "balance": "64000000000000000000" - }, - "ca0d08f6019884f94f2b5b191ac9bb247150cd13": { - "balance": "25078089364984000000000" - }, - "ca2c6e6ed3d6a1d030807f91e1fd5c79d36af86f": { - "balance": "849454139892000000000" - }, - "ca7c7bbc24cac0f3aabfdccc77df21004672e634": { - "balance": "6952718700000000000" - }, - "ca998c74383b55c8dcddd46b49f95456fb056b7a": { - "balance": "2000000000000000000000" - }, - "caa989e6a1e934532aaae6cad282c18b1a0b9fd6": { - "balance": "2335540529729000000000" - }, - "cab32ee5cce74e0ee88bbd4b505aa587ef2e4bbf": { - "balance": "75914058971000000000" - }, - "cabe9f0d0a18de8d3495dd063b04c6a33584a8c1": { - "balance": "116083536145000000000" - }, - "cacde94daeafc06e46c86b1e20387a23d909ace8": { - "balance": "1521003430346000000000" - }, - "cafbad01b81ad6cc401883773994a9dd6e6ed913": { - "balance": "10000000000000000000" - }, - "cb343b882cfe866f73cd5f0f31fc68cebaddd882": { - "balance": "221801563082000000000" - }, - "cb3a7aa2e97517b6ea8d9ed0ac270a6a9cc6e079": { - "balance": "958830201738000000000" - }, - "cbd2c4916211ab2c234bc8a51e6f680b59aff782": { - "balance": "24279462419000000000" - }, - "cbea4ed5e8d2ffad442e482fa5f8d551ef2a58e6": { - "balance": "26730000000000000000" - }, - "cc001ce4f4417505116486bed9fdf04bf97ca246": { - "balance": "31740534557000000000" - }, - "cc0b53b26b6dee9f8226f25b834085bde13f5eb5": { - "balance": "132440104515963000000000" - }, - "cc174862456f02f349303d1b8328495de8ccd789": { - "balance": "155951512603000000000" - }, - "cc2af3921727d6d2de31d5f656f837a5475de6cf": { - "balance": "10000000000000000000000" - }, - "cc3201749f55f0d7b450110bc11f65b1ce165d2a": { - "balance": "123428947550000000000" - }, - "cc3f37ad6b449e39c544e26bbdf4d7be66b9dab0": { - "balance": "348574664284000000000" - }, - "cc5b36c9ecea12ebfd0721a58ac11b0c340a3f44": { - "balance": "384197170701000000000" - }, - "cc5b410c7797faa05ac4233eb31b468ee4bf279f": { - "balance": "10000000000000000" - }, - "cc60b223554cc6425374c5e2424df7007621368a": { - "balance": "1128118098000000000" - }, - "cc7027381d98c2e883c82bb9c2f85b985e1e7b4c": { - "balance": "1370000000000000000000" - }, - "cca378f16e07258b9c15921233110fb4729645d2": { - "balance": "151974946930000000000" - }, - "cca781d996c3ef985bf7d2b4d68d55f52efe1905": { - "balance": "2217463190039000000000" - }, - "ccd0b9f6ffb0383553c355c6a14be1200966d47d": { - "balance": "12917165349191000000000" - }, - "ccfa4594129bbb9d07cb4ae8dc2b1c8f3bf98508": { - "balance": "524845286088000000000" - }, - "cd19c879df458106d179bbb5b7f44609d68e6e5f": { - "balance": "8601633489844000000000" - }, - "cd1c55037a0570e8f9aaa95ef157ae81a1969250": { - "balance": "10000000000000000000" - }, - "cd1e47695b0fc93b82cffd0326852dc04d8441f0": { - "balance": "144000000000000000000" - }, - "cd1f90c388d76b3aeaf77850f2191f12a2311f51": { - "balance": "1728456799866000000000" - }, - "cd3aecd58de07f80b64044875fa6ad4f18f72789": { - "balance": "2648597880142000000000" - }, - "cd4f39123ece1e0ab52cfa2a5d059b49c4d63c3f": { - "balance": "1661718859439000000000" - }, - "cd6ed2f7ab49515f8fd70aeb4d72bfae8956b5f1": { - "balance": "183807926254000000000" - }, - "cd9d9d07fcf476a8ee7240324a602449606d75f4": { - "balance": "100000000000000000000000" - }, - "cda66d375a10a22f13dff8a9c40b63461daddab3": { - "balance": "1116940051064000000000" - }, - "cdb0832ee5b26da24b1775c4cf0dfd669b94ce00": { - "balance": "23919219542965000000000" - }, - "cdba5805f17df1f3e47647464de978944ed36b62": { - "balance": "4204539000000000" - }, - "cdd1df8bd54941e26ea26eebbd537e751f64f5f7": { - "balance": "5000000000000000000000" - }, - "cddf5b34342200c37ba96eb0dd662ca4c29f89f8": { - "balance": "10000000000000000000000" - }, - "cdf6c838980afd91a600e3fff755a4848d138568": { - "balance": "25000000000000000000" - }, - "cdf7f55a5a16572d2f2bbf7faeffe3c4d64f86ab": { - "balance": "3115969322502000000000" - }, - "ce0f1dbbfa3490a21ee4b28232db612f44bb7bf1": { - "balance": "9227310122000000000" - }, - "ce33184573c33dd859450304984fa63ea4f2b62d": { - "balance": "7055925237496000000000" - }, - "ce33a3db107f01c51d30b24a8db80faf05308bb7": { - "balance": "10996113113089000000000" - }, - "ce4922b3daef62914f0580a55c524e6a02e31d83": { - "balance": "5541295938315000000000" - }, - "ce4ce8a8540678dda16380c211482dd8c8b71092": { - "balance": "6224176337062000000000" - }, - "ce62cfd71abb9979a0acc398c17dbb5cb6da4721": { - "balance": "13448605175000000000" - }, - "ce724bb30c7821a9c847e0a3e9c12843c3471f9d": { - "balance": "252657175031000000000" - }, - "ce8af01494c2c5b4e74bb02dc6de982e7234fed2": { - "balance": "77349533545000000000" - }, - "ce8c774b7f92045faec43e9cc1711224a3b32435": { - "balance": "370287579971000000000" - }, - "ce8c9ed5018559f36ec72e5a9b0701724e498b51": { - "balance": "142866501748000000000" - }, - "ce995c13568a8b1521d4c9721cfc11da4891860b": { - "balance": "1000000000000000000" - }, - "ceab9dddc767a9651e98527fcf51f6e85c9ae402": { - "balance": "5251411770975000000000" - }, - "ceace25f8c7cf853500a461df007f9c9703ac4a5": { - "balance": "1428847332255000000000" - }, - "ceb0c49dad36f6169ec82a2f0d80da36c87e4209": { - "balance": "459821324064000000000" - }, - "cee8083233bcb4d50ddbf2121c90b5c2019ca58d": { - "balance": "557985245088000000000" - }, - "cf0c6bcc66eb75899bc7f8ed4b8d2b29437bfe85": { - "balance": "3252418478000000000" - }, - "cf32c5bf1d7ef0cb0f2f190f8468b01a4f2d93e2": { - "balance": "6593164924646000000000" - }, - "cf6e47463382153fcf0ec6738880925dbc08116a": { - "balance": "1091910654350000000000" - }, - "cf7539096fd0cd97cd316efcfe9d3c87a101a74c": { - "balance": "741847588809000000000" - }, - "cf9439bf2fbab65cecd783e135a37127f585f1e5": { - "balance": "50100000000000000000" - }, - "cf9bdc902604fab070c611ebf6a989ac4a785c82": { - "balance": "1501000000000000000000" - }, - "cfbbefc0e6013fa2caeabc54ac05f45dbf17ca13": { - "balance": "230809632301000000000" - }, - "cfd53f18ac7d94cadd032a0f4cdbdffaf4765d6e": { - "balance": "64000000000000000000" - }, - "cfe66dc4aa9ac9c9f87fdd05c1b2b95da5211703": { - "balance": "1656993051100000000000" - }, - "cff376eef4d69c4a47d6c7916583228fab3b5967": { - "balance": "5904462494391000000000" - }, - "cfffcb819302d05ed763026bdf84b48818938fb0": { - "balance": "289619807900000000000" - }, - "d000aa72a77d55911a5e66c2906da9206db86633": { - "balance": "3008989624945000000000" - }, - "d02d7b42213e873f91e789cbaffc734ffabd1087": { - "balance": "144960809826000000000" - }, - "d02db5279e918b3e93ff81d00d4025cc71dccaf6": { - "balance": "2386625717975000000000" - }, - "d0802cbcca2bb516f251b873eb20bb5e94af7f37": { - "balance": "9287997718210000000000" - }, - "d0c07380308972a36f57d1cd9081d7389d0421cb": { - "balance": "1280367167470000000000" - }, - "d0c131c1b60891b91e58fbed787ee4567e3f2038": { - "balance": "6360752089492000000000" - }, - "d0c71159d46c4d2af7699f682a055c79a1a68a0d": { - "balance": "1527974433762000000000" - }, - "d0d5d9f242f2613079b3b443c359c2e18ed5faab": { - "balance": "637334647476000000000" - }, - "d0dd208ce92da02eee3ee3de335e67f819581a33": { - "balance": "100000000000000000000" - }, - "d0e55ec0ad0f8986dd9fa9d738007c5bdc22f840": { - "balance": "53012893797000000000" - }, - "d0f222cec657ee444e284c07228d585155b82c0a": { - "balance": "7368748129592000000000" - }, - "d11efb07887d8b5b87a77d8fd388190614e8c077": { - "balance": "4703283503278000000000" - }, - "d129f1b89045ebfb4d1df1d9077e9359fd2990f7": { - "balance": "14496053137000000000" - }, - "d15a509424c4e04868bdcf59cbee09882ba04c8d": { - "balance": "65042393236903000000000" - }, - "d162416912b03fa65f3972a63e357ceaa3b621f7": { - "balance": "325650177224000000000" - }, - "d166183164b81bd049b2146a3ccfcc78cc6a0bdd": { - "balance": "1000000000000000000" - }, - "d173d759f0916e61400d56ca690cbf1743fe27b0": { - "balance": "53550838679000000000" - }, - "d18dc883e3881bf4c7db2afaa097bc2d33656724": { - "balance": "5000000000000000000" - }, - "d19dc9b5ae689dea1ccbfea8b44ec6034559e326": { - "balance": "135552499885000000000" - }, - "d1c79160d0b8c1a1546b86db5123e87645a45d13": { - "balance": "10000000000000000000000" - }, - "d1cccaa22259c547993df3c147d5b545f003adb8": { - "balance": "10000000000000000000000" - }, - "d209c9f32f3292ac4d15ef353fbe6f6efcd4e49d": { - "balance": "81000000000000000000" - }, - "d21ac89a20d67e309f96f64adf05fc48f55918a9": { - "balance": "500000000000000000000000" - }, - "d21f6e7adbf480600295af683091f9b9833f5330": { - "balance": "1229445878922000000000" - }, - "d22700a47a0edb137d2f0348aa0f8d4b6dbc5850": { - "balance": "21301422923000000000" - }, - "d258ddc9372e3b70ff53da171252239655ca9886": { - "balance": "16000000000000000000" - }, - "d274c69317dd836df48562455e8f5a7bd2e47d19": { - "balance": "156091832558000000000" - }, - "d286b68a358fcf8a6cec70b83467079664632ae9": { - "balance": "90377010699000000000" - }, - "d29284915d9b924ae5673e8a4a557478f68a7471": { - "balance": "324678197320000000000" - }, - "d297e64ac2bd8e98e6d276d6fe080679c398a26a": { - "balance": "3401930527000000000" - }, - "d2a1e7b51f6b5930a0d9e2ee55736f3d83a1b323": { - "balance": "44578900750000000000" - }, - "d2c9b0b0bbe61de504e4f210c168fa5999c9c23d": { - "balance": "76537483113000000000" - }, - "d2d49f650d222ec3e2cecba163ee92f0e934ca14": { - "balance": "3312486482635000000000" - }, - "d2d803bf10ba18adef5716b4056c1b1d61c45abf": { - "balance": "964679698000000000" - }, - "d2f673b589df7ef5cb32fdeef842d48d66130567": { - "balance": "1079010447581000000000" - }, - "d2ffaceef1af3f1c3e3f35e4062cd9f9abd1da59": { - "balance": "3041453068594000000000" - }, - "d30a74f5041ec6e73d066a375a105116699ce177": { - "balance": "21814020745000000000" - }, - "d30d849a2d8ff5041304014ecf6752dc769bf004": { - "balance": "1247532881540000000000" - }, - "d3113f558c6376321691931c9b21205e31f4a56e": { - "balance": "572224428451000000000" - }, - "d314bac1bf85eedeac0b359dd2106dbae8fc6947": { - "balance": "20000000000000000000000" - }, - "d3283e17112028b324327ef64a238183ba189207": { - "balance": "136000000000000000000" - }, - "d33ce3c3b64d1b3d399651432c15ecb943d16c70": { - "balance": "10000000000000000000000" - }, - "d33e1e4b10a98e82810f6d161df5d35e5677e35f": { - "balance": "10169656674000000000" - }, - "d34699fd152fe38caacd3c096f6abb1cd79e88b2": { - "balance": "25056644550000000000" - }, - "d369c0e01b9a9d519b3b099a98fead19867c019c": { - "balance": "100000000000000000000000" - }, - "d388dcfe55a9b710d05c686f033fdbdd7861ab71": { - "balance": "1439589263065000000000" - }, - "d391a7d45c7b454b743bd867f8f62f56894f9b65": { - "balance": "484904747488000000000" - }, - "d39a75b4831543e1bc99e7a5ca8875c4f69da45b": { - "balance": "10000000000000000000000" - }, - "d39ed6978b6a90fea29e735f8ea3f1d20e0fbd15": { - "balance": "144000000000000000000" - }, - "d3a0a1a00dcbd6bc44c9803ce351a4b36a69c929": { - "balance": "191222401916000000000" - }, - "d3bf1c0a6b0470c30fc49d995025af5e6b639e61": { - "balance": "10000000000000000000000" - }, - "d3cda762bafaf204469f85e6896ec64147a3452c": { - "balance": "468094119213000000000" - }, - "d3d04d78c1ab9e6887a9467b8b1e31b5c9910e5c": { - "balance": "81000000000000000000" - }, - "d3e1bfdd9396aba00d3e78646ddcdaf139a967c0": { - "balance": "833333174120000000000" - }, - "d3e502c42ff0274da12ba87ffd45fa593bba052a": { - "balance": "100409899947269000000000" - }, - "d3e76066c2e32d9a693161de07f2d3b7e6ea07eb": { - "balance": "10000000000000000000000" - }, - "d3e8d577323d97407246b198c4c61f7943c468cd": { - "balance": "10000000000000000000000" - }, - "d3fd4d1b0edbc314b103d350fff023ab75b7d7cd": { - "balance": "84129547428000000000" - }, - "d40087fca8feb72d130bbc9622575d4987f12895": { - "balance": "1000000000000000000" - }, - "d407d4126cbf3619a422c532ccf20c3da1495dbd": { - "balance": "99622000000000000" - }, - "d41a28761c8e5de8c803813667f1dc0918a105be": { - "balance": "157507410260000000000" - }, - "d46ed38228a3c3d78065b2d8b71b325bf0f0e685": { - "balance": "6787045850000000000" - }, - "d4a7463d202e804b39a93bccd77491d8791baf58": { - "balance": "171694163573000000000" - }, - "d4c20716ff7288d811d05fd6f0696a9f5627a11d": { - "balance": "100000000000000000000" - }, - "d4d95059c808cf41e64f7f353246ffae635419d4": { - "balance": "10000000000000000000000" - }, - "d4ef925157c6d0e2d649332f44416b85f8abe69e": { - "balance": "1392945162611000000000" - }, - "d4f0cb25801794f6d803306878763e08209d19f4": { - "balance": "64000000000000000000" - }, - "d55fbebc4dcf2de6341c2325448e9c198f0f06a3": { - "balance": "14206622892000000000" - }, - "d566968c40211fb25114105e36b5a7219cde9d5f": { - "balance": "4898442964000000000" - }, - "d5817b95c6b504a6d07f64faccc9aedf408b0ac4": { - "balance": "54387832478000000000" - }, - "d59679fc40a71897065bf1b3a73f331226cdae72": { - "balance": "20000000000000000000000" - }, - "d5a7deec4a5898f094e1600f9b15768d8aada258": { - "balance": "100000000000000000000000" - }, - "d5b91c29bf772ad3ba04033dfb86b672b245ad77": { - "balance": "100500000000000000000" - }, - "d5c1a9bcc5e68b7547354178fefb3d870572fd67": { - "balance": "2252066779089000000000" - }, - "d5da2a826f5909a221bfd8561dbd7dbf4aca4c35": { - "balance": "13839784966766000000000" - }, - "d5dcc82fa169b4677a3fc26d78f38e27dcc763f3": { - "balance": "10000000000000000000000" - }, - "d5f344ee8a1b954ae5fd8fc7ac702174749bc8a4": { - "balance": "1398836216771000000000" - }, - "d61cd03afbfc1bea186e5a3a51347c2c4ee3a2c3": { - "balance": "109879472702000000000" - }, - "d647fd7ca17203a0049c28ec6759612d767cfcce": { - "balance": "162681136487000000000" - }, - "d656d14acfb2f0fbde2ed2a137a52d852bb6288b": { - "balance": "20000000000000000000000" - }, - "d68130b421b19c193d03a9017b2dc687c7307d26": { - "balance": "128569735484000000000" - }, - "d69a41f7ca76b40ee94b0d04a3780a00c6c651ba": { - "balance": "2801054372864000000000" - }, - "d69af2a796a737a103f12d2f0bcc563a13900e6f": { - "balance": "7412286547000000000" - }, - "d6a5a7e149cbccb72a50b0a3ae00e6756b0a7eda": { - "balance": "1075352201657000000000" - }, - "d6aa9957f141f0dfed77e943c39aeed978834fdf": { - "balance": "20920740110000000000" - }, - "d6e99ccb72d24e8a60f24d47afd4074b1d1fd336": { - "balance": "15415994387186000000000" - }, - "d6ea4a9dda8d5bc832229c916fa45f05f99c093a": { - "balance": "27075799893190000000000" - }, - "d71de419d746ac277baa955761cced4b34c376ec": { - "balance": "1388473506822000000000" - }, - "d71ec6b5e5d4c604f741bafde0974eca49c56156": { - "balance": "61938809628000000000" - }, - "d72f90d9879f6d2d407b4fdf5d128b98d518f1a5": { - "balance": "10000000000000000000000" - }, - "d743d7925a0cfd08150814cce8cd5d3f7099e1c9": { - "balance": "25681376856000000000" - }, - "d7575a09e7498f21cda3e9e7266b7fde91dfe19b": { - "balance": "9841565066000000000" - }, - "d75c2eb5e0a2b2ee72ef4fa7249c1a1ce03f333d": { - "balance": "134491489751000000000" - }, - "d77088329ec1e280ea7a087ad20c5e965721ff4d": { - "balance": "3949070941222000000000" - }, - "d78d564bb79ea19e4a93975a38fe0882018f177c": { - "balance": "992717434142000000000" - }, - "d78efb176b252ce67b5648e04088d12c4668aad1": { - "balance": "10070463674000000000" - }, - "d7a25e43d7d4e23744f0b10e2b4f2911fd3b3bc1": { - "balance": "1000000000000000000" - }, - "d7a941cd82f8aa63c55baa81db44bcb347b8e529": { - "balance": "49000000000000000000" - }, - "d7b34387880daede6cbdad11bb3db67daf942975": { - "balance": "20000000000000000000000" - }, - "d7bca0770e2f890c1e93c3595641241454a31045": { - "balance": "2000000000000000000" - }, - "d7cb675cea1c0dafded44f611c9c344e2a5e053c": { - "balance": "25000000000000000000" - }, - "d7e53a2d8eaefd18e02bbadb7e64906ca8613151": { - "balance": "166599594268000000000" - }, - "d8076b9db0b7496efbd198b73c4bfcf51ac080fd": { - "balance": "210272077089000000000" - }, - "d81dcf5756da397ff1f783ffe5391d1ffd4ff227": { - "balance": "500000000000000000000000" - }, - "d833c6d08f5fff8f77628ab1e86584d052976d1f": { - "balance": "10000000000000000000000" - }, - "d835732e85953baf2af9e49f770bac1caa1dac23": { - "balance": "152211441541000000000" - }, - "d84005fea447e8c6aa0b5436ad79654a75348456": { - "balance": "22563694224690000000000" - }, - "d84d9c59a445911922e88c0f22cc6534f33ca3de": { - "balance": "3054115413381000000000" - }, - "d84e69926216065749e624d87783e90ce3015b82": { - "balance": "1420803164313000000000" - }, - "d884bdbdb7e13cc523e7f192310230c7bdbb4a07": { - "balance": "10000000000000000000000" - }, - "d88eedca1dd9249702f5ffc807c1e439eee1c5e5": { - "balance": "36000000000000000000" - }, - "d8a23fd234bada1c726622925ade62d3021e0037": { - "balance": "1567046607931000000000" - }, - "d8b1aee24264efebd1c677fcab6ada6e0f000cc5": { - "balance": "20000000000000000000000" - }, - "d8ba7afbb8bf2910b983a114aedec626eb7426c1": { - "balance": "275491152435000000000" - }, - "d8c8af55ebf116ba3c3904f8ac39d3a7d31aadc5": { - "balance": "1499999998278000000000000" - }, - "d8d97645f5f62aa89bf0046362dd0f45d40f821f": { - "balance": "25000000000000000000" - }, - "d8ea0e24a7e28285c4454f54181d581324da2583": { - "balance": "53039425000000000" - }, - "d8f5d258164747ccf790f5ed358162c756de49db": { - "balance": "323009990690000000000" - }, - "d9477bb62d3eb668a83a9679f3a7ef43f17c9e4d": { - "balance": "14045557127869000000000" - }, - "d9585e1b03fc86636dde1e64aed3cad77868549a": { - "balance": "1000000000000000000000" - }, - "d975f9ce3fe773fac3f8338a034a757c58f6e11f": { - "balance": "25000000000000000000" - }, - "d97e490faf19de612fb49c041d3f9e7877d3c0bb": { - "balance": "65766847746000000000" - }, - "d98117b74b2f2888d7078d3116d5758e2d09bfca": { - "balance": "1749157484422000000000" - }, - "d990b3f69ec700bdc095c184b3804551c832d612": { - "balance": "509385034698000000000" - }, - "d99b35298e709e5f54e6a5c612a326a83f4268c4": { - "balance": "71963571266000000000" - }, - "d99d9ec76005da26ccc721ec26be4ed9b3b1c586": { - "balance": "469607736824000000000" - }, - "d9bc61075c3201351584a026e5bdfb7cf9a7b6ab": { - "balance": "200000000000000000000" - }, - "d9d07b72f83491b6db26602f6b7039aeebfe6b61": { - "balance": "144000000000000000000" - }, - "d9f6f1ddf03e836b3744d008b62a6424544c67a5": { - "balance": "74347470143000000000" - }, - "d9fceff07ad69bf3b4aef54a7eee541368980cf6": { - "balance": "1143407707495000000000" - }, - "da0285fb7e37fd4be66fb862b248cea94ea8f6db": { - "balance": "80770216661309000000000" - }, - "da05c7aa330fcc5834e19deeb0a808e9ab7f3d99": { - "balance": "169000000000000000000" - }, - "da129e4481bd25450e6c7b42fe417c87ee2ce7a7": { - "balance": "256000000000000000000" - }, - "da32e3ec421993db088c71e256263158f7855b61": { - "balance": "18540215888567000000000" - }, - "da3c99669acd202ccbe6f80902c807588eca0880": { - "balance": "1000000000000000" - }, - "da72a7bec114d43aee6449db830d2d3f16e4d9b6": { - "balance": "744534872932000000000" - }, - "da72ec2cd7b8e3924f8baaea75d5ed23ef39394c": { - "balance": "38646377617204000000000" - }, - "da73078957f491827d62cb3ca0c484c2d1004ba7": { - "balance": "891774109242000000000" - }, - "da828e50c7c8580c6ce81718f11fbd43b2b0541f": { - "balance": "66094097819000000000" - }, - "da91483db6a6a034e068e69a6b46674838c5bc80": { - "balance": "4000000000000000000000" - }, - "da9551b635c3619f81641571e267755b89f7fe1e": { - "balance": "670841942250000000000" - }, - "da9b43a9c1c574580ec43da9f6acb687fc2f8c68": { - "balance": "761695404114000000000" - }, - "daa7f446923f7481115ad285ca468c865147e563": { - "balance": "10000000000000000000000" - }, - "dac6bfd15954efa4c9254e24e5831ab1884f8d67": { - "balance": "960042043423000000000" - }, - "dad85d0b8bb5ebf6ef811d0d35c89f9f343c833c": { - "balance": "37664599958479000000000" - }, - "dad9b01652de5d50bf30f9bcb0c6edc6315139e3": { - "balance": "21500996724000000000" - }, - "dae9c7d6bb0efe3f7ea20442b184f6d99b2a2c12": { - "balance": "937830189066000000000" - }, - "db0d6c28e9b913f611accaab15cc887f9b770f58": { - "balance": "20000000000000000000000" - }, - "db0e5341d64817885721c5abff04c30bd38df40f": { - "balance": "62600679700000000000" - }, - "db387dd404d14478babb60bad2391720d68b92ed": { - "balance": "115096708329000000000" - }, - "db3fb19e8a4a6ace4d8c6c02085d4cbba528b532": { - "balance": "1000000000000000000" - }, - "db4f05a66c0ccf0532ea1ecb931e05a400a6f4a7": { - "balance": "20000000000000000000000" - }, - "db571f1cdf8e83fbff6fb48cc0c81ef95ede12a0": { - "balance": "118317387393000000000" - }, - "db6a6a6db2aef3f43afbfe23027b670ebb3d33bf": { - "balance": "9960755220000000000" - }, - "db8bed34f8f34f45cb83ab19ed33fad76437d217": { - "balance": "21003651205000000000" - }, - "dbeba6a2a7f66c20c6db7b9270a5aee74de3f441": { - "balance": "4086905723945000000000" - }, - "dc04efeac13b2dab3d07833a7e7fa728fc23d18a": { - "balance": "1161834099120000000000" - }, - "dc092386c3a3e28b6b2d7d70db8f3d11e79ef5df": { - "balance": "124362293793000000000" - }, - "dc10be66aa11acbd42a2b1953714f09b5281681b": { - "balance": "20000000000000000000000" - }, - "dc2d58a383ce0bd40bed859ec2f25412b68eca0a": { - "balance": "104917823922000000000" - }, - "dc2e38183dceb2bc82b23e8ccf48dd96ea1c97b6": { - "balance": "2847787376064000000000" - }, - "dc5d9d94530d88451cf081fe7f2ac33667af9d8f": { - "balance": "65321904051000000000000" - }, - "dc993112a8d89136e0e73d67e2f26191583a50ec": { - "balance": "1000000000000000000" - }, - "dc9bb69b295945589a41feb794406558ce65dedc": { - "balance": "104077637254454000000000" - }, - "dcb0109d4fca2dace08ddca5d989a09d470161a0": { - "balance": "28897833222000000000" - }, - "dcce3a4ec516d833f5a9790c40ad0334b0d2dd01": { - "balance": "25000000000000000000" - }, - "dcdb21cc811ab733c2a80a2d5c8e5bb49cb2ddc4": { - "balance": "16000000000000000000" - }, - "dcdf8dd3ce03a2fe0d72835dbbd58725e1ed2c57": { - "balance": "113330414284000000000" - }, - "dd2165839ab95d6b24591307adcde9ee1819927a": { - "balance": "20260199589072000000000" - }, - "dd3015a5fdef66e749a000585d5574f975e3432d": { - "balance": "85465001652000000000" - }, - "dd37c478727f44943c5fd79ace30f21fae5a589a": { - "balance": "108577233510000000000" - }, - "dd3fb5810c31d37652bd17b92497ed479faf123d": { - "balance": "669996966072000000000" - }, - "ddc3bda30f7cf36bd535de4e20c9becb78d159f4": { - "balance": "99998278000000000000" - }, - "ddcce2d2431b67d4157c7ac4bd77f20c24831de6": { - "balance": "36160893899000000000" - }, - "dddcebe609f8b4354a1f27ab1915135e25800344": { - "balance": "1457846339959000000000" - }, - "dde223eb48f81748abde6cbc08cf1e6b0e8e4e5a": { - "balance": "1501921107087000000000" - }, - "ddf4ba402007060d9940a96f8e7c39f0a2c6108a": { - "balance": "377268151287000000000" - }, - "de05d9ada6626a8492acd137c7c7f7080a987cd1": { - "balance": "222144234923000000000" - }, - "de0fab89f79c4edf9766c3b7b1f508cb43c5495e": { - "balance": "8278000000000000" - }, - "de1070f3ff6c47237768fbdead88b2d5184fbe2f": { - "balance": "1000000000000000000" - }, - "de2b16d7f36f630329287822f550ec19415acb3a": { - "balance": "25000000000000000000" - }, - "de3faf6884337a99e54ac5d3f08b34be51b0755b": { - "balance": "51926806905184000000000" - }, - "de4614fd632ddac888d177de0858e62bbbf7dc11": { - "balance": "52506376589000000000" - }, - "de54cabb241dc5def530191f948f67db942a85b0": { - "balance": "9691177060000000000" - }, - "de81e488284acc4f8f6061d3a73bad112efa7a40": { - "balance": "14654060992000000000" - }, - "dea86ac3a661272691c877c1bad8355789382b69": { - "balance": "903877103000000000" - }, - "deadfc79f2a722dbf1c1a92f2824da8874189fea": { - "balance": "98905944986000000000" - }, - "decf1af47e153f6f3749a1b7abadefdcf1607a0f": { - "balance": "529000000000000000000" - }, - "dede5fa984f0def639d5b633f54c60fc5aaa272a": { - "balance": "8193771708654000000000" - }, - "df23607c63b3fd4b5fde6aab093c0c56d1188f95": { - "balance": "14687379916000000000" - }, - "df5b74bf02902e4c466821de798406b663d4d73e": { - "balance": "9000000000000000000" - }, - "df6402ee3f37389e7f65720561b54e26e5f1cbaf": { - "balance": "358266132937000000000" - }, - "df83ea5b770d5abeccac7f0cae803e8bd7b9831d": { - "balance": "25000000000000000000" - }, - "df92802ffe9892c7704875755bdec648914430e6": { - "balance": "20000000000000000000000" - }, - "dfa108bcd80e824a255679a38b2450d428e2f939": { - "balance": "489209553654000000000" - }, - "dfa9f18e859353796afe384d05353dc80b3ffc43": { - "balance": "121000000000000000000" - }, - "dfb0d6580f011e68a39d7727818b0890e70f3036": { - "balance": "537675412560000000000" - }, - "dfdf006abf2293aadc58feea6af6b35db428675e": { - "balance": "9000000000000000000" - }, - "dfdf2ba93bd47d7243b7419413458a947effcf67": { - "balance": "45080282196110000000000" - }, - "dff01277ac23a8cf93383595a80a7c070eafe5c6": { - "balance": "312778552103000000000" - }, - "e0450154c441e52c5e507e8316d4e9376c59c12b": { - "balance": "170163401434000000000" - }, - "e059374d6a7e6c63e609b65642272869fa3b2b3c": { - "balance": "300122497803000000000" - }, - "e0c0d8e739a2f274a43f019a07f7f61d7d8e11a7": { - "balance": "2630310240000000000" - }, - "e0e779e4e3573ea77096daec252ac2b3f1c0013a": { - "balance": "10000000000000000000000" - }, - "e1325eb586180a67873718a2016172afeb03c6a5": { - "balance": "531691399657000000000" - }, - "e13958af480da6443b9ec1067f0f33440634a282": { - "balance": "10000000000000000000000" - }, - "e142daac753b2c4d215372797999e9c88b65dfc9": { - "balance": "585813299366000000000" - }, - "e142ea343bc36ec49989fd43ad5c403c70a40dbe": { - "balance": "656734902975000000000" - }, - "e14d0a3d259db6bfec2fc4ef6e18729e4d93b007": { - "balance": "210234446279000000000" - }, - "e16a5316e3a113f27bafdf3d4fe44fe30ae9c210": { - "balance": "16000000000000000000" - }, - "e1770944aec145a96c9491497eacf7f3fb03c1b2": { - "balance": "335417250470000000000" - }, - "e199ac237661dcac0a4cfab404876abde72ee209": { - "balance": "340000000000000000000" - }, - "e1ad427471023f38cbdf07fdca3728ec343810c4": { - "balance": "343957267368000000000" - }, - "e1ae0223cecd738c8e530a0007ef05e8f3b33769": { - "balance": "950528515289000000000" - }, - "e1d2d4ef39f01a60c3bb5d671af91c5298d87711": { - "balance": "121000000000000000000" - }, - "e1d4a8888cbb383f3671ca96e7b55310b59a2541": { - "balance": "242387826125000000000" - }, - "e1da9039ddfe117e6a0b484fd3962426c112871c": { - "balance": "3710499693813000000000" - }, - "e1da9f16d57c601af8b6d102323c20408af8531a": { - "balance": "3135322588771000000000" - }, - "e1e1c163f391ffad2d0be68641253b0860485a95": { - "balance": "10000000000000000000000" - }, - "e1ec6361df67ad915df9e9661cd0932186db034a": { - "balance": "4279936304854000000000" - }, - "e224050bcd723e63f1fc0567a86942546aaf8d13": { - "balance": "12007628539000000000" - }, - "e2342c7f411d7ca3a86484af59a9c3f3180e2f0f": { - "balance": "16000000000000000000" - }, - "e26f2b026a258ce5801c90bb8fd6f7a152b8d267": { - "balance": "304593714834000000000" - }, - "e2717eb5fd0a1da51272b50ca8d12858009c7016": { - "balance": "506943817535000000000" - }, - "e27546d5620e6398829260e58e8cf4a3a03f4164": { - "balance": "3000000000000000000000" - }, - "e2762bb64e0606a5d635032e15164b01f612a74f": { - "balance": "884716158811000000000" - }, - "e2882066ed0a3c041d09c00c8532850fc42eac06": { - "balance": "42441412728970000000000" - }, - "e294c5d64daf7b7c0994aa9d03669c4b2658c9cf": { - "balance": "6996693830997000000000" - }, - "e2b179f0ed6870a6268aea64b0c7b39d98d97fcf": { - "balance": "334205318353000000000" - }, - "e2d1f6f7e3128340b789565b527bb91de96d54bf": { - "balance": "100000000000000000000" - }, - "e2f136d3693aa0b2346a968a22aca6707fc1d0e5": { - "balance": "10000000000000000000000" - }, - "e2f229054293e32cf3e83f9bb88d9cf1d6acd66b": { - "balance": "20000000000000000000000" - }, - "e33b8f4c9a49554c8b134861f88c8fffc399e456": { - "balance": "83552502198000000000" - }, - "e33cfc7727b1460324b34277dde14cc49bcb273d": { - "balance": "100000000000000000" - }, - "e36af9bfed4f912cae21f3d899f7354e1c902601": { - "balance": "31474316356000000000" - }, - "e36eff7c061dec48446d47675f176b4da3c2e950": { - "balance": "10000000000000000000000" - }, - "e383f3cf431f3cf645f26c7d5e5e2f77348ede6f": { - "balance": "776224304171000000000" - }, - "e398b9f004a4f891cf871a57d9124a97b56e89e9": { - "balance": "84846187740000000000" - }, - "e39ab2415144b46db522e92ed51b8089a5ec01fd": { - "balance": "4158925896363000000000" - }, - "e3aa7ac7e15e9a8a6f54565067234a9d4bf7b569": { - "balance": "1080385576951000000000" - }, - "e3ec5ebd3e822c972d802a0ee4e0ec080b8237ba": { - "balance": "2129139289000000000" - }, - "e3f1fbff8686af23ab95eeeee6a6a03782d72416": { - "balance": "401776848194000000000" - }, - "e4001b830fbd86df257ebab54aec0c66314ef9aa": { - "balance": "518220809325000000000" - }, - "e40790bff894f0b3e534942b5ad6f6592cd6e896": { - "balance": "25000000000000000000" - }, - "e409170a296e46fc96d85a2395e4324212a470ee": { - "balance": "1072528749756000000000" - }, - "e41546f68bbe1771febbdac2a4a5999eef50edf3": { - "balance": "1000000000000000000000000" - }, - "e425d63d711a9996c09d928ba8df94c88163aea9": { - "balance": "10000000000000000000000" - }, - "e4432ff1aee13f97f73a8407e4c7d6e768b8040b": { - "balance": "700508995102000000000" - }, - "e4690f5d024a395355a7cb5238fb7e0dc921b1e8": { - "balance": "1000000000000000000000000" - }, - "e4829684fb36f054766a61fb2a8f6ecdf27c9e87": { - "balance": "73885178137000000000" - }, - "e48a68e1ac007e14ac08c1b3b0df2b5602081ec2": { - "balance": "1389262869176000000000" - }, - "e4d699b3f4117eba7ed27b323048c9ffcb46ed42": { - "balance": "183131036697000000000" - }, - "e4db688c29fdf9a1c16114f99797d8409545955f": { - "balance": "16000000000000000000" - }, - "e535b94d370190d1e0955d3c0d12480e558f00dd": { - "balance": "20000000000000000000000" - }, - "e53966d4bb17fa9b50d29b44ddf3951c9ca67caa": { - "balance": "6400630678000000000" - }, - "e56f2656fdd1a5f7d3716e65dd89a37dd6e42dcc": { - "balance": "1000000000000000000" - }, - "e5a364113076273352e0c31bf505028e0b7edbaa": { - "balance": "10000000000000000000000" - }, - "e5a3c80518fab6a0a721ccbdc3e673680a65f6de": { - "balance": "171727917465000000000" - }, - "e5c71c7170e5c9b07e62cc307d81a4a3053ed64c": { - "balance": "10000000000000000000000" - }, - "e5fb6408db128c55cfb3e7fa1942d6347e34932c": { - "balance": "10000000000000000000" - }, - "e606883236f8b2045393c574153a100675cd4b90": { - "balance": "14005226900000000000" - }, - "e61869d1cf72f25e195898217f5bf5bcec9c9038": { - "balance": "50000000000000000000000" - }, - "e61e2e29c0719457ab1bf7d6d9fe442bd6107b07": { - "balance": "30943034333100000000000" - }, - "e61eb97093e9ee609647bd55f434a27bb30a9401": { - "balance": "200951434577471000000000" - }, - "e62812ad5834747f17c92435d863639e84d132fc": { - "balance": "3017271391299000000000" - }, - "e630b92aa8443eb077e1f6990a2e194d99cf53ec": { - "balance": "1000000000000000000000000" - }, - "e656fd1641c15e1a4b753be41bc4aa438b44b42c": { - "balance": "26972744083000000000" - }, - "e663f0257b98dfa80602a2af1bea1f901c4a7612": { - "balance": "97075813547000000000" - }, - "e66e411a8a9d019b53bf2e0a7e44703e1aa93ac1": { - "balance": "25000000000000000000" - }, - "e6712675d13fff27af43bb1cb3f2f283755bacf5": { - "balance": "227572496234000000000" - }, - "e68e8f04b2cff484da2d41dd639ae8880920f781": { - "balance": "20000000000000000000000" - }, - "e6972b5d7e0fe8c722dec9146b92f89291a0207a": { - "balance": "2115924954211000000000" - }, - "e698b491330cb55ecc4cc4b74015cd94eb927fc4": { - "balance": "1038111785278000000000" - }, - "e6c411e67b90109dbb0fa75f0f07ae8a504e9637": { - "balance": "123792105420000000000" - }, - "e6fb1dabc624edb45b040ad66f30dae010a6b634": { - "balance": "16076893670852000000000" - }, - "e71dac161206e7d3686d13b98fd922ab73587988": { - "balance": "500000000000000000000000" - }, - "e773f9be9b3f4b35ac149b4d759b9e47c8000bdb": { - "balance": "329623043336000000000" - }, - "e781cbbd2dccfdf68595d54fa44104a80d52dd22": { - "balance": "188679476509000000000" - }, - "e793666c7850a409b1d5494f576d122e85cfed9c": { - "balance": "1141845197779000000000" - }, - "e7a5527c6deb922e9f84309c502048f49f0c8f14": { - "balance": "81415566708000000000" - }, - "e7b0f75f9c69ae464b1b63cf295555d0815fc532": { - "balance": "10000000000000000000000" - }, - "e7b43cc673e321e607190a6fde996b71508f4d81": { - "balance": "103958781426000000000" - }, - "e7bfcf3125e37755e57804dfe4479657b212a8ca": { - "balance": "10000000000000000000000" - }, - "e7d33cbbd4eb38365c5be04ce32658a5ac741cfa": { - "balance": "1545192252109000000000" - }, - "e84cfbd7844f6aa3e830258a6b1069b6a7ff5b7e": { - "balance": "543989509107945000000000" - }, - "e8aa0cbc5c1f59fadf3ec122fa8a59ebfc60b5b6": { - "balance": "61271973066000000000" - }, - "e8adb5303c30a8ee044dc09c49818c02a16f4254": { - "balance": "737375689166000000000" - }, - "e8aeef5114e19d467c3064938c5965d04830f2ae": { - "balance": "51130466380000000000" - }, - "e8b5a83497198a513fb2e244bcf05f9d4cf09d62": { - "balance": "10000000000000000000000" - }, - "e8b6818cf0d24bd0e7ded854b3d368662a150dab": { - "balance": "63697741112000000000" - }, - "e8b68b9cb24169fd688db7a626d79d0363777c75": { - "balance": "427222669643000000000" - }, - "e8b8b57b23ea953943da3ef7efaefced9cdbb44c": { - "balance": "16000000000000000000" - }, - "e8f85dca364d26c2149b767904c6c06249c3d88a": { - "balance": "199342917246000000000" - }, - "e916c7801cdcf1b6cf640fcd9dcc1e3148c80105": { - "balance": "9000756000000000000" - }, - "e93cbef13277324caae7816c3d601e2f6bb42589": { - "balance": "121000000000000000000" - }, - "e9415fedcdf8939b551999900128530195a2a5f0": { - "balance": "85165078941891000000000" - }, - "e9a79ade714ce48a07fe88532a20d8f8ed27bac9": { - "balance": "30768493367842000000000" - }, - "e9b35c7ca775661bbd3a4844e2c6bc5effcdea58": { - "balance": "134719523000000000" - }, - "e9b819dffb600373bfd1b1608fc9744cc9167855": { - "balance": "1537634693002000000000" - }, - "e9c5ef50d4a194e53928659b4486a1c456df9e56": { - "balance": "50000000000000000000000" - }, - "e9e21f4523b11567516f6fc525e8967ac707f988": { - "balance": "2498740681000000000" - }, - "ea02821d6c730e061a9947b75188eb8bc0bbf9f1": { - "balance": "12822292582000000000" - }, - "ea3bca3a17c7e724ac0e15acab6442f222cd8688": { - "balance": "2789689549000000000" - }, - "ea4f7923d7045a148d50153f5f4620dbd31a74da": { - "balance": "113595858930000000000" - }, - "ea6d4cbae3cfe49ffd36653bb0d64c01b2bbc0b8": { - "balance": "49325017701000000000" - }, - "ea76cd4cff825301932a5c1d3a1de55a0ff00797": { - "balance": "1282028021000000000" - }, - "ea8e4c8c6500856777e2b41832ff00443db291ce": { - "balance": "553674550359000000000" - }, - "eab52191e5afc804b8685fe13d7ad6f5dc64fc12": { - "balance": "244412435341000000000" - }, - "eac1b0868b710e40d6d5c66a461dfc8f78abbaa9": { - "balance": "10000000000000000000000" - }, - "eacac2c75920b8f6e65f37ad81deb113d526d031": { - "balance": "53028042076000000000" - }, - "eacc9ef8b534143560f420031a8a7f030ff1a36e": { - "balance": "381111853842000000000" - }, - "eaf2cc9fdfe6272de269f32486b2d4c248a05afe": { - "balance": "2793234915237000000000" - }, - "eb0220406832a8a5d4f242538e82c80bd83d0ac6": { - "balance": "10000000000000000000000" - }, - "eb20efc0e0af48c8e6da4b21efa9c9f02d92d29f": { - "balance": "152958793764000000000" - }, - "eb41bce8e3aac2bcf662854a3151e3c83d98c6f3": { - "balance": "219455327737000000000" - }, - "eb44c591306972c29a7084079720d8ee5fb9b0a1": { - "balance": "49000000000000000000" - }, - "eb4b26ab55dc35df2e78d47a90fc43148a6de881": { - "balance": "12139574483030000000000" - }, - "eb4f53510db5edcaad6ea169e521bd094e8da4b1": { - "balance": "100000000000000000" - }, - "eb4fbfb7c0082aa0e7edaed934c5166fee955e5b": { - "balance": "299713748180000000000" - }, - "eb6067ab544af6289a73111e7693dc449d5c2134": { - "balance": "20000000000000000000" - }, - "eb86fea82d10d309b1365237e4855a48684e0e49": { - "balance": "81510415589000000000" - }, - "eb8abbcadeb6e19ab4392cded7a407c8d5df2d5c": { - "balance": "25000000000000000000" - }, - "eba44ca2d6f36df8221a2021bf0644cf6cb59452": { - "balance": "500000000000000000000000" - }, - "ebacbc0eace170f66415df48f74d98eb31828d15": { - "balance": "19046465915296000000000" - }, - "ebc72fb8a1029139d8abdc08da23dc559f87e1a8": { - "balance": "24177703742991000000000" - }, - "ebd561bb9001991cb6b02c8ff9e7ece8a3d73dde": { - "balance": "6684606759000000000" - }, - "ebe1dc3ee857ae4add6fa6636b678af8451d1701": { - "balance": "1485349608007000000000" - }, - "ebe68dc904c737be83aa2ee7f613dd51a6d436e4": { - "balance": "11206782120918000000000" - }, - "ebecf4db55a99f018bf136173ae823528f211380": { - "balance": "191817711082000000000" - }, - "ec15ad0aafe0c0f18089de50b2397509e15a20de": { - "balance": "20000000000000000000000" - }, - "ec2e56973a6cbd8b37d0294b16ef806ab5943ec7": { - "balance": "12031630315394000000000" - }, - "ec432a6a4685ebf6c1e872001d1de246140c8d98": { - "balance": "280056522277000000000" - }, - "ec866ba1bdadb91ca25f5ae035b0f69421ed4377": { - "balance": "431849961155000000000" - }, - "ec9be854224d3d371b79ffc1230fe704ba03be2b": { - "balance": "3692428502391000000000" - }, - "ecc2d6e129c7daa37a93f559c6d4f575171d8386": { - "balance": "20000000000000000000000" - }, - "ecc3aca2a21cb317c5b9debdcb2090f3931d5cd7": { - "balance": "100000000000000000000000" - }, - "eccc9a49ff40aa4b07aa0e1271cfb6713de683dd": { - "balance": "617207728367000000000" - }, - "ecccf24530629033fd6234ae32bde2052ebaa640": { - "balance": "16000000000000000000" - }, - "ed16770d5a56dced87224d4ff68a361a2285fef2": { - "balance": "10000000000000000000000" - }, - "ed23b8e782d5ddf203f9b80e5df83ec32e484fc6": { - "balance": "5000000000000000000" - }, - "ed3244e4168e669ae9d54175173c3f0f0e7c4c7a": { - "balance": "803397672115000000000" - }, - "ed48f39d3f022b321c0864d4955e1cdc8cf54834": { - "balance": "64000000000000000000" - }, - "ed4cb42fa6737cbbbf095f181e1425b3bc3ab4f6": { - "balance": "8974148344000000000" - }, - "ed560f7d83c27a26965f84dcface3930bc447fc5": { - "balance": "2092287996000000000" - }, - "ed6ace91369ec3b06cce474e67d1ce4aba6475a6": { - "balance": "1227081000000000000" - }, - "ed8249dd4a91f70176ffff310e5546e7e0c30b91": { - "balance": "813069034369000000000" - }, - "ed8987fa3d4d42bb8f009c99cda5868633d94f5a": { - "balance": "174952234860000000000" - }, - "ed99b72a58a519ca7aa8f46b8d254c3f1eeea0d6": { - "balance": "10000000000000000000000" - }, - "edb720c9bde4801e204e90282de2a6cf1c44c4ad": { - "balance": "10000000000000000000000" - }, - "edbea23cd0cfde3705d83aada88e78b9f4bb1a50": { - "balance": "4000000000000000000000" - }, - "edc1f174655205bb961ddf94a997cdfd24f1c2ed": { - "balance": "65211537189000000000" - }, - "edd1d2dcba881202bc546943194d64e59bf74bfd": { - "balance": "10000000000000000000000" - }, - "eded28fbd959f2351b4252abc71f0e809562fd4c": { - "balance": "1000000000000000000" - }, - "edfe4d4c83c7db76e5e8a9ccafa34d9841669dac": { - "balance": "2578239411258000000000" - }, - "ee1ef79de869b89334d883ba766e65150f3f6cf5": { - "balance": "779780646165000000000" - }, - "ee27b2da240e862f0848d31116a7b4ed91835c8d": { - "balance": "111637484977461000000000" - }, - "ee3195bdb69e97796911c63fdd3fcebad61ffe9b": { - "balance": "214483035823000000000" - }, - "ee43306530c21793c4fd6039b51cf54fbc912bf0": { - "balance": "374531713769000000000" - }, - "ee4515e30ee1b8dba4779ef213d89e8dfff26ea6": { - "balance": "1166743135013000000000" - }, - "ee591e9ca7948b8485eb210e2a3f706b97e6f9e2": { - "balance": "27793157052774000000000" - }, - "ee5ba6c854d633a04f7656d311817e5104c6de14": { - "balance": "289361919166000000000" - }, - "ee909db4ee48bff3adb9e43db940245a8e5e094d": { - "balance": "582143490064000000000" - }, - "ee94d1afa82de70eb65aad0662f48ef3170495cb": { - "balance": "242490158636000000000" - }, - "ee97e18e09bbb16137a7b4aaae464e97d70e6606": { - "balance": "442709862861000000000" - }, - "eebe957af00050c2841f3ef8768c6a77a5394012": { - "balance": "9000000000000000000" - }, - "eec052f4e2902f7cc496162ca6525997d2b3ede4": { - "balance": "69349303517000000000" - }, - "eed30e1a939d5f0b4a39598967a5f149a7b7cb8c": { - "balance": "1637195595000000000" - }, - "eed7bf1ba39bfdad0ce1b6b8d4c9bb31dc1a9843": { - "balance": "203331701702000000000" - }, - "eee276140ea24e36eccb4fd748f675df1acd3b73": { - "balance": "1000000000000000000000000" - }, - "eefb33b290741c4cded862cea777efe4b14a76da": { - "balance": "64000000000000000000" - }, - "ef17a60d15ecf68a62b4bfd5e3acd6201e1931af": { - "balance": "113292502078000000000" - }, - "ef3f4df42127d3e94b4b5883ca97ee63f90b68b5": { - "balance": "17819622000000000000" - }, - "ef4aa6833a69cf72fbf3eaac57da236970aa4241": { - "balance": "1638520372091000000000" - }, - "ef958a1db06e5b8e12547148f3b01da9a8841aad": { - "balance": "12847752197000000000" - }, - "ef9fa861eefe12a3b4c161a47db5d94b1fa873a9": { - "balance": "49000000000000000000" - }, - "efd9b1ce6bc3932961e41e875edaaa367d318b36": { - "balance": "1626378762077000000000" - }, - "efdce7f577c77f0dac6afc78dcbf5ebadc1c3a73": { - "balance": "627500067619000000000" - }, - "eff3f26bc45638d89f28b3ea7a5471af0b680b72": { - "balance": "1650959950189000000000" - }, - "eff6d78814ddae79d6d09d830dd44de55f3f919d": { - "balance": "44409266093000000000" - }, - "eff739e22b9aeb3781dc301da70761fdd178f08f": { - "balance": "574842224234000000000" - }, - "f0059b3c8a32d3d012b4fcb993431a484b67762f": { - "balance": "516933429840000000000" - }, - "f06747d8e2c76b8827bbd0bf4ea3a68d390ee8f3": { - "balance": "8124594790100000000000" - }, - "f0e29fc0aecc36d1bdd818148878ea7d01957476": { - "balance": "79821431871000000000" - }, - "f0e42acf4e027aa61ac2f56e3d2c171ec0fd6ebf": { - "balance": "672499252575000000000" - }, - "f14338307bc5e6ab71fa202447ce240947568b3c": { - "balance": "13990001528784000000000" - }, - "f14f9a1206eb436a3d2e4ba9b3976137f67a6596": { - "balance": "1086707451000000000" - }, - "f15fcf1772fa5b2a578ce4f9270996430d533000": { - "balance": "496026996898000000000" - }, - "f18c691a5827ff1fdc44b54bd9a64fabd53c1cf4": { - "balance": "3112912699000000000000" - }, - "f1960640b52af75fc71101aec2611499c17cd9c6": { - "balance": "195957678178000000000" - }, - "f1abf01ddd474949713bd7fa67ec81d6b56c87b7": { - "balance": "121000000000000000000" - }, - "f1b93a6cfd4b1c7e0e89ebed119c5fe55af2035e": { - "balance": "1000000000000000000000000" - }, - "f1d14c7659a10ff38f4ea74ff5b07ac035984b6a": { - "balance": "9986323720000000000" - }, - "f1dbf37470a2c4fef98b1023026870ae8f7df2c0": { - "balance": "132757602000000000000" - }, - "f220b958b619d5d848597dd00824ab8b1401ebd2": { - "balance": "1461699635849000000000" - }, - "f2484911e0aa707f88d9dd970db21e8f24b9de2f": { - "balance": "20000000000000000000000" - }, - "f264c15790fd7a36d9ce7a454f6bfbe878708a50": { - "balance": "64000000000000000000" - }, - "f2662356cb3ae7b82efd6c82c3591ee40854892b": { - "balance": "50000000000000000000000" - }, - "f27ae5783b96ef637bde4179080a8f5af63ae692": { - "balance": "784985848611000000000" - }, - "f2a62fc212717e411f72f9a694e30b8da21bb31b": { - "balance": "614971541702000000000" - }, - "f2d0a9594231efb87ac833c365b80944251f29d7": { - "balance": "478622654587000000000" - }, - "f2df99a3df0b9b448d0ea48b9fd5cb1ce9ce50cf": { - "balance": "851116673037000000000" - }, - "f2dff0ae1f5f74808624e4f26fa814e4e19c216a": { - "balance": "404457730686000000000" - }, - "f2ea1ac6282364ad5904c6f058827a4382111d94": { - "balance": "5502482915000000000" - }, - "f2fafdcdb2d887eb13b5362eb76be2a682868643": { - "balance": "6174264174000000000" - }, - "f314adfc2fbf632a6e5d8a261385b6054aca31b6": { - "balance": "1267558242119000000000" - }, - "f31a66a88394ed7dd6609aff07dd26a60a219bd8": { - "balance": "346102834465000000000" - }, - "f3535f2b42d8613363e6d9717cc21a8ec3a74fe0": { - "balance": "35723093185103000000000" - }, - "f36a149466982c030ce3b9717f34b593613804d5": { - "balance": "10000000000000000000000" - }, - "f3828b0eaba4acfbbcf3c58277ceb4616a34b630": { - "balance": "633998941064000000000" - }, - "f38f767eeb8002ef051b32fe2f40193bf0751d92": { - "balance": "50000000000000000000000" - }, - "f39bce177817a7338b1adaf713222e515c0d762b": { - "balance": "1128231726329000000000" - }, - "f3ac7ea27a1cefc7787e5ba54dacfd8385ee4afc": { - "balance": "11364602682758000000000" - }, - "f3d9ea511335ed418b1837766da11832aedf5578": { - "balance": "29188596603509000000000" - }, - "f3ef05ccd19df167e06797d962f6afe16037e134": { - "balance": "144000000000000000000" - }, - "f3f630148eccea0ad7bd67bb806bd5676a4ea4cb": { - "balance": "87187208643000000000" - }, - "f3ff31784e0b8c3cd2f7e18cfd07c682a42d1c8d": { - "balance": "10515373125000000000" - }, - "f40b976e8519a2c97f64783bca495ed3f2e4a7c0": { - "balance": "780184503985000000000" - }, - "f416a3af7f3181ad9c8a916989949d35b0b636ec": { - "balance": "16114504005275000000000" - }, - "f419759927eea6afe77701c4cf4a98791a709ad1": { - "balance": "1032589347112000000000" - }, - "f4368f9c9ad8236b56413f174562d6b6fef21d1c": { - "balance": "5447645343000000000" - }, - "f43c57f984b0e2b7ce4d703e82f41195585504a4": { - "balance": "1135809111749000000000" - }, - "f4449f52895de96a4638c927dc389f010bbd530c": { - "balance": "693196063498000000000" - }, - "f449bd417a674c8bfa1db3a3e09c2b03da0f0c04": { - "balance": "106343287319000000000" - }, - "f44dec8340986c06d64dc98d78772a8a9cdc41ec": { - "balance": "1379381904815000000000" - }, - "f4642be1a7685aea0dc7b362d36f58f15d806b72": { - "balance": "4717509847323000000000" - }, - "f4712925f57391043e0cc2e671f33124a0bc8613": { - "balance": "419736833200000000000" - }, - "f47317fba5927dd8dffc4049d4f3277fcef503d6": { - "balance": "149279442682000000000" - }, - "f47ce4c5aaef82692e47f7a810ba38d1faec0eea": { - "balance": "10000000000000000000000" - }, - "f491ffc412bf142788bb82d48bd4eccbe9e0a286": { - "balance": "77276422315000000000" - }, - "f4a1e27e669c29f15b9f89ac15f702340a135743": { - "balance": "324000000000000000000" - }, - "f4b5cbfa50a6c4f5f7db7a93fa565362cc7aceac": { - "balance": "195951823248000000000" - }, - "f4b949c6e10615b651675016f0d7d6ff64e31aee": { - "balance": "35516207325223000000000" - }, - "f4c5e2f043ef3548a2c1c27d968087bec65e2f7d": { - "balance": "100000000000000000000000" - }, - "f4c79ea9c6f7297e016c39296d86f0304070c31d": { - "balance": "71036374423000000000" - }, - "f4dde3733a72872a7efc095cb412672c50928f1b": { - "balance": "129914864759880000000000" - }, - "f4ed736a413464eb93f8a430e093a64f0bd4222d": { - "balance": "10000000000000000000000" - }, - "f4f07e45560fb63d5207ed7e8d7cf4fe29e06d18": { - "balance": "293103814503448000000000" - }, - "f50eac35eef0a1bfa23ba31020ef60e89bf8e9df": { - "balance": "10000000000000000000000" - }, - "f51236dfd888929ccb2fe1f1fc5554abc5df4ce2": { - "balance": "25000000000000000000" - }, - "f521eb42e9092350f2ad4391ddb42bfe7abb4db9": { - "balance": "217462745186000000000" - }, - "f54e7062b6a9a8b283acf00fcbad58aca0737676": { - "balance": "7327357122437000000000" - }, - "f553301efd81629d0856d9c95c70f4a962e602ed": { - "balance": "1500355826530000000000" - }, - "f55c555b0991b2413f2f2764d8ed6a0d77825965": { - "balance": "1174679810163000000000" - }, - "f56ff110d521ceaec29dbf2842f1e78b24463cea": { - "balance": "20000000000000000000000" - }, - "f573fec366236ab87ba041f7dc6a88d92b1fc9b7": { - "balance": "4659857040000000000" - }, - "f59987743b239379aac9353e17e0e4442aa2c684": { - "balance": "25000000000000000000" - }, - "f5a9ca298e88c5492dd44a66d815b649c2f01d39": { - "balance": "95879585325000000000" - }, - "f5b4933164c55b5ba99db906ecaa52bba4f95164": { - "balance": "25663623936000000000" - }, - "f5d20af68c6fed98144718b6beab82fde00dfedc": { - "balance": "16000000000000000000" - }, - "f5e49ce72be9b17ff39688860e5cf6fd500a886c": { - "balance": "106142276914000000000" - }, - "f5f472405a4530075805fbc11928544770fd61fe": { - "balance": "64000000000000000000" - }, - "f62096c7305eb97b221bb637f4269246fe59262b": { - "balance": "855993602798000000000" - }, - "f622bf9b8f7be2f75d5ed73d318a0e7fa62a587f": { - "balance": "20000000000000000000000" - }, - "f6231f31d524ccc444bd046123ba33bc224bdd52": { - "balance": "97550810879000000000" - }, - "f641b4a721dcefa497274fd06888eb998b9bc038": { - "balance": "39401014566340000000000" - }, - "f64f0c5172c99d74b2450a4685c3ec715b379922": { - "balance": "28337413668000000000" - }, - "f65841061cd55cbf20843d9594bce9ee133aa644": { - "balance": "9064540188290000000000" - }, - "f65f0106f3d148d0660547f0683ded4dffc12fe9": { - "balance": "87334071785367000000000" - }, - "f677961296ed933db9e1dd887711387540c0436d": { - "balance": "3982789899000000000" - }, - "f68ba7530f423b8df1625cee36f8df2363a57c49": { - "balance": "5000000000000000000000" - }, - "f69c6eaf077b795f19a9590ee8b578543558e4c4": { - "balance": "10000000000000000000000" - }, - "f69dfe3f0f76e50e2850e44e9e36b6966e277eaa": { - "balance": "288231750575462000000000" - }, - "f6a73c4b958b4d6044f3f4da7147d0fa80e2ea31": { - "balance": "50000000000000000000000" - }, - "f6b0864be5f7bbc4210a3420aa3ead614a8fe7e2": { - "balance": "880968828000000000" - }, - "f6f43a6d9517471436d2ce5047a2b707580e7149": { - "balance": "20000000000000000000000" - }, - "f6fb414d1ca7c29be35b5f97096c817bbf70b070": { - "balance": "15156317416682000000000" - }, - "f707b491ac27b2d2e5e1f9d4123635ee0af92c5c": { - "balance": "500000000000000000000000" - }, - "f71179583a471767a1b399842d7d29caefe57a5e": { - "balance": "429648186876000000000" - }, - "f71ed909eca6bfd574cd670389bc9250493d686d": { - "balance": "38189267531000000000" - }, - "f72ccdc70b7878cdb94f42ee72ca5b4b35a46238": { - "balance": "86065647347000000000" - }, - "f74035e85dbfdb961037bf689ee7dfdcfaf32d64": { - "balance": "398451682882000000000" - }, - "f77668db085a87b0a0405a275e1c2516d3e02b66": { - "balance": "10000000000000000000000" - }, - "f78990d9e50876b49f933e9d74bda44197e9aa7d": { - "balance": "51984216556000000000" - }, - "f79b9df28b7d94d1b4491fca1cbe50bd36aedb3a": { - "balance": "11546152485156000000000" - }, - "f7c773b89be413848dc4a96f064693a0c3a2eab0": { - "balance": "7084247258755000000000" - }, - "f7e29c20bb0023e9ae079da589346fdfd960dae3": { - "balance": "93132014782000000000" - }, - "f8124428ea619d30a335ecc4c2f64e36500abdcb": { - "balance": "8838170798391000000000" - }, - "f843c9d70226e6c2c8cd4cef78e2db66a8eac027": { - "balance": "498377670361000000000" - }, - "f84bb3c0d872dcdbe99d6abcc57c6b5c2b2e35ad": { - "balance": "1405105232436000000000" - }, - "f8679b915ae94e4668f2e27d1094cbb2d97cf428": { - "balance": "1000000000000000000" - }, - "f86dbb82c634cdfa818e4d0dbcfcc9a5c47a9ddb": { - "balance": "196000000000000000000" - }, - "f88bad7726aa66bc1d0ca5824044072f3551fd15": { - "balance": "37432374800000000000" - }, - "f8ab07d0751a2c283ebe2a7e28c5b6e57867e1d1": { - "balance": "25000000000000000000" - }, - "f8afb4f5684c56ff7ce71b4e4cf7e42062470e08": { - "balance": "10000000000000000000000" - }, - "f8c28df0d1a0982289ddfa2a6d562e5c75a5dd01": { - "balance": "1447386977682000000000" - }, - "f8cca137f9c12b48eafd43f038e55e2d3c481919": { - "balance": "35370515421000000000" - }, - "f8e50d1816a5e5c649756ae208209b03b1ece0c3": { - "balance": "48449640035000000000" - }, - "f8fb33ba1d93112d9c3672806e0939083f09a88e": { - "balance": "419743187776000000000" - }, - "f903bebfcc6a7050fc2c5bd14248af9b300f1600": { - "balance": "473363252199000000000" - }, - "f90ab9078f26dd881fb054b4b6e3b3e17fa94718": { - "balance": "156449634345000000000" - }, - "f93e3f392efc057f0af3a91416858a515c1ed996": { - "balance": "1147663044625000000000" - }, - "f94eac538ca66931869c312acb67721c4337842f": { - "balance": "368103335377000000000" - }, - "f94fda503c3f792491fa77b3702fd465f028810d": { - "balance": "317241487661000000000" - }, - "f95dcedbefee8ed01086c91d91a4c115ad8fc947": { - "balance": "147059838786000000000" - }, - "f961a293bbce366a6fcc98d2ba0342e2ef3c5519": { - "balance": "10000000000000000000000" - }, - "f966fdbc4a42f055f8f52d31c23ad7b6a07a5e22": { - "balance": "10000000000000000000000" - }, - "f9a3a61a2f1469835240bb0641eae40c07451e30": { - "balance": "218000000000000" - }, - "f9adcf232180378b08a46d6c8d9d97f01802e01b": { - "balance": "15658216517944000000000" - }, - "f9c68991ff7ac307e41ea1c673f8ebb1a6afbd99": { - "balance": "10000000000000000000000" - }, - "f9cc0c60431d7bdb0c7581a9ae7f011b0abefeb1": { - "balance": "16000000000000000000" - }, - "f9d43c329b61ca2169600e45c8fad3c94226adb8": { - "balance": "120128558137000000000" - }, - "f9ef5d4e2ca8888216b939d3d938438a34dd9da2": { - "balance": "144000000000000000000" - }, - "f9f3d14cd3bd09e2c4c89035b4f50e93f6175cef": { - "balance": "725000000000000000000" - }, - "fa0f5a03601bd1fc76865cdd69d9671ba6073592": { - "balance": "225298289139000000000" - }, - "fa12f10db0eb552b719194becef20af9f45de8db": { - "balance": "1012484659496000000000" - }, - "fa146c58a0709951bc2e9bccddcd002c5a0bb7dd": { - "balance": "199563276701000000000" - }, - "fa159185c156f35fa450b77c48846c2dab6349b7": { - "balance": "100660066567000000000" - }, - "fa193312655f79c7b0ee7d7ef904486836180026": { - "balance": "48141690266000000000" - }, - "fa2484de744918bd8c91350fbabc0dab8b8a44f0": { - "balance": "36000000000000000000" - }, - "fa36dc463b026d8edfeb8ac4acac43a51d643457": { - "balance": "9608761064478000000000" - }, - "fa84199010be2bf53e803c23771e0d15fd025386": { - "balance": "1474902394742000000000" - }, - "fa958bbfa367a745bcd0904db2c4e30445edaefb": { - "balance": "175679888121000000000" - }, - "fa98bcaeb55285ad7ead12ccaa15cf488f567ede": { - "balance": "136105143781000000000" - }, - "faa1be631da42b41a026774f4166c1b831ef41e9": { - "balance": "86358861589000000000" - }, - "faaa857e7f149968434f313ab8db596e1b0ae75d": { - "balance": "36000000000000000000" - }, - "fac2b85ab274055cf1415d57394e8aca4541857d": { - "balance": "289000000000000000000" - }, - "fb23a508ccdb4e91b252f5c06c465c55ed59b1db": { - "balance": "14698710175236000000000" - }, - "fb24d4e47ba70aa4b984372b4852ad3d082daa24": { - "balance": "4526648424830000000000" - }, - "fb27a7e8b8b4ae43c69ce025b46187e538608769": { - "balance": "121000000000000000000" - }, - "fb2cdb5e85872f52c99985f219b8fb4125c6a8b7": { - "balance": "8568367153000000000" - }, - "fb3d76c8165bcb3c93fd3b2b10c20588d0fa97aa": { - "balance": "500000000000000000000000" - }, - "fb5161b2cc9d48a53f47d66002905f0458e3cd9e": { - "balance": "225000000000000000000" - }, - "fb72756c4845f18ab35d29f632b662c0c0d4b94f": { - "balance": "883095068524000000000" - }, - "fb8b7efb02ea5292304c0f0abc8c555684653587": { - "balance": "10000000000000000000000" - }, - "fb9ee61e337a5c7b57c5140e84919101570e2cb7": { - "balance": "16000000000000000000" - }, - "fbae69f44b116c186a86cb0de79323ca3d6b99eb": { - "balance": "1359504686067000000000" - }, - "fbbd399eb9e5d3dd67efc48927973601dcd84321": { - "balance": "2049018637367000000000" - }, - "fbc9a3c3c429990cc306710b3dd44174dcc72ad4": { - "balance": "55507457947000000000" - }, - "fbce66a6898ecd70893db6b4b8c3d00afef8e20b": { - "balance": "20857164902458000000000" - }, - "fbe8fe04084fc93dff8228861fe100bfeeb057b6": { - "balance": "10000000000000000000000" - }, - "fbfb717f902ad79ef63565f9ab57f041ff5f7626": { - "balance": "16000000000000000000" - }, - "fc0b6c8c6be79bf0c9554f7855dc8c4a617d02c9": { - "balance": "17347593956000000000" - }, - "fc17518d05e605807847bbf6f407da89037bca00": { - "balance": "1796383702108000000000" - }, - "fc2793424c809cc80938a1be1292813adbc8ac8c": { - "balance": "10000000000000000000" - }, - "fc35930abb108ae6cae33fd065dfb799808ea326": { - "balance": "912737460000000000000" - }, - "fc5a9209799e563ae8d958774dc86345a3bc7ed2": { - "balance": "29049176573000000000" - }, - "fc8011850c09c9288e737ea58ca5c15cded6dc8d": { - "balance": "10000000000000000000000" - }, - "fc9183ed137be071ad183d025395a0ebe2674654": { - "balance": "500000000000000000000000" - }, - "fc98c9d88b1fbbb68dbdd6448aa6a32e8282800d": { - "balance": "900000000000000000000" - }, - "fc9f4b9da7a46c2bfcd50cafe1f892b9984be0ee": { - "balance": "21577116424370000000000" - }, - "fca525b732a673b953f1c23083c276cc8cbcb86c": { - "balance": "77653618624000000000" - }, - "fca57b6a4798f33478b6e23622173cda3fe1b9a0": { - "balance": "793368066098000000000" - }, - "fca79b446c513a7bed643603c42f35ff0fa89f49": { - "balance": "998082799053000000000" - }, - "fcab42f7f07735a7b09074c1f1769287069c88c8": { - "balance": "94824830574000000000" - }, - "fcacbbc6810c586522012ad32c3dfac80eb563b4": { - "balance": "10000000000000000000000" - }, - "fcb38809b63810b6673dcb4c947e01f7b49fb1b3": { - "balance": "725937240372000000000" - }, - "fcc0e531d9f6265672aa885af361534464a11015": { - "balance": "22121462657000000000" - }, - "fcc49c62d7738fa1b92aa6a69a12b671e4c7c8d9": { - "balance": "50000000000000000000000" - }, - "fcc95394fd796ca5bd8f3814883b1150d74dd9a5": { - "balance": "144000000000000000000" - }, - "fccdb068dfd599d7d5c290a6ae65eba9151d5b29": { - "balance": "5369426564000000000" - }, - "fcde41ae28bdf9084a28f47a9348d8aac5b3dd43": { - "balance": "409599263197000000000" - }, - "fce5816f066ca32d1fa02e9e8b5eb8a7fa3e4dea": { - "balance": "1193272309645000000000" - }, - "fcf9fb8996d6d9175ade6d6063be0742de20ea1f": { - "balance": "16852526239339000000000" - }, - "fd10488d55e6861cb67f7f50950d78892e7032ad": { - "balance": "165069902909000000000" - }, - "fd23e8263d89256add0dfe93da153d305ad917c7": { - "balance": "26633825496000000000" - }, - "fd3a98cc3b3f1439af35f806de2fb05fef98f279": { - "balance": "1043321187464000000000" - }, - "fd3d79185a91984a117ee6f9fd304725875094e2": { - "balance": "2349991833898000000000" - }, - "fd5e6ac22634f04ec4ace5da8996c2b7b70b22f4": { - "balance": "10000000000000000" - }, - "fd62ed1cf7a535c989fbd742b1660205a2f69dd0": { - "balance": "49000000000000000000" - }, - "fd645043bd4d7b71e63e30409b91e9fdda3a86c0": { - "balance": "362957768837969000000000" - }, - "fd7014fc1c70af482115247ff94ff6bdbd3d364d": { - "balance": "743383172317000000000" - }, - "fda0cfe95df9021497752b04863c3ec44d13e853": { - "balance": "15586809617955000000000" - }, - "fdb5b964808bcb974d3e888cbb45bcd57e57c907": { - "balance": "5549247772273000000000" - }, - "fdbaaa865ec38da13e80554b6d0abc437f60d8a5": { - "balance": "3736861227131000000000" - }, - "fdbb8693b3c20c0eac5fb585e2347d41debbffce": { - "balance": "100000000000000000" - }, - "fdbdaec57829f25ad48e18d94e0b8533f2801818": { - "balance": "6934630922926000000000" - }, - "fdc318ba5b1f8ad33e00528828b93a840592e2fb": { - "balance": "10000000000000000000000" - }, - "fdcf6a997bb10806e4d87eb4222e9f93b4202179": { - "balance": "1000000000000000000" - }, - "fde5a9911a10770d733db4d32ca9a5493478399c": { - "balance": "20000000000000000000000" - }, - "fe39185a6b84378820ee215f630533e658731ca9": { - "balance": "17022202932000000000" - }, - "fe3b1032e524674cba5f329f940c837850fa53ed": { - "balance": "50000000000000000000000" - }, - "fe3bc4ff2c3b66bc582558314b80030407e7de96": { - "balance": "1669870860988000000000" - }, - "fe668dbb1f3de744d16e13e0ed6f5708c2c15d1f": { - "balance": "39974355655263000000000" - }, - "fe95bfb97fa60341f8af2ad621e606b85e3c2e57": { - "balance": "528601649597478000000000" - }, - "fe99cf2a1fbbe7c46e4235b2d135a3a093fcf16c": { - "balance": "7271022106877000000000" - }, - "fec1f6ed4b3ff01e7ebe13fb53f60ee5a3b9e191": { - "balance": "1316316072034000000000" - }, - "fed9bec1b2145452ed5535e4ba29fafac6c35fbb": { - "balance": "10799354586000000000" - }, - "fedced7aa1cf3f3a7eec321cc0274759b154ea8e": { - "balance": "11740927210323000000000" - }, - "fef5063701a93ad02676fe0b99d0f4d2da0ccd67": { - "balance": "10178531012000000000" - }, - "fefd5627a408ca099587892ee2a46fa8cc89be19": { - "balance": "458504035686000000000" - }, - "ff1fc0f6f26188cbe18cf65d8a344d3775aecc6d": { - "balance": "81000000000000000000" - }, - "ff4fe483b3c04ebc8d6705c699ecee3e92071715": { - "balance": "1000000000000000000" - }, - "ff51bfe823394b2bce05947a6068bd5158d4af0e": { - "balance": "692533626783000000000" - }, - "ff6652e4e45f6b0f95ad4c9ec2bc80476e3f7fc6": { - "balance": "46457898024000000000" - }, - "ff68246ac7640091e5e58345736b249e036364fc": { - "balance": "2626125272000000000" - }, - "ff6d4b8a8393a503047ff829dbf2bf8e9172dc6d": { - "balance": "2865001878255000000000" - }, - "ff6fe19e056a7211b7e484c2c540d5aa5f1d83e5": { - "balance": "36000000000000000000" - }, - "ff7fa33529e1781c1b2951e57581780b229e3fda": { - "balance": "10000000000000000000" - }, - "ff82d1052538539d07cf3955476cc9a5027d8e4e": { - "balance": "83572023121000000000" - }, - "ff8acfe75afcc1efb1bc44be9f9bb242a94f73f7": { - "balance": "7556034521000000000" - }, - "ffa2b5f1685de9fcf1af4653cd3a584db1beed64": { - "balance": "114892199805000000000" - }, - "ffb1e9be68ae8be8d7d066c473589921e68825a2": { - "balance": "484660652980000000000" - }, - "ffbf91a9d1a6377b7435e3e734132e7b34188dac": { - "balance": "20000000000000000000000" - }, - "ffbff1fab9f2bc2f387d0cc9cc28f6aac533c813": { - "balance": "10000000000000000000000" - }, - "ffc4ff6433ea35544e7a07fda170e62c451301df": { - "balance": "29238210920000000000" - }, - "ffc7534b64a8fe8760e931a710883119d28ae106": { - "balance": "500000000000000000000000" - }, - "ffda6b8e3de72d7f7c18b892e6a8b80b886d5fa5": { - "balance": "214366938289000000000" - }, - "ffddb1fb7521c9772ea4886aaf022c4375ef904d": { - "balance": "554864446437000000000" - } - } + "name": "Ethereum Social", + "dataDir": "social", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x2B5E3AF16B1880000", + "homesteadTransition": "0x0", + "bombDefuseTransition": "0x0", + "ecip1017EraRounds": 5000000 + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar": "0x0000000000000000000000000000000000000000", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID": "0x1C", + "chainID": "0x1C", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x0400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x3230313820457468657265756d20536f6369616c2050726f6a656374", + "gasLimit": "0x1388" + }, + "nodes": [ + "enode://54d0824a268747046b6cabc7ee3afda48edba319f0d175e9e505aa9d425a1872b8b6f9ebf8f3b0a10dc7611a4c44ddec0fc691e5a5cde23e06fc4e4b3ff9dbef@13.125.185.147:30303", + "enode://7e150d47637177f675e20d663fc2500987f2149332caf23da522d92363be8a7880ef9150a6183e9031288a441e0457239474967a111eafce17e19a4288076ea9@18.219.40.235:30303", + "enode://6244c9d9cd288015d7ff165e90f3bb5649e34467e095a47c6d3c56e8fb8c849b3b4db683ff3c7ae8a654bbdc07ef12ee2fd7d72831ac213723281c1b0cc90599@13.250.220.98:30303", + "enode://e39f162b9f4b6ed6f098550f7867c2fb068fc66f362b3db0f45124c43ea18508f5ceef4e0e4de53d301e14a6f1683226aeb931d7401b4e83b5a583153ffdd7fd@52.57.98.157:30303", + "enode://54b4a117d66dc3aa93358dec1b31d4f38e72e4381b3e28a65ac6f1aaac3b304ebbe41d32cc864fa69a9a6815c34cf9b8965690dc174a5f72af14547b601b7924@222.239.255.71:30303", + "enode://851f14c5cc86cbc0a81acfcbe5dd99ad5c823435357219df736932c5f89ad4318f6973a553857a32d97a71793f5a35c062d46320be282aa0a80b06b9c6b624e4@13.125.232.71:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "ceed1c8254abaf069669fc6045e90482543d1f2e": { + "balance": "38000000000000000000000000" + }, + "6f22d7f8c38e0135e36be87e77fc8d4ae4b3d965": { + "balance": "38000000000000000000000000" + }, + "d016e982b7886302428d7c741392c658337513d2": { + "balance": "38000000000000000000000000" + }, + "defa96db5c8a41772bc56f68f95e307ff71a2c60": { + "balance": "38000000000000000000000000" + }, + "951ffd4253ffcf31b2895dd3f7f2a8a9bb2933e5": { + "balance": "38000000000000000000000000" + }, + "b7071dba21cfbe1b70abd7ddfd2f0f83d5d19a61": { + "balance": "38000000000000000000000000" + }, + "6ca420cd8d5407c61a9b14adcb38bee0f26e2848": { + "balance": "38000000000000000000000000" + }, + "b50d185b6cd04499a38afc0fcfcb59eaa74d0956": { + "balance": "38000000000000000000000000" + }, + "7ba8c49a444c117f2d2a50650b3f700d4ee659fe": { + "balance": "38000000000000000000000000" + }, + "83f9959ecc532dce071fcd0c62dc23cd571b689b": { + "balance": "38000000000000000000000000" + }, + "001327afce7ebb623a7d0f17b2ffc358fb863b5a": { + "balance": "9844198127334000000000" + }, + "0015ac7f8bb2a2c7d954fc2dbd4e20c0db5942a5": { + "balance": "1000000000000000000000000" + }, + "0021e69c041be2d28744b69361105ff51295da59": { + "balance": "1379639894000000000" + }, + "002cfd27bbb8164681b8762e71b2891beb127fdd": { + "balance": "25105286685000000000" + }, + "0033cf217bc765ccfc338869451588ce448fde65": { + "balance": "23425485280069000000000" + }, + "0048f1d1735979cd8ac9c0886088336b2d4a43a6": { + "balance": "10000000000000000000" + }, + "006a79cc154917cf204d8097728f290e29716d43": { + "balance": "20000000000000000000000" + }, + "007c8db36e4f649b14516dd78202670b671ba753": { + "balance": "1000000000000000000" + }, + "007d131b58388f251075a3c61020ce301106c5cf": { + "balance": "381079535880476000000000" + }, + "008e8fbffc2fdbefaa7e3be4f4a9160db826d05f": { + "balance": "10000000000000000000000" + }, + "0126d86b9814b0e78c4e01a3916bee6a7778145b": { + "balance": "10000000000000000000000" + }, + "012cb961297c837630251a173b7861e77724856d": { + "balance": "494562376059000000000" + }, + "0145886dfab5ef4f2def50a56b4a074cf5b18acf": { + "balance": "680585022951000000000" + }, + "0167918bab62aa2118cfa4d3eb80da0e71c71d8b": { + "balance": "122395119468000000000" + }, + "0182f7286ae9d4d6bc514d5175d14685d520bde7": { + "balance": "10000000000000000000000" + }, + "0184e9c8fe99d85100fe28a0e8877b14768b372a": { + "balance": "193295614762000000000" + }, + "019eff7dce7f31c2d4f7318da71d212cbf89d36e": { + "balance": "64004138198000000000" + }, + "01f3351ea66c352346244dbb79189066bed62fc5": { + "balance": "937056266523000000000" + }, + "0202ddd7f4f32bc575f7df24612f8aa9f9a7ae42": { + "balance": "106905151080000000000" + }, + "022b8c65e959cab71f56688b7073257b58bbef4a": { + "balance": "9682681149566000000000" + }, + "0245ff6382eb93ab1e8ed2e3c0bce7a1b9a9713d": { + "balance": "289000000000000000000" + }, + "025e117a69ca9244ed430732c11e550e3ee67577": { + "balance": "1861905310567000000000" + }, + "026e7457eeaeaec7898fdee1ad39be89e92733b3": { + "balance": "7529030978000000000" + }, + "028d2def8c54fcc77bf0191b183c0bc4570ec1c5": { + "balance": "9056720934000000000" + }, + "0291a087605b516e465134797b5459436d320e6a": { + "balance": "481100929805000000000" + }, + "02a4b18b3e13ec79307e712fba1867cbf7fb6155": { + "balance": "9000000000000000000" + }, + "02a812d4cebcac1a92ae470ade92fde7bead127d": { + "balance": "66793603497000000000" + }, + "02f718c94b2c8e8d62752f8632443504c1e4b6e2": { + "balance": "1000000000000000000000000" + }, + "030dab52b47b37505b72e5ca0985f65ead590816": { + "balance": "1376851176362000000000" + }, + "031c59846f75de1aefb0e8a95e0fb822fd06555b": { + "balance": "140978338628000000000" + }, + "031ee87c672d83ec73059c86a312a9e972142054": { + "balance": "96406273341000000000" + }, + "033182e860564cf695cb403c8c0f078053368d7d": { + "balance": "1504349255824000000000" + }, + "03788dc6528fa33a90e90e03295ae4b792d56644": { + "balance": "24356250426000000000" + }, + "037aae119047028157c5b3bc9d3d202b02cbce42": { + "balance": "105627739575000000000" + }, + "037d45b323cbc5cbac999c5001169646e690b94c": { + "balance": "2000000000000000000" + }, + "0390ba35c454a24519d845405a7e24df71250748": { + "balance": "1872501898509000000000" + }, + "03ab8c1e7f904db62437b16d28aeb539b2dee55e": { + "balance": "55000000000000000000000000" + }, + "03af4c69728a888fa26b1aefa439005989771fdf": { + "balance": "27704588237757000000000" + }, + "03b33fb19d165e5e33bcfbbfc009f418d71f30fb": { + "balance": "1999139000000000000" + }, + "03b34c79f8167a4e8be0f6133254d2b50cbd878d": { + "balance": "111065050160000000000" + }, + "03d7e8638b74ae44a2770287285489a95fa1ea11": { + "balance": "20000000000000000000000" + }, + "03d870bf719f03250c0dc5156a36751b3aa21f18": { + "balance": "981119649953000000000" + }, + "03de52c12b05fb8bcba3a1cfe02a0ad1bc9761d3": { + "balance": "362007990932000000000" + }, + "03e516db27b1abe008ffc57ced48f72f872d8b08": { + "balance": "3389116345657000000000" + }, + "03ef5ff863ee5f1167f38cdf316e4d52a242b750": { + "balance": "12395856876000000000" + }, + "03f27766760f2bd1cae1cb85ddf43ab59c871e47": { + "balance": "49000000000000000000" + }, + "03f4e1a8fb4eedc776f4835fcc85d0f236612f9c": { + "balance": "27210590272692000000000" + }, + "0404936ee04cc79cbb3aedfa33a53f94940f772c": { + "balance": "29919204637416000000000" + }, + "040501ffde9649be794b7d41643273ed6285ab39": { + "balance": "686000000000000000000" + }, + "040e449de680f69614120f0a2e894cde36e4adf1": { + "balance": "81993180085000000000" + }, + "041531e906dbdc70d89f5e255151d9865a059308": { + "balance": "2163418749315000000000" + }, + "041ad9f6bf970541e4ea8a14dde1e789d0fe4367": { + "balance": "44999979000000000000" + }, + "0446420c07cf73d2b3741b945c1cc8444b4ba6b6": { + "balance": "138749371512564000000000" + }, + "044c1a540b8ab286c218c2fa9d5bfbc2761e7626": { + "balance": "1" + }, + "04526b2c62911e78a939816aa4575fe30baa06c7": { + "balance": "2983093150081000000000" + }, + "04adf59f8a0ad3820a7972c6243202b3b0617fcf": { + "balance": "50000000000000000000" + }, + "04bbb42882a475eed58aae47fe530ed19c1cedaa": { + "balance": "278038763863000000000" + }, + "04cff7a7c2b9b0bf31c5ad4a5de8b0eade70aafc": { + "balance": "515406205244000000000" + }, + "04dcd325dc1fd37ff3c87da3b21c47ddfcc37cc2": { + "balance": "5831887315000000000" + }, + "04ec8d0b5157370f5a2671a2aa68ae486b7a7842": { + "balance": "10000000000000000000000" + }, + "04f50f2a6e89ee497a64c11baa90759a10a1247a": { + "balance": "25443071621949000000000" + }, + "0513a769ebef58ad3a4fd7011ddbe19799ff5600": { + "balance": "64369494797000000000" + }, + "0514c1151f356070ace281435f25c86b58280715": { + "balance": "38967380881301000000000" + }, + "052fda414fe1279c6276a237b07e1b4148a8cc77": { + "balance": "10000000000000000000000" + }, + "05431089cc62a987d0e99847e10a006233146f6d": { + "balance": "268977485219000000000" + }, + "054ed2f55028257212b996f9a3d34758d1d4ffd1": { + "balance": "100000000000000000000000" + }, + "05a68cc758560addde302baf814f2fdbe0ef2c2b": { + "balance": "10000000000000000000" + }, + "05c669d9ded79fe9e4e3718052bc7ca18a3205ab": { + "balance": "7347158140000000000" + }, + "05d77ce5c87477b05e90e829dafd8eb3a8c87823": { + "balance": "21191998933000000000" + }, + "05ef2894a2a1c6eb6c0a768d04ef5b573f357712": { + "balance": "20000000000000000000000" + }, + "0601011f80279190b96f641205c6a524a8ad5a28": { + "balance": "12025716447696000000000" + }, + "061a8acdb1a340ba7c550814831e27262708fc98": { + "balance": "234029764576000000000" + }, + "06219483e217c9ad479f76a95426f689ef4d5951": { + "balance": "1509408723551000000000" + }, + "062d0db8a650f2241f8a4295326a2570a7c771bb": { + "balance": "717459720227000000000" + }, + "0633ba746235d8fc8243751b1aa31646c299f262": { + "balance": "49000000000000000000" + }, + "06b6a5cadfe1fdc88015512e835d840e58ae4123": { + "balance": "1000000000000000000" + }, + "06d08fcbe96791514d900d2cb6c0f029d8d791d0": { + "balance": "19196168602258000000000" + }, + "06e5c0bad43a7011878b12a682abf01ccdfaa151": { + "balance": "30000000000000000000" + }, + "070656bb11ec36074d47c791c0b306394b703401": { + "balance": "1245216075291000000000" + }, + "070d84c938217163b60ed38e4937eea7158c03d9": { + "balance": "27507979787000000000" + }, + "07428c95ef3862026e54d3a963911cdc673dbcd9": { + "balance": "13792309994528000000000" + }, + "0781cb21df142ec5f67b956bf995f02f6f24985f": { + "balance": "224940990659000000000" + }, + "078c38c153b414cc4c12818fce2ea7ba09a34e51": { + "balance": "1410646136000000000" + }, + "07bfd0de7a9a1c927446aaf2d7ede55b471daa87": { + "balance": "77778844734000000000" + }, + "07d1ac83140188b8d7f4c8c607d0da22c5ba523f": { + "balance": "7713686418107000000000" + }, + "07d8ef8fc6dcde319a5af5b6cea18983bdc4c8fe": { + "balance": "3801361173000000000" + }, + "07dfab72dd3e44fcbb1ced625899bf20e0c52ffc": { + "balance": "154177778806000000000" + }, + "0817ce33d943e84c7b3261cc3e37b86b5d6d76ae": { + "balance": "90753785862000000000" + }, + "081be00a2ff62cbcb95a8eb020ac0efa33f93a42": { + "balance": "1027889807304000000000" + }, + "085ffdc6043b04653e51b1a34af20b609d158607": { + "balance": "3314058000000000" + }, + "0882c2228f5df24064bc37e8b7199199de308bb8": { + "balance": "98420617420000000000" + }, + "08918776e9a7136cedad5d0cee52f5d9dd833ece": { + "balance": "1263170315026000000000" + }, + "08bdbcff16919abc5e15fa68ece56eceef33f48d": { + "balance": "2552990000000000" + }, + "08fc8c7bd03fe1249266b233edfcf830693d0e10": { + "balance": "283490111768000000000" + }, + "090f79a4178b5180150444805f62c26cd21be897": { + "balance": "884195010282000000000" + }, + "0914a9dfc9d6ecc063a55e5320050112f305fe17": { + "balance": "15373898854941000000000" + }, + "091791ab5f8ab86f1d8f566ed221b268cbc55347": { + "balance": "2207516004000000000" + }, + "09529f8b1633ce4375451bb44b1025f6e5f9facd": { + "balance": "151697652792000000000" + }, + "09600bbb9d9b23661d269dbe1ed066d8e573b5e1": { + "balance": "802935104935000000000" + }, + "0964d2af1d5883fc0e0a77459f6a141824de7356": { + "balance": "9610980935058000000000" + }, + "097c731d1fc6792ac0f0ff92be4403c3749cc1dd": { + "balance": "165134479709000000000" + }, + "097f152b3f837d38ab1e8c0683d62f5a01d67902": { + "balance": "20000000000000000000000" + }, + "09a6772629ef0bf402ae6d27cd32e6eefb220a12": { + "balance": "20000000000000000000000" + }, + "09addb954d4e4b4e95e0c66d324115d609df5a99": { + "balance": "8435321515000000000" + }, + "09b2eb03e0fa321102196578eb40dcba3a46ec9c": { + "balance": "12723517962933000000000" + }, + "09ba0ed4dce470ba0bcb4d46b507c3b024b83070": { + "balance": "99999979000000000000" + }, + "09efbd6dfea375065be1b3a8f4541f024da21a34": { + "balance": "5870833623000000000" + }, + "0a24d4ae66edc7723bbb314e9b96dc7b9a31e813": { + "balance": "70000000000000000000" + }, + "0a3ee710909382f762648deff8ac7c8b30e2ce10": { + "balance": "407656462445000000000" + }, + "0a42b3145257154e76a97db8147c93be4cffd97b": { + "balance": "10000000000000000000000" + }, + "0a7cb6037f1eba5d19fe781335ecd37b7229c5f7": { + "balance": "74113322448000000000" + }, + "0a85d1bec4d44e309068b115abd517d3733fc56e": { + "balance": "14836218750000000000000" + }, + "0a891ba9ca7b99ecd815b1dcec9243dd4deff866": { + "balance": "178004857988000000000" + }, + "0ab69370b537d4ff5b45704fed293e46e3464f87": { + "balance": "1258876668246000000000" + }, + "0ab77a2e8ab9a3b659d1f1d37956c3607a0f9a60": { + "balance": "6283300817712000000000" + }, + "0abc7e8d52f5b0dcf1d4713e5fa4909102251dfb": { + "balance": "39307290577000000000" + }, + "0af2c0471c802d2e2b20aadf9dd4ec842d313ab0": { + "balance": "1529468143183000000000" + }, + "0b08c717bb3982fc8b92d5b3d30e5b41265a0d0f": { + "balance": "1184600154874000000000" + }, + "0b3f2aa9dc5b57b0469398d62f60a13774ec0e87": { + "balance": "132187640280004000000000" + }, + "0b3ffe85aa89e71a6e51e938c7265d2a7173061b": { + "balance": "2106793086824000000000" + }, + "0b468562e712d22b37e1a65f54b1fa825beebd1b": { + "balance": "15130906006000000000" + }, + "0b5333eb668dee29ebc0e335d74f33ffeaae9ac5": { + "balance": "125953133109000000000" + }, + "0b59a20107495e951b509187307782ca9dfa441f": { + "balance": "25000000000000000000" + }, + "0b8b7fb066601ea7744b81f6e1a21b8e489359cf": { + "balance": "101782000000000000000" + }, + "0bd7791097f79066d71ac0a2c94bce6628a63373": { + "balance": "44389955028000000000" + }, + "0be541af06e167206b5d1cbe08e8fb2b5ebc82cb": { + "balance": "9000000000000000000" + }, + "0bf178bba463f4f6c33e3d81b1a78d220f7b5d4b": { + "balance": "111784804790646000000000" + }, + "0c1f000249b1f1ac9e43c4f10e2da1cc2adf886f": { + "balance": "91251997635000000000" + }, + "0c74e46b115e19726997dd559d2b6ff1bfb79af6": { + "balance": "879229287149000000000" + }, + "0c7c1ec152c920a068c25626c22c4fae7f435536": { + "balance": "39849464104000000000" + }, + "0c85fbd7492d1ae87bf3d286c4750a34f1fd3121": { + "balance": "20000000000000000000000" + }, + "0c9fd6123e313f7d1f0cb25d99839102da08b2c5": { + "balance": "10000000000000000000000" + }, + "0cb051e3bdd9d96e667fbcc00a766d4f149f89e4": { + "balance": "1000000000000000000000" + }, + "0ce32bf6c433cbd26c6f09a1214db0374002784e": { + "balance": "3293279842000000000" + }, + "0ce6374ff04430e34edec8b6323feab2bccab92d": { + "balance": "93983447000000000" + }, + "0ce646412a1524c3f73edfd753c0ba3ee7338275": { + "balance": "10000000000000000000000" + }, + "0ced803e56eac3c99269ff7409d2d200d62d7c25": { + "balance": "49539379000000000" + }, + "0d1dc2be9f78ce2b2591e7f5b8af9dc778499bd5": { + "balance": "2235348003595000000000" + }, + "0d235583458a168e810275f907b5f87bebb2d1cf": { + "balance": "83106439283110000000000" + }, + "0d28fe6e8b7d4b8c90ef7c52b9656511ce5867f1": { + "balance": "1347248794799000000000" + }, + "0d5cbe0da660cbca831787efc45fecb20e06e02b": { + "balance": "297528508941000000000" + }, + "0d7a24f324176f6d793c3a2eb6c54d6ee47eca79": { + "balance": "25637813467000000000" + }, + "0da26a24e3650e84c52fedb36ef76225a8d9d259": { + "balance": "15467820321000000000" + }, + "0db7eaceaf3df21ebb49c56fa2d2e2c8e85dec52": { + "balance": "196000000000000000000" + }, + "0dde52823bd8fb2cb179e6d417c07ff285c31775": { + "balance": "347321514878000000000" + }, + "0df9585f1aa83189e0a813f5eac6e6e0b2bbb8d8": { + "balance": "2891430551000000000" + }, + "0e09af9368f05b476164953b7b9db60ac95248f0": { + "balance": "573644391203000000000" + }, + "0e18315dd2b663ce4859b5bed854403191452c2f": { + "balance": "24174325261000000000" + }, + "0e29bef5f4f66c38a0f05cca1e4938d57ff09c70": { + "balance": "10000000000000000000000" + }, + "0e443353b42e042ff5168e9b3c6de37070368223": { + "balance": "20000000000000000000000" + }, + "0e8cb6e439516b312158f169b546937b715db3f2": { + "balance": "8049136367000000000" + }, + "0e980fab23be601f3abec7b9a24e1335a5e765c8": { + "balance": "8301885845897000000000" + }, + "0ea63fef218ebf570a4ee62ef6ed712dbe623c44": { + "balance": "10000000000000000000000" + }, + "0eb60e3512336e4447ceeb8664ce0ecaa3eb0bdc": { + "balance": "41401696400000000000" + }, + "0edafc1058879a9568e711445b18ec4da31d2480": { + "balance": "10000000000000000000000" + }, + "0efce4565062b23b43dbc1e261463e363e4a5b4c": { + "balance": "10000000000000000000000" + }, + "0f08782c04bf7249ab08f4e251abc60aee792a96": { + "balance": "1380257622493000000000" + }, + "0f19bfe1eb24def828bf1be69791c63ba1de1263": { + "balance": "2223687184885000000000" + }, + "0f2171161eb9674218add261be61d18d86b846a6": { + "balance": "121000000000000000000" + }, + "0f42ef6c5690b6c95f8b8c9dbdc16f717c04852e": { + "balance": "81000000000000000000" + }, + "0f47f5063d321b34a0d800951bcdc3f53c07e32c": { + "balance": "5288516165000000000" + }, + "0f529a9beedb2c2a087a220f0013cea4f8454bfc": { + "balance": "114585457979000000000" + }, + "0f6751d10aaf855454a6e9e4241cfcae3b0ed732": { + "balance": "94160300063000000000" + }, + "0f6ed5a4c3ec100afcd59e9066ba7fcb63cfa6dc": { + "balance": "1000000000000000000" + }, + "0f77025519cc76c38e1cf0bd8721f4a5b9c814d4": { + "balance": "834620571043000000000" + }, + "0f773db2a1a96b775e4481575704f5f087b067e0": { + "balance": "554268361745000000000" + }, + "0fa0f73adbe82f8e09f8adbce15b051971e289c3": { + "balance": "11329911975000000000" + }, + "0fa6397d747d88a25d0c755b3be4eee0e3f68912": { + "balance": "31394936138000000000" + }, + "0fac8635a61bf7652d86725cc75c307949bd4f2a": { + "balance": "49000000000000000000" + }, + "0fb0ce787306ce13dcd614ab3d0e15d9772106ac": { + "balance": "50000000000000000000000" + }, + "0fb1d306d240360056f60f197dc7f68f732ac515": { + "balance": "20000000000000000000000" + }, + "0fe3571f498a6d945e123ac8ff6e3fed348d9432": { + "balance": "20000000000000000000000" + }, + "0ffd6b01ea9a7bd2576fe4a5838fe09e44c1639e": { + "balance": "100000000000000000000" + }, + "100bde3d73fda700369e78229127b58d2ade9177": { + "balance": "10000000000000000000000" + }, + "102028c7626970a28677bbdc7733484c8b14c2d2": { + "balance": "500000000000000000000000" + }, + "10245044be6a46ad41d4559129cb59e843379cf8": { + "balance": "857437279765000000000" + }, + "10417d0ff25c115b25915dd10ca57b16be497bf6": { + "balance": "10000000000000000000000" + }, + "10579870e6685ed7e97dd2c79a6dc3528bae968e": { + "balance": "5187866041491000000000" + }, + "109736465b4bbe31ea65ad01fc98f04498271e6c": { + "balance": "20000000000000000000000" + }, + "109c0535a4a86244c5094e99167d312a77657dd5": { + "balance": "138277702073000000000" + }, + "10aa08064689ee97d5f030a537f3cd4d8bbdaf74": { + "balance": "10000000000000000000000" + }, + "10d8bc8c3d3e2010e83009290586ad85b73321d1": { + "balance": "25000000000000000000" + }, + "10f22b82460252345753875555de2cebebe63a93": { + "balance": "765947730644000000000" + }, + "11111c3a2cfa55e52d6aacf533e1d412f8c8c01c": { + "balance": "4827254128275000000000" + }, + "11386103a0bf199db9504b617ccb3bbd780eb9fe": { + "balance": "10000000000000" + }, + "1156a129183e5bdfdf2bf7a70963285a979363a0": { + "balance": "10000000000000000000000" + }, + "11589cf70a6a4fbaac25224e2ddab222333f78e6": { + "balance": "49000000000000000000" + }, + "1162fabeb3eb1e4124179b00c4a1e01503023f54": { + "balance": "817145350625000000000" + }, + "116a7d140f4b7f9b4689063a8417ac07a32bae00": { + "balance": "106088220142108000000000" + }, + "116dc38ddb4b138b19ce6a51e5922c287da5c86b": { + "balance": "100000000000000000000" + }, + "1175f84f835a5ae40d49b8ca17e3e474c1eceef7": { + "balance": "1698584794716000000000" + }, + "119f822a796fee9c41a488949fcb14b589ffa628": { + "balance": "20000000000000000000000" + }, + "11a99f6019b6a53f5dc8cbd0c34f1ee75ced33b8": { + "balance": "102126982156000000000" + }, + "11b9324406068e8bf598d3a9ea59ef31c52f51fa": { + "balance": "6525925895203000000000" + }, + "11cb7be6869a10f5f9e8a47c6c92f729b083084b": { + "balance": "182959434323344000000000" + }, + "11d96a76166ec579e2b6cfa903f66da4af669351": { + "balance": "1000000000000000000000000" + }, + "11fcee55f78278df60f50096d45da1aafe72722d": { + "balance": "222859488179000000000" + }, + "120a1fc914718acd85bf92d9492330165d78075a": { + "balance": "3736627235906000000000" + }, + "12366136d83c77befdc30e04d4f5d808419f504f": { + "balance": "88008649003000000000" + }, + "12435af3f2f92ec43e8f2894be9c72fa932880fe": { + "balance": "1590548436852000000000" + }, + "124ff67125a00aed24e58b6d64ffa887a59b48a4": { + "balance": "20613022349070000000000" + }, + "1296f04910ebc89556ec7ab1b178fdbf14d0295c": { + "balance": "36000000000000000000" + }, + "1299f180e42bfaa1162d36110d29ab062e43e1c8": { + "balance": "321570118362000000000" + }, + "12abac62150c526866ec958cd0e3721b2c78d550": { + "balance": "51898545633262000000000" + }, + "12b345087cee385b9adccaaaa6741b767c82d7ea": { + "balance": "36000000000000000000" + }, + "12cd5e8c0c93f8e34b589b95954b719f54d1515b": { + "balance": "1000000000000000000" + }, + "12d262cdd25edc39b6fd9ae78184eb548e513927": { + "balance": "500976168000000000" + }, + "12d933448218629702c48547b3446b629ec65883": { + "balance": "2168010577395000000000" + }, + "13054aa42d3e119220ac359641c15f8b54bfffef": { + "balance": "24986834005530000000000" + }, + "130bda09f463a982199849ae617062a1d68f3a85": { + "balance": "154504844790000000000" + }, + "131a5da679863c05dc627d53634f2925ba0ce731": { + "balance": "10000000000000000000000" + }, + "1334f2752b5c21f681ba9e23a9fe95a85f8e05f1": { + "balance": "121000000000000000000" + }, + "13634512e2ae79fe3febb9e55e03b47bc350d7ba": { + "balance": "338331304738000000000" + }, + "136fae842aab625768bef9079ee1711e8c007d8f": { + "balance": "2759741687626000000000" + }, + "139fa969e8b74bee1f6113a362f15060ea998b15": { + "balance": "10000000000000000000000" + }, + "13c7e1d694bde6f8f6a31eb6c99f38dc739d61fe": { + "balance": "10901074773586000000000" + }, + "13c849944ad6ad12a46c46973d562bee8284f46d": { + "balance": "35114615504000000000" + }, + "13ec3aa8f4a427ecdecc7901060ccac9bea7a61e": { + "balance": "10000000000000000000000" + }, + "13f478c74acfd6897d13e602a8d362893f4fd038": { + "balance": "3521111850000000000" + }, + "14403970d0784a6458a7bf2584a53d14234e8860": { + "balance": "25000000000000000000" + }, + "14440bb7410337e34a064a92206075575f5362ee": { + "balance": "14918844868393000000000" + }, + "144a88e7a8af70b8bef5c4b70ee0cff771d0c252": { + "balance": "67961927542000000000" + }, + "146b79f474176a4b0069199b03669ab6467a4787": { + "balance": "122518123211000000000" + }, + "148893e7811c36c6bd1ada367681ab8327b3b2fa": { + "balance": "1313118418375000000000" + }, + "14900a17784e3b4d89d98b6cb31c74c685418b89": { + "balance": "131112181597000000000" + }, + "149a483758a98ffe28f7f25cfa17d7433f852ebe": { + "balance": "10000000000000000000000" + }, + "14a03c8e84f07c5596687a98d1e0b1859e9b34ac": { + "balance": "55000000000000000000000000" + }, + "14c7899cb34b5447d6363d4e8355113ebf4bcc66": { + "balance": "197554844582000000000" + }, + "14efa63ee285277c0f8e0d5cc22193e17984e11b": { + "balance": "106221254735000000000" + }, + "151c6099b3fb5b18e0e36a3335dff186dcd2904d": { + "balance": "4304311254087000000000" + }, + "1525dce233a971eb1387f130fdf0e5bf3455723b": { + "balance": "45004174531000000000" + }, + "15271904676f2bc2511294e500152d05ea9acc85": { + "balance": "9300898622566000000000" + }, + "1556ba42ea69d72c1d0faf802906645268e36aac": { + "balance": "171939212653000000000" + }, + "156558fb71ff986953d899c9916a121fd047675c": { + "balance": "290926338537000000000" + }, + "156fbf32614aac2cf462952ec1a3f141f797316e": { + "balance": "6084388860000000000" + }, + "15b9497d6bde8017baf3c29e12430e05a47efbf4": { + "balance": "206126229839000000000" + }, + "15d532e828bdcaf1246696d679a2eb66a154db5d": { + "balance": "69656571015000000000" + }, + "15e26a60cfaf23dfd9bbb999a30904d11b6ddd05": { + "balance": "9839303178835000000000" + }, + "15f3be2f11ee3b19472cc3d171931f050d8629a2": { + "balance": "13572825921000000000" + }, + "16254bed335420e5f793de2295b0081ac41a08d1": { + "balance": "144000000000000000000" + }, + "163aa91bc2ad588116141d48fcbd943985455cac": { + "balance": "618250979557000000000" + }, + "164cff4b9341d536b8aaf2d1dd0e3ed35ecb1db7": { + "balance": "671554639913000000000" + }, + "164d2a9a63868ac25bfe26ecba446d7ce256c351": { + "balance": "7233638188261000000000" + }, + "164e759b64d3ee0a23ec3030f50a1b454a6ec15b": { + "balance": "12281161499000000000" + }, + "165d4a0f23c016b8064adf0dcf7e31bc06350777": { + "balance": "256757922324741000000000" + }, + "166b862954dacddc3333aba4edbe523d693df858": { + "balance": "123677971414000000000" + }, + "16858eb1a6f0e7ff01b91aa9c92d0a433a5f767c": { + "balance": "500000000000000000000000" + }, + "168909a1c2a43cff1fe4faeac32a609c25fbd1e8": { + "balance": "62258808044224000000000" + }, + "16987ad8e10dda7f9e5d95c0f0ee36f46b10e168": { + "balance": "10000000000000000000000" + }, + "16b5dffce79573300a6514ace5f2e844d26fc64e": { + "balance": "5576805697087000000000" + }, + "16e01370a93befe24f6ae6076cd04c84cd3515b1": { + "balance": "1922179181578000000000" + }, + "16fbafd4fc871c7589e63062133793ab244c2019": { + "balance": "2865030627000000000" + }, + "16fdf76180796c6e4335eaa2842775b2e4a22e0b": { + "balance": "20000000000000000000000" + }, + "17081d4d6ebb9f4b163e181a59c2102c99fce6bd": { + "balance": "490625378000000000000" + }, + "17218ff455aa87b29ad4c4f7ba21e9c6f74fc97a": { + "balance": "1607392037652000000000" + }, + "1725bce47f3700f4646efb343f950e2e8ba66607": { + "balance": "58472967071000000000" + }, + "172c5f71aabf072507664471ebaa435779d74a32": { + "balance": "16000000000000000000" + }, + "173a065f351ee0513cfebfe9b950fd2c641fc8cc": { + "balance": "25000000000000000000" + }, + "174e1793c96cefb584ae0a67fff85c65065dafc5": { + "balance": "50221000010000000000" + }, + "1794bc4d622d514f95da5404358ed404b3f59aa3": { + "balance": "36000000000000000000" + }, + "179839d61e7c7a0382fe08e0573bcfbe42a108ca": { + "balance": "203299791419000000000" + }, + "179eb30b5b28a961eac70a919d26ca96e6472166": { + "balance": "55000000000000000000000000" + }, + "17be72168606fb5d27761157e48fc14789f84634": { + "balance": "311205588354000000000" + }, + "17cefb6611033759b8755197b983de2d7e98315e": { + "balance": "10000000000000000000000" + }, + "17e07cc7d89bcd1708b1f05ab6e1252c629d71cc": { + "balance": "903234908997000000000" + }, + "1811be559b657685c2f163122479101c404325b0": { + "balance": "10060694170000000000" + }, + "181417a4883c429ef26a4baeb48e70d4f00278b4": { + "balance": "4621446218088000000000" + }, + "181d345cd6b5f518bdab8d40f5d4896a725b3f3d": { + "balance": "114349561983000000000" + }, + "184625e544aa31552d2911023a892f739df84be7": { + "balance": "5303698708000000000" + }, + "185e4f6eee203ca3c089baa1e643ff1aab7cc8f4": { + "balance": "33969718257699000000000" + }, + "188e4a1a7b23ff35ec90b7bf7561db9e3c0f53bb": { + "balance": "394325508701000000000" + }, + "18a4dbf513be132f9ecfd69e3eb683d710e28c4b": { + "balance": "5997985132329000000000" + }, + "18c9298f62635ef47d0ef215b8a693af60829c27": { + "balance": "100000000000000000000" + }, + "18e7e2ee0c86bc1ba3595fee3d40257776fe8172": { + "balance": "185584626033000000000" + }, + "196575e74499b741877793f8c8facf2f3b1ddb8f": { + "balance": "30318381929000000000" + }, + "196df33f2d3ed473e6e07650419969f4a39fd03b": { + "balance": "15442864665000000000" + }, + "1975c5293ec9c72a28e6cc74173cdfd8de682fea": { + "balance": "103624886552134000000000" + }, + "19832cd1b2fc4138c8d9291a0f404d3c4326b48f": { + "balance": "4732362673000000000" + }, + "198705f46f31c7ca22f5b88fab210bc5b0c7647c": { + "balance": "548940869737000000000" + }, + "19a5a213e6abfee29f17e871222cbe9ac45322c8": { + "balance": "10000000000000000000000" + }, + "19ab9a7a4e9f9c08c9b4295c406b78389a864ba7": { + "balance": "369299839157000000000" + }, + "19f19f5f01b3f6a1c4f645dc7e3992b1196ccb7a": { + "balance": "97759406000000000000" + }, + "1a11a0b0081522e60e16f154e093ac2e005d24ee": { + "balance": "88024675252000000000" + }, + "1a27309b0c09be2234fd64afdbcfb099f8e2e7cd": { + "balance": "10000000000000000000000" + }, + "1a3d61754974bea23503a61ef0fe584b7b6e6cf3": { + "balance": "326950210355000000000" + }, + "1a49bbde1457a8d4c247606b206ac8d4d389da5a": { + "balance": "402438941516000000000" + }, + "1a7a4b41be64fff3a31eb6166db59741e073d0f7": { + "balance": "250000000000000000000" + }, + "1a8d282e82c606e992f69ce618ba634d98bf2683": { + "balance": "20000000000000000000000" + }, + "1aa0ba27662816e5e3d79e223cc18f5dfef089cf": { + "balance": "187581622694000000000" + }, + "1acab416a1d3e8caa65faca378c79aaf2065b851": { + "balance": "1000000000000000000" + }, + "1acd37af3f87da1dff743dfcb97038d178b1dc4f": { + "balance": "708034481300000000000" + }, + "1ad8f036022c3e5258455d6aa05fb4be5dd121b1": { + "balance": "42957064709000000000" + }, + "1aee811e06c579c21fbcc3b53d2dcf9d5f24808e": { + "balance": "52480060284048000000000" + }, + "1b03b7a4e9908c3531618f49f8d050ba6afb4de6": { + "balance": "28410489187000000000" + }, + "1b073d026e93de51db34d5a8e19047784c277ea1": { + "balance": "20579129628026000000000" + }, + "1b0b87e414bc8fe4920fe104b6de7d17db3a1a19": { + "balance": "10720000000000000000" + }, + "1b411c692c80948e59cd805a0f8574dd67519288": { + "balance": "5416615538000000000" + }, + "1b8d57e995749618c7bb3e60194ac6fc57e9b3eb": { + "balance": "10000000000000000000000" + }, + "1b913efde1255516346b40ae2a48ebf62251682d": { + "balance": "100000000000000000000" + }, + "1ba7276c133f93d43db2f2caddec08e0167eaf15": { + "balance": "82559173174000000000" + }, + "1ba919f7742160cabf2756eb6eae67b92530f3f3": { + "balance": "1102304139883000000000" + }, + "1bb20857de494694fe15bd11f8cac1218435fbc0": { + "balance": "10221322567000000000" + }, + "1bb5c5e81d451f03e899852edc8556a9f7aac5df": { + "balance": "18781017696028000000000" + }, + "1be3507349ed07d3e7902951d490f560a75e96be": { + "balance": "660691718918000000000" + }, + "1bf1c0b2e6f64b612f35f2bf98d894b13dda9bf7": { + "balance": "3050161851140000000000" + }, + "1bfd3c2ba6a537e97cedd542cd554a5050963d54": { + "balance": "20000000000000000000000" + }, + "1c4af5003f9e7223f4141107d21640e4a85a4827": { + "balance": "612390629874000000000" + }, + "1c6a94810bd0afcf79ceea11afe86c34f6813211": { + "balance": "10000000000000000000000" + }, + "1c7e277460191c886cb1647173d27122c2146252": { + "balance": "209062806527000000000" + }, + "1c818ffa9caa61d512fa5d7d6e566f3ae37d5434": { + "balance": "454897845316000000000" + }, + "1c9599d5f8e5eaf8f68d35d52132e15a153f6d3c": { + "balance": "36000000000000000000" + }, + "1c95ab5229fd08c638a1728c022f09291b8dc55d": { + "balance": "20000000000000000000000" + }, + "1c962808c175ee5e5e365483d066c8ea95993700": { + "balance": "1362779746855000000000" + }, + "1cafad295b2188f10192c8a32440931f7e3554e4": { + "balance": "36000000000000000000" + }, + "1cdc2899ec563d79569d1ba776bc03cff331e786": { + "balance": "572163587827000000000" + }, + "1ce0042e7b4f13589f5f8490836dc63e0ca60c3c": { + "balance": "25000000000000000000" + }, + "1ce62051fd7801d294bf31a7b44cd87510e8b545": { + "balance": "2008112411284000000000" + }, + "1cf20f30cd901b2e5fef3f948289dafaaabaa77d": { + "balance": "1444000000000000000000" + }, + "1d449764d38b7a4ac848f49e2dc99df02dfd8a53": { + "balance": "48215693645000000000" + }, + "1d635125c494b1137ca5f15ac95dd6d93c3a9546": { + "balance": "10000000000000000000000" + }, + "1d85a61353c3e0b6d34e105e35c8c7833b6a1e35": { + "balance": "16000000000000000000" + }, + "1d969134ee156c41c98c3721c5dbb092c0b581a6": { + "balance": "64000000000000000000" + }, + "1da12434596a9c318dab854f06d404fe61f0a69d": { + "balance": "16675185416000000000" + }, + "1db0d23fb63681958a66e716e99df3e0b848fd12": { + "balance": "1103581911968000000000" + }, + "1dc628820da657f07ab5eb887d5f512378b5b61f": { + "balance": "6272287019755000000000" + }, + "1e05cba75b0dd379037940352e0073564957b7d9": { + "balance": "12453446342664000000000" + }, + "1e13f037a92ab6f19c4484ae3301b3ac6f48575d": { + "balance": "106244918916000000000" + }, + "1e167bc07f094915c00e7aa4c43b607ed2c998b9": { + "balance": "1000000000000000000" + }, + "1e1f9409bf92c3ef59aa2fd82dce55cd90e23f19": { + "balance": "99139000000000000" + }, + "1e4dfea7871d941e72a161022b62fdb01818c86d": { + "balance": "81000000000000000000" + }, + "1e5d0b525228167334e94314a201388bba08153b": { + "balance": "1138044078759000000000" + }, + "1e6633290c9898abf5fcac54396de770164edc5a": { + "balance": "25052055674000000000" + }, + "1e76296584058670ea80fe9a39d8f457c03747c5": { + "balance": "10000000000000000000000" + }, + "1e88b2c8dcd289929e51a15c636d0b0f3b035569": { + "balance": "87357600832000000000" + }, + "1eb59a1732a159a91a9371650943840e0eb61174": { + "balance": "20542821429000000000" + }, + "1ee077bdef6d45d491602342cee008cd1e2912e3": { + "balance": "10000000000000000000000" + }, + "1f1ebf2f80afced68424cb7b0b966fdf42d508a4": { + "balance": "1460082126494000000000" + }, + "1f3d4a903bd32a537efae19592f5516698c95a20": { + "balance": "10000000000000000000000" + }, + "1f6431696efc6f1ab98dcc2ef0e8553da697e6f1": { + "balance": "20000000000000000000000" + }, + "1f657552b745acbdf731f2ad107d6362480abc88": { + "balance": "162042599568000000000" + }, + "1f699a7682c1266291a3f49e19cac0846470abf5": { + "balance": "712268213248000000000" + }, + "1f7a332dabb00851705274c59187817d859cb9a4": { + "balance": "199999999160000000000000" + }, + "1f7c333047e168f5d3408c42a4919bd44b8f7961": { + "balance": "3918096658000000000" + }, + "1f8226f7a4525b9f3cd4da3acc1bb34529f8d28a": { + "balance": "3530829464000000000" + }, + "1f8b6fcea9e0991ad0b0b25dc65748518a28713f": { + "balance": "142069368416000000000" + }, + "1fa3de6913e4de78cc4828e246554785950c3c8e": { + "balance": "178437291360000000000" + }, + "1faa75d57fd597d2b58d2ac6f65bc2bd5946911f": { + "balance": "13092024644362000000000" + }, + "1faf1721dba3266cde1e04a7e9c789bdabdd930d": { + "balance": "862698523071976000000000" + }, + "1fb861559361701fca1df6ab4ef4d2fb9d2d7e13": { + "balance": "100000000000000000000" + }, + "20154d678cdde9ca1c0acb94726f26617a4da0d8": { + "balance": "2288800561677000000000" + }, + "202484a46ca9d54d0d456bc38e2a74ec5f469349": { + "balance": "50178714107336000000000" + }, + "20324278018b4d8e0c49e0fd1be35d3494079165": { + "balance": "484082383314000000000" + }, + "2033ef68ef6297e9229bb73e6486330543aa3eb7": { + "balance": "51260669473000000000" + }, + "20b1e0ab7b9d62a314946b55a5775f24ae3cfa00": { + "balance": "1540424185584000000000" + }, + "20b61f2eb5e18b1e8568d18235918f9e2f596c32": { + "balance": "10000000000000000000000" + }, + "20ed8ca39dd148edf22e03b8021af32cecadd42a": { + "balance": "20000000000000000000000" + }, + "20fd5feb799fbb021ba262d28332b4dda8f44a2c": { + "balance": "7607475714434000000000" + }, + "215ab8aad1c8960838225294d086f0786c2dd796": { + "balance": "19929201327000000000" + }, + "21681cda53aa1a4cfb3e3ea645c8eeaecfc3ba4f": { + "balance": "10000000000000000000000" + }, + "217b75eaf2c0be12108120ba56ddb709e1885324": { + "balance": "36000000000000000000" + }, + "21be1d75b93e96017f088f1ca64ba7076c8edf07": { + "balance": "150798073752000000000" + }, + "21ccdbe0216b486cb39c94ed13767aa061c75ce9": { + "balance": "11070639373000000000" + }, + "21f2289f2d274bddd7928622fffdf3850d42d383": { + "balance": "268859368544000000000" + }, + "21f54f92a7d9a91915e1751ceb02cb8e3ed3d622": { + "balance": "10000000000000000000000" + }, + "2202c70ec23f4605394d69944edd9f90e488eb61": { + "balance": "9000000000000000000" + }, + "220e2253e1ab9ec348cc28d38bae4cb2d5d9cf8f": { + "balance": "116100821631000000000" + }, + "22328e434957107884854999e666ad0710187e3b": { + "balance": "233364805270000000000" + }, + "22851c0487d119ee3f150010515358d6ff14807a": { + "balance": "104464221701684000000000" + }, + "22a38000f5eca29001e387b52c18fb6030683fac": { + "balance": "55000000000000000000000000" + }, + "22b655a19810307750ed1b6b093da10a863d4fe2": { + "balance": "11840799203605000000000" + }, + "22cc48cf48e8ee207bc08411240f913a4e594529": { + "balance": "10000000000000000000000" + }, + "22d6ea6cb8a9206285ccddd3b6d0d1471ba66f17": { + "balance": "64000000000000000000" + }, + "22e2f41b31a0c69472a1a02d419886539b7b6197": { + "balance": "39885451304000000000" + }, + "22e962f91d01480d027ee0060030f529a7a64c8f": { + "balance": "93285203531000000000" + }, + "22f169328fb1104b386ad7fa69f0c7bf3e9a7d3b": { + "balance": "63366769386000000000" + }, + "22f35f5e0e7a8405714de66a5875c7ef84ec4891": { + "balance": "60944382032000000000" + }, + "23041bdc8d371dc29ffc890f19317dabeef12634": { + "balance": "402327389857000000000" + }, + "230eff5e8595f418686737ae671f1f1d225080a5": { + "balance": "114574598112000000000" + }, + "2331e1756d9800800fc9b54ee6e43e1150b6e58b": { + "balance": "44594796226000000000" + }, + "233a72b132e4ab1d3884274d4402d1a2a6399f0b": { + "balance": "1372148909093000000000" + }, + "2369d9dbbfd0f8aa8a3d84d8f2aea840a0cdf760": { + "balance": "500000000000000000000000" + }, + "23754e5cef31ab60aa97a0c8f9ccb4f2969f2d6c": { + "balance": "24764775861000000000" + }, + "2387973589fb07a8c1ec92492c0b8ba9ab5e52a2": { + "balance": "11642113696681000000000" + }, + "23950cd6f23912758ebe9d412166e27994fe6ec2": { + "balance": "100000000000000000000" + }, + "23b383e11573f3ca9be84e1e11694f58a432324b": { + "balance": "206558238838000000000" + }, + "23c329bb641fa51122ea476e3bc614f5d4f9cf00": { + "balance": "35908627324000000000" + }, + "23cb9f997c39853486adfc1a8b029874d1a6af15": { + "balance": "1400984459856000000000" + }, + "23ee14215c531f6ff1baef2c74b1754306f4532d": { + "balance": "10000000000000000000000" + }, + "23f641f765cf15665b6c28d77229d3b2a58fd857": { + "balance": "266570948120000000000" + }, + "23febb49d9541360b9d099377df16b5630dfbb52": { + "balance": "228513797641000000000" + }, + "24082040652a09cbed6504f3dd6491e0ee9d2bff": { + "balance": "91160839809000000000" + }, + "240d3edf4aaf42e99d366ca36d82c370271b8e8d": { + "balance": "65535355843947000000000" + }, + "242b63ebf47678f17c176d5d4a670e46e66a823c": { + "balance": "469668185647000000000" + }, + "2433612fb939236a87a97261ff7b3bc7b754afb1": { + "balance": "20000000000000000000000" + }, + "246bb03a3fab572b3c64fc23b03dfda42b7ea34c": { + "balance": "936364046000000000" + }, + "246c510dfaf5b49bc0fe01c8256d3879c1b5f89a": { + "balance": "100000000000000000000000" + }, + "24bf4d255bd3db4e33bff1effd73b5aa61ae1ac2": { + "balance": "302436106595000000000" + }, + "24c0378e1a02113c6f0c9f0f2f68167051735111": { + "balance": "36000000000000000000" + }, + "24cf04b7450a0fac4283fa6fcfef6215274b273e": { + "balance": "83714002622000000000" + }, + "24f5f8e7d6a23b55c95fcdc1300de05f9d2abd83": { + "balance": "20000000000000000000000" + }, + "25204bfb27a08dbdee826ad6d9c3398ec6d14fe1": { + "balance": "5929256591480000000000" + }, + "253d95911b4174805d13706b449879413b1672be": { + "balance": "37012901440000000000" + }, + "256065f7e919c508b68957b1d2c9120d29181e12": { + "balance": "25000000000000000000" + }, + "25624542c14c2ecb9a0fe7daec9ac5af16868ee7": { + "balance": "16000000000000000000" + }, + "256d05b6de445179e504a6c94ce1253ae159e19a": { + "balance": "12048598744001000000000" + }, + "256d37fc8980a969063b1f7e7fda8b87d4210da6": { + "balance": "107293553721000000000" + }, + "2588af91a0e8f3ba3ab636781bb84e263acd1f52": { + "balance": "8910000000000000000" + }, + "259774584d4fcae1d84f5997c00beee8a380e46c": { + "balance": "1140713354605000000000" + }, + "25bda1418853a22eb6a5380e8a2862d2a74949bc": { + "balance": "10000000000000000000000" + }, + "25cafdab7f79f7b95d55b4c2dda1f4080aa74d64": { + "balance": "2525573681000000000" + }, + "25cca69b41bb51c51b387c47ece83f30b9a78daa": { + "balance": "163449631440000000000" + }, + "25ce9dabd0a72b02e0056931155ba99c94cbc837": { + "balance": "230073284349000000000" + }, + "25d9d1785c96acddd926b3ed52987ff74f9083f6": { + "balance": "780460361789000000000" + }, + "25e56bd3e1461f27db4eb0cce8bb5ca1574401f8": { + "balance": "1001937531200000000000" + }, + "25fa2162d5c86cda10e4be42c14a24329e455ad8": { + "balance": "50000000000000000000000" + }, + "260a932a23b344056acb8e676714ffac0a13ad2b": { + "balance": "2000000000000000" + }, + "2622efe8836095fcf48d9c8019f48c8320d6e0f2": { + "balance": "5451866545636000000000" + }, + "262447c4d8826ed23ea25e9703a11b4ad3ae9388": { + "balance": "33992454005000000000" + }, + "263eee3badb9b0dd13579c09361806503705a1de": { + "balance": "1134831344000000000" + }, + "266f4c232ebc946c46979cd90d70868380e186d8": { + "balance": "20000000000000000000000" + }, + "267dfe6fa918686942f5e1d19d5fa615f6f2086d": { + "balance": "3569373363935000000000" + }, + "268ad2272c2b71243a7391020a600fd8dfa42d45": { + "balance": "122768017414906000000000" + }, + "269e4f43be9865f05a277933c2fbb466659ada7f": { + "balance": "22064992930948000000000" + }, + "26ae161c20acb26a320fbfbd60c97335cda28bca": { + "balance": "170710653621000000000" + }, + "26b4da905780fb0c5c3e7e5315989fed3aeef135": { + "balance": "20000000000000000000000" + }, + "2704312aa5a4202f14fa3b08e587e4f0ef13accf": { + "balance": "124259630994000000000" + }, + "2704e4b0e8df0c1f298843109ae3bb26c29a22c4": { + "balance": "3155521256785000000000" + }, + "2709347d12251c01aac6455108c6bebe72f0af2d": { + "balance": "220898650215000000000" + }, + "270a32b41dde877463d2106ea4f4529557a5e1d3": { + "balance": "10000000000000000000000" + }, + "2738b3746d6bda9bd72858eaa76f8b5ce7a88c8c": { + "balance": "10000000000000000000000" + }, + "27593d2271aced83e81034e8dd603d098238320c": { + "balance": "20000000000000000000000" + }, + "2771ba4b5944bb12d74b1888255c60e0db215fd2": { + "balance": "412946979808000000000" + }, + "27780086136ea3e97d264584d819dcb2176d7544": { + "balance": "292224348060000000000" + }, + "278936fff8afb553043f038c39fe93906bdb1f4f": { + "balance": "1448466441752000000000" + }, + "27aa0d45d3506f8446816e0e2e9675d46285f6e0": { + "balance": "20000000000000000000000" + }, + "27e655dcc5728b97b3b03fb2796c561090dced1a": { + "balance": "9841344000000000" + }, + "27eb0529279f7a71e50efb70bb1767cbe1ffa4ce": { + "balance": "10000000000000000000000" + }, + "27f564956c837d7949739f419d6ac99deb33d790": { + "balance": "1505247707018000000000" + }, + "280f5618a23c41ac8c60d8bef585aa1cc628a67d": { + "balance": "1316618646306000000000" + }, + "28167a591d66ae52ab22a990954a46e1555c8098": { + "balance": "1000000000000000000000000" + }, + "28257eeb8d20f2fe5f73b0ff2eca3214e30ece4f": { + "balance": "95924728584000000000" + }, + "2827abfc49828db0370b0e3f79de448d46af534e": { + "balance": "769862008499000000000" + }, + "2832b92434e3c922206c2408442bc8274606cbd9": { + "balance": "103421320914027000000000" + }, + "2854f190a38e9b9c04cf499259c6577a68b0b5ed": { + "balance": "144000000000000000000" + }, + "288923bd91be164496e5378ee484f0e4c6c16ed6": { + "balance": "10137243270703000000000" + }, + "2897ff80794153edb721801fb91c6d8373c965f4": { + "balance": "10000000000000000000000" + }, + "28aa06e2290010374097aa2f87a67556d8d68083": { + "balance": "84783245638916000000000" + }, + "28b04ec8eb18b0c6a384f9d92cfb44d1d43ecb51": { + "balance": "14364248730194000000000" + }, + "28db0c000cad3a524bb68dfdd74ffd47b42fb13a": { + "balance": "43586590410000000000" + }, + "28ecd4c5fe98cff66a5b8423f4a27cba9634e2d0": { + "balance": "56106658052000000000" + }, + "2930822031420731f09dce572554a8b8c1eaa09b": { + "balance": "1170839742000000000" + }, + "295154c4522d7bcb2e24b7de9c543dcd1c5f51d9": { + "balance": "179028680906000000000" + }, + "296be4ef7402b00d7af673c1770a50162d7ab602": { + "balance": "8206640005889000000000" + }, + "297b84150756fa89101dd59750a7beb36fb8785c": { + "balance": "1168894124400000000000" + }, + "297cfb72cd1b8b2808fd1b25cdcf7d8de279ad96": { + "balance": "500000000000000000000000" + }, + "29cec0eca9f8508a1ba192a90bb6dee18c40745a": { + "balance": "260217025084000000000" + }, + "29d8f7e72bfa297f17fdce9cf8f4a398f547e200": { + "balance": "307787433251000000000" + }, + "29e14b01c59ba894dd090382fb193ea441164b90": { + "balance": "229028661439000000000" + }, + "29ed634e165084b720e446d28893dbeecd6a7018": { + "balance": "226530464200000000000" + }, + "2a0f8136d43248233f652fe579ef3bd2281dde24": { + "balance": "4007544428000000000" + }, + "2a10204a0c7c9f7701e33c1b71c9427ea16e2e45": { + "balance": "50000000000000000000000" + }, + "2a319ee7a9dbe5b832beae324290f7df6d66f516": { + "balance": "28127560161000000000" + }, + "2a50bfda2b06a9fb28c73f14aaff4f7ef865db65": { + "balance": "10483823413828000000000" + }, + "2a7b7feb145c331cb385b9fcb9555859c16820f6": { + "balance": "1017182951264000000000" + }, + "2ae076c36b18a60f1e3c05d434276a1e16f3f838": { + "balance": "10000000000000000000000" + }, + "2ae2e51ea2ee6a848acde342db2bf6eac927e5af": { + "balance": "494279795271000000000" + }, + "2afd69fac54c167e7ca9d8198a8de386f3acee50": { + "balance": "227162683047000000000" + }, + "2b08018d6e65a7b74ddb5ce1af99976a484b9f50": { + "balance": "16000000000000000000" + }, + "2b0c1d629ad2958ab91e31f351a91219fdbca39e": { + "balance": "113239399820000000000" + }, + "2b2bb67fe9e44165d2108676579a9437c760da30": { + "balance": "20000000000000000000000" + }, + "2b2c99e88e938d1f1416a408a7d0041a605bce16": { + "balance": "6118539729000000000" + }, + "2b5c97b6402ac189e14bbca3e7759319ca8a9222": { + "balance": "10000000000000000000000" + }, + "2b813339c7f818f578b45f17c41c7e931c7828e2": { + "balance": "842834712955000000000" + }, + "2ba6fc21f743968d51f80113aadfc0fdfe8499ed": { + "balance": "309973507270000000000" + }, + "2bb75b272b279cb54498f12b6805261af643c8b1": { + "balance": "1426727673809000000000" + }, + "2bdac062364abd9cf67ba7de214a2cceb0511033": { + "balance": "1090525272063000000000" + }, + "2bea658caa805241aa921f48c8f10cb49e16ffae": { + "balance": "1295499213027000000000" + }, + "2befe7e34299a7c1ad53fc9988ce77e2d9fab20b": { + "balance": "4326342236300000000000" + }, + "2bf466a83cd44aaf0f627606a1c954fd31deb782": { + "balance": "1388986370166000000000" + }, + "2c016a23890e9633fc17b0a8d328ec1ec7ee0113": { + "balance": "92483174342000000000" + }, + "2c45a87a63cc5c8c102d12b83bd9a3501ee41995": { + "balance": "394657687589000000000" + }, + "2c600a596368405e584f3b869f7fabef4ce54aa4": { + "balance": "9879984853585000000000" + }, + "2c7032da8b7816e16095735aee43d1c3f1c43acb": { + "balance": "10000000000000000000" + }, + "2c7275511fe06ee86663b3a618497168b35b0cdf": { + "balance": "10000000000000000000000" + }, + "2ca4074843e9519265447c0dd9ac84ddc2033c1a": { + "balance": "179612279567000000000" + }, + "2cac03ba2c45a6c8186bdceb095b7c5feced3114": { + "balance": "2022060470376000000000" + }, + "2cb8c2cd506b2d7b4cac88ce63230022d412c62d": { + "balance": "211378154058000000000" + }, + "2cd27561cf37ec229982dd592c71d1aab9c2d7d8": { + "balance": "42189968284000000000" + }, + "2cd2e85310a4fbb7f296c3d0d1cee07b191239eb": { + "balance": "1940327317417000000000" + }, + "2ceca4501c5f2194518b411def28985e84d42913": { + "balance": "25000000000000000000" + }, + "2cf7abd42394634689aa2a36d263a6345116b7df": { + "balance": "3553167226295000000000" + }, + "2cf88f29356c166df8383d3312cea10397e25150": { + "balance": "76961677759000000000" + }, + "2d0b62fe49592752cfebaa19003a60b8b39b1cb9": { + "balance": "10277397502735000000000" + }, + "2d2051887107bbd8ed45b405b9be6974a13172d9": { + "balance": "1928781992000000000" + }, + "2d2c9525e2811f4d1016c042f476faf23274aa31": { + "balance": "1000000000000000000000000" + }, + "2d2ef9e1c7a6b66d9a2994adb3ac4a9921408e69": { + "balance": "10000000000000000000" + }, + "2d3bcd18e5c97ddbf1cd28ab37eabe070e9a04d1": { + "balance": "323879852538000000000" + }, + "2d3e60496d0092a4efc665389a916be1a9f8b378": { + "balance": "161958437779000000000" + }, + "2d3fb0ae9b17d3a57d23549ae5500fbb163de25d": { + "balance": "25000000000000000000" + }, + "2d8106dbee6f728c0ff11887690a6370a7d9f5a5": { + "balance": "3102418708000000000" + }, + "2da48eeb788686811ac8270ef3baf0159fc47446": { + "balance": "252187695395000000000" + }, + "2da9d2a6f0b92651a36b05c5e9d2a717c6e166de": { + "balance": "500000000000000000000000" + }, + "2dad81b23d8447190259119019c04a4ef61ab91f": { + "balance": "53428719965000000000" + }, + "2db1faf35901e272aee74a2469a278fdaa6e6e18": { + "balance": "100000000000000000000000" + }, + "2dbae8e1ad37384ca5ff0b4470d3dbc73559841c": { + "balance": "10000000000000000000000" + }, + "2ddf9e23945c181b8592d7965e782068b4c38b37": { + "balance": "100000000000000000" + }, + "2def05d1f2abbaa193a219b87e5319c7ecd48dea": { + "balance": "51359946957000000000" + }, + "2dfd221f96a21e41ffe4dca67b15cd352fe9637e": { + "balance": "36000000000000000000" + }, + "2e1371fcfea9d8dc8e692897a91753400caa9c3a": { + "balance": "5199902650733000000000" + }, + "2e2e04945adbfaeec698ea0f5275f1ad5ffd3d5b": { + "balance": "42034514567000000000" + }, + "2e41f865cfbcf8b89f848405e04de9114087f4ff": { + "balance": "44875730962000000000" + }, + "2e530254768ce94db0ef1204ede0e12b3558e7eb": { + "balance": "14319506377747000000000" + }, + "2e5c43868f45de268967fb22f3f4107da401510d": { + "balance": "20000000000000000000000" + }, + "2e5d2e117d2ba9af9697ec023a4d10b5a2436902": { + "balance": "16000000000000000000" + }, + "2e6000778fb225ddb3e1a2f297d56774e85d9c9d": { + "balance": "10000000000000000000000" + }, + "2eb64b8ab13f0d7823158217d15ba310ed3d0e58": { + "balance": "58724606000000000" + }, + "2ec3973ff33a06d355ad4e8f73b657af8a5ed8e9": { + "balance": "1165606294808000000000" + }, + "2ed4362ea5edf510e210af733089b294f87e8f67": { + "balance": "427561040806000000000" + }, + "2ed8788f1c31b508e37079098a7337bff77b49cc": { + "balance": "10000000000000000000000" + }, + "2edbbe1e2ea482920c76a4ff4c14602b4d37c955": { + "balance": "294409476945451000000000" + }, + "2edcba2bd76128750c8aa00f832c62db30aa7868": { + "balance": "25000000000000000000" + }, + "2ee5abcc0d0d51d4b18947b5aaaa95d037be4e2c": { + "balance": "20000000000000000000000" + }, + "2f058187ef141c06c7c87da86cc1953d2fcf70fa": { + "balance": "9000000000000000000" + }, + "2f16b101da9986a18f4b0d30a26557860338c4e0": { + "balance": "254907899725000000000" + }, + "2f4363df2c61273d230071286bb0157dfefee2cc": { + "balance": "64000000000000000000" + }, + "2f6099a8cb7bc3713b87dab20994d8dc09342003": { + "balance": "1902400000000000000000" + }, + "2f7b3902ce56f74adb0f83cc7d3a99df440cca1c": { + "balance": "825246221388000000000" + }, + "2f7d0298ff6a363375b7eecfe754fca0963c8a1b": { + "balance": "101000000000000000000" + }, + "2fb7c16232b3b1f2e3a676d6d5c93ae6fe5cb14e": { + "balance": "1000000000000000000" + }, + "2fbd5ccc716d2f510d10ec84def3fa69e49f46ca": { + "balance": "1000000000000000000" + }, + "2fd84376be11772e5d072cd74c96b0d9a49c27fb": { + "balance": "1000000000000000000" + }, + "2fdab070e20e2c8923a24c196bec72c33ff0f220": { + "balance": "64000000000000000000" + }, + "3003e6007f69902a0f5e4b4e6d0468277897fc70": { + "balance": "1501210602075000000000" + }, + "30095e6a4ccd1ac2014c3d1d98dce003d775708e": { + "balance": "500000000000000000000000" + }, + "300e47e0fa556371f6c882eb98423be44de7c239": { + "balance": "9108837665958000000000" + }, + "3011231224920b62bcfcbf0aed4fde35dd0a4bdb": { + "balance": "374689586073000000000" + }, + "304be24debce62e70943efddd20457d34e85ab40": { + "balance": "81000000000000000000" + }, + "30912555bb14023e9b7c90aa2314721918cdf1f9": { + "balance": "10000000000000000000000" + }, + "309a94ca7b44bc84a7909ee2b93ed1c94eaf75a1": { + "balance": "39000000000000" + }, + "30bcc93965fa36bbaabcd781326e42227c4e1a51": { + "balance": "10000000000000000000000" + }, + "30c71fed91d24bff69f286ff8f0c6c02a21736a8": { + "balance": "409782329653000000000" + }, + "30cbaf4103757013fd8fb71c44a985939e212b86": { + "balance": "7424807960947000000000" + }, + "30dd59e66093d0bfd87b09c5f6588b9857e9a6f7": { + "balance": "26123006239871345154" + }, + "30f692235f254b02f583d5b515f4701a35c7f692": { + "balance": "148184457997000000000" + }, + "310763019a24a927ce42b00604ee664ca53ff6d0": { + "balance": "393757908273000000000" + }, + "3118a5d4d06ca8b7c8835f4860e6973228000ee2": { + "balance": "56188713212579000000000" + }, + "311adec5bfcaed44680691cc644ee120a484aa05": { + "balance": "169000000000000000000" + }, + "3124e387aa7023995643344c782dac84b9d8c7d4": { + "balance": "1393596696367000000000" + }, + "31379702391cb5a737db3f3ffc336bd03aaa181f": { + "balance": "10000000000000000000000" + }, + "3145606c3ccbaf337610185ffac14ac4f0583c0b": { + "balance": "196454968572000000000" + }, + "315e11501d2c57a62af1631fc2662d4d8745401e": { + "balance": "225000000000000000000" + }, + "31a785ad3eea177c59fb575cad0b44f9a48a12e9": { + "balance": "38039017162416000000000" + }, + "31ae64035e95c1205bf957afb5e1636df00dea3d": { + "balance": "1718600907000000000" + }, + "31c0bb22fd2e9d22984f248a16ec3ed9ad834517": { + "balance": "5982762676000000000" + }, + "31e73a3b5451ebe1163571e9e0567c425bbbfb83": { + "balance": "10000000000000000000000" + }, + "322543c74039ef61fd051021b5e6f16b54bc7c1c": { + "balance": "101346282441000000000" + }, + "3233c7ed11c25bfc41d506c3ae0daf5a3c7c1278": { + "balance": "20000000000000000000" + }, + "325dae17b5225f6734a02c677d43fd126bea89b7": { + "balance": "365067246683000000000" + }, + "326ce8166a4094b93c15557f50f2b1d47811e72c": { + "balance": "16641460224765000000000" + }, + "32cf76046ae48b609524b1a6203eb6296d04853d": { + "balance": "1094839482061000000000" + }, + "33456a28f36aa240262cf95b78b4ac2cd8aa77f6": { + "balance": "3077123488326000000000" + }, + "3348bce2ef90ffd6a59ef5079e1af84b2dd604a7": { + "balance": "9000000000000000000" + }, + "334e5f0ae77dcd3d32dfc2c4ec6ab5e2826dc4b1": { + "balance": "3176777762079000000000" + }, + "335775e19200cd0305e529bc4cdf7295a47cb2d3": { + "balance": "2945631571804000000000" + }, + "336ba81ea6ec4f0da38c1a1761ed3d97fd3ca28c": { + "balance": "3587379203826000000000" + }, + "339191e03e9d5a08ae7b58f4c860235a0721b5a1": { + "balance": "2732237722000000000" + }, + "3399bf9f94c5488c89450257b39fdf3ec8c7f413": { + "balance": "477423805836000000000" + }, + "33cb8556a6c6c867e1be7de591cb22c1b7e9824e": { + "balance": "62293494164000000000" + }, + "33ed633804f39367078e830328dd223254be3366": { + "balance": "22842013797896000000000" + }, + "3409025dce86ad441a5a80f30ce03768d37e40bc": { + "balance": "1381667933000000000" + }, + "34153174cd4d3f1eaed7438638d302f6414d5965": { + "balance": "50000000000000000000000" + }, + "343c6b82b13f0dc82d4269e2c806d2d58e6dde35": { + "balance": "9546969736042000000000" + }, + "346089ea81f7dcb79caf2444df34bd6ee78be4bb": { + "balance": "4344080889000000000" + }, + "34984a8f96dbbfd1f977826a4c2187482559a2e4": { + "balance": "25000000000000000000" + }, + "34a5cce96d2211feb04472260c4cd368bda8432e": { + "balance": "1240050112677000000000" + }, + "34c026a39e44955d1051e8669f9cc58a027455c1": { + "balance": "20000000000000000000000" + }, + "34d730652f4aa002a9f39a47212ca3bc47506b8b": { + "balance": "418050617956000000000" + }, + "34e1d8c8a32ce0f6378abb9bd05ea1f9bfdc5782": { + "balance": "20000000000000000000000" + }, + "350b228870445141f4417ea5dba4f009d693b96c": { + "balance": "76995849736776000000000" + }, + "350eaec708d5d862831aa31be2c37b2fdcef97c6": { + "balance": "258753545822704000000000" + }, + "351fc1f25e88b4ccf090266ebb408593418d8fde": { + "balance": "10000000000000000000000" + }, + "3523ac7a6e79162bb8400bf161cb59389432aa51": { + "balance": "436606776923000000000" + }, + "354d490095e79a29bda2fa11823328450f14333b": { + "balance": "50000000000000000000" + }, + "355a555a36e319e76042e62875a15e1db3012b86": { + "balance": "20000000000000000000000" + }, + "3568840d0a26f39248ab088653ede831f150ce29": { + "balance": "16000000000000000000" + }, + "357096b9c1c7c8d51b682ed3c43d150f55629ff2": { + "balance": "900090781248000000000" + }, + "3588c47ba9204b672c456ee9b5c1ae70f3c738ac": { + "balance": "10000000000000000000000" + }, + "3591edeb9c036e871b4fc6fb3ae6d42e0c0d7203": { + "balance": "1000000000000000000" + }, + "359d92e3e8757a4a97187a96d408c0c11f5c7eb9": { + "balance": "22330509101591000000000" + }, + "35aac2a948f316ba93ed111ac127e29ee9a3adb0": { + "balance": "364387817746000000000" + }, + "35b20459a7daa5f44ae423fd4a1b451ea5090b09": { + "balance": "20000000000000000000000" + }, + "35cdaa84c1f3bc2673bc0c60222c133bae0d3db1": { + "balance": "15234182435000000000" + }, + "35d554233ca690130aaa43501e121a208c657226": { + "balance": "10000000000000000000000" + }, + "35ed399940ece44d01ac873b9c0d3212e659a97e": { + "balance": "55000000000000000000000000" + }, + "35f164612afc2d678bb770f317085ae68cce19bc": { + "balance": "693763596328000000000" + }, + "3601b36cb475101d0d0976a8de9d38e5f3483a08": { + "balance": "1000021000000000000" + }, + "361368bc42c8daf365bce9f9ff3b611373d7b690": { + "balance": "21658400518000000000" + }, + "361bc43be077a269e3e37c11e91479017c47f847": { + "balance": "268900383140000000000" + }, + "363c7a2203f6f93287de091bde3c87eb6800e7a7": { + "balance": "20874859005000000000" + }, + "365dc06856dc6ef35b75b1d4eabb00a7220f4fb5": { + "balance": "30000000000000000000" + }, + "3660e246bce68e2b6e4a802681f188587d2c1c99": { + "balance": "55000000000000000000000000" + }, + "366868ef8e193d7e649ee970d476e6774d5ff1ac": { + "balance": "2544456626840000000000" + }, + "366f7f762887cfb2d09cefa4a5108cf390bdeb41": { + "balance": "26837527714000000000" + }, + "36759f9c92a016b940424404de6548632c8721b1": { + "balance": "1033159825798000000000" + }, + "36a939be88508646709d36841110015bf7cedd90": { + "balance": "144000000000000000000" + }, + "36adca6635db6b00d28a250228532fe560127efb": { + "balance": "3370820618318000000000" + }, + "36bfaed8099ee9f216193ade26d21656c98ce4b5": { + "balance": "1353728563832000000000" + }, + "36df854d0123e271529a8767d1cded4e7b5f31d6": { + "balance": "10000000000000000000000" + }, + "36f59989a902cd10725ff7fe2cab1689aa4e9326": { + "balance": "20000000000000000000000" + }, + "370d6999ae70e781c81d12dc259ea304183b01eb": { + "balance": "45563989086590000000000" + }, + "370e8af59a64a3171b422913921a1e2f982dd512": { + "balance": "170263356254000000000" + }, + "372e01083072214134018f50bde3c8ac4f6e071d": { + "balance": "1400474252324000000000" + }, + "37410fda52f94185d824258ad5f3c9ad9a331257": { + "balance": "11830521097085000000000" + }, + "3752b7e1628275522cd693307787b9564501d959": { + "balance": "67839627078000000000" + }, + "3776f82701c384ce6cbf6a8fea40772cb882b66d": { + "balance": "50000000000000000000000" + }, + "379f63e538168925ba6313f9a6a3b6e7f0e8ed52": { + "balance": "292876625446000000000" + }, + "37a24c1a8080ab429a136c5582782b276eaa931f": { + "balance": "6099055841000000000" + }, + "37abbeaf24b5e6264c87633734852e243d377010": { + "balance": "1051360014489000000000" + }, + "37c50cecab8fe9dcd81aaede95050d27c53f4d45": { + "balance": "106051638566000000000" + }, + "37f82962c3097f0cd9ff605db66e792025a540cb": { + "balance": "10000000000000000000000" + }, + "382ba1e6c53cd7b9c360ef894962d281d557561f": { + "balance": "216789631461000000000" + }, + "38309b458993916efc1ac8b0b5d41302fec21095": { + "balance": "999139000000000000" + }, + "3847f25956a97a32caac059fd9e4cdc105756e25": { + "balance": "876497264905000000000" + }, + "384fe5f399638d277d4fb93f26d527497939287a": { + "balance": "280035151914000000000" + }, + "388335d8b92b445b1b19a3107547bb6ca7c0763c": { + "balance": "167140942784000000000" + }, + "3894a1e65973a542101caa4dc01e9553a5521d63": { + "balance": "34262479791000000000" + }, + "38a0e019c6120a19acaf0e651dd8338982cdaab1": { + "balance": "153843170492000000000" + }, + "38d4bdb10819a7d4ae9a32f4abb82402dff319b5": { + "balance": "1471131830647000000000" + }, + "38e56a55e2ac8320a480562f4a7cea9220306ee3": { + "balance": "907464312139000000000" + }, + "38f18123f3643e03d24ad759afbefc90ed923a2a": { + "balance": "943729130798000000000" + }, + "38f764c861def6d5d65e5ec099536f4cfcc3af55": { + "balance": "20000000000000000000000" + }, + "391e12b51fc85fb879a72fa746ca06c7a5659e6c": { + "balance": "9000000000000000000" + }, + "392342dc7b475c3975877a41622be0fed8e386be": { + "balance": "218719857770000000000" + }, + "3944cc960b8f1993ad841629a79e53d0535a88c8": { + "balance": "210571656485000000000" + }, + "396219864b8cfb0ffb3c675690ccd7026424ad4b": { + "balance": "138984508746000000000" + }, + "396403f26b388150b4876485b124a49845101464": { + "balance": "10000000000000000000000" + }, + "396f1e0f9e7ee86d1b2159ab8f9353677d12d340": { + "balance": "121000000000000000000" + }, + "397cc9f6254d56c721c767e41628a9078bea878c": { + "balance": "225000000000000000000" + }, + "39878b0c7049fb179aba0015279eff6cc3136816": { + "balance": "33962071375000000000" + }, + "3a06b58d0cceee5b091fe6aeb0fc0db5774e9395": { + "balance": "272033811720000000000" + }, + "3a3330e0152d86c5aa1d9bdfe9e1697645d3377e": { + "balance": "2165107207206000000000" + }, + "3a3bb8ed3130e09fbdfc21db3571d4711fc92d60": { + "balance": "885484658836000000000" + }, + "3a4ac96c489c864765cb1997a0084ba745b67a87": { + "balance": "1257436384863000000000" + }, + "3a69e1c351978ced418cea6cee019f220bcb065f": { + "balance": "579242822216000000000" + }, + "3a76a23d81929bed05ef7e1982d32b456e62aa7c": { + "balance": "1027078338792000000000" + }, + "3a7beadd1e11d0e3326c0dcd0f670530612931a5": { + "balance": "20633069818937000000000" + }, + "3a867c44d0dd06517a82ad467d0aefd7f11ce729": { + "balance": "12323708574000000000" + }, + "3a969ae486215e24c7ab89e38929562e2f85d923": { + "balance": "18955477335000000000" + }, + "3ab81366d898a8b798afb08a4b722ab0eb883652": { + "balance": "1220090012596000000000" + }, + "3ac1e14ed5929d382f6488c5444e717373ed29ba": { + "balance": "2030543873000000000" + }, + "3accf4b8ef20e4fea983f13f99ab257a5f9e988d": { + "balance": "156030342415000000000" + }, + "3ad38fa6e3c078025794e213d9dcc5aa397050c2": { + "balance": "36561766773000000000" + }, + "3adef81b2c861ae39c418d55be99aee2306e29fc": { + "balance": "15752410974000000000" + }, + "3b21ff4d5801d3976643899f195fbfd1b72a50b3": { + "balance": "8971221745646000000000" + }, + "3b2f2635dd428ac0b5873088a9a81800f09d6e02": { + "balance": "56922872447000000000" + }, + "3b39919c7bc8d0afec792288c56ab7f4934dc7d2": { + "balance": "1678237240464000000000" + }, + "3b468d9d5546810aa837c29ccb8349548b0e8170": { + "balance": "1100000000000000000" + }, + "3b83d1b651f117f1559a19b04ef408619c2dc4a7": { + "balance": "53628552066000000000" + }, + "3b9a72201bb1e8e678e36129cb1570e3ac99270e": { + "balance": "25000000000000000000" + }, + "3bcab1535b04a0a3fbb673bc41fedaa80bf7901c": { + "balance": "1526488015042000000000" + }, + "3bed42c3d0c49ffac87b9d482f6338fdc9e3880e": { + "balance": "26189771073000000000" + }, + "3bf736b57f0ae47f3714a6bb852090a543b9d367": { + "balance": "652395174320000000000" + }, + "3bfd481651956105ed909eeb98be404ec5ae77e9": { + "balance": "177520143473000000000" + }, + "3c0a12a327545b5f8b7b5c1f7a1ec6a341ec9578": { + "balance": "4184342789398000000000" + }, + "3c132698d59927fe08cba433a41d08acc96c0edd": { + "balance": "151913899135971000000000" + }, + "3c27bd92c4be1a19974ec773bd20b13afe582c9f": { + "balance": "10000000000000000000000" + }, + "3c2ad171573a608286f1fa3f5ef9e6099823983e": { + "balance": "3240802189194000000000" + }, + "3c4b5e808b9fb8baab1144b981b6cd53e216fcdd": { + "balance": "61214114118619000000000" + }, + "3c4cfc6ead044819ceb41c1c64ceda1a228af801": { + "balance": "9000000000000000000" + }, + "3c553afd45535f7c2a70c701d00890e607b96ffe": { + "balance": "2678827200938000000000" + }, + "3c620d55268c55b6deea3b7dc7f59dbe93b6e141": { + "balance": "55494311990000000000" + }, + "3c9b204db23b902d4295e6aba3405917efd59449": { + "balance": "55543672571000000000" + }, + "3cf233b7730a175d05a861318b7bb917bb5bee06": { + "balance": "1867187351033000000000" + }, + "3d292272992397ed5f27d5202da693128d023d35": { + "balance": "79770828413000000000" + }, + "3d353cfe84e9a93aef90547fbeb6e4b4bef83069": { + "balance": "36000000000000000000" + }, + "3d54da4ddd0621822a114581ecd15572e6488be9": { + "balance": "1623867132383000000000" + }, + "3d62ddc67d366fb055eaf92c936a6e7df5085454": { + "balance": "124933526793000000000" + }, + "3d754df1151b9b62a6ed48b477225121c29af063": { + "balance": "50000000000000000000000" + }, + "3d79d1ebd5224ffdc13e27924ab7f9f8e3452ec9": { + "balance": "520163228474000000000" + }, + "3d84fd9785a6bd3148847038c6f1e135042a892e": { + "balance": "10000000000000000000000" + }, + "3d9574c3860f30bcb42523a0cbb08aa7dd83e733": { + "balance": "15259904884000000000" + }, + "3da809a5911ccc77f892034049a97a9022c35e7d": { + "balance": "1415009021101000000000" + }, + "3db9a6c6ab3d0cf6d3bd7e04bdad39b4d419ab13": { + "balance": "9999781764000000000" + }, + "3dc7367c3218f88de8867c425f89102d2f2056f4": { + "balance": "10000000000000000000000" + }, + "3dd273dedb28824d1309c7d60a0744a6b6353e79": { + "balance": "9000000000000000000" + }, + "3dd6b25eb91dd2f3468e0786e8beb465abe7f515": { + "balance": "275172962210000000000" + }, + "3e0d14f83b304136311a33bbac2720c0cd66f117": { + "balance": "3390479675000000000" + }, + "3e15e947ee76f52f0f2a7d84da7c4ab060eb5cbf": { + "balance": "6751398714759000000000" + }, + "3e1b5469e1da4ec27537513f4df3f1a338a7dc2d": { + "balance": "161899580000000000000" + }, + "3e3329bcc90e47e4dabb5c93572b18b5e0efa024": { + "balance": "10000000000000000000000" + }, + "3e5a585ad0f34d78899433edaed574af052616f0": { + "balance": "910225655353000000000" + }, + "3e6be9615713bb06198bf354ef434a9db649699b": { + "balance": "783525278181000000000" + }, + "3e7c7c082f2f99b1ad579400a2e93586a24ed992": { + "balance": "159035553843000000000" + }, + "3e86ea5713f90022c0914fcc25e97c39487eb957": { + "balance": "101867287023438000000000" + }, + "3e9dabab6e50a696edfba6bcd44230d087c8d04c": { + "balance": "3315882414579000000000" + }, + "3ed956f86fe78223c86e164e4f372c9a0bf4a279": { + "balance": "119959915220000000000" + }, + "3ee87e776fb12e9c894e36fd5a61daa984e8a5cb": { + "balance": "50000000000000000000" + }, + "3ef1c8f294443f776a794563ce7569a8fe4d5d20": { + "balance": "25000000000000000000" + }, + "3ef6a396d6611df6c79ec1e6ad6bbd253917fbe9": { + "balance": "10000000000000000000000" + }, + "3ef727346fc631ae6473e9a36e2e5e54df696195": { + "balance": "121000000000000000000" + }, + "3efdcf2c0998637cb82d2b5fc24f27162578d207": { + "balance": "1054861112990000000000" + }, + "3f2cb2335e2bc07744175c497e2f437e87c2a146": { + "balance": "48999979000000000000" + }, + "3f4d16663a4f76ade93eb8bd6ca8fe2158e24322": { + "balance": "237117597268000000000" + }, + "3f7c5e6aea7f3f74d764df50f0fc1aa758fc99a7": { + "balance": "63372222562060000000000" + }, + "3f92239fdb41c6ec228252248c2db3f23675e275": { + "balance": "28538064487000000000" + }, + "3f9610454b621c04f00f01f4d54046502edb21fb": { + "balance": "16000000000000000000" + }, + "3fcfb30cbfe53c0c43f58c28386d9a6e5b49f7cd": { + "balance": "79080579219000000000" + }, + "3fda0c9a3d3f0000635376f064481d05d1b930bb": { + "balance": "10599947385000000000" + }, + "3ffce0475430de0bd9b09a412e404bc63aa28eea": { + "balance": "10000000000000000000000" + }, + "3ffe7583b568448ded5183e1544bca0d283680d2": { + "balance": "1076944549283000000000" + }, + "4003a137e577351a4ad7e42d1fc2d2cf1f906b6f": { + "balance": "25000000000000000000" + }, + "40215fc4c6300d8d8179383d9028fd2d909c6cc4": { + "balance": "3941346079000000000" + }, + "4027d7bbfa5d12c1ab9d08933a1659ae8dd023ee": { + "balance": "1156537386462000000000" + }, + "4039439c960070394dbda457726d97121c7b3669": { + "balance": "4444061364102000000000" + }, + "405978c24a12d930ada6163a44fc4a70c16569e1": { + "balance": "707298643296000000000" + }, + "405d2c1b55ba3f67c8634456b99c19092b407a10": { + "balance": "1462185951849000000000" + }, + "405ddfcf45005cf5a0ee1bfa605a7346a0167945": { + "balance": "88775535985000000000" + }, + "405f72a6940acf5d36a29498075f2d0d7a75bc22": { + "balance": "402796678569000000000" + }, + "407253b005ae97857f812fc60d441e5367b4bac8": { + "balance": "1484147810895000000000" + }, + "4091e1fb1c7af51a64c201d6a0c8f0183dfb7ca5": { + "balance": "10000000000000000000000" + }, + "40950bad9580d4b111955da7d3f9ada26dd9f05a": { + "balance": "500000000000000000000000" + }, + "409a28106192cae7a76c6aa8add0f73dcd63d2c0": { + "balance": "214832616721000000000" + }, + "409d5b872b059aea9a773e854f9a17ed2d5c2ef3": { + "balance": "64000000000000000000" + }, + "40a6e3c753b04c42fcf89cc30df8f50418caecb8": { + "balance": "754228409494000000000" + }, + "40e5ce1e18c78d6c792f46ed6246bfb31bcdb6af": { + "balance": "500000000000000000000000" + }, + "4121692a14554ddca1ca662fb577d7152d4fa7d0": { + "balance": "49000000000000000000" + }, + "412acb10c8ca937ddd64cf0d413b1dd34760f72b": { + "balance": "6073360870000000000" + }, + "4166a5c94d5ae48ced410f950d40656182bf8990": { + "balance": "55000000000000000000000000" + }, + "41752b7d0d3ee58a6b69d8ba721c0894ff701237": { + "balance": "585556720807000000000" + }, + "417c86d6bf734e99892a15294230771bbfd7e1e1": { + "balance": "38233258264000000000" + }, + "418414498f7361b29428c54732e1f49fb394f813": { + "balance": "2063786326155000000000" + }, + "41a424dcbff6bf31686f5c936e00d21e8a4e0f78": { + "balance": "33554754580438000000000" + }, + "41a893429d5f8487c1866b87779155d4bfe33198": { + "balance": "20000000000000000000000" + }, + "41bbedd607fa576d130305486824cd2871bf6b05": { + "balance": "649728993301000000000" + }, + "41ee42c1fb1bcdc9c7a97a199fdcf9b63623521a": { + "balance": "7906012418597000000000" + }, + "41feffaf56d1712af6965fa6eee1b06bd624e7b8": { + "balance": "49000000000000000000" + }, + "42107e765e77ea76b3d6069d3775bc3aef7d692c": { + "balance": "25320783684183000000000" + }, + "421f4dab3240e15a1c78e3ce8642de9b578b8e4a": { + "balance": "832511242936000000000" + }, + "4246c52c3601541a873d4bbaafedf28b9bad5b73": { + "balance": "10000000000000000000" + }, + "424efe1ba28bb1aeedc38a3a5135547d0fe80751": { + "balance": "25622294162729000000000" + }, + "424fb0a3ec325bf42e7edbef7e450f2ffd1cf318": { + "balance": "20000000000000000000000" + }, + "42714c04d17f6c29029daf7f50d1cbad6590cfad": { + "balance": "271755674161000000000" + }, + "42b66e9123d304b70fef3dbcfe8587fd6189b5c4": { + "balance": "1030481609000000000" + }, + "42dacbc412b829cb304ffbc316b3f81b379bfc80": { + "balance": "304208485736000000000" + }, + "42e3d9832c8b6cdea39c97525570391803dee276": { + "balance": "2581020833000000000" + }, + "42f757898f95c1b46f64a4a6b7f86ab03022d672": { + "balance": "100000000000000000000" + }, + "42f7956fd659e00d3be2f3d1d4f3ed187aef04d6": { + "balance": "50000000000000000000000" + }, + "43160b2bc00f7f8f7fc806e2f6e2ffdc62b3a651": { + "balance": "1000000000000000000000000" + }, + "431b77cdd067003eeed26c1aee32f67fb94f7092": { + "balance": "902514849986000000000" + }, + "434e44583786e354731bca250d94ef0d8860a538": { + "balance": "1187789683866000000000" + }, + "434f1b9b193c88bf58685124aac0167fe69f9014": { + "balance": "500000000000000000000000" + }, + "43535982688844fa703cb9bd5723790cab364049": { + "balance": "100000000000000000000000" + }, + "43559f405590592c254e427fa25f03e774d8defd": { + "balance": "6913200000000000000" + }, + "435c08c481d59308a64afec0d6f936321bb120bf": { + "balance": "9005920819593000000000" + }, + "43629748a92b846f21f637aac5103412fbabb9a6": { + "balance": "1177513692845000000000" + }, + "43650b37552882d225ccc977aa2b7a86a4ca9bb1": { + "balance": "16000000000000000000" + }, + "4385de394371d26a45f18e8b3842effd015027bf": { + "balance": "187331693412000000000" + }, + "4386ff9648fe420503c9a36fe7b97c079de3b770": { + "balance": "2714401478778000000000" + }, + "43b370c4457cf39a3be86cc00c2b27614ca6e638": { + "balance": "8316429850934000000000" + }, + "43c464ea740172fe6f4f09974106fd24029837b9": { + "balance": "129643160399000000000" + }, + "43ddd2d33dcb7e578f4e59ad6b9c61a24c793aa8": { + "balance": "500000000000000000000000" + }, + "43e0f8065eb7faf3bbd13bc7c5d5d8f5ff1bdac3": { + "balance": "4454324716300000000000" + }, + "43e96cd065d7934b246d0fec8cd2dc6b36d56d7a": { + "balance": "81721481452000000000" + }, + "43e99acabfbdc6cafee3afb12fa7ed1345370b2d": { + "balance": "4595292398872000000000" + }, + "43fae764c7555b859b93d2126edfa59cfbf298b5": { + "balance": "105746805109558000000000" + }, + "44052eb938c02776b5240f38ec99f5ef51ef0d87": { + "balance": "38446396949881000000000" + }, + "440fc7621cc17f121f0bdf2a68c5be2c3af4fd3b": { + "balance": "1026958147051000000000" + }, + "4440ccbc77249a4d891d9ab5a5f2026b17aff7c7": { + "balance": "10000000000000000000000" + }, + "447f3f702c13a3fbdc8675c6285702b5aa2b66bc": { + "balance": "1089533398014000000000" + }, + "448f152be153fdb0497403f70e37d876946a5021": { + "balance": "614429461682000000000" + }, + "44a1e3a044f5d1fb00f4beb3772a3ee08d8b7093": { + "balance": "1000000000000000000" + }, + "4515edc7154bedd7143b69a04c4e738f8aa4ab18": { + "balance": "10000000000000000000000" + }, + "4572148fe5ea9d4795e1f1ed93097aac1d70991c": { + "balance": "2873782218000000000" + }, + "457581f223b8eacd757abb292613e317d6f59305": { + "balance": "3582446780073000000000" + }, + "45b450961882850f7038d5cdcd2a8fa2dc4b5469": { + "balance": "20000000000000000000000" + }, + "45bdfdf3840d4341503cd7fc87e4b66f6179e5fe": { + "balance": "10000000000000000000000" + }, + "45dd9baa87b3c94df66308d8ed4f3a5bb65c3dcb": { + "balance": "25000000000000000000" + }, + "45de332b8ee95d886cf11b99291b46f46c1ddd45": { + "balance": "36000000000000000000" + }, + "45e06afdbc70288a2cc55bccc4fb2d8195aea028": { + "balance": "790360485306000000000" + }, + "45fce5fd1acb2bc5507723c897cb340437e39735": { + "balance": "100000000000000000000" + }, + "46045cddd940d80596826ce5354489b3047663bb": { + "balance": "100000000000000000000000" + }, + "4610286f8a2649dcfbc6d91735745f418a6abc75": { + "balance": "10000000000000000000000" + }, + "4615905ecc6f7df0ccb7b86a3e1d3770adb2f874": { + "balance": "1000000000000000" + }, + "46256e00ff927d54b0ca139ddccac2148784273b": { + "balance": "10000000000000000000000" + }, + "465e40e7d129ad310fc60ff0f17c0f968611118f": { + "balance": "677971225649000000000" + }, + "4664a920f7fe9b0d78a665e1a4aeb95f287d6059": { + "balance": "20000000000000000000000" + }, + "46679de1c6143138fd9c44ff05853a52371915ff": { + "balance": "363627463229000000000" + }, + "467cdc210ae48ba99740d37ee79fa57c4216bc81": { + "balance": "10000000000000000000000" + }, + "468053d193debb88735571acb24b764f2676272e": { + "balance": "49000000000000000000" + }, + "46826d1f1418abbe4e7b9236d643e5b57a0f0208": { + "balance": "37752144164916000000000" + }, + "468df2ea57972ddeb88d470a5f3c2c0e2284ac17": { + "balance": "757320434551000000000" + }, + "4695ad5b686520ee8426d24b50ff7a5f0d703443": { + "balance": "2851082366000000000" + }, + "46a149bc8ec2b85fdf938f753a6c53777dcca2b1": { + "balance": "10123698633000000000" + }, + "46c081440f760a21b74c2499bdda13aef8245930": { + "balance": "180752319265000000000" + }, + "46e615324f6e4fb242f9bfecffc0c802ba7733c9": { + "balance": "10000000000000000000000" + }, + "46eb54f09dbdaaf3b97a1f79a3d82ee2e902b3b8": { + "balance": "3430510380318000000000" + }, + "46ebb24b04919ec0164f0bafcebca2309f2d3035": { + "balance": "129155832233000000000" + }, + "4701f9fe78111011f820fe28c47522e601655678": { + "balance": "9000000000000000000" + }, + "473f44e2c1d5d7aa53cf7041d7ad19a0d9eaf1d8": { + "balance": "162679637505000000000" + }, + "474f8bf4d03a7efa4d190905ce062eea7c75118c": { + "balance": "1259904506149000000000" + }, + "47598330e862a4f7cbda8be74ac10cd5d370a55e": { + "balance": "291763101699000000000" + }, + "476455d48fc858a06bd7854fcf1bd60bcfde9ed3": { + "balance": "10000000000000000000000" + }, + "476826d58192ad822f4686311d6c6d4d4f66ee5f": { + "balance": "453184657722000000000" + }, + "47a231eb3fdbc24f2d008f06228624b2a45ae5fa": { + "balance": "1000000000000000000" + }, + "4805f4c0eb1c83c436118ec9148019e5fc1962e3": { + "balance": "1311161626928000000000" + }, + "4809f373cdd56c8481ba3bce5a401d55a7e50a50": { + "balance": "2284845194349000000000" + }, + "4839bf9ad56873abd5695057bf71972806cde827": { + "balance": "42264923611000000000" + }, + "486dba2a47decabc9a85d1d64d74687983ab273b": { + "balance": "49000000000000000000" + }, + "4877993f5ecf02451f8d4591594cb2f30dcf9f26": { + "balance": "100000000000000000000" + }, + "489723e325f609e27be14528c4111fb3eec13f7c": { + "balance": "2489030141000000000" + }, + "48b710d16e9da736b773453089d69cc6ede116b5": { + "balance": "26651593216000000000" + }, + "491088e1e4b5c3d65870f2deef9be6ec3dc6c7c7": { + "balance": "1446809481953000000000" + }, + "49174451320ad2e14cb2b05ecdd251b75ace3038": { + "balance": "15533380764616000000000" + }, + "4956ead915594b621131b2fc2dbbb49ba43c5559": { + "balance": "1175638488000000000" + }, + "4973a0d32147ba89f525a18f989518dcfce93b0e": { + "balance": "522848489444000000000" + }, + "498c6f9063705054fae07260d4176c3d55a97650": { + "balance": "732941433000000000" + }, + "49991f68f2a76bd1cffa3e9721be36f3fd8351b8": { + "balance": "17742568700019000000000" + }, + "499a8af194e0040f349e893937fe3858f8267fca": { + "balance": "80704784160862000000000" + }, + "49bcbb7b263febf54f8ff498525bac8e7241f966": { + "balance": "603044032468000000000" + }, + "49bd72773656c4e1a4d16284aea2fb05546d2b31": { + "balance": "1896607093054000000000" + }, + "49bf80fcdefebe8cd4830ba09e46ccd7231c8e6f": { + "balance": "10000000000000000000" + }, + "49c9d82dea78f14b1c52efc0196b67f508f7859b": { + "balance": "2313040051399000000000" + }, + "4a2daeacf0468d137e3bc464d6d5fa3893a9136b": { + "balance": "10000000000000000000000" + }, + "4a6c428f245e8d9115b34764bab17eb86ac472be": { + "balance": "10000000000000000000000" + }, + "4a6e8d037acf1960dbbf14e7a02fec0ac656f9c1": { + "balance": "6516295825438000000000" + }, + "4a7e7fc3c72f2f9b92bf0dcd5297cfb19f077d7c": { + "balance": "99426213999999999" + }, + "4aaa6817a5000bb7596e000135b3051c5931e7c5": { + "balance": "102884105546478000000000" + }, + "4abcdc3d7d3d314a163da92aee53a56b87313a2e": { + "balance": "44402243657000000000" + }, + "4ac9385ade2377b061f4211b392ed6a6e7fb83cc": { + "balance": "1000000000000000000" + }, + "4ac96e1e26cb66ff788ed8c62db811d7b4fdbc74": { + "balance": "68476115774000000000" + }, + "4b10c247caf33fb872d9bf86572424410aa86752": { + "balance": "337915294240000000000" + }, + "4b23ffff1894df49005c7afc0828880924571299": { + "balance": "169848767272000000000" + }, + "4b486895caf3a0b5afa198df744de7082eec8666": { + "balance": "1672587376054000000000" + }, + "4b98fc960610573be456c0e1e319f4f863bf9095": { + "balance": "259382246718303000000000" + }, + "4bc0cc483be20223f40ed6deef63dd9645c216c4": { + "balance": "4322684620000000000" + }, + "4bf4a046afdd4ec9d0e50730ff6ded5ef2327442": { + "balance": "70601389160000000000" + }, + "4c0149058e2e74f7c900e6d6e5fa12eea882c5e0": { + "balance": "2017399852886000000000" + }, + "4c17a3997fb70599794d01a33a27a6d5b52b6f01": { + "balance": "469002093209000000000" + }, + "4c4559e7b32340dce112cf7a021ced1b113f6dd9": { + "balance": "25000000000000000000" + }, + "4c4f02b3f232b8ce8485d425639271510cd0486f": { + "balance": "68828038140000000000" + }, + "4c52ec56142bb6e8c8830e5c17b01b5165915f3c": { + "balance": "321766233041000000000" + }, + "4c58defa57875e709ca039a54a2be5aed6672f6d": { + "balance": "121000000000000000000" + }, + "4c5a886ab90b6bac68677a7eb92a06bf33ff2930": { + "balance": "236899852150000000000" + }, + "4c60539363edbd812334a54543c40ecab8af2ac8": { + "balance": "3281904094699000000000" + }, + "4c76897d0d5d39195354194710c5e7f99bef63d1": { + "balance": "10232271258305000000000" + }, + "4ca3c03780c20a64f3b5ebb75669982a71ee8a71": { + "balance": "377172198976000000000" + }, + "4caf77eefe062a6f053a464171bc75254b47f52b": { + "balance": "20000000000000000000000" + }, + "4cb7d7ce805e56f6e47e94cd755b6d97f8f996a0": { + "balance": "120998866000000000000" + }, + "4cd34f8f3299d3b7aaee180baa0b432369e1b3d6": { + "balance": "197088135242000000000" + }, + "4cd7aaa5415d809f405f520e4c0319a6029b981b": { + "balance": "686627368232000000000" + }, + "4d01067555f1ef63883f25c562b07168f79fa80d": { + "balance": "17547055698000000000" + }, + "4d2cb4c1da53e227b08c0a269402e9243a13f08d": { + "balance": "324000000000000000000" + }, + "4d38bb5f48ec37b751d16de32a4896fbda479ce1": { + "balance": "802530078718000000000" + }, + "4db3e76e2f68896cecc9826e10a5e09df0352c28": { + "balance": "555180306924000000000" + }, + "4dc8730d9f032d33dc493bcd3c6375b38f41afff": { + "balance": "5726933881000000000" + }, + "4ddde96556f5185a13617f01ebd9102800bc9e9c": { + "balance": "1181822708402000000000" + }, + "4df9359cb204bf649668ff8086a7f5e24709083c": { + "balance": "262998978400000000000" + }, + "4e0a1a3dff0d33c418758263664b490140da9e01": { + "balance": "100000000000000000000" + }, + "4e0dd6d8de5caa3a3bf9fdd6f2d7b30618623cc0": { + "balance": "10000000000000000000" + }, + "4e11af85d184b7f5e56d6b54a99198e4a5594b38": { + "balance": "76658631121000000000" + }, + "4e314349abc52c686d47dc771ebc8040966be386": { + "balance": "632341985941000000000" + }, + "4e3fb09c35375106bece137dbe0e5491e872871b": { + "balance": "153648535396000000000" + }, + "4e4f0d606f7065bfb1545e60b5e684ae1934e055": { + "balance": "48998635468000000000" + }, + "4e50957aa6c91c548075add8ec625b74c0973abd": { + "balance": "1000000000000000000" + }, + "4e5c6efa76493f0e9422582016aac50539ae60d9": { + "balance": "2078967343000000000" + }, + "4e70bbcb50c4e875fd573dcb694908abf3b30b37": { + "balance": "20000000000000000000000" + }, + "4e7f5670a7dd168a0803e53b8bf72f4db280e3ae": { + "balance": "1658463113665000000000" + }, + "4edaf859990a10977bf378df45b32f93422c84b4": { + "balance": "121000000000000000000" + }, + "4ef41923a1a426772832d3c267adbd84e5994edd": { + "balance": "5432615017384000000000" + }, + "4f11a70d80f36f46ed0c2a5fff1a39b711f3bae5": { + "balance": "8415785077000000000" + }, + "4f159095afcc75b8f5cfc90c9d07a0d77ac8ed69": { + "balance": "25000000000000000000" + }, + "4f2652322736cc18b24af582d4022fe329a9dfb7": { + "balance": "9000000000000000000" + }, + "4f328173f352f3dfdca0ff5e3185f26de77c6f75": { + "balance": "10722917874680000000000" + }, + "4f47a62aba6ea049fc0e92d8afbe1682472d98bf": { + "balance": "10000000000000000000000" + }, + "4f4c3e89f1474fe0f20125fae97db0054e9e14e0": { + "balance": "50203638983000000000" + }, + "4f5ac8dfe79c366010eb340c6135fbee56f781d8": { + "balance": "50000000000000000000000" + }, + "4f672cbd373183d77d8bd791096c6ebb82fa9a2a": { + "balance": "978111227765000000000" + }, + "4fb179c9c88decaa9b21d8fc165889b8b5c56706": { + "balance": "24750205150000000000" + }, + "4fbcf391c765b244b321875d6ab4381c44d0747a": { + "balance": "99999580000000000000" + }, + "4fc979b38b981fca67dfa96c6a38a17816d00013": { + "balance": "1088876196468000000000" + }, + "4fdfdd1832b114b4404aae23305c346beee14e1d": { + "balance": "278724179057000000000" + }, + "4feffb1836029cd0e9b8f4aa94b35ae3982fa770": { + "balance": "1674590934924000000000" + }, + "50045745a859f8fce8a2becf2c2b883b3723b2c8": { + "balance": "169000000000000000000" + }, + "5028bde29fe88e03e3de069b3907fa9df551c379": { + "balance": "196000000000000000000" + }, + "507096ed771fa8a1d004ee5377c01506df461b32": { + "balance": "2669205000000000" + }, + "50788574a0967580fdaddc4758f834d8978455f6": { + "balance": "1648581593000000000" + }, + "508d8e8f338ca98d3c09f0f15fd9e7baa80701e8": { + "balance": "16000000000000000000" + }, + "50a4dc916845172b83764a6c8b4b00d6d02d41d3": { + "balance": "3020744393592000000000" + }, + "50da06418780c220ced4898af0b1fca533f73cca": { + "balance": "36486700700823000000000" + }, + "50fb6fd8432a66219e754234e9eea1dabcc07676": { + "balance": "489500000000000000" + }, + "5104bb1b831902333732dd25209afee810dfb4fe": { + "balance": "1333614132000000000" + }, + "513963743ec6ec9dc91abf356b807ebad64df221": { + "balance": "1508002412172000000000" + }, + "51397ca69d36e515a58882a04266179843727304": { + "balance": "941648956414000000000" + }, + "514a58f2b36c2cf1b6293c36360cf658d8af30ed": { + "balance": "1233397704089000000000" + }, + "514fe0cdb3de692cab9f2ef2fd774244df71be66": { + "balance": "9670444445882000000000" + }, + "51583128081fd800d9550144afebdf3fe88149cb": { + "balance": "231190355520000000000" + }, + "517384fe92391187d0e65747a17bfaadf967c331": { + "balance": "1943121865489000000000" + }, + "51aebfaa26a54071cfe6c2d8f81157ec313984ad": { + "balance": "1422225031261000000000" + }, + "51d4f1205b272e491e94fe21f0341465f14141fc": { + "balance": "552384783614000000000" + }, + "51de598faa85276bb26a68b135028755304b6700": { + "balance": "2068484560002000000000" + }, + "51e08e0304f08ef768c80ca149da4721fcf482b0": { + "balance": "194629207228000000000" + }, + "51fa3da695e24f602952a71966f37ac3596a94a4": { + "balance": "17008166261720000000000" + }, + "520b22776b1befd3064636da0dd251afe569ef13": { + "balance": "18538137781909000000000" + }, + "52219a1e1aa82b78b971088c30583a3bbe675c8e": { + "balance": "411959222637000000000" + }, + "5252b8a0688096523498cb5c1f42bcd1f61923d7": { + "balance": "1863936864000000000" + }, + "5259154e1a5a809b2e3dab80372124cebbfd56e2": { + "balance": "110000000000000" + }, + "5264f2de516835e549710bfe34ef03b08b8557dd": { + "balance": "1216000000000000000000" + }, + "52b17fae7e9cac447f026db71dba4034a1d53174": { + "balance": "99001631977000000000" + }, + "52b3363ae882a99354faeb76733d0fa2cbb89787": { + "balance": "102517584327000000000" + }, + "52bee7fb24a7fc1f34cf0874ec2f06c5fe847cb1": { + "balance": "54443400591000000000" + }, + "52d1f12d391c7a2f3b52939a61a20da5f85eecc3": { + "balance": "2707175772061000000000" + }, + "52f27099483589e883e7eb789896de39c61e46da": { + "balance": "358944977251000000000" + }, + "52f3b715b678de95d1befb292de14c70f89f5e03": { + "balance": "2989868434000000000" + }, + "53259780569f6dd6753c1da1d53d0b155c5b30d2": { + "balance": "200489122590000000000" + }, + "532e4908e8297c90d75d2280b432b469aaafa2ac": { + "balance": "20000000000000000" + }, + "5334d1e399feacabc9648cebcd93172db95d43be": { + "balance": "25000000000000000000" + }, + "5341665addfb5e367f7a7d35de95b87a0cceb3a9": { + "balance": "60544291695000000000" + }, + "535a39a854ed1c2f0afbc5944f1ee0e2e68cf65a": { + "balance": "2141913781000000000" + }, + "536515c0c08988ee69da1d75f18c706f6b9bf7a3": { + "balance": "169000000000000000000" + }, + "5387a1ce4cd2ef4f90075c15dc3c0744948ec356": { + "balance": "50000000000000000000000" + }, + "539a30ee5724978010990718bb8b0dd25f89fd15": { + "balance": "1306896514000000000" + }, + "53a5f87dfb17149b8c2934a2a9d519ace4ac9724": { + "balance": "4569449510000000000" + }, + "53b24fb36e72c22eb830dc93857a8188b03397a9": { + "balance": "64000000000000000000" + }, + "53cc35b3daf4b8e1982e0e63d0bc68d7252e7fcc": { + "balance": "68213426853658000000000" + }, + "53e1f85147e000ae1ff6a5910407395e388c683c": { + "balance": "20000000000000000000000" + }, + "541f43ff66ed5eb1a1ea0ae3f86355ecff665274": { + "balance": "49562725831000000000" + }, + "5428a31f736c0d2b3c4e80baefb75a76ed44d3f7": { + "balance": "10000000000000000000000" + }, + "542f732aec0873bf531f6941828b6f0ed0611106": { + "balance": "8407722276000000000" + }, + "54300b6a77b95545373b2bba73e60f37c31eb1c6": { + "balance": "1581215621996000000000" + }, + "5434bd65a492a4d14d3b97eb49f6e491350ef73c": { + "balance": "484000000000000000000" + }, + "5444a1735913eeac177d947ef38de7cd6bdfc0a6": { + "balance": "1000000000000000000000000" + }, + "544ffeab53bdc59ef8edaff0042b03c2ea123615": { + "balance": "10000000000000000000000" + }, + "54613713df6c5b89c3012a7835651f25cdac8331": { + "balance": "98684037547000000000" + }, + "5471fb39b4e48c118f855492830ad9e2eaa68179": { + "balance": "91791250228000000000" + }, + "5472591efd048dd60a4d6afdb549e95a65578b0a": { + "balance": "50000000000000000000000" + }, + "547b4c1ae70567fd77a896dc05eb536f502ac8a4": { + "balance": "14037444012000000000" + }, + "547fa9f6f86a2939f9144aacb74e0af60d434535": { + "balance": "428416957729000000000" + }, + "54841d6a478cb9b6e717a9de35577a1a4a504b0d": { + "balance": "144000000000000000000" + }, + "549157e5b1c92a88a0eef335b1bcf4d162482017": { + "balance": "21019502942000000000" + }, + "5492757c55c72ac5946b21514ee16c5065ecde7b": { + "balance": "10446737491000000000" + }, + "54984a41eeaa8e710e4e5b8a7f68c96057b7df3a": { + "balance": "10000000000000000000000" + }, + "549a3717a1bca3f38d24655197c3ccef1e8c273e": { + "balance": "4416133255000000000" + }, + "54b047fbe004191cd02f31163d29bd61ccfaadf7": { + "balance": "52649445905000000000" + }, + "54b125d8b260386633b756056b7d7e78e7071715": { + "balance": "10000000000000000000000" + }, + "54ffad1ae76ab45c4218ced27e49bf2745b2a2e7": { + "balance": "1426474871178000000000" + }, + "550b28968bae36f4e99780c6d7deb54c158be6d8": { + "balance": "10000000000000000000" + }, + "55117923e8393dbf233c0f10819e7de75569962c": { + "balance": "470094520022000000000" + }, + "554a2471e6ecf2320da545d559c40b8b622465ab": { + "balance": "4052895973949000000000" + }, + "55607b39da9480ed8f54d74d0818ab8798136589": { + "balance": "13704276648975000000000" + }, + "5561cbe99fd775f5d0f05903fd62ba4877b3319d": { + "balance": "1007596371374000000000" + }, + "559ba7ab58670d4a0b118bbf6aed7f6fdb276594": { + "balance": "3127762973000000000" + }, + "55b0bc444f2a5952a98f216f61cf07382da1e156": { + "balance": "18683409750727000000000" + }, + "55c0a02dc68123aca7ee0c9cd073ead50b16406e": { + "balance": "99999999580000000000000" + }, + "55c47d593952afd637050c5758a921a204f23fc6": { + "balance": "1615608723958000000000" + }, + "55c6855b3970e5a550f0c75d5727329476406d91": { + "balance": "600705012673000000000" + }, + "55eadbe33899f53138d0fb204f42e272f447cfd6": { + "balance": "1671128311341000000000" + }, + "55fa59fa0fbba06b7184ea78868d438176eb96eb": { + "balance": "1553000000000000000000" + }, + "560a11493b5a0ec28589e80276fe975ee26c6a3e": { + "balance": "10000000000000000000000" + }, + "560fbb31d83bf6dc49e5fb15bd582d70c49fd273": { + "balance": "46015432815000000000" + }, + "5620e17ccf094b1be1a93f6f3388fb96e3a90165": { + "balance": "484000000000000000000" + }, + "5633512298cf74f4d2b8663e6f291e9e25436e7f": { + "balance": "10026444446000000000" + }, + "564423f92b8841b3b1f8bdba443067b580916e65": { + "balance": "465451550122000000000" + }, + "56730e1d11a84970355c43ac7659f2f4786dadcd": { + "balance": "20000000000000000000000" + }, + "5678851984add045f3d054623c198dfd4665d54e": { + "balance": "227651903234000000000" + }, + "569cf18b4bcb99e3f3d27235f2c4c0d8d160af03": { + "balance": "4124979731000000000" + }, + "56ac5f2c3486a9ce744a71599ab89a606e7464a7": { + "balance": "9000000000000000000" + }, + "56bc5936a6ea37c1d0839bf64bcec0d366840ace": { + "balance": "14741201469670000000000" + }, + "56bf62e0135e903525cc46b0a3cce33f4a16880a": { + "balance": "534970476270000000000" + }, + "56da0781a80a0abf5dcda4da35861e9de601bfbb": { + "balance": "166898390441000000000" + }, + "56db15729e52d615a744a04f8a59d63e3b9f735b": { + "balance": "10000000000000000000000" + }, + "56e32ed78e7f5be6b00c28847efe7b3589cdae1a": { + "balance": "1046236086484000000000" + }, + "570f7a08150e0088178276f8116bc4103f885903": { + "balance": "1124393518440000000000" + }, + "57147fdd9b52ef53b4ebd4b5712d29da83f99374": { + "balance": "39000000000000" + }, + "57395fb355fe51f1b32c1baa4e9ee0fc2b8fe05c": { + "balance": "7701013675397000000000" + }, + "5752f0f11ed12bb1d5041b0cee4ddd500cd8806f": { + "balance": "151337200533000000000" + }, + "575907d73ad5ad4980a2037efbd20860afc67ad9": { + "balance": "3568754158000000000000" + }, + "576acb4c0bccc89903ad285ac08c70fde514aaf2": { + "balance": "25000000000000000000" + }, + "5784cb8a17cfb5392c4aeec2edbd173849ca6ee3": { + "balance": "15804767597000000000" + }, + "579234645eb857a3ca51230b3a02b964f8efa2f6": { + "balance": "20576922380000000000" + }, + "57989f9fa52b4c0502e7d0c3caac0c37a0b20516": { + "balance": "462711082812000000000" + }, + "57a55c376ea03c22e21c797d83e2fb039508ad3c": { + "balance": "10000000000000000000" + }, + "57d1612ea1fddacf088b62f625ad8cd49d7517cd": { + "balance": "18001023230648000000000" + }, + "5811590907050746b897efe65fea7b65710e1a2c": { + "balance": "310984892882000000000" + }, + "582ffd8c43966aa8ad3c6cecdfc18eddc56fe5c0": { + "balance": "69136214255000000000" + }, + "583b90b3c4d00b9ddf101efbce75bb811d969fe2": { + "balance": "7839200298177000000000" + }, + "5841fee8b1965141e51b8c146b6af00f6a879a8c": { + "balance": "1210322907244000000000" + }, + "5847a576f7799ba1a35e36906b2c2a5aadeb99b1": { + "balance": "183765768447000000000" + }, + "586dea7ada0a54150f5afcf54198db473ed046a2": { + "balance": "7123598380000000000" + }, + "586f545062ec7dc0ffc213eacd59af80660df570": { + "balance": "10000000000000000000000" + }, + "587187488758f67912bd5bb8a5be787a73d97ee3": { + "balance": "702757402654000000000" + }, + "58be0a3482dc3411571f047f4128387049cb9798": { + "balance": "1000000000000000000" + }, + "58d546e2ae82efc4d8efc887ac6fd30f7eb5dac6": { + "balance": "1486717153455000000000" + }, + "58e7010e6b8d97a556c0e7f0d90151224ebf674e": { + "balance": "20000000000000000000000" + }, + "58f991b3b12d29f09ff4cc2c6e83d576e95b1f59": { + "balance": "25000000000000000000" + }, + "5923a65a796934e69081715657e8dfec8874e40d": { + "balance": "10000000000000000000000" + }, + "593b7c43073b8954355ed76020ff3780dd6ae783": { + "balance": "1403468567787000000000" + }, + "5947f1dbd79a622bcc3fa64b19f9b6eda164dcce": { + "balance": "50000000000000000000" + }, + "596311e2fc09ae1eaee57900f2ca188afd5e68a6": { + "balance": "448723397560091000000000" + }, + "597a3adac4607d457c90817220f67eb4abcf129f": { + "balance": "18000240000000000000" + }, + "598201a9bcff0a773e9323338a8a094e9d9b3999": { + "balance": "74904485722481000000000" + }, + "599e93031704c2ce36308f44d4ff8166e71ae516": { + "balance": "100000000000000000000" + }, + "59af0178699f9f3d8f0ea645dda75356119a6e2e": { + "balance": "152462578058000000000" + }, + "59b0c06e40475cd75728797add9c69c3fdb17b4e": { + "balance": "23147237210000000000" + }, + "59b79577f183b9d39c2b458646a26b2fd6ed806e": { + "balance": "4244859516807000000000" + }, + "5a03b51d67a9c660258ebc030120d5d1d4f687c5": { + "balance": "4451691855300000000000" + }, + "5a0d03dff6754963c757eb15a3339ac6c4ba6196": { + "balance": "215126489934000000000" + }, + "5a34ab3937854e407a8739fa14574d3d20e30d6f": { + "balance": "1375979293937000000000" + }, + "5a352fbeb2fd78bbe0268b0efd34f68d401e2769": { + "balance": "27929247671418000000000" + }, + "5a47c2ca4c0fad7e2fc7bbdf5f2356d68843c564": { + "balance": "3218227936000000000" + }, + "5a538adb2c7f6a80634b0ec20ec5152ff6bb4d5f": { + "balance": "10000000000000000000000" + }, + "5a8fe770c221072a7cba79ae7759cae0185adde7": { + "balance": "11913943233694000000000" + }, + "5aafe1efac688583d7facb09d3e569d58fb5a357": { + "balance": "4713219466825000000000" + }, + "5ab68d762750d5185138187db7751c9f71db5836": { + "balance": "500000000000000000000000" + }, + "5acab69851959dd5a6f0673ef757009ed36dfa3b": { + "balance": "974443209942000000000" + }, + "5ad9f2ab11b5e59b756404395f350aad6019d7a7": { + "balance": "54151179981663000000000" + }, + "5b1dc013ba1a28235cc70e785a00eff8808faef6": { + "balance": "516289257133000000000" + }, + "5b1eeb44ef61c7f35482503b7041162bec9b1e32": { + "balance": "125493885394000000000" + }, + "5b3db31996bca4625d22330686128ec234270206": { + "balance": "362316593128000000000" + }, + "5b401fc9ff3be7cdf5f0df870843bbef94f43285": { + "balance": "1373804724122000000000" + }, + "5b47ba296069041f25768e61be14437b8a469e81": { + "balance": "3152706392234000000000" + }, + "5b5030b5057c0457c190489c5d709d7dbdddee8f": { + "balance": "1154404278000000000" + }, + "5b5a4a782d37154a307868cd79bec9cb2a8f0161": { + "balance": "100277816425153000000000" + }, + "5b5e0b6b7cc27b06456ba4c7816ac4e89e1e26a3": { + "balance": "1023749119000000000" + }, + "5b638e4b6dfdb6928b07586e63d5879dce69a1f8": { + "balance": "1000000000000000000000000" + }, + "5b7be81d6ff5228a2b8c2913deea3f86823f1dee": { + "balance": "36000000000000000000" + }, + "5b7c4804bc2b8c72f3112b73d44b59c0711f83cf": { + "balance": "6803857604000000000" + }, + "5ba26d941544d07100744d8ffd6595a8eb7770bc": { + "balance": "583051897662000000000" + }, + "5bd58fc88733632b63d4f26893bc5c08fb60e2ad": { + "balance": "3480620567502000000000" + }, + "5bd85b5f0ecad08133fceb486c43998e537b3451": { + "balance": "484263880245000000000" + }, + "5c12639a5ab107f9e580cbd2278568dde10758d6": { + "balance": "101293252434000000000" + }, + "5c5522df05d6c6d960394c4762599e74247ab102": { + "balance": "149088856773000000000" + }, + "5c722f3ac94421f95389756af9cd97d0eaa6b696": { + "balance": "1435349483553000000000" + }, + "5c7b14ce51abf629bb0953ee4e2d9d87fc86eb4d": { + "balance": "10000000000000000000000" + }, + "5c8b215403da4e7912c1a1704a949087e091b111": { + "balance": "1440961256910000000000" + }, + "5cab313964f6730888e4158234bbd4806db0286e": { + "balance": "32284637230203000000000" + }, + "5cd736bf65c99469490d0523b10a658178cab10b": { + "balance": "99740204082000000000" + }, + "5ce91ef7ae254b2bd6d910cbf0d380814200811b": { + "balance": "50000000000000000000000" + }, + "5d15fc3a0ba8b3d87b80f9bbf972320112c644f9": { + "balance": "64000000000000000000" + }, + "5d2ccc795b19df400f21f24c0dca4d0e9e898093": { + "balance": "10000000000000000000000" + }, + "5d879b8b31af1e400cf53eb7170f82583190b96f": { + "balance": "93765337844000000000" + }, + "5d8dd54178b68bb36e1963d47d29c123864fd0ef": { + "balance": "20000000000000000000000" + }, + "5da1653bbe8353134edfff6158211ad7ee21dbef": { + "balance": "1491149937915000000000" + }, + "5da733ef41a7bdc0cf7975f83ed24604fbb4d40b": { + "balance": "10343699901151000000000" + }, + "5ddf5d7306f7c603b8d3ff993f03906dca14cd8b": { + "balance": "862558469755000000000" + }, + "5de87ec54e2160c7c2a8eff2d859414737501ae2": { + "balance": "21579321171000000000" + }, + "5df1b805b1361c1f39ca844aebe5ecee8a8d06b2": { + "balance": "411820472746000000000" + }, + "5df86b0a183b5e7f702e4da582ce9a8116a05f61": { + "balance": "256000000000000000000" + }, + "5e22359e20dc14be6930c6c1ce5a0c81c039cac7": { + "balance": "10000000000000000000" + }, + "5e2d38a06f33c784303abf2012f9af12622d9e5a": { + "balance": "10000000000000000000000" + }, + "5e479e616585e7fa84bd6f7465d394a1c0302be7": { + "balance": "10000000000000000000000" + }, + "5e4a55027a0d372f6da042b7f73720b143347d9c": { + "balance": "16175516772000000000" + }, + "5e52e86eda3e05f96e353d7e3f0ee90f08864f84": { + "balance": "21255916842000000000" + }, + "5e91c4d3a21c9dfac2c0994ed8890c78d58626d5": { + "balance": "325349462011000000000" + }, + "5ea797b18caba45d5504e57b80b12f5f5ae630aa": { + "balance": "7805696321000000000" + }, + "5eaec8815e859c34dba88cfe7b7fe28572c964ba": { + "balance": "145852682588000000000" + }, + "5eb974b5716fc4712d431bec7fbb2c49057a7b84": { + "balance": "4890681156035000000000" + }, + "5ee5f8407dedbac839f509419051106219458006": { + "balance": "3042761975468000000000" + }, + "5ef782abb28d1ca889ceb3039eef98713effbf32": { + "balance": "40915083108000000000" + }, + "5f23b88f06430c42570ac3fa33b1c7503b388a3c": { + "balance": "2376070180325000000000" + }, + "5f2b1641c0f2605b090039851aacf297e35632ef": { + "balance": "141615261000000000" + }, + "5f44cc8083340e644d19d3debc84dc14a0cbc53f": { + "balance": "291829106275000000000" + }, + "5f633f89adcc70e9da0b66611a5da108b4b221cd": { + "balance": "50835573000000000" + }, + "5f94ef8e9612b03a5c6ffcf423ada9a19a40818f": { + "balance": "102566595099430000000000" + }, + "5fae1977b76a5e899b384f572e4d94855f9cb52f": { + "balance": "773616125740000000000" + }, + "5fbd22cb3de462c794e523fd1ce36f230cc84b83": { + "balance": "1009995132839000000000" + }, + "5fd91676bc95bd6b5e69db8b9216dc83ed9dddaa": { + "balance": "1000000000000000000" + }, + "5fdda8f5271a08cf1b830faa497019d75fa9d231": { + "balance": "4149626365000000000" + }, + "5fdea351c5eccedf2394fb54437b149ae423ecf3": { + "balance": "100000000000000000000000" + }, + "5fe70ee123cb2e03c768138b2f71c1e1ea75ad17": { + "balance": "1074496282650000000000" + }, + "5fec9df797214459f85a040a559b186ee9161c88": { + "balance": "205282872821268000000000" + }, + "60037df7e4092466656a6b9571437fc4600c66e3": { + "balance": "1000000000000000000000000" + }, + "6009a0bcf531640a5a7f1664a69fe0f64b564ede": { + "balance": "50170000000000000000" + }, + "601668d8b678c95ec5ef98d9d2624decbdd52e9b": { + "balance": "23592727870000000000" + }, + "6027bafcd0ade24fda8c345dcbc812d59df74bf7": { + "balance": "10000000000000000000000" + }, + "6029514f24825c1fadc68cf8614951de5d53268f": { + "balance": "1389262963614000000000" + }, + "606de6db14272a314d778cf0e67913b7fabea45c": { + "balance": "144000000000000000000" + }, + "6074f20675f975ae2c081930cae8f299710f0bba": { + "balance": "10000000000000000000000" + }, + "60850fa9e09d414af3690e4b5daefb1b906b0d20": { + "balance": "10000000000000000000000" + }, + "60ad0b6239dda5df7ac0f0ca941684cf20ae0fd8": { + "balance": "81000000000000000000" + }, + "60d6136e6db631be45fefb9667c3dfa69e9d6054": { + "balance": "651902184266000000000" + }, + "60d733dedec6886908520ba57cab8c9d5c2d7f7a": { + "balance": "555461746642000000000" + }, + "61202238aea4010d115c5c64322ad790576cee43": { + "balance": "10465801848035000000000" + }, + "6142d92b61111657de4b2d65698a3621411e3adc": { + "balance": "100000000000000000000" + }, + "61879bc1a022d9cac8b7d57c8f528065beb10bb2": { + "balance": "72766025231000000000" + }, + "618b15c9a60ad89e7fc28afc79bbf7f28d4998cf": { + "balance": "444855210015000000000" + }, + "61c1169e8ba43ee6b919e5be2eac19542eb913b4": { + "balance": "500000000000000000000000" + }, + "61f1cd6efce17f5458325f022f363fd9772d8f20": { + "balance": "19704989598372000000000" + }, + "61f7d39211a0af2e226d8cbc95fb673168653b0a": { + "balance": "484884476279000000000" + }, + "621aa67f09e6506efb2fd141f080fb1d96693a57": { + "balance": "1694451603196000000000" + }, + "62332fa5127b98bd2a627a0ac22d3a1bdb418efd": { + "balance": "926882233406000000000" + }, + "624a465696ad409586a2e67d84750ba50a971fee": { + "balance": "25000000000000000000" + }, + "624d866f0d61bdefc3ec2210bfe36b6d51018f9c": { + "balance": "199592183194000000000" + }, + "6255d6d3b49443891661b209056d530ecd63bcca": { + "balance": "10000000000000000000000" + }, + "626c484055e6739d46e2ff25190c8b3a4af3fe0f": { + "balance": "1485276462321000000000" + }, + "62865e637d723393ab9654d6439db7fb5abf8803": { + "balance": "10000000000000000000000" + }, + "628a47761d5ce755de88444aaf6d7736b911672f": { + "balance": "18625552918216000000000" + }, + "62df6a38e8b15a1c4f4a7aa7c1736c612f54a0e4": { + "balance": "16468111299582000000000" + }, + "631d7916ddbb5f7c469f8ba07cd48e377560319d": { + "balance": "2493487426430000000000" + }, + "632754f5afcae7dc36d9286cfcd91c14abf0f7bd": { + "balance": "1424933496931000000000" + }, + "635788343997ea9f145c508b0cd2ed36e180f46d": { + "balance": "143040938538000000000" + }, + "636973e7dbda9e3042a8c03e25696d0faf27f025": { + "balance": "5491869128148000000000" + }, + "63707efa26d34d7ceadf4e6439324e7bde0ebc3f": { + "balance": "1000000000000000000" + }, + "637d92494f7872d397340c9b5183dce354c8c43b": { + "balance": "724687404033000000000" + }, + "63b9c2e6762a431752f7669b8bbedae9f37120b3": { + "balance": "1360967549741000000000" + }, + "63bd281d8c4d1279519237a2b68f2a73c228f7e1": { + "balance": "217457311664000000000" + }, + "63c0eb8c9a0019e36ec9a731b4bd947271a5bed0": { + "balance": "36693488147419103230" + }, + "63c6362eff56de328a29b7e9d32ced28f3602b6b": { + "balance": "148335309448000000000" + }, + "63c979c787a7b037693cadfeda738ae33178c009": { + "balance": "81000000000000000000" + }, + "63d4621d91906215d32f6fbcee1ac48bd773f630": { + "balance": "1006939236069000000000" + }, + "63ff99fec1cbd2f6e83c0e6de3c0ea4b7c7e1398": { + "balance": "1201300688980000000000" + }, + "640ffd856e48528b05d5ef1e60348048ce291960": { + "balance": "20000000000000000000000" + }, + "641c25f7c380e2745c81a268384a029b2e2be0cf": { + "balance": "635133477665000000000" + }, + "6427792a164bbeab45f6c3acf17c76f721b90e81": { + "balance": "10000000000000000000000" + }, + "6437986b4c545af9c4a5ee96371a5807275e9221": { + "balance": "2951152516627000000000" + }, + "64460d09d1bc5c425d62bef5969eb0c5916963c3": { + "balance": "1680000000000000000" + }, + "646381f92216b97abbd86ca100a773eebdf7545b": { + "balance": "211234535515000000000" + }, + "649f73d1cafeb3ab0631432f04c9d08b9f438c22": { + "balance": "248900746448000000000" + }, + "64a239be45a92df83bb85b25f8ed7de5d82313b9": { + "balance": "100000000000000000000000" + }, + "64a3d97f82e3d42eea78bbcee31a95d33767b055": { + "balance": "2511466286000000000" + }, + "64ad579975888f455217e0f801e371900d9814c9": { + "balance": "7118859416319000000000" + }, + "64af5edbfec8adea679951662c08a781175688bb": { + "balance": "822966999709000000000" + }, + "64b7f2c22c20a59c07cb0dd7f8f692153c68f3f8": { + "balance": "20000000000000000000000" + }, + "64bc17e28d468b7b8368ee8a8375710d21c3ac5d": { + "balance": "875002262415000000000" + }, + "64d17aa662e56061cebb3c2e2421e637163e8dd3": { + "balance": "363241251465000000000" + }, + "64d714ec3145308e8f939bab7591b0773038b886": { + "balance": "338231954012000000000" + }, + "65199fc9ba95434382c108b44ac553534a9a3670": { + "balance": "2537340957145000000000" + }, + "6527c67c29e47833dc2440570596023318a7bd99": { + "balance": "555434226832000000000" + }, + "654b9d299077c90768c5ca6635e5802e8099f51a": { + "balance": "119004827465000000000" + }, + "655908513607cc38de35351ff3738b201bbf39d4": { + "balance": "652902936029000000000" + }, + "656ad16063b2d397788c231e537384ece94eb0d2": { + "balance": "63116382606000000000" + }, + "656e622970b8829a7cfe24f5b82696c7777683ba": { + "balance": "20390269890405000000000" + }, + "6583a6ff4dfcf447e3b163a61b0d5cb84ceee375": { + "balance": "3858529344000000000" + }, + "658d2b7e8a6517256efafd74321757d5c384a2b9": { + "balance": "221114751567000000000" + }, + "65920758857ee5b27b0f31487ccc3c5d6986df3a": { + "balance": "16272975796000000000" + }, + "659d60d67a07774ecc5cfea9e56809bec024d639": { + "balance": "20000000000000000000000" + }, + "65a1a3f968bab5fc1f097b8e297099a3d34ef45a": { + "balance": "16000000000000000000" + }, + "65b5e3163d20b2a6fc75c0219b7f97d83479a26d": { + "balance": "1716459529041000000000" + }, + "65c9bc3b8b0ce7c4d16b35abe1a5c285a59f672e": { + "balance": "20000000000000000000000" + }, + "65d5b458d9b1a9659c1125d20d970d5e6c29dc3e": { + "balance": "20000000000000000000000" + }, + "65e75bb8ade25eb7975ea12b9afdb17ac21063b3": { + "balance": "2270407774714000000000" + }, + "65ed78d0c4ef1150e8765b24b210f056e079cd59": { + "balance": "500000000000000000000000" + }, + "664ee5e334b8378928becfbf5d5e51daaf001125": { + "balance": "860160259186000000000" + }, + "6679bdb26adc179d046607d49f4b10c65d8a40d1": { + "balance": "436794739763000000000" + }, + "6680fe9d6eda3ab9fc4ac1ac933339b533eb682b": { + "balance": "551296206326000000000" + }, + "66a1249501cc5076b040bbb165ce032ace216ea2": { + "balance": "36000000000000000000" + }, + "66a475d014c2f976704bfb93ce78dbabbfc5e072": { + "balance": "1140135640169000000000" + }, + "66ae43d92e8fb2231fee8c72d720ff90cdd267ff": { + "balance": "796696150339000000000" + }, + "66b7e0c810d6959afa8210f6ca67e3e40bd24eb9": { + "balance": "16000000000000000000" + }, + "66bf8be16f33b111b2a425743bb7ebcdfbb35034": { + "balance": "538590591000000000" + }, + "66d2eaf7fe10900d93eab17823ebfde5486aa2b7": { + "balance": "121000000000000000000" + }, + "66e525bb01b3ede1a4a105bb6087ec8a76200616": { + "balance": "1506610219207000000000" + }, + "67291e0df83d6e9f1386e87a1792d7d147341df9": { + "balance": "272330177662000000000" + }, + "6730b27b62e064b9d63df3bcbb8c4bbb0e500afe": { + "balance": "331282968154000000000" + }, + "67318617bfe19b739fac9a126fd129223db52498": { + "balance": "12699924981000000000" + }, + "674dd0b036c91f3a83288af44897b4ceb2e15a12": { + "balance": "4352791270187000000000" + }, + "6751bffd04be55c86692994fed06694cb78b62ff": { + "balance": "26049487516000000000" + }, + "6768d99a0cdcd7bb7c7d0aeee466d6bdc7208bbc": { + "balance": "309909685000000000000" + }, + "677ba2de3e5c68a4c354c9e3129ed1c41025312b": { + "balance": "127426274611000000000" + }, + "67b83745856551f1878027843be20e1473191944": { + "balance": "185757248875000000000" + }, + "68170edcfaf2c6df4e6542b2856ad33e9e2d6623": { + "balance": "4003453949471000000000" + }, + "684ae403d9a08e4f4f971cfedf81094074daa77f": { + "balance": "25139713925794000000000" + }, + "684f3b8a749c002aa434bad6af7a3e2579c69315": { + "balance": "16000000000000000000" + }, + "68538a9e8246be5a5c5ea315cb325344062cf8c4": { + "balance": "14009193210480000000000" + }, + "68935ff3a3a3b6ef16ae7df58cee50b157658dd2": { + "balance": "20000000000000000000000" + }, + "689f508256ea64f5dbd6bb77f1ce1bdaf36d7152": { + "balance": "10000000000000000000000" + }, + "68a3e6e7c191a8c1add988bfbbb9b51d4f36f521": { + "balance": "10000000000000000000000" + }, + "68a74ff2a5577321f854b56d3834a55d3c41bd94": { + "balance": "88873831171000000000" + }, + "68e6da521bde13cf4e4f423a78fda2f69b3d1c2a": { + "balance": "538392460838000000000" + }, + "68ecd5cf8cf8d9704fafc36d8da53930afeb0553": { + "balance": "1090923641219767000000000" + }, + "68fd0b8e000bd2788be6cb10fc0496fe2cbe155d": { + "balance": "32853847745000000000" + }, + "6904045feb5ef94e096894b863d314ff8a0f206b": { + "balance": "9892165615000000000" + }, + "690fbae5153849bb20797af7b8dea66a728a06c3": { + "balance": "6082107223716000000000" + }, + "693d909842877d017e0f102e37a55024517dd0ae": { + "balance": "20000000000000000000000" + }, + "694cd00fac9cded484ef2cfcd44faf161354f288": { + "balance": "3049716150137000000000" + }, + "6964c3c2c7bc719ec94a51bc4bf412e137d2b4e9": { + "balance": "1000000000000000000000000" + }, + "69a5c692516940bebad8efaa2243a8fbdf2ade62": { + "balance": "2803346939929000000000" + }, + "69f566c44802b0140f5e1c9234f46006773c03d4": { + "balance": "20000000000000000000000" + }, + "6a17eef3a6bd407260f52067592226448182cdc3": { + "balance": "1116509364305000000000" + }, + "6a200e99a0f50aab32fa7373c7880817c81f472a": { + "balance": "1836680122795000000000" + }, + "6a2a29f5f441876816dd17856051040787f48a64": { + "balance": "1131603204000000000" + }, + "6a3f855c7dceb75d0de7fa18fbc2f40c81b76756": { + "balance": "32267494586000000000" + }, + "6a46af653b938643e781cc4a0edcf5357852fd21": { + "balance": "1140718780752000000000" + }, + "6a4b2e5b45da0d70621ce71f165a11078a1745e2": { + "balance": "3768326643000000000" + }, + "6a530c813595a5b7776cced05a865dedcb110d94": { + "balance": "270559347097000000000" + }, + "6a6e3e82f98ce891f47721770301dbe2652a9e25": { + "balance": "10000000000000000000000" + }, + "6a828d6f2f7f68bde4a12608024020e593540010": { + "balance": "7531817000000000" + }, + "6aaddd1f4ff6b4d414c87271619b826ead27f09f": { + "balance": "64000000000000000000" + }, + "6ae6bce1e2865ade0d02eff9899ea3767b5511cd": { + "balance": "6893781798524000000000" + }, + "6b04e7c6a837d218fd3322b87a267fdd979358ef": { + "balance": "302679180175000000000" + }, + "6b2210b8536803b134e69c5046904acafef48cdd": { + "balance": "47823456459000000000" + }, + "6b2da6f36c2e7f61cabd7580480065360c995c93": { + "balance": "55000000000000000000000000" + }, + "6b3401986f2be7ae5a4ec160b8f96b2a651fce73": { + "balance": "16000000000000000000" + }, + "6b3847774e99dec307dcf5bf5adba49df4a9f145": { + "balance": "43276069579000000000" + }, + "6b57f2d9d95cac67fd2f70c0911d48c7f09de072": { + "balance": "1000000000000000000" + }, + "6b65d736a8ca89ec8508b52e4aca5166f9703732": { + "balance": "766421968820000000000" + }, + "6bcc55d897829e98fc3f3ac8beb331e59c33b942": { + "balance": "318115956882000000000" + }, + "6bd76e7af1775b88743d5f53ede0ce846d3d7ced": { + "balance": "139548017482371000000000" + }, + "6bd7cca99acf6eed5842417c2327c642df5473fd": { + "balance": "3321731000000000" + }, + "6bf72c4d39d6700181954a8d386c3df216634412": { + "balance": "12742769034078000000000" + }, + "6bfd3aedeac7c6ec086c0a4ec29d2d0f5bd69bc5": { + "balance": "50000000000000000000000" + }, + "6c025962810a6fb8374af5e07d7fcd631d10b1ce": { + "balance": "674126722005000000000" + }, + "6c1b72df836f410038af9e020fa2ff2ead398ef4": { + "balance": "1851293017364000000000" + }, + "6c1fddb4254ff46b3750de322ebb7d6238c0a606": { + "balance": "9977629348276000000000" + }, + "6c37069a361c5c72355bb5a56879dd0a9735a237": { + "balance": "1062230154063000000000" + }, + "6cb166eeca248a234c971b2a864a7b3fdbe5a737": { + "balance": "390222992865000000000" + }, + "6cb797289059cadcfa77eab0365e6bf1ae12df46": { + "balance": "100000000000000000000" + }, + "6cc787e6bb4f484828b080330667b93953e7a3c9": { + "balance": "16106440380234000000000" + }, + "6cdf7b334fb2ef8115198d475d431eeb7d88df77": { + "balance": "1940904395351000000000" + }, + "6ced85b035b787e9e427d0904aaf96e011417310": { + "balance": "103417697874000000000" + }, + "6d6e09acc07f388cbab99e53959f75e9ad8f07bc": { + "balance": "1305917678000000000" + }, + "6da91b02f512f412d374392247a9aaa853e9dd59": { + "balance": "2300525907893000000000" + }, + "6de5d70481cd40db468f64227228cdd362ad9980": { + "balance": "10447389944082000000000" + }, + "6dea87255c9ebfa63f017209046e894ecbbc03b7": { + "balance": "1527216854064000000000" + }, + "6df6f6b9953c2f2a8ce5985e19dd6835ae2c566c": { + "balance": "6539856530000000000" + }, + "6e013c83cac111a38fbbf8d47778fda0d3af25d5": { + "balance": "12139181929380000000000" + }, + "6e18a484f402fd433a5ac4dee5a4b8bf6f22db47": { + "balance": "23215906572368000000000" + }, + "6e4fd058e4dcd502c2015f83f3677f680ec58110": { + "balance": "480059342014000000000" + }, + "6e501ac7357fc758caf5dff6c29a995c806a1a7f": { + "balance": "1573491311733000000000" + }, + "6e6912f9fc21dfba736055e6ccef074dd62dcc59": { + "balance": "256000000000000000000" + }, + "6e869c68511c1458f4fbed9a4c5296fe961eb47e": { + "balance": "68488423994541000000000" + }, + "6ea6827b377b3d3ecf7c7628ed8daad7fd8eab1e": { + "balance": "188825714738000000000" + }, + "6eb9237738339fcaad3763466509f23efd0c5054": { + "balance": "48417242786000000000" + }, + "6eb92a61390f9d9ecdac80a8833aa801c3926b13": { + "balance": "1412936326723000000000" + }, + "6ecb93f18153ef2d2a552286ea3b7436f1f8168c": { + "balance": "20272577229669000000000" + }, + "6ee087c04cf16f4768c783a548686448fd125914": { + "balance": "1397039628538000000000" + }, + "6efbae7a34c71233329d0bb4cbec45274824ebf4": { + "balance": "8910000000000000000" + }, + "6efcd6776f287c25a6eb3cf71018adc282eeab6d": { + "balance": "1310659853178000000000" + }, + "6f9ca805ddaaea5205e85778dedb2eff4a5aaa75": { + "balance": "2585733757016000000000" + }, + "6fbbea927469f4d18942ce0aade164828fe23a2a": { + "balance": "4671857880000000000" + }, + "6fbe9df6c42151c453502960d99170445dd3ac0a": { + "balance": "20060296562115000000000" + }, + "6fed121fb310431f1659e637f35f4c878a7256c7": { + "balance": "55170085399000000000" + }, + "6ff2dd5373bd72966ef48d3183c60d74a6549cb9": { + "balance": "24103445361000000000" + }, + "703a490c4783776da244384c964897491aed3711": { + "balance": "2001677632732000000000" + }, + "704dcd2d9f75f0bbfb73f2fe58bcbf4508374381": { + "balance": "439603954369000000000" + }, + "70859a14f33b8ab873fa5781a4af1ce40dff65c0": { + "balance": "10000000000000000000000" + }, + "70b9cdfa5f6d41c60e1c0d3f544f569c9b340ea2": { + "balance": "198355566698000000000" + }, + "70d0ee793e28e320b34267ef2df69050fca0a9e0": { + "balance": "8010660534227000000000" + }, + "70dc7e5951752c22a0e3c50e8e7b1f7af4971d51": { + "balance": "3991137321749000000000" + }, + "71057f5afbed7d82c92d50790e3797fd7395d036": { + "balance": "49000000000000000000" + }, + "7109a3b3d5d6af49693549728691099d696ce016": { + "balance": "4119694297000000000" + }, + "712231a5161745fa1b33c7b0f6e8c767e1de4f81": { + "balance": "1353809351914000000000" + }, + "712aa38999c0be211654e5c84f59e3b2e018f597": { + "balance": "160199774000000000000" + }, + "713229fc94a86b71a5bd1ea6498b9373e3f3c549": { + "balance": "98289185940000000000" + }, + "715de29a0b6f467b94d4a90dc767ad52d0fb3b9e": { + "balance": "948824982990000000000" + }, + "71776853ac97ce04b008c9a7b64156a3cafc52a4": { + "balance": "608309596513759000000000" + }, + "7189f6dcfe64e1ddbfb5e51fd5f3174bc636dd0e": { + "balance": "5674608906899000000000" + }, + "718a4da87464caf6e83ca374d5ef9255b8f7cc3e": { + "balance": "761891873568000000000" + }, + "71bc447761cdb68915cc2288b4929fdc0adce02d": { + "balance": "10000000000000000000" + }, + "71d78531896642069b725bf82fc385789c63217c": { + "balance": "33103960195000000000" + }, + "71e328deeafbb1724051d1062609c43eef56ecdf": { + "balance": "493550967964000000000" + }, + "71ed0310fb51b86a61794aea17a3c792dd301e3c": { + "balance": "3234918634449000000000" + }, + "71fa264f58041e41cfe36e8f8d4e0cb22ab71925": { + "balance": "5558941960000000000" + }, + "72059c57d0fc05bc02ba54ebea6cefd1efbeadf1": { + "balance": "4458278271443000000000" + }, + "720847a28916a532bcab33e1fcbde5d1c4d820bc": { + "balance": "1392418942284000000000" + }, + "723cd2b5b836b0ee8481d37b9c51b5f3f1beddd2": { + "balance": "1856420455522000000000" + }, + "72430c6664d23c7051b0e99912fa54dfadcfdeff": { + "balance": "102078926010505000000000" + }, + "72652c4320dda25348f15c0ecfeb4b3b3ceeb7c8": { + "balance": "307639955659000000000" + }, + "7288bd1b9f4c068dd5df9bcd6fec1ccecd240195": { + "balance": "80161087899000000000" + }, + "7299cb8a288abe8e1a22c11b53a903acb7db5827": { + "balance": "752198565719000000000" + }, + "72f6bc0c3ae437756c099e02e9c084febedc5569": { + "balance": "696294297587000000000" + }, + "730e5907b344c80e0a6115723a90a23e3635192f": { + "balance": "6056082041729000000000" + }, + "732e97b992e4f8a53034cf29cf11aacba7452261": { + "balance": "100000000000000000000000" + }, + "7339df65ce293b3d501647a04c83819099f0bd38": { + "balance": "706500983417000000000" + }, + "73482f8135ca2231db5e0e034a235a9d244a8656": { + "balance": "1143989148865000000000" + }, + "73769e43058d30a530048e5a2bea7e9333534e93": { + "balance": "113542901996000000000" + }, + "73bb9e6f1709fbb7964df7b3cc0f9170c3152f38": { + "balance": "1639793026701000000000" + }, + "73e261da7978764044ee916f88bf66680952607f": { + "balance": "100000000000000000000" + }, + "740154120c4f41c50b0aaa0636a2000ff1e870ad": { + "balance": "10000000000000000000000" + }, + "741fe2a1537284b70e97e3ff659eedfd7fc5b1b6": { + "balance": "75911502037000000000" + }, + "7420bb277d834763e4429db9bf37f053f71ab769": { + "balance": "3100160195046000000000" + }, + "74281371c3b569c774da6bab686e7d7a45d4dc4c": { + "balance": "25666397941223000000000" + }, + "7428d261b5418652c5ab248d6abc3d2af25d904a": { + "balance": "56252809397000000000" + }, + "742c876433297f5a8fd4a25f75ee9a607726bd3c": { + "balance": "4132793019677000000000" + }, + "74302036cf52e11aa3f32a371bb4992e2bdc3f39": { + "balance": "19557661364000000000" + }, + "7445c657c24d014f3a9dddc3e446868bc2dbd13e": { + "balance": "10000000000000000000000" + }, + "744b8fa69d2542be3557267edaeaf2cfa8a9e991": { + "balance": "16000000000000000000" + }, + "74728999963524e7cc1736abcb4deac630142c44": { + "balance": "37000250991000000000" + }, + "74926cbdacd0e871cad0d926c8e17cb2c00475b9": { + "balance": "20000000000000000000000" + }, + "749e115a9e675bb15af5e1c04f81fede07c40120": { + "balance": "440913547154000000000" + }, + "74b7e01acf825898544d6c1b61e53356be759c56": { + "balance": "25000000000000000000" + }, + "74c5fcf875e2e9b726a7cf6e176dc2f7eb84c200": { + "balance": "59208835472000000000" + }, + "74f44579859e4a7944dda7bd810088e116ae9910": { + "balance": "1038454108527000000000" + }, + "750b1e2955ba05c1fc8a1f9dbb1624ed11587edd": { + "balance": "9545712605000000000" + }, + "75375129cff2a051f656b91f868325c3b35ee1ae": { + "balance": "25000000000000000000" + }, + "753ca28fbd89081382a996fe938da7e6c3ae6cfd": { + "balance": "156582454263000000000" + }, + "753d91c04e554680cc32a97c1abc96280e8263ee": { + "balance": "725101425969000000000" + }, + "754e5b5d64c267e83fd4804d112725531cf5abe9": { + "balance": "83276113115000000000" + }, + "7588a96a2bc65569a6c124c4a4acc55863a8ab78": { + "balance": "24062602342000000000" + }, + "759075dc3a6b9d2499a74bc57e346c9ed7ff834e": { + "balance": "225000000000000000000" + }, + "7591d6fa043801fe12462e11d9e33a53f438c073": { + "balance": "1863874274000000000" + }, + "75bda5bdf6aa749bbd62b6107941a7dd9ce3880a": { + "balance": "36000000000000000000" + }, + "75c2d3a99f144c4b9962b49be9d0a81b203906e8": { + "balance": "9000000000000000000" + }, + "75f587a69a97eb4d1c4c4078418d5fa85dff6f94": { + "balance": "10000000000000000000000" + }, + "75f67649605f49d98d866102ea2d6881ead9bea0": { + "balance": "814929108418000000000" + }, + "7602abce0f510b6ca471fd8d734e21a2591886f6": { + "balance": "50000000001006000000000" + }, + "7629b788160531b0be28bf445bf305fbe2c514d2": { + "balance": "23022256366212000000000" + }, + "762aed2e3aa2293e69dc2110b1fc6c806ae799a5": { + "balance": "10000000000000000000000" + }, + "7637b89130bc3f87e90c618fd02d6dd27179101d": { + "balance": "77765738300000000000" + }, + "765136022facade53e7a95c0c7aa510787e674d5": { + "balance": "1478178932688000000000" + }, + "765274015a308a9e6b1f264e5bac592d267f2f7b": { + "balance": "3058788819393000000000" + }, + "765cbc0a89fd727a2c1a6b055139faee53f11330": { + "balance": "500000000000000000000000" + }, + "768bb6d4b190c18a0946d92073ee446d68d98a6f": { + "balance": "144000000000000000000" + }, + "76ae8079894c760f2850c02cf5a0d7bb41e5864d": { + "balance": "156059816821000000000" + }, + "76af4103a231b1302d314c486a0ba524d0427899": { + "balance": "10000000000000000000000" + }, + "76b6394cd02ddf761e981b6a6ce1654c0e575443": { + "balance": "1078304803757000000000" + }, + "76db33eafeaf965dcf15d5460b64a48b37285259": { + "balance": "1000000000000000000" + }, + "76e5721c0a39d41274f84cb572039967a07e9beb": { + "balance": "156298167226000000000" + }, + "76e6ca6ef145d2711ab27f82376a065cc6f62a29": { + "balance": "100000000000000000" + }, + "7705d637cf9f6ceaa452deaca7ccc581beb5fa34": { + "balance": "36254762908065000000000" + }, + "7706c80af4eb372e168501eedfe7bda6dc942243": { + "balance": "50000000000000000000000" + }, + "771493da92c9fc6c6b39a4071ae70d99f6a588d3": { + "balance": "2000677471360000000000" + }, + "7719206286f26144c0f20b5e1c35cf4495271152": { + "balance": "1380480863056000000000" + }, + "771adcba1409fa2df6db19d9f784abc81a7bbf36": { + "balance": "15416381820915000000000" + }, + "772f7baa80a852e05b2fb3903a36061da132b2d8": { + "balance": "121000000000000000000" + }, + "7731a4175eee5077e2ede48878e6e2a18fce0f9e": { + "balance": "10000000000000000000000" + }, + "77385deeba01e3cd7a63e13d6048011020f56724": { + "balance": "57204247488000000000" + }, + "776808e7688432755b9e91a838410d29e532c624": { + "balance": "120318608715941000000000" + }, + "776d1b406f63082b80e250c4a0073fa0d83b9090": { + "balance": "243779839900000000000" + }, + "779848a59036ee3cd23b93ff6d53620d874f0bee": { + "balance": "82228810849000000000" + }, + "77d02a031274bd4ed2a16f3cc29d94e755142036": { + "balance": "408567696646000000000" + }, + "77d609a407aa0d126d58090b8d635f5ab7a02d6d": { + "balance": "776754055755000000000" + }, + "77dec41e116301dbd6e542f139816bfd9bf6d154": { + "balance": "16335989583000000000" + }, + "780398b42f81167731a8ef6a8bd1d14942b83267": { + "balance": "25000000000000000000" + }, + "780a645d59027e7b0670d9565898dc00704cbe5f": { + "balance": "20000000000000000000000" + }, + "78182a7711c773f306ec42ce6da3e983cd49b00b": { + "balance": "580861257254000000000" + }, + "7822622f07fec12995c4bb8eb32d62aa7f00be05": { + "balance": "5018461926846000000000" + }, + "786410c679101c0ebf06fb4f36102368121f3c8b": { + "balance": "16098386724761000000000" + }, + "787d5476038ab0a09b846645285ada23ffd7318c": { + "balance": "492047430907000000000" + }, + "788e9e27ed979d1e7aefadda798f69df1de1d1bd": { + "balance": "30965301214000000000" + }, + "78ab2d2dfaf5d2580ed89c970e771572bc91d3be": { + "balance": "36000000000000000000" + }, + "78ab7ac6f379ff084a7acf4a1a31fe2e5a6834c0": { + "balance": "107332516726000000000" + }, + "78aba95da37385c736ef93d0ca8318baf6c5ff3e": { + "balance": "9000000000000000000" + }, + "78cecbd82229dc91a530bd555c9e45125e2a6bc7": { + "balance": "28474069251604000000000" + }, + "78d4df90990248f3ac67e492a0a1e3f4ee455507": { + "balance": "10000000000000000000" + }, + "78f6de3768abc604c49b10d798e0656948cd334e": { + "balance": "9000000000000000000" + }, + "7909aca95ed899743de222e56c231f9bed1b518a": { + "balance": "5355599376491000000000" + }, + "79193e660b4431e8aca9c821b7daa88064e33750": { + "balance": "100000000000000000000000" + }, + "792487caa23b0d9b9998002810cf29439f7190bb": { + "balance": "4828579961131000000000" + }, + "793f56adea51063243a9633ecc1d1e620a91f327": { + "balance": "926742377449000000000" + }, + "796d187077c1d7591583436ae64d10a641490ca5": { + "balance": "242664407084091000000000" + }, + "79a6b7fad3b5a655679450ca82818ec2d6f58688": { + "balance": "1400472715109000000000" + }, + "79acf627e67cedf48297c26fd135973bff6c57da": { + "balance": "444598475759000000000" + }, + "79ae0dda1964ff0191b98d28c9b52a79dc9ab078": { + "balance": "325908985422000000000" + }, + "79e71dcc52fa1b28226c519f715faa3cf63cfb09": { + "balance": "497898493594000000000" + }, + "79e98193ff8770f26af824734bbb1c2ce8197b6f": { + "balance": "10000000000000000000000" + }, + "79ff3d790d52c58b7317a415278e9058915d5241": { + "balance": "48502649691864000000000" + }, + "7a0b02d16d26e8f31e57106bbdad308f513d436c": { + "balance": "841000000000000000000" + }, + "7a1d422352ec7e6ca46131728e4b71f20ed84e2f": { + "balance": "50496873413000000000" + }, + "7a2a3fbe27e33df867ba8800788995d7662c046b": { + "balance": "100000000000000000000000" + }, + "7a629c4783079cd55633661d2b02e6706b45cf8e": { + "balance": "50000000000000000000000" + }, + "7a62d8875f53e54b775ee2f67f7e2ec137bf724f": { + "balance": "25000000000000000000" + }, + "7a67285fd883d36ea3107aa3fe7727c68a99eb2d": { + "balance": "254787158217000000000" + }, + "7a90fbec48492473d54b0fad128ceda94ea66100": { + "balance": "313715004199000000000" + }, + "7a9e11463d84a08140d698972e32e66bacf7a7c9": { + "balance": "3602603216258000000000" + }, + "7ac4f33e1b93ef0f9c15014e06da24904ef4419e": { + "balance": "101000000000000000" + }, + "7ae082ad247275fd5a9e77b127cee5693784e9e1": { + "balance": "1921957343533000000000" + }, + "7b27e070ca4158d13f8333b34842d4c28b678c92": { + "balance": "10000000000000000000000" + }, + "7b2e34374921e4dc10fd9cfc670a40f5d092da1b": { + "balance": "2098457950503000000000" + }, + "7b54c6c8041c8b09240de1ff06e0d3d2d8d877e0": { + "balance": "944752036841000000000" + }, + "7b5aecb798d8f4f5a04bdaef909e09a35bde8d47": { + "balance": "21975115049000000000" + }, + "7b88a7ef9201966bd1ca634779c3b7f40c22f0d7": { + "balance": "64344833519732000000000" + }, + "7b8c22ddc5c7e59e571587d7c776fa50e65f4845": { + "balance": "225108110445000000000" + }, + "7bb4d8a169f72432494ac362eeab005ce1e02d81": { + "balance": "2098993419448000000000" + }, + "7bbaaa6690698e749d095447bdd27207c0caee43": { + "balance": "490069993631000000000" + }, + "7bbf27f92f9f726381d4f68b21ed86af8f792d04": { + "balance": "806346082666000000000" + }, + "7bc6f172fd78953c3456c571ac8394756715d5fd": { + "balance": "81000000000000000000" + }, + "7bcca29b477730ee8f219a5d1bca24415c7a4625": { + "balance": "36273885000000000000" + }, + "7bd296e1cb29ad87ed28b0ed18440ee686b157e0": { + "balance": "35964679698000000000" + }, + "7bde6d49a1af34a5a9dac0b9007e9a5583c65ebd": { + "balance": "1041474566346000000000" + }, + "7bea6240f245e649563253fa4c1da39b12625da7": { + "balance": "100000000000000000000" + }, + "7bf096396c56f27f9c39c4056ee6cfcb0db44bc6": { + "balance": "407261849111000000000" + }, + "7c3b58d3ba283bd9b1580832e9d014eff48bff7f": { + "balance": "7074518779349000000000" + }, + "7c5a56c45f23c353ff9f6f71ec86c9a6a1a0ca67": { + "balance": "11277879639596900000000" + }, + "7c783ac9b07bc6576835635f37e7e3c137055c8c": { + "balance": "16253676225000000000" + }, + "7ca2fbc0a0d1370e95048a21a300eac4d6056df3": { + "balance": "2772084065617000000000" + }, + "7cbe95802a20eb765f9fcff0a068859cc35d2660": { + "balance": "255153842674000000000" + }, + "7d004fb3a6a81c00fd2872e8079ad2912841b0e0": { + "balance": "642630220843000000000" + }, + "7d30c788d4ea18849ebae1173373c8915ffd7a35": { + "balance": "61062263242000000000" + }, + "7d39324f5ff62e849b0f0f46ab8ee396fbd85581": { + "balance": "100000000000000000000000" + }, + "7db0ce6c04537417dca1dd3415a5bf213edc2028": { + "balance": "30393443462000000000" + }, + "7dcfaa795586c92f1ce7d5c7b10608fe6a773fe4": { + "balance": "183173395920000000000" + }, + "7ddd111cfdc3133f59b82568e3deefc3cf10b0d0": { + "balance": "5622149283840000000000" + }, + "7de81daaa7ed5cbf4d379cdd26ae353cbd5a2489": { + "balance": "10000000000000000000000" + }, + "7e0a11af993a41626c5564f719442c0dfd608ec5": { + "balance": "1532083534600000000000" + }, + "7e34971b187047e7f7980650630b936eedc11023": { + "balance": "10000000000000000000000" + }, + "7e5214e16851b33c4a4d29e5a06929461d3d9555": { + "balance": "371790231197000000000" + }, + "7e52ae9c7e4b888015a3a5af7a91444510aa18e2": { + "balance": "109879329128000000000" + }, + "7e69b383671f96b7abc2d1fed8b61477b87a58dd": { + "balance": "10000000000000000000000" + }, + "7e733b1fcadc9a20dc038fba74e236af0b5a39b3": { + "balance": "43583614302000000000" + }, + "7eadcf955c90040668fb0f75a61f687e4e41f314": { + "balance": "332201682206000000000" + }, + "7eb51f3ead1dd0f5384c199ad5518ec55f77d35c": { + "balance": "38487884822000000000" + }, + "7ee73c0d64caf46f47f439969060092ecafdecd9": { + "balance": "15063618320000000000" + }, + "7ee8e4c6742a4c6d8efbfacc4d56119bc6c74ea4": { + "balance": "31882319329000000000" + }, + "7f16d981521c06347db8324da38b25eab3cee23c": { + "balance": "400000000000000" + }, + "7f6ff7db81a26fe78dd80636f0b178c669344393": { + "balance": "10000000000000000" + }, + "7f792b094c0b96d6819823cf21bc0c402fc27bf9": { + "balance": "50000000000000000000000" + }, + "7f84ae97c21cc45a7e56603ddf97449d803fb246": { + "balance": "81000000000000000000" + }, + "7f89c2b9daba034841f19ae843cfb6cd6f75b1d7": { + "balance": "20000000000000000000000" + }, + "7fb18f8b0e1fd1ed8c863a66226082bdc0429ee6": { + "balance": "11465417544634000000000" + }, + "7fb4e30579c64efe981d0057204e5bd8770a1f87": { + "balance": "249801873762000000000" + }, + "7fcc4de10e837d98691acc52732e1568c890304a": { + "balance": "1000000000000000000" + }, + "7fcc77798cd50345b2784a78b81a25dd4c1e64ab": { + "balance": "2676882485895000000000" + }, + "7fe33e773a02b995278ff595d55a0741813b19d4": { + "balance": "5788279057355000000000" + }, + "7ff32b13d531ceef500ca6c6806ffc0773639264": { + "balance": "1000000000000000" + }, + "801380158ef8f24316bdceaa00eb89c3d886707e": { + "balance": "35627521347898000000000" + }, + "804fdccdc8603858d15dec88666437505b2a106a": { + "balance": "14607090269617000000000" + }, + "807915567eed99bb9146354a32409812b9490d70": { + "balance": "1083142734057000000000" + }, + "8092ceeb2be5b271f4c156d85fe14977e919c7e0": { + "balance": "761607160308000000000" + }, + "80962bf961d0d713395dbe00379a6e207b425a76": { + "balance": "524215754483000000000" + }, + "80a9787124075c8cd44b9c8674967a54445e2354": { + "balance": "7600078997429000000000" + }, + "80aacd59dd76bf443c47ca02976178af8453f23a": { + "balance": "411856023767000000000" + }, + "80db788f7fbd7613f0fff66c21389eedbbd4bd35": { + "balance": "956888725645000000000" + }, + "80e449a70e3c7707d6441ae8863a44aee2d7f3f2": { + "balance": "16260784762856000000000" + }, + "811a2c3d0ba4e1c36a848495585da824ec3a7620": { + "balance": "36000000000000000000" + }, + "812a3c55234d5849a854ad76891c34ee90c8a0e3": { + "balance": "703378980438000000000" + }, + "814b4b5eb67afb8d1a60e3d240fe804bb752f632": { + "balance": "17578964576000000000" + }, + "817025619f37838470b90d0a25af2c02de80dae6": { + "balance": "96000000000000000000" + }, + "817233a104d87cac34d9c90243aebd7f68e0a9ea": { + "balance": "510051038684000000000" + }, + "818be95c0c13c3018b4084ea177556705e84c1f5": { + "balance": "332239667000000000" + }, + "819618c19a4a490b821f8156c5633749ea782ca2": { + "balance": "10000000000000000000000" + }, + "81a80d26b70626e07e8747bc1569dd2855834f7c": { + "balance": "521696417321000000000" + }, + "81b2fb0db882bf2538cf8788bae1ad850cef3bab": { + "balance": "102457067052000000000" + }, + "81d4c3bf72837b21203b2a4f90bf42fda10acf48": { + "balance": "10000000000000000000000" + }, + "81df59e5d7b9a2db5463b53be83b4d7c7673d163": { + "balance": "887372337013000000000" + }, + "81ef38d074e0aa9ad618deaab01bcd135301fb67": { + "balance": "24072930558567000000000" + }, + "81f3a4c5291f13f8f97a067a6ed744a686331eaf": { + "balance": "56612148225000000000" + }, + "820610d0ddd3e9f3893f7cc13f32b1ad0d169f81": { + "balance": "50000000000000000000" + }, + "822d6388145e96cdeb2900420a0e0436e940b670": { + "balance": "20000000000000000000000" + }, + "82323b748fdee9f18e34aefc4ddebd4993ac6293": { + "balance": "112752706047881000000000" + }, + "82324995b36f4ff15be3559ccee14742d5b4c75a": { + "balance": "1184047304377000000000" + }, + "8235bfba0bf0fb664271ebe534616456a78852ce": { + "balance": "6804584686000000000" + }, + "824df7b17a61392f88f7e3067f8c261abb48806b": { + "balance": "144857897574000000000" + }, + "82555a7aebfc95a01a3773aa5370394cadef0302": { + "balance": "40069354268401000000000" + }, + "82831d451b8f92fbf6a763adb708010a3e66bb60": { + "balance": "8750983992240000000000" + }, + "8294176178418f46bb18440cc87a07cf40c1669d": { + "balance": "4439783816461000000000" + }, + "82a1c733c3c937ba0a1a49481e4d1f6226157d2a": { + "balance": "50000000000000000000000" + }, + "82ad0b5dc23bc763da0352f5983efceeaee6ea08": { + "balance": "171723633433000000000" + }, + "82b4a3d16655fd71f4020e6a562592a621ff6e1c": { + "balance": "190211621484000000000" + }, + "8357d5a016a00aa5e3ef05d3ce210826adf4c501": { + "balance": "10000000000000000" + }, + "836c41d7f9e72131eff839b7d510fd0ed412f939": { + "balance": "15575572364757000000000" + }, + "8377fff2b0eb03393543ddf5ffae90b3311af5d3": { + "balance": "2058810049054000000000" + }, + "838859e6fd751539a88d00581b0e19bc98c37e47": { + "balance": "338264241636000000000" + }, + "838da0414211392b644e73541e51e9f0fba26615": { + "balance": "20000000000000000000000" + }, + "83958896a43d23ef4ba01bdf6757c36105985096": { + "balance": "9000000000000000000" + }, + "83b88314b606df40d5e716df488980bc64125b46": { + "balance": "10985538717083000000000" + }, + "83bf53fa162e1d85751be0bc6f46e8ec881392e2": { + "balance": "1497107276676000000000" + }, + "83d7c52608b445e18fb1e28dc6198908d66bb6d8": { + "balance": "265446362740000000000" + }, + "83ee8ebaed62092d2116de6b4e90778454e8dfc4": { + "balance": "1000000000000000000000000" + }, + "8402fe573658250f50fbe111596ce35ea9ec01ca": { + "balance": "3479737676000000000" + }, + "8412b877e708a7d5db2a38d9b0f4f23d12231f63": { + "balance": "9225027744855000000000" + }, + "8418dcc09fe052febf2946ee22bcc8c53d548eb6": { + "balance": "3000000000000000" + }, + "84199f54ef96bda5e14f60aa1723e811f755d3bb": { + "balance": "129197612052433000000000" + }, + "841b1400f97ecd2ca008e7b4f5a95274bc3e99dc": { + "balance": "2095180906854000000000" + }, + "844177191a120d2dc4be9169ddbc3b5430e9e238": { + "balance": "3620793599287000000000" + }, + "84578fcffc73be7d65bfa81b0cdafd26885bafbc": { + "balance": "37592478429000000000" + }, + "8460acb05c6c476ca26495aec7224c2bf90996fc": { + "balance": "8999580000000000000" + }, + "84696cdb9f018d3e7bf453efdc174e1a586e9c25": { + "balance": "118007806297016000000000" + }, + "846a8a91d2890000d1e995fc1663cf5b7c22211c": { + "balance": "27266838638307000000000" + }, + "846b5ef52d5f7ccc17d9c7e5f49db807908c63f3": { + "balance": "375423381758000000000" + }, + "847409e5d6ed2c4e54ff97f2ed58217ac5fc3d68": { + "balance": "23972870617025000000000" + }, + "84bf432c967540caafb8bf49cdc9983e8953a18a": { + "balance": "453476687224000000000" + }, + "84eba1bb76f7a3f6d2b9052d068cc6c48d449d76": { + "balance": "17655334922000000000" + }, + "851245ef1637a07578241b3c35acf215908e1898": { + "balance": "1269389304110000000000" + }, + "853708e974fd4810655d9cd19fc8dbfd3d5e1e36": { + "balance": "18000534000000000000" + }, + "8547989af8c99a3432038a03d3fb30a054d90413": { + "balance": "10000000000000000000000" + }, + "854ba39bac4c7bf619804b6773fe43bc71f3255d": { + "balance": "15999580000000000000" + }, + "85636f3e113cbe1d1bbd1b3a23e9e98edbcb94f2": { + "balance": "1199038399611000000000" + }, + "857167896b859394babf897c4c6fa57b3a057117": { + "balance": "921057404898000000000" + }, + "85799226a1474371ca76f05597a1e3835c17e7d7": { + "balance": "562141544946000000000" + }, + "85a2221cbbb47e8b74fc2617d6087a98f47e2738": { + "balance": "10000000000000000000000" + }, + "85be0bd55fb9143ff17387914a82d0a2650224c4": { + "balance": "4038654147145000000000" + }, + "85c5ff0e4956ef0fb662a2cbf6a86325a53dac8a": { + "balance": "28690160424000000000" + }, + "85caff4ec0e1719ad963e97c1c02828683070370": { + "balance": "2022427900763000000000" + }, + "8630cc2780fee566f172ed0437264c45421ce675": { + "balance": "669721278148000000000" + }, + "8633d245c5f1b63403e3d7828dc197ce1cfafc0f": { + "balance": "10000000000000000000000" + }, + "867ccceae3192a27751d870ae13b1d3d2c3584dc": { + "balance": "1491436265909000000000" + }, + "868bed241f77983ff4a7a8d0bf121299b6b2248b": { + "balance": "5600000000000000000" + }, + "868ddd283a76a26c8bbb9761df3ca647bea267e2": { + "balance": "9000000000000000000" + }, + "8696e546f96f6e51f405905e095902db8bb90118": { + "balance": "533558981421000000000" + }, + "86ac0eae4e4c20cb7019325f4dbebad053f92213": { + "balance": "697960117764000000000" + }, + "86bef47f9d2cd7526495454eb4d1737510696a5f": { + "balance": "2938307902381000000000" + }, + "86ddd4e3f444b395be8b2b2b75c35c78877fefb7": { + "balance": "15615434748526000000000" + }, + "86f115ed19a32aba4f98270b8ad45820abbc4653": { + "balance": "151868798605000000000" + }, + "870f19e7ee358de61ad0fd3c7710441156d68f66": { + "balance": "674715936435000000000" + }, + "87141a2d3857fb8a328ef8e7b503ed965294c85d": { + "balance": "1609607183158000000000" + }, + "87257783d866af25a7a71b46ea6c2bd1e9ab9596": { + "balance": "64000000000000000000" + }, + "87298979a9a0dbc272b0e15b7e5f2e42639c9912": { + "balance": "722087160930000000000" + }, + "8757b784015f88d072229176cabefa358a0e95a4": { + "balance": "204003337866000000000" + }, + "8760e60a56c5b8b61276634a571400023f08e3ac": { + "balance": "1000000000000000000" + }, + "877e54ea7e8ab03bb8e2b842dadab16bf4ae0a4c": { + "balance": "341020957932000000000" + }, + "87919285fc5d98169bbd073cebb1b3a564264dd8": { + "balance": "579080463078000000000" + }, + "87c39cfaa9c82d84119f306e6a233a3abfbb0ad1": { + "balance": "121753433796000000000" + }, + "87d479659a472af7c8ea78a3c658605f8c40bec6": { + "balance": "20000000000000000000000" + }, + "87d933ad6fba603950da9d245b9387880e6d9def": { + "balance": "1087642723520000000000" + }, + "87ec448309024bb1b756116b81652ea518cf353d": { + "balance": "344562808694000000000" + }, + "87fbbe010837f8907cc01a5bbd967f402a216488": { + "balance": "185411503628000000000" + }, + "8805a3c529bef4d19a6491f3b7d7b1b7232bb93d": { + "balance": "264150205918000000000" + }, + "880ec9548864fcd51f711ab731d847260ed0e3d5": { + "balance": "723225945994000000000" + }, + "8818d160b56b18e196871a6c7ccf02112dc13342": { + "balance": "2857439182291000000000" + }, + "8836e25baa08c19a9b0155c57072582b49f7dbef": { + "balance": "5468425690148000000000" + }, + "885b6303d06142accf2ddddbbdd4a9379d1cd124": { + "balance": "11853214736000000000" + }, + "88656958d9cd758d71546ba52c4ea646b658c84c": { + "balance": "10000000000000000000000" + }, + "88740acdf9ab5711d015391fe8cf4a7c70a0bc86": { + "balance": "510027156671000000000" + }, + "8874966976d776c3154261afa802692afedf3d3d": { + "balance": "305634301700000000000" + }, + "88aea53c727d7a5dd8a416e49faba1c4f741f01a": { + "balance": "15358334295959000000000" + }, + "88b67d05997ae3852259ca638a00ce9b9e7e4a61": { + "balance": "278125551806452000000000" + }, + "88d730e074a102048008de81d3adcba831335736": { + "balance": "5984576042159000000000" + }, + "88da27b1f0a604a87fdedd9ea51087a331179cb4": { + "balance": "10000000000000000000000" + }, + "88efaa91dab9671f5c903e69aa6ca4d9a04b5ddb": { + "balance": "1996126782729000000000" + }, + "89a9d702f64f14fae4d1a69717744dd700208d9a": { + "balance": "251686323241000000000" + }, + "89ac81571265bebbf9d3c09e9459fd1ba7fb1297": { + "balance": "162368080974000000000" + }, + "89c75c4f0ce41d283587beba1a3e3efab05ca6ad": { + "balance": "16000000000000000000" + }, + "89d44cb81cc5a1bdf4d573c4954ee641f3cb91d1": { + "balance": "97965629614355000000000" + }, + "89e2fef4f7b7c255b36afa81cf4033b22de3db25": { + "balance": "7278615226888000000000" + }, + "89fe5d3cb5283c7b87daf6103bb568f92a230631": { + "balance": "64000000000000000000" + }, + "8a07242231f4a654aeea65b857d1519385a18065": { + "balance": "20000000000000000000000" + }, + "8a5a415f0fe2a8329e14628493d11ca20d4e482a": { + "balance": "157274758238000000000" + }, + "8a6ce9f270fe3ec33a013be9e5b1ef823c0dab53": { + "balance": "20672772672000000000" + }, + "8a6fe4fa2f86f879ec9b2bf643beeb0876da46d4": { + "balance": "1041983771868000000000" + }, + "8a765ff2b429dcdf59b65a34c4bb41798dfb5886": { + "balance": "355487172996000000000" + }, + "8a9b9b65a3d443a6e4dcf696a64983f3b625774f": { + "balance": "3185351572575000000000" + }, + "8ab1f5443cf9149773b9ddb69de3e6ea047ae38f": { + "balance": "161619949415000000000" + }, + "8abeacee0078e07fb417277e8bf15dcc2cdb9fa7": { + "balance": "144000000000000000000" + }, + "8ac0d9e0e77aa4ada4080604f2118b3a5a0f8102": { + "balance": "100000000000000000" + }, + "8adae0dc99300f60d31bfa619ec83d45b48ea22b": { + "balance": "697262590215000000000" + }, + "8aef59e59a27a8662043f1a4abcaf945a5e3fafc": { + "balance": "26780431538000000000" + }, + "8b3386f32e2d77526c223ee8bb95b7dd111ced92": { + "balance": "2179932854210000000000" + }, + "8b34d5e457ef6451bb7f5ecc93c80678a30e3194": { + "balance": "31492358338840000000000" + }, + "8b47e07f192c33bd7d298bae717dfcd68a8097ae": { + "balance": "1000000000000000000000000" + }, + "8b55bff4b281f6a24ab428d66b91f9bab06f7b96": { + "balance": "1596248680941000000000" + }, + "8b576b1e2391f22193bb4f91bec5f2a8aec02af7": { + "balance": "29660301836269000000000" + }, + "8b9097b762c7bc38a487974f3551fea697087553": { + "balance": "260887123991000000000" + }, + "8b92c50e1c39466f900a578edb20a49356c4fe24": { + "balance": "35654824979000000000" + }, + "8ba3933337108841a997accf0b5735e005373f53": { + "balance": "574965182000000000" + }, + "8ba3eeb2d1b27e021ed6bf5827280807f32c7897": { + "balance": "64000000000000000000" + }, + "8bb23a5b8c48ec5bde84f39b463559b7c048c853": { + "balance": "16186405874000000000" + }, + "8be0b6ab14e15b46905335d07df03726fb1df0e8": { + "balance": "500000000000000000000000" + }, + "8bfc53af1ae6931f47ad7f7ed2f807f70fddb24e": { + "balance": "20000000000000000000" + }, + "8c0599df87df142d3aea37d50c975c1813ecb642": { + "balance": "871085782287000000000" + }, + "8c2deeeaf095be075a2646ed7b8764d3665acf14": { + "balance": "10000000000000000000000" + }, + "8c3e7381b0598356ff81e860faf25390ae7de9d9": { + "balance": "36000000000000000000" + }, + "8c5671a6f4610ddbd05a5139659c7190f54117b5": { + "balance": "50000000000000000000000" + }, + "8c60582c4e4e60da665b4a5a2d18f514ded6c49d": { + "balance": "16806447782991000000000" + }, + "8c8464ea6b17687eec36ef04966d59c7c91fa092": { + "balance": "1872124465602000000000" + }, + "8c85c5a318cc0227576adba3e91dce6adc73f6a2": { + "balance": "52479305517000000000" + }, + "8c8f3796a2942a2298d14ff1a9e3264e9f63f2bd": { + "balance": "10000000000000000000000" + }, + "8cec1886f2cc71b09ca32a1cf77a280ae3a6a9fe": { + "balance": "500000000000000000000000" + }, + "8d0b26d57eb52a62814d7876d64c8274f4371464": { + "balance": "20794037603000000000" + }, + "8d40b92e41f3cfec06e767d64b4dafc5612133b6": { + "balance": "25000000000000000000" + }, + "8d41ea1cfb70d0ef1f6572fd72a6b417739ac7dc": { + "balance": "738777348304000000000" + }, + "8d4eb54646f9d14882fc8ebb0ef15f6056d1afbb": { + "balance": "1003867239086000000000" + }, + "8d51ab29ccd190bfe12bcd94a651e9f49a003253": { + "balance": "442251355663000000000" + }, + "8d6c0c8e4ca47626115433b39feb939014b8738f": { + "balance": "119828137027000000000" + }, + "8d7acd92d664a485625bb9884e7cac9cc6077f41": { + "balance": "1381910232084000000000" + }, + "8d7ee7a9c1c263ba8061f54dcf62d9f8420e2008": { + "balance": "20000000000000000000000" + }, + "8d941c5d0c6e2b8e2934c9f80f8a63e2fb5868ef": { + "balance": "116443644149000000000" + }, + "8da0dc43ed3ccefb18f21aa13f3fa42c13e540a6": { + "balance": "516000000000000000000" + }, + "8dab4500316475e8fc3bb6494be09f549dedf026": { + "balance": "2736245677000000000" + }, + "8db39a95f4e63bde0bd8c02e386122ce2c57a30f": { + "balance": "12577347153000000000" + }, + "8dc718b49fb68584d9472490743f9be1b0ad683b": { + "balance": "50000000000000000000000" + }, + "8dd05e26224aa8a6deb0904b6d3bbb34d268e901": { + "balance": "613146658282863000000000" + }, + "8dda0e7ddde515480ef08cf90a1eb4e78f50a2c4": { + "balance": "19265526663314000000000" + }, + "8dedad1511c11798c338334dde7be967de96e9b2": { + "balance": "50000000000000000000000" + }, + "8df63c04f18a854d7bb397bca3e2ba19202e9da1": { + "balance": "1479940547081000000000" + }, + "8dfd7edb7d28e8b3df1faab70a8ef9e3b923d998": { + "balance": "10000000000000000000000" + }, + "8e2c3af057e931b5f82e83873b336a7f68e7eb03": { + "balance": "27138009123000000000" + }, + "8e2f4eaddd60468bdc09d47f65839b96f50596ef": { + "balance": "970529157231000000000" + }, + "8e750010c88ba99d75b0b5943c716d6fc0d01802": { + "balance": "42271114987000000000" + }, + "8e889d47f3307a18490e53f2108dc31b14d6300e": { + "balance": "115722965933000000000" + }, + "8e9e1953c82217ba56365e7a9c54b1ded73914bd": { + "balance": "6248835752208000000000" + }, + "8ec980d3066cb6afa793577cf88ccb46ce8d13f2": { + "balance": "100000000000000000000000" + }, + "8ef324c861de7e042c445776bcc8ac026533bc15": { + "balance": "1869634994148000000000" + }, + "8efd14464465e50af087a80a5fbe652445de373d": { + "balance": "1157403424927000000000" + }, + "8f1b57304406fd8b2eb5dabcbd322e326dd873f5": { + "balance": "194188733254000000000" + }, + "8f36ffd921e12083e374335d3cc43fcfeeadfa46": { + "balance": "100000000000000000000000" + }, + "8f813b88e6e125eab71a63455f326322ef505501": { + "balance": "19087691927734000000000" + }, + "8f83892d4d2892cd57828fde2318610a54b14498": { + "balance": "22833507983000000000" + }, + "8f89c1bcba85757cf1718d5b9eb007e27e5195ab": { + "balance": "2241600478705000000000" + }, + "8f927ab63df4c2ce46f1ea35bc875a0c006d2d4f": { + "balance": "327487123409000000000" + }, + "8fc3c231df0f93a84bbe348aff12ab576284d70f": { + "balance": "25000000000000000000" + }, + "8ffa089b07ed1388a5d1a428daf54d9591e734e6": { + "balance": "1347580402248000000000" + }, + "90040e00f585f8be44c82597037fde452472e741": { + "balance": "2746884591879000000000" + }, + "9034eb46aad2a76bdb812c981565d4701dc10718": { + "balance": "10000000000000000000" + }, + "904ca1ac2381702bd18472b175262a8928cde5f1": { + "balance": "304421909590000000000" + }, + "90502c1123692c3b86e99b328d07fae473d4a283": { + "balance": "227491252462000000000" + }, + "9052ca7e9623c1bbe3568668673d6d252b56a764": { + "balance": "35268091378000000000" + }, + "9093d12d8410193293e1fda0cca98a43b85b91a8": { + "balance": "6829489147119000000000" + }, + "909ba8cdc707c12ba577dcd8ed1df1c02a7ce2ef": { + "balance": "60524108169000000000" + }, + "90a2cc3aa73495531691e027a8c02783cea7941d": { + "balance": "65263780625000000000" + }, + "90d7c82615f151953a8d71a68096cee4d428619c": { + "balance": "298774379499000000000" + }, + "90e02deb31d98b9c85fcaa7876eb5ec51d721dd4": { + "balance": "2000000000000000000" + }, + "90e538746bbfc6181514338a608181a3c4286d1d": { + "balance": "6069511690189000000000" + }, + "9106dddc1b693e7dcb85f1dc13563d6c7c9d8a6e": { + "balance": "1977000091291000000000" + }, + "910d1e0d3f71054835ee0d4cd87054dd7add3e38": { + "balance": "40104690362000000000" + }, + "912e2349b791fe702692a6c1ccbf6f0f06b826db": { + "balance": "6305336897000000000" + }, + "9144cc61c01eb819e654b46730620c230da9e936": { + "balance": "144000000000000000000" + }, + "91478d4c15d9ba02816456030915be08fa3aa208": { + "balance": "200078339107000000000" + }, + "9160c466b5f9020b0ab1c0ff497bf0345598ec90": { + "balance": "17705350930000000000" + }, + "919025625787101c572d8340ead1444a96593424": { + "balance": "2418027749789000000000" + }, + "91926323868c65f91b6d74c85c07279610651ede": { + "balance": "538073886450000000000" + }, + "91950cd6e2dd99e024854b65c09c5a7476777a21": { + "balance": "11629505934425000000000" + }, + "91ae8d74c26d3dcc291db208fc0783347fcc197f": { + "balance": "7604593786920000000000" + }, + "91b9ac26869abc9eb3090f1d8140eabe97f41001": { + "balance": "25000000000000000000" + }, + "91c349651afb604f9b00a08e097e02c0964e148a": { + "balance": "117290771022000000000" + }, + "91ddc95cadeb6dcf6ebbdb3300a29699ac8ded39": { + "balance": "20000000000000000000000" + }, + "91ebbd36714cc069f8ce46f3e0eda5504fdd3aa2": { + "balance": "203944728497000000000" + }, + "91f2765125b84923bd506a719d72b0c1de030e32": { + "balance": "452269960816000000000" + }, + "91f2e54a9d61ef52a33d150da50d5a8f2ebcd6bf": { + "balance": "242321058694000000000" + }, + "920dc90d11e087a0d8912c1d43db102e9ba4f43e": { + "balance": "20000000000000000000000" + }, + "922ff522cf7f3ce0bab9312132df51704caa755b": { + "balance": "1414824682473000000000" + }, + "9251449b0f757ef62f63c2774eb63ba15bf3712b": { + "balance": "102688517037000000000" + }, + "926255c17386720fdc1701747a2f024475063d4a": { + "balance": "25000000000000000000" + }, + "92808a38ffc5a339b1ab6b0b472f9975718d4a07": { + "balance": "500000000000000000000000" + }, + "9286c4497e820845341e3b9127813c1b7c884830": { + "balance": "101241387488275000000000" + }, + "9298e1df6730e91e9892d19f7ce18a3db9b5d2a1": { + "balance": "169000000000000000000" + }, + "92d98aed335c29402a43ba96c610251bed97308b": { + "balance": "3032350763000000000" + }, + "9319153f24814a81d920c60cbee9b5f2f275fac0": { + "balance": "56619610984000000000" + }, + "9347532d6396bc0b86bcd34eb80facd4c3690684": { + "balance": "258912194626000000000" + }, + "93487691d71e6248d88f06b1fbaee58b6fe34615": { + "balance": "1593901704394000000000" + }, + "9375154a7f19783b26ae1c9e48f114e1cfd1307a": { + "balance": "9000000000000000000" + }, + "9377947e0db688bb09c9ca3838ca2197fb262a1e": { + "balance": "323993393587000000000" + }, + "939ca9030b28d356dc1b071169f98b0728a9aef3": { + "balance": "218900305967000000000" + }, + "93b71636b8332515c2af031aac7a8805de716a62": { + "balance": "1640174743698000000000" + }, + "93bca153afd427b0c3c1de4a5584610e4a6595b7": { + "balance": "654782426410000000000" + }, + "93cb3b73fee80cedacf5197f8b4ac8f18f0d0184": { + "balance": "100000000000000000000" + }, + "940fcd215bab373d1b736e354f2def501244885a": { + "balance": "13133641534585000000000" + }, + "943f4bc76f20580b6546b6aff2800448f82cfdc0": { + "balance": "1927982550280000000000" + }, + "946ddb5c46fb13010b9c7ec56e4055b4f3e24b4a": { + "balance": "1410000000000000000" + }, + "947961dc367226f78d722361d5821cced52db01b": { + "balance": "115598797369000000000" + }, + "948eab3ffe44d5f1f381de2c8cadcb311c25df2a": { + "balance": "870664355820000000000" + }, + "94bf674593378243fb6b811f331f77561efb4106": { + "balance": "226539311455000000000" + }, + "94ce082887dd6324d7dcfa6cae17b653be021b25": { + "balance": "420000000000000000000" + }, + "94e2aaa4b5e2b36a12f866c96e3382a1150a97b4": { + "balance": "7344059136611000000000" + }, + "94ea5b1cdceb3f1a9d5ecacb6ac8dd2db9a461d7": { + "balance": "1951787237292000000000" + }, + "95218633176c0fe2f32fb55ad3df9f387e63aed1": { + "balance": "99999999580000000000000" + }, + "9543cb22853a46cce3aadc60e46cbddbd3fcf593": { + "balance": "2806074281914000000000" + }, + "958842c5389656d156aab05ac1731a20656716ff": { + "balance": "391064461038000000000" + }, + "958fd9bbc96531a00adc5c484d06dc61ccd717b6": { + "balance": "8021794447667000000000" + }, + "9593ce72919cb0648ddacc58af233d942963e2e6": { + "balance": "32322940730755000000000" + }, + "95a8e371af9128c97c9d4d7c4d58f5f75f2d07d4": { + "balance": "49000000000000000000" + }, + "95b9a9ad563a4c1ff7b6ebcf5fabcf5dbdb4a6a3": { + "balance": "10000000000000000000000" + }, + "95ef5fac6aa3ab1b4a87246fa800cfceff43dec7": { + "balance": "119666779022000000000" + }, + "961a3aa8015cd520de43bd47d81f5194ee4dfdc2": { + "balance": "248589901007000000000" + }, + "962bad39df25d64ee1c6b4ae9c14a18d316bfc06": { + "balance": "2404608291000000000" + }, + "96392119198c4b644c64284c9a75f61210a6292d": { + "balance": "1000000000000000000" + }, + "963c82319380587eeba0bd7b07eb63ea7042984b": { + "balance": "1480123630618000000000" + }, + "963e05fb6245ec11d67ed80e9feba6e2c0a8b4ae": { + "balance": "276053287417000000000" + }, + "964452b86b0d1d4b34aa881509a99e7b631d4a85": { + "balance": "64000000000000000000" + }, + "9644a2af2ff70eb43584a4351bfbe027c42ba3f9": { + "balance": "500000000000000000000000" + }, + "96572a017489450f2dfc0e31928576acd3bc6808": { + "balance": "1140183097730000000000" + }, + "9686bfcc0dc3de20604eb77787d0dba818cc5016": { + "balance": "10593448987804000000000" + }, + "96879780764b4433589d26573fc221f5218f1877": { + "balance": "154136576560000000000" + }, + "96ac1e62c95e33dbbd4f6ed389007e16c00b205e": { + "balance": "4130528000000000" + }, + "96ba703df3a8a6dc3c5d6be02cbf6a4afa2d1650": { + "balance": "2885298549532000000000" + }, + "96d516ded110f1d7e0290716689fd1b7964d9d42": { + "balance": "40665675241000000000" + }, + "96d75950c9354cec6084ba11058dd52d00fdb1f2": { + "balance": "903158106646000000000" + }, + "96f362c59c72fa1d39ae3ec37a7b715d2dd23679": { + "balance": "110000000000000000" + }, + "97115f7544cb05009b3fad2f0c2817f3ee77dd4d": { + "balance": "10000000000000000000000" + }, + "971cbaeafd4b0fdbad24fab946051b8949efaebf": { + "balance": "8462381628000000000" + }, + "971e195e980b4fd4db8d279c80968ca1bd390edd": { + "balance": "10000000000000000000" + }, + "9722648970c455929d621546fddbff27c49acd3c": { + "balance": "70337427969000000000" + }, + "9772027a4ea991eb9eb5ae6b8f34d750a917538b": { + "balance": "148918416138000000000" + }, + "97797e3919aa35567b9eb1224be87f96c6c2e1b4": { + "balance": "973342196399000000000" + }, + "9780a9c86160e27f627179535c3d3f23b6b29917": { + "balance": "10000000000000000000000" + }, + "97a85f4e3f53aa066825de15f1d0e25d4189b037": { + "balance": "2435764858719000000000" + }, + "97f46465e99910539bd3593c16a572e159bac87d": { + "balance": "25000000000000000000" + }, + "9882505fcb54ca2d2f4f79b03f0a5ead61936979": { + "balance": "249999580000000000000" + }, + "9898e969629502a891b758efecc9fdc5ada7d32c": { + "balance": "20000000000000000000000" + }, + "98a52d325e28ca9b4474846c7e4c07a223440fab": { + "balance": "418260286015000000000" + }, + "98a9b2f7d1ba7838e3242b5e4cbf1f2897aa4bc5": { + "balance": "500000000000000000000000" + }, + "98b8308c37a2f6cc1bb382dba2ba95a3c5ca2834": { + "balance": "10000000000000000000000" + }, + "98bf0170a61f98ab0710a68810bf152b7f6c56fd": { + "balance": "2279761566089000000000" + }, + "98c8a323a0022bd147a466fa1ac867977e12eb92": { + "balance": "10000000000000000000000" + }, + "98cd102caf0866ba0a74604b01f54049503905d6": { + "balance": "34739921273310000000000" + }, + "98d7e89c2765aaac224d4015aa277fef208953c3": { + "balance": "1291811952000000000" + }, + "98fe96bfd1e10fb60b343e512b15e955aefc0778": { + "balance": "464922897623000000000" + }, + "99064a57d693e45559a1a910c9ef7d46cce0e703": { + "balance": "8969733492948000000000" + }, + "991ea5429b91a8bfc4352a1d93304dc463be5b90": { + "balance": "149367286734000000000" + }, + "9921d405fada890fee6bf76acc39141fd34e5d2b": { + "balance": "5021308706457000000000" + }, + "9938d357d3d5dcc6f6fc7fb47a98405c0ab6830e": { + "balance": "516293591974000000000" + }, + "994f4e6521a3a5752359308b9f6b2722922c60b1": { + "balance": "23993133615000000000" + }, + "995a6a1c38f037b3a9f0a2e915b8fc0efdea082a": { + "balance": "1403498530728000000000" + }, + "99709e57748a7da6556b1670ba4f15c45aef4689": { + "balance": "36000000000000000000" + }, + "99789f65655c6f917d575169f4ba8192440e659a": { + "balance": "393071814319000000000" + }, + "998f66cbde2693603fa109ad7aaa8bc42a8765a9": { + "balance": "49000000000000000000" + }, + "99afd42a58af31daa54ad9ba35b06954330107ba": { + "balance": "25000000000000000000" + }, + "99b6a9ff2b2ac9ac0361af007aba107695ff5fad": { + "balance": "12860157225353000000000" + }, + "99d16a5955d43723ed8e2b1a642f8f1195f38b64": { + "balance": "62907829047000000000" + }, + "99df609926ca536ed3be80e35dbaecc42ae67f2f": { + "balance": "316809833612000000000" + }, + "99f3faf97a36fabea7306979b30b08fa70110e29": { + "balance": "173292373556000000000" + }, + "9a26110067b473e3bdc0fc32951b39596c967a56": { + "balance": "78192198764000000000" + }, + "9a3a8eff6fb82377da6c17ba658dca87ca0dfe26": { + "balance": "50000000000000000000000" + }, + "9a3b06257088ef8c17410a8f2d63392edb9b55ce": { + "balance": "239567000000000" + }, + "9a426842301802866cca0ef89794d928d3e8f843": { + "balance": "776173297821000000000" + }, + "9a5f2c0a6d41131d9aacdb4f8c274958cbdd377e": { + "balance": "441954000000000000000" + }, + "9a6893023ac6f34b493d33e4dc63ef697169a58d": { + "balance": "439689418527000000000" + }, + "9a86eefd848acafcbd9960003e90b22162b15ef9": { + "balance": "294190908093575000000000" + }, + "9aa711f3e4eb67d2f6405b5ee6290a014d203a72": { + "balance": "9101556549634000000000" + }, + "9abf9ccf6abb8d55ede458d2d12a279d0a823944": { + "balance": "17609693072000000000" + }, + "9ac1909b983c754f0800559174025c0f0baa9d31": { + "balance": "80921948093000000000" + }, + "9ad62cd855d629e1ddab632874a6dc2b812f2348": { + "balance": "2068118534000000000" + }, + "9afc2c33aa2c9a42600abb18aedaefa433326122": { + "balance": "2485353229354000000000" + }, + "9b18d230b221a99c74877d4a1dbdee2214c7d60c": { + "balance": "4024172228743000000000" + }, + "9b18e27788c9d59053072032a480569e142595a0": { + "balance": "110789164888000000000" + }, + "9b4535b23af0b8e5f488a6f318ff6badf71d16c1": { + "balance": "84756740661000000000" + }, + "9b5e7cf43aece7b38ea2af6d08bebe2d3b926840": { + "balance": "262771268227000000000" + }, + "9b77dac92fedd0ad3eb4326d4fafe0f4315a8844": { + "balance": "3616321626000000000" + }, + "9b8f6f223641f9b1bab319dd1e88c49fd411a765": { + "balance": "2054417462086000000000" + }, + "9b9f94861d80365464912e5c7213403405a6cd8d": { + "balance": "2367093088000000000" + }, + "9ba24397002929e6239848596b67b18a8dea1eef": { + "balance": "5000000000000000000" + }, + "9ba99736c5ac468d6b644e39b8d515c39151f51d": { + "balance": "311900650761999999999" + }, + "9bf2d4ff366e1bb2313ae9a93ccca75d6bc0d232": { + "balance": "764870206925000000000" + }, + "9bfce7dbfc9ae62d450e862261d1e21e68bac92c": { + "balance": "1000000000000000000000" + }, + "9c003e74b62f192a864045d678639580c672fc22": { + "balance": "50000000000000000000000" + }, + "9c128bd2c0c96b896db6c0f398e908c98302809e": { + "balance": "3251059363800000000000" + }, + "9c255daa89ee16f32fc0ab1ed8e22db39342e6ca": { + "balance": "37695843594589000000000" + }, + "9c32e714bcb601a56a8a4e6b3f7bcd9e1c7a1b54": { + "balance": "50000000000000000000" + }, + "9c503e087b04a540ed87056c9371d591afa72df2": { + "balance": "64229084991000000000" + }, + "9c54297dd3527cbbb8ca8c305291b89bfb7ab39d": { + "balance": "61682466962052000000000" + }, + "9c55bb1db3b2bb06e605a66ced9ea2ac95718205": { + "balance": "16512365324000000000" + }, + "9c59dbc48b9cf53fe668784e89d30493da9995b3": { + "balance": "50000000000000000000000" + }, + "9c61b58aa760265f7fd1b9e749df70122ea81175": { + "balance": "50590272373000000000" + }, + "9c6c7eaf4bec0566a7bf8acd30e10311a963267c": { + "balance": "999999999580000000000000" + }, + "9c91dd4006f9d01d8caf5f5fb4f2c4f35ee63ffc": { + "balance": "175730980227000000000" + }, + "9c99275f5dee14b426302b1a47a8488c16432f2b": { + "balance": "2000000000000000000" + }, + "9ccf7b23528d062da63f6af3e26531b775c83c52": { + "balance": "928373869120000000000" + }, + "9cd21c30ccbc1087c9b351395fdea17ad669cc2e": { + "balance": "529762292313000000000" + }, + "9cfee47d6f24880af7b281cc00e1fc58e0a4a718": { + "balance": "198888257958000000000" + }, + "9d08251f7d4cfd66d15c17e1ea6bae5c795e290b": { + "balance": "813841349140000000000" + }, + "9d5411490ce89359bfbacf9f9957ebfbbc18debb": { + "balance": "22263187467000000000" + }, + "9d61e1dfaa7d0e0c5f5d733a24a1883c4e201f3d": { + "balance": "144000000000000000000" + }, + "9d754d94a15ab6d738e511fe4c775ee6d20a53ee": { + "balance": "20000000000000000000000" + }, + "9daccedf104fdcc3c39f2961ddfa1c64eb632476": { + "balance": "1237093270947000000000" + }, + "9dad4968c0e44aa729fc5732f3ee903c6799637b": { + "balance": "838788687517000000000" + }, + "9db73ca677bacbb622f44fe90b53ee1d9f0c2009": { + "balance": "472858335000000000" + }, + "9dbcb5026e0f444a33197da240856f108db14ff0": { + "balance": "10000000000000000000000" + }, + "9dc46cf729187ceed8001c4ab14fa4fc21c35f32": { + "balance": "3320792646995000000000" + }, + "9dd895c1bdac2ed9864134aaa8c543473ee5f19b": { + "balance": "1430620966869000000000" + }, + "9de2687242cbf9fb94fee0ad873acc7494ebd2bf": { + "balance": "20000000000000000000000" + }, + "9deec036282717aac93ad5cc1b6d4a5354e85c2e": { + "balance": "2048627955362000000000" + }, + "9df8dc66395aeae9b4c831b4d63bdf48db08811a": { + "balance": "215874670561486000000000" + }, + "9e1fe68a70abd8ab517878b03961da8564b43eb5": { + "balance": "67908329894526000000000" + }, + "9e33293006982abc668e199aab20260b9b754463": { + "balance": "49000000000000000000" + }, + "9e65616282a0baf89469a58915fd8fdbed210e3f": { + "balance": "829209872657000000000" + }, + "9e7b7b522834dd7e83ff2bb6b6e4cd2972330899": { + "balance": "500000000000000000000000" + }, + "9ed134b3a8feccb4056b2e511cea9a8ec58a3e77": { + "balance": "18787546978390000000000" + }, + "9edcf477687a9dee79341ed5d89d576c9a854c2d": { + "balance": "500449025554000000000" + }, + "9eeb06d4b532118afa013a01c9e89216fe0475ae": { + "balance": "1823939486758000000000" + }, + "9ef20a338e85044922f08f3648355e834874d551": { + "balance": "50000000000000000000000" + }, + "9f0855f9cc429fd3590c6ad05bb66a9e038efdca": { + "balance": "8017999878252000000000" + }, + "9f3befcc1884d16b65ae429228d26fffc146c8dc": { + "balance": "1016482445089000000000" + }, + "9f4571748463eee19e59ff9bd734a62a66613850": { + "balance": "20000000000000000000000" + }, + "9f51de282745f77b8e531e1de0b7c14e3369ba54": { + "balance": "1010657089383000000000" + }, + "9f6527175a2b581cc79f2a68c35202e0a7f2af20": { + "balance": "216495522463000000000" + }, + "9f70204d1194f539c042a8b0f9a88b0a03bbcd8b": { + "balance": "10000000000000000000000" + }, + "9f70e44704049633110ecd444f9540e241b50783": { + "balance": "9139000000000000" + }, + "9f73fea741e8506ba7acb477745dab1cfab8366e": { + "balance": "4461472359634000000000" + }, + "9f88d33d26c90e74c39c9676b8b580d21bbad124": { + "balance": "54437240781000000000" + }, + "9fa47455be14ad2eecce495281ed0eea926ec6a6": { + "balance": "10000000000000000000000" + }, + "9fbb15b595d154754a2ae77c77283db9d4e9f27b": { + "balance": "6195722646556000000000" + }, + "9fc480ab1823a59fd6130c3948980f95ac99f1d2": { + "balance": "24101151540000000000" + }, + "9fe5f054165fbf1943b1b02c01063f04e0c3890b": { + "balance": "1000000000000000000" + }, + "9fe7d3d5976e7b8b5ad6baa15ceae96c43c60fea": { + "balance": "55000000000000000000000000" + }, + "9ff116ea0e219814970cf0030932f5ce2cd9a56f": { + "balance": "36000000000000000000" + }, + "a01f6c36193839bc3a31e6d0792324771040fc05": { + "balance": "48298750000000000000" + }, + "a0264706d668522b737bbdbe949ce3e5a60fe314": { + "balance": "1423066922869000000000" + }, + "a02b13bb3b13027045ffb9b44bc7380a942e8ebb": { + "balance": "86845430807181000000000" + }, + "a03d246a931c3d422e5d2bf90f64975923a93643": { + "balance": "5834171660287000000000" + }, + "a046caaee59425ea1040867c62a6fcda11652a23": { + "balance": "83087966538000000000" + }, + "a04b57b2dd8b2082c53517d956f5909d25e14b69": { + "balance": "4518538234851000000000" + }, + "a074ef9e0ffe15619103e3de490f5813be53dcbb": { + "balance": "4568113810000000000" + }, + "a07bae42b44c085067de16e7d9846db529059acf": { + "balance": "4000000000000000000" + }, + "a08530e5fb7e569102b2c226aa5e53dc74483e4e": { + "balance": "2325665286793000000000" + }, + "a095a2c666f4f3203a2714fb04867c13c2add4be": { + "balance": "14768043990000000000" + }, + "a0a967418a3fcb3ee3827a08efa851347c528a60": { + "balance": "20000000000000000000000" + }, + "a0bb293071e07418ecb2fefc073136569ebd1736": { + "balance": "25871128320000000000" + }, + "a0c6c220a53b7dc790f7a5b462a106245c761f70": { + "balance": "1000000000000000000000000" + }, + "a0f06c86c49b248f4835bff405b620d12ec80d07": { + "balance": "484572382390000000000" + }, + "a10bc9f4d05678b26c4ffd2d92ab358163020b61": { + "balance": "10000000000000000000000" + }, + "a10c1197f7bc96639d01a652df73e49c669165dc": { + "balance": "1205859101575000000000" + }, + "a1221b2001f85f71e0655551e300ce115284b8dd": { + "balance": "1376698025177000000000" + }, + "a13fce836d65124fe5bcfa2d817ab2a043acbcf8": { + "balance": "55000000000000000000000000" + }, + "a15f1f609f7464906e0eb9d5e1d26468b90d9198": { + "balance": "16000000000000000000" + }, + "a1617dcf3acda60737e5ca9e4d0ecd82a98ef667": { + "balance": "500000000000000000000000" + }, + "a165c5f151d0daab905ba4a6d1fe5d5114fd7686": { + "balance": "41039049526000000000" + }, + "a17d5bed36c1059561e184a8a90a38ce955b92e4": { + "balance": "10000000000000000000000" + }, + "a18efb4e0950e7ac95970cd4591dacc286241246": { + "balance": "12403188476000000000" + }, + "a191fa6be64f2f6d2b4a7fb5a586416a605552c6": { + "balance": "60340281461000000000" + }, + "a194c15518cefbe94edbef3a2421586b51f7e1f6": { + "balance": "4153525550636000000000" + }, + "a1d0e41aacf83fc62fbecf35f8e873f8d734ecaf": { + "balance": "9000000000000000000" + }, + "a1ddd1f615ed483ef895e341f3266b6891f9b59c": { + "balance": "180411786335000000000" + }, + "a1f4d1e03114707a56ef9069bc20c6094e810d34": { + "balance": "51949145435222000000000" + }, + "a1fe101a65616cd03e3af03092be63434b7bf203": { + "balance": "1005401878265000000000" + }, + "a25a8225ce67c54048737601eac5e0d063c2fa17": { + "balance": "272038848571000000000" + }, + "a2714999233bcaff7294fa3e3b64c63ad45a928b": { + "balance": "14560781294000000000" + }, + "a28db3f7fb1771a3d77dfb19b54f88fd55b15c8c": { + "balance": "8000940572576000000000" + }, + "a290101bfe5fbc73146c4ec3ab5266c043eb701c": { + "balance": "1397563244603000000000" + }, + "a2924cfbcd37d0b321d6abbe57c645f9ce32340e": { + "balance": "200000000000000000" + }, + "a2a26c34f3d950c795fc965f6b1df3990e111403": { + "balance": "34525064429023000000000" + }, + "a2a2855851711bfc051c1f298821ae89e4c872c5": { + "balance": "491025000000000" + }, + "a2b956dd6f1934a4a44a026a18ac345ddabe42d5": { + "balance": "20096625821563000000000" + }, + "a2b9a118a79be81711d95485aa12e3efe78ca256": { + "balance": "10451051632647000000000" + }, + "a2bcf08ddd1778b30ea7882518148edfba2d9b20": { + "balance": "347033754668000000000" + }, + "a2bd489ec4790f4145f8a9a95c9c829c5c020146": { + "balance": "100311110878000000000" + }, + "a2ee35300ddf6a2491ec0e1848f8b56defafd7fe": { + "balance": "500000000000000000000000" + }, + "a31adf082ffd212df18d5a84b105a937e83b1b1a": { + "balance": "7124891785000000000" + }, + "a32c944e6c5fe186794b88d6bcbf51c47bea55ab": { + "balance": "732129357042000000000" + }, + "a33105d543f5d2b1220d4e1ecfdcf85699324dad": { + "balance": "74798779358000000000" + }, + "a3330c73e2d79355a14e570da1ec2e80f8048c69": { + "balance": "10000000000000000000000" + }, + "a3580034590e3052b9de5abd635e514ec5ba8694": { + "balance": "10000000000000000000000" + }, + "a360d8e2519dc6d7793cc371d91ad6add75e3314": { + "balance": "192622260840000000000" + }, + "a36b9b8b2adb20fb4a84d3025bf2e35baa8b7fef": { + "balance": "20000000000000000000000" + }, + "a3771b191237bef48339aa77ad5357f6227b358c": { + "balance": "512633055119000000000" + }, + "a3892bfd25705387cfb4eeb6d21089753c22e3e2": { + "balance": "258136912825000000000" + }, + "a38c793775ebfc7330b4331fe2dc848abb862b73": { + "balance": "1193250172232000000000" + }, + "a39417002ab94845541aded4a614a5a04af8187b": { + "balance": "1185722898000000000" + }, + "a3a79a9f929b54075de43689adb665ef914812ca": { + "balance": "100000000000000000000" + }, + "a3b59ea3d366f818ca09980846ac533d4685c121": { + "balance": "59734700360000000000" + }, + "a3c7b7c594a64225922e02039669e4d0b43fc458": { + "balance": "11779233750000000000" + }, + "a3cc39a68184e51f6445d3ba681a55f4157d4383": { + "balance": "10000000000000000000" + }, + "a3d414d9f210f7b77f90790ce09f6128abe50adc": { + "balance": "10000000000000000000000" + }, + "a3dfda16e5ae534ac100f56741b77b6f86786615": { + "balance": "9000000000000000000" + }, + "a3f79b9d1fc9d6dbaaef49d48fa9c9fb5a822536": { + "balance": "108910000000000000000" + }, + "a3f87414bc9e6f01c2fbde966fc8fb6edbf58c29": { + "balance": "441000000000000000000" + }, + "a3fa3f58c802d9a9690de760716275f14449045a": { + "balance": "437227558095000000000" + }, + "a417ec5a9749064a6521ca2bf9d05f208eeaed54": { + "balance": "959205202638000000000" + }, + "a484d5b883d2b99b81b7bef27e307957ecb64b15": { + "balance": "126491152120000000000" + }, + "a488cd48258e57d66f44e73a60c121f963cb29f5": { + "balance": "20000000000000000000000" + }, + "a488e3b5096e964b21cdeba12ab423f391765b6d": { + "balance": "1712050478592000000000" + }, + "a49dba65f28909e9bd2ce5675bd091f498c6c5db": { + "balance": "216802821062000000000" + }, + "a49eb6a791022c1324facc23d8813f9954d1c639": { + "balance": "287438914902000000000" + }, + "a4cc080a5c4649f511b5844a8e0b031927e13a87": { + "balance": "20333578449000000000" + }, + "a4d2624ac5e027f72edaa625ef22134217203b5d": { + "balance": "1000000000000000000" + }, + "a4d30e35c9617eafeda82866c96c3ce6bf14400e": { + "balance": "1223254927978000000000" + }, + "a4deae7355bd2e1d57eefa56600601b8b475a501": { + "balance": "36000000000000000000" + }, + "a4ff3b5abfe4e50adad16d01aaf62c3d4cdb5260": { + "balance": "20000000000000000000000" + }, + "a502b109869ef07451576bf0e13ab294e1f236b9": { + "balance": "94843398055000000000" + }, + "a517a3b5e4324197902e16f8a29e47335cf39c11": { + "balance": "100000000000000000000" + }, + "a51e101088da23c82907e3e2c65a058f0454b131": { + "balance": "196000000000000000000" + }, + "a52bcff6a7e2e70cd714058bc30a16138fe39899": { + "balance": "30429750204000000000" + }, + "a544e84c2bc4b17859d06f136b6e377e4e398b22": { + "balance": "143977568178000000000" + }, + "a54ddacbc17a98b9fb6292aab3d92f4c5753fd0a": { + "balance": "100583192014000000000" + }, + "a557754f6637a19c1a48cb9bf58c1fe897acf434": { + "balance": "2087038692036000000000" + }, + "a56649205d9ea247b49e03dacbed6c78c21beb4a": { + "balance": "5046177099585000000000" + }, + "a568136446ee6b3bf62a20238db3b11397a065f2": { + "balance": "11652249158033000000000" + }, + "a56a7865b526e315a9eb41f4847485c7e0c952fd": { + "balance": "50000000000000000000000" + }, + "a56bab2a9aac9d08a7bc9265864a80089b68570d": { + "balance": "37138466291329000000000" + }, + "a5965a601c5df7765cd70e5dad27dd23da67ac99": { + "balance": "10000000000000000" + }, + "a5a3161c44c34c441784b7df795067760b0ee569": { + "balance": "35053289069000000000" + }, + "a5c245cf843e691956007b94e259b437a4e6b7e3": { + "balance": "18749166170000000000" + }, + "a5d7de961c3b991dc78f2d6c0448fa6225116d3f": { + "balance": "1574510758868000000000" + }, + "a5f47d2081ef728808786128549a28a5662e92a8": { + "balance": "1750000000000000000" + }, + "a610c90f5b7e5f33044956ba431a3887de1c969f": { + "balance": "25000000000000000000" + }, + "a61c1919bc3f3181dc94e2230d35574cfc972d78": { + "balance": "8990565120000000000" + }, + "a62f1aabd91cbc0112e796d1ec3727fcd26fa293": { + "balance": "1311277302001000000000" + }, + "a64fff0bb32e32f81a541c393982bc59fa183b1e": { + "balance": "8291357610655000000000" + }, + "a673dae555d367b8d4a784274577a1884615b9d9": { + "balance": "27416452091330000000000" + }, + "a6c780b585355d84d9d3c13be5bd05374588e240": { + "balance": "913657165911000000000" + }, + "a6cc1f6f51862c2798adaa1d266988022005a71a": { + "balance": "284500645805000000000" + }, + "a6d9c82784fa20dcf28266d047db441cfeb8855b": { + "balance": "10000000000000000000000" + }, + "a6dae08f99e4fb57b066a645a259d8e4f7ac2bc8": { + "balance": "9044922773690000000000" + }, + "a6f49f36f8d10a796bc2afc9e069cb0c76004ddd": { + "balance": "128555691078000000000" + }, + "a721ce1c294a0f1957ebf9be20b0fffcf90111ad": { + "balance": "3392103457630000000000" + }, + "a72b82c33bd3d6060e8a04392d236775d48ec3ae": { + "balance": "1434465940701000000000" + }, + "a7344654f2a1a44b3774e236f130dff8a4721e82": { + "balance": "100000000000000000000000" + }, + "a748cced92a87066db8b29f931fb92e827488a9e": { + "balance": "5487679824758000000000" + }, + "a78dcb2bcbec2d0a60661e1715c9a95c9d573a68": { + "balance": "346798292989000000000" + }, + "a7a6c0505e7090e0b2c21394877f91c50be6b45f": { + "balance": "4125233658872000000000" + }, + "a7dcdd9b9785a44a2dd4c5eeeb863ac1feae0f66": { + "balance": "10000000000000000000000" + }, + "a8013e9dca1bd38975748de2fb6cb3af5cae74d9": { + "balance": "10000000000000000000000" + }, + "a807bf78b15c15cd9e8edcf586849db716fedbb1": { + "balance": "1458293606310000000000" + }, + "a83410ff00fb4b913dd0ea2003b38c5c3247350a": { + "balance": "2876442029807000000000" + }, + "a848f61298a409e77a03900712017572f35a3319": { + "balance": "2783106133600000000000" + }, + "a85bb81d0dc57f824a763814759fd93fe3020569": { + "balance": "4558027813744000000000" + }, + "a860611cd098ce98974313030d9f6f462bb274d4": { + "balance": "961594154368000000000" + }, + "a8799eeff72929ee6cbfb5b0c02985cd4841be3c": { + "balance": "500000000000000000000000" + }, + "a8c29b9b1349fac0be9a65873e1911b7439c9a63": { + "balance": "1264035560749000000000" + }, + "a8c321024a3c015d881efca33bd1b2c1788b379e": { + "balance": "528752788000000000" + }, + "a8d02e8925ed48f4274d8bee62253dc0d4f2989c": { + "balance": "209083880937000000000" + }, + "a8d2bde2ccd6bad67ee1b9550c9310accb37cd79": { + "balance": "49000000000000000000" + }, + "a8d61abc6a403adc183aeb74c83e4221fd28ee1e": { + "balance": "50000000000000000000" + }, + "a8eb6aa5a0c5b6d9260a202dc76ab674d9a5f3b9": { + "balance": "1041257515142000000000" + }, + "a8efc57efc776dcaaf4003a8cfa63f215ab0284d": { + "balance": "166144142685000000000" + }, + "a8faba86d87678294e311cfa7f8cbeb6f9d8a499": { + "balance": "124541781000000000" + }, + "a912e02f8eab0cb620316129875f919455201117": { + "balance": "6454482105955000000000" + }, + "a929ac95281d1a77a3eda3b5ac90a761ef03ff16": { + "balance": "1074305309650000000000" + }, + "a92a4e40519003813f5574397ce328d046f75802": { + "balance": "9188437500000000000" + }, + "a93850ba8fff3bd18ab259f87c58bbce84165fff": { + "balance": "39018890852058000000000" + }, + "a9843660a17c2d972246028cb8045472abdd346d": { + "balance": "1052681604185000000000" + }, + "a9866c6271733971e46df3c9bb27b3d3c513c166": { + "balance": "200000000000000000000" + }, + "a9b1299c0c064e766f9f29f4301a78c6e4931fcd": { + "balance": "267785134400000000000" + }, + "a9bc33b9c99dd5a3967387c1e99766f9bc74d591": { + "balance": "65356157048000000000" + }, + "a9ccf1cd2f816b15182997e3207d9a681bf21b06": { + "balance": "17521053440000000000" + }, + "a9e54bd9826f853f65e0be1ec0bb9c28f95e0eea": { + "balance": "6260000000000000000000" + }, + "a9ef563c872342f49817a903a5725b504d455ea9": { + "balance": "50134015139000000000000" + }, + "aa0d69c7e1382cd16c527a3fee48db19c38e1398": { + "balance": "142562301500000000000" + }, + "aa12abcc3ab373d07bf560fd200652c8580fd967": { + "balance": "5509242259903000000000" + }, + "aa1d6b968b3f8046a94f128864bfc612fc2e2700": { + "balance": "489179780895000000000" + }, + "aa20b8559d6dd1543e8c528775ae4b04c6242471": { + "balance": "169000000000000000000" + }, + "aa227e9d6074a60ecd43e1cc24092ee58560374c": { + "balance": "596190898010000000000" + }, + "aa7b660fec7b05968ba656eae9a8aaef4481720e": { + "balance": "674642002744000000000" + }, + "aa9e04077d44d288978a3a3ab0d7c251c0447a4c": { + "balance": "10000000000000000000000" + }, + "aaaac1e72955e9d67625cf8bed73fa643fb1cc1a": { + "balance": "9781187987000000000" + }, + "aab46c0c2db4e330834081f97678906252746f97": { + "balance": "16440184245000000000" + }, + "aade5358c52b8aa5ad8ff285c6b297e86f49fa0f": { + "balance": "982846000000000" + }, + "aaedb3fa2cf0ebca0ef4a121a28a406264ccc900": { + "balance": "100000000000000000000000" + }, + "aaf30bf76362a03450aefaf5bd68d28b84eb4962": { + "balance": "509106199370000000000" + }, + "aafbaaa6b6369e986ba72b196bd5f08cc458e344": { + "balance": "216372214000000000" + }, + "abb03c888d61c9102827a1dc0950145beb9d96b3": { + "balance": "144000000000000000000" + }, + "abc6dc937d7703a6b0c83659a328cde0d5008e32": { + "balance": "4052429106341000000000" + }, + "abd3910139a97cb92dc09a8a0352575bcc9ebed3": { + "balance": "24028359215749000000000" + }, + "abdc3953ef293c98989802063f8cb55e0e506432": { + "balance": "64000000000000000000" + }, + "abf1a47c582bc87d36e47cfce24e0ad249f42e73": { + "balance": "71947491720909000000000" + }, + "ac0b6e7aadfb5ffafd5cb3ef3620ebb0691cc3fe": { + "balance": "10000000000000000000000" + }, + "ac1a182607046b56e7a4bbab87cc1182874f79ef": { + "balance": "453499500178000000000" + }, + "ac251b311f781ad7a43d01b0b4b20fe891004e7e": { + "balance": "304621378298000000000" + }, + "ac258cec5ef49f96612d659f66dd4e6ea88e3c87": { + "balance": "255185373455000000000" + }, + "ac4000d9ad080740ef4a2ebe4a3075877bea277e": { + "balance": "10000000000000000000000" + }, + "ac7445c09372f15259fd852cc458783d6140c0db": { + "balance": "10000000000000000000000" + }, + "ac8d29dc05ea6c2f5409a76abe04321bf9381f32": { + "balance": "22464474197854000000000" + }, + "accd52b63822d8cb5117d9deb56596e072462614": { + "balance": "20000000000000000000000" + }, + "ace63a86a2ddfc79f677344e93dc0c4750b8fdcf": { + "balance": "1355066360964000000000" + }, + "ace83deb83fa8d319979658592b75ed13bdf97c7": { + "balance": "20000000000000000000000" + }, + "acf91515df16b21f1e5f5474dbefe596e4929b96": { + "balance": "1153047238967000000000" + }, + "ad04381f7ba89220e8fcd7e200f98a476683a904": { + "balance": "2000000000000000000" + }, + "ad22225bf225d8f705f93bdcda8d301180ea28dd": { + "balance": "1272512717188000000000" + }, + "ad3f74034ff5ca89f97b2585edf12376820307ab": { + "balance": "12303261515593000000000" + }, + "ad43a3527ad2b9445417cb73cbcb42965a5f469c": { + "balance": "67607364133000000000" + }, + "ad61cf9bf560bd5da75d55738477bd9aa25fb0b8": { + "balance": "4358939446693000000000" + }, + "ad649e8a3e1436e0604b0b8c9b1a5f1c09e06d7c": { + "balance": "344000000000000000000" + }, + "ad6b584813814db4c72c4c7eb31447d224074b46": { + "balance": "18445595367000000000" + }, + "ad7d404afc67c0e457fd3ce142cd30b506408683": { + "balance": "48218702840000000000" + }, + "adaf4d39b6806d132128ac438c2862c0a1650cff": { + "balance": "500000000000000000000000" + }, + "adda124baed2e1fdc1acc7b4a048eab0cd249212": { + "balance": "1074765673925000000000" + }, + "adef437c429d90a350b99750d4b72bc8538c5f98": { + "balance": "931901903135000000000" + }, + "adf826a0ea7dc4322d26e9d8c54c4180c1827216": { + "balance": "323567723315099000000000" + }, + "ae01d8b1668f8bfe6e225bd9bc746f7e839ac0d8": { + "balance": "321211880744000000000" + }, + "ae17de3ae6127022e53ebcf9e08457174cdee0e9": { + "balance": "3817903000000000" + }, + "ae243b0186793eddc6ebbb1a2c1f0b1cd574b07c": { + "balance": "9000000000000000000" + }, + "ae3ae1d41dfb16e19a1817b3639cd4300fd166c1": { + "balance": "55437674845679000000000" + }, + "ae506999882d4c6f05cc7979c342c0ce559a8df0": { + "balance": "1391755905401000000000" + }, + "ae524cee5aa23025d6ad185ccab75a6974335d53": { + "balance": "797132751509000000000" + }, + "ae5a55075d0541f179b085152bfc8c72c74abe23": { + "balance": "589408139567000000000" + }, + "ae63d02b18b464f0bbab4de943766bdc7ba2926d": { + "balance": "300261019201000000000" + }, + "aed8ffb86a49c09ae3a83e93d9045851434a9f0c": { + "balance": "1031991707237000000000" + }, + "aee18a9a2ccdf6025d61005827753ce4f510f7e8": { + "balance": "1818639022863000000000" + }, + "aee67910c514fa63a228769d5e15ca40bc4b26c2": { + "balance": "5688989238568000000000" + }, + "aef744eb2ec682dca128dc3149afcf881e367121": { + "balance": "818801643225000000000" + }, + "af04430b3e40e746127623532353a0f177a88fe3": { + "balance": "100000000000000000000000" + }, + "af181833edb15c9b2ee2329dcf1845b977361b7d": { + "balance": "93228805338000000000" + }, + "af30db29765b4fda6f075af96e8acd5046b099c4": { + "balance": "1000000000000000000" + }, + "af31fd30cfb10f1b0a12c2e7dd7ca56bdf517745": { + "balance": "36000000000000000000" + }, + "af70d6820e1d26194b0a9965b55254a287b162f3": { + "balance": "87593999609754000000000" + }, + "af96a573fa86c07389a71db797bea689419b23ca": { + "balance": "36000000000000000000" + }, + "afa4c5b674934e31a9aa5e3e723d85060d51c4d0": { + "balance": "10000000000000000000000" + }, + "afa6e4b4060c2e5969c2329d13cc42924412efde": { + "balance": "127502378589556000000000" + }, + "aff2308ac607f85392f4c8a6a043af67b7b849cd": { + "balance": "11130371831000000000" + }, + "b00ea9c459105b650def1e8569c85fa01837454d": { + "balance": "94928352162000000000" + }, + "b02a7d16ea8663c88416e6f64eaf57787d230be3": { + "balance": "17215604601000000000" + }, + "b03f4e9aa5c352cb1cec953d1123c2f22cd94b5b": { + "balance": "206022552274000000000" + }, + "b051459b91d253c5e8251a5a68282c291833466a": { + "balance": "297127749975000000000" + }, + "b055bdc874ca5a7d2f4bcbc51f1cfc3671b55f72": { + "balance": "1421913523478000000000" + }, + "b06156b99b891b756262c5b40db9bbe39fddc77f": { + "balance": "49000000000000000000" + }, + "b076893b9841d2775ec8883f05b74f1e5aec327c": { + "balance": "22591055478000000000" + }, + "b095de644af3c9f960f67502da6ac5eb050a158e": { + "balance": "4958067562725000000000" + }, + "b0a1f794cf70422395f74395abc9a7d0b271846c": { + "balance": "812057322000000000" + }, + "b0d36e0f426a99416425689c657fc6d64ad698ca": { + "balance": "1157727077158000000000" + }, + "b0f35fa554d6ed657bf3996cc027d045c3971fcc": { + "balance": "64000000000000000000" + }, + "b0f76b4c9afdfe35c41d588265642da60f1b97d1": { + "balance": "1000000000000000000000000" + }, + "b0f76b4c9afdfe35c41d588265b42da60f1b97d1": { + "balance": "2028311808491377000000000" + }, + "b1445842d56c56bc532d2f33ab9b93509c732a3b": { + "balance": "13522982470164000000000" + }, + "b156bafe05973bc839c4f115be847bbde8a67cb1": { + "balance": "10000000000000000000000" + }, + "b182e4d318893dc1c4c585195dbde52a84ed4ffd": { + "balance": "329498977335000000000" + }, + "b18f506e77df4db80ca57cefeaca4f1010f78f50": { + "balance": "956339304078000000000" + }, + "b1b6f617b110dd79c8fd77e729584d1fdfa9aa09": { + "balance": "16000000000000000000" + }, + "b1bba36e2d9e272e0131f4bae09bcfd92e0a63db": { + "balance": "64000000000000000000" + }, + "b2285651e57ae0ff27c619207cceacd20884d152": { + "balance": "1345938295122000000000" + }, + "b2419a93732d0d324daf7707fac3782a77b0dff8": { + "balance": "625000000000000000000" + }, + "b27206e9f2ac430841fb8da69b49d505f1558b8b": { + "balance": "29507819229000000000" + }, + "b2801fe902c7bbc987ba12ecae98765c99980fef": { + "balance": "240016083000000000" + }, + "b2843d5215ceb761e78f281402a1660c3abadf5b": { + "balance": "3335539720927000000000" + }, + "b2a22e6a04a2ce3287da3b8b6eed4ea1f18f05dd": { + "balance": "99999978999999999999" + }, + "b2d55a061fc6f90d2a05e0cbd26ffe0a1c3321c2": { + "balance": "1000000000000000000" + }, + "b326aec1cd523948ffec2fd1e8f21bd2b4308f40": { + "balance": "913000000000000000" + }, + "b32abc82b251e2d310ea7588cae4ad4acb657cd9": { + "balance": "26946233911000000000" + }, + "b36924d578973aec05ce7ab556d7ed00004949ca": { + "balance": "393041705867000000000" + }, + "b37482114c83e857c730588d7d959d300b8142da": { + "balance": "29429544454000000000" + }, + "b39998bade135ac6ccadff41cd709e161d01aa60": { + "balance": "26272579375000000000" + }, + "b3a995ee94f1d63d12f10cea5ab3d596c7c6f284": { + "balance": "64000000000000000000" + }, + "b3bf35e936fdbb7d0bbeeb1cf076f243855ed477": { + "balance": "754081187934000000000" + }, + "b3c2ac85b99abed4a2a52b5f96a2c98040d16022": { + "balance": "50000000000000000000000" + }, + "b3d1a2c0ab2d8987446d74f49e357adf5bf15986": { + "balance": "10000000000000000000000" + }, + "b3fbcd24c8394a5d2b7fe877f18681a109a404e5": { + "balance": "2558689648423000000000" + }, + "b4110f4e38405adfc054e55ff73c55842db8e2cd": { + "balance": "129000000000000000000" + }, + "b417f4681fdd4e53cfdf8550e3d326dbb0a557ec": { + "balance": "1000000000000000000" + }, + "b422970fb8799d83642b7ff715fc941d69e86053": { + "balance": "81000000000000000000" + }, + "b4237be71920497715826eae8d85c26cb3c111a8": { + "balance": "10499979000000000000" + }, + "b431839de4b21dfb44150cfc6ed00ea430a81687": { + "balance": "26839560174813000000000" + }, + "b43a0d6399c7d1be943c4b45838156a47c88f909": { + "balance": "10000000000000000000" + }, + "b44ec608b95d0d51105ce5f4b48de5dd72f346fd": { + "balance": "448125120000000000" + }, + "b47f63e14f6de6c3413b2be95a725e367ac18fb6": { + "balance": "500000000000000000000000" + }, + "b48071cd1b15f45028e9dec2237f14f10b7aedf9": { + "balance": "38042711385000000000" + }, + "b4b874b323b560aa0e4811ca574bd48b65b3fc72": { + "balance": "18063913676592000000000" + }, + "b4e4d4af0667f8158cf817bf1bc3eada08a551ca": { + "balance": "2149067370317000000000" + }, + "b4ecd625ffe470ee1fa1d97832e42ddf3f9ddf6a": { + "balance": "1181738860120000000000" + }, + "b53f380ce92787c1db461524290e8fcede552fe7": { + "balance": "12640674931821000000000" + }, + "b547e04ab8a44d3cae38704356f1f59408457b67": { + "balance": "286604155735000000000" + }, + "b562e4010a0a5fd0906a4cd9f47fc28f6f51e210": { + "balance": "1000000000000000000000000" + }, + "b584de7b38a2a2e3d9ff9c055b309ca56e5da5a9": { + "balance": "237896887904000000000" + }, + "b5c1129961c4a43673324aaedb8296f5ade82516": { + "balance": "4213058948283000000000" + }, + "b5da6711c72bf27c87923aed4a39349b4192e6b4": { + "balance": "55180742586465000000000" + }, + "b5eac5e7e03b9d31e40393e16e956cd588cb7566": { + "balance": "4508019435556000000000" + }, + "b5fd46ee4e02946dca3485439f98bdab290c82b7": { + "balance": "108321600045000000000" + }, + "b5ff2a3caef6ec30365f4f0ecbecbdeec1cacbba": { + "balance": "979696597242000000000" + }, + "b609d05242f7c13a4ae4036f6da9c0bae18dd70c": { + "balance": "229121731278000000000" + }, + "b611156a2f87fb45c431a5cf5740ded90c2dc542": { + "balance": "401783365700000000000" + }, + "b61c7623144afbd0f6cf44c951e4219ef8096119": { + "balance": "36000000000000000000" + }, + "b61cbe0e58ff6fa4c810ad03c759c79d9ff052a5": { + "balance": "1034495371371000000000" + }, + "b622bb67e95a03f58dc9aecf82c217e86f2cf7c3": { + "balance": "500000000000000000000000" + }, + "b62a50be3ce0e7cf8f61991daf8fa7e23775141e": { + "balance": "1000000000000000000" + }, + "b63cbff6b1747ad5cda101d5f919ce81dd67e363": { + "balance": "2570089937000000000000" + }, + "b65e80551a8687c9cef2d852949177c0e3b56e51": { + "balance": "100000000000000000000" + }, + "b68126ebbcb5ab9b0371b62597a38d5c1685b0df": { + "balance": "671140851028000000000" + }, + "b69f5830c371cad5a74ae823eb8892d153ef3c23": { + "balance": "18446744063709551616" + }, + "b6b4468c4db64e0b85cddc251d02f32fffcd1f7c": { + "balance": "10308006217291000000000" + }, + "b6c129312505e571148dbe69833d30550efc12c9": { + "balance": "5105834767567000000000" + }, + "b6cee8ef00b8674a9a96447e4511b30d6564ff67": { + "balance": "667754569888000000000" + }, + "b70f805aeba260d44f0730f0a9dec60f2b4f54a1": { + "balance": "2751303297000000000" + }, + "b71a901dc4b6c6463f7d221f868677bcadbcc680": { + "balance": "169000000000000000000" + }, + "b7385bd8f8257331f4c7a87c7a23724f615cff8e": { + "balance": "196000000000000000000" + }, + "b755692bc027e30730dc1d0e0b2a883830a84115": { + "balance": "30713083153428000000000" + }, + "b765305dda3c1e069a7a022ec127ff2140d0a820": { + "balance": "603122990932000000000" + }, + "b77403a4c56ffc7715b4bfdfe4b054336aeca466": { + "balance": "130840969728386000000000" + }, + "b78b2f6dc731d7d84b7eea151805f9208a1d0cf0": { + "balance": "142084687500000000000" + }, + "b792a0fd762c002a7585cfdefd36cf7ffb42fc05": { + "balance": "10000000000000000000000" + }, + "b7ccd7164aa7fb871726d9d043a8f8f890068c0f": { + "balance": "1170997140237000000000" + }, + "b801f49018317caf30f310dbe116f4e876184874": { + "balance": "50000000000000000000000" + }, + "b81ca2bc63cb4008cebdda3ce8f4eaba322efca6": { + "balance": "4678481047354000000000" + }, + "b82e3d50bf8c5b471c525ec8dd37b06688ed6178": { + "balance": "1202448975553000000000" + }, + "b841162a7a8876296f10794d8847d8095426aa54": { + "balance": "73500210754000000000" + }, + "b8421d375c3f954e22b6fd304235dd7c43b68bd0": { + "balance": "6499782706009000000000" + }, + "b859b76d77eb604728093c61fcabe6f9d22433b0": { + "balance": "196000000000000000000" + }, + "b86536268ace9be93a1db2012d6e3e59023ef2cb": { + "balance": "52878034904067000000000" + }, + "b87e1ac4fc423ab37e10ffd221df8056537b1d03": { + "balance": "119159824674000000000" + }, + "b8825a99806c5a968423e69d22f2b61a2f0ae9e4": { + "balance": "999999999580000000000000" + }, + "b8835acaf63e0e5d41fb743eb0f954040a38d381": { + "balance": "64000000000000000000" + }, + "b8844c74b227781d4b3fafd32e39ff6fa9857f77": { + "balance": "490694157000000000" + }, + "b8962e8bcbcf0f69144f8fcd2ec3ae8e54c05034": { + "balance": "1425313342735000000000" + }, + "b898b4ece8e0eea375f6eb85615652cc5c221593": { + "balance": "2284038029169000000000" + }, + "b8a949bfd9751c29c4cd547cca2e584d8dac4e12": { + "balance": "50000000000000000000000" + }, + "b8ad5ce2ae781e2d245919c15bbbc992185e5ada": { + "balance": "733786526623000000000" + }, + "b8cb6a9bc5a52b9cfce26869e627b2af0ff5ed4a": { + "balance": "98364826821577000000000" + }, + "b8cf6aac7b9028649f0d55a57b61640d70cef120": { + "balance": "104799890645000000000" + }, + "b8e827b5d1e10a3944039adb1a3dd7ff6949145c": { + "balance": "172413427060000000000" + }, + "b8f6d7f33ee5755ba56647ab8fc9ca27b8aba677": { + "balance": "1430769696978000000000" + }, + "b9221177e2b09725bc95f08c72c17c42887eea62": { + "balance": "1212779749827000000000" + }, + "b936e0d83cde9bb810b85ad58eb5ff0fa9c11654": { + "balance": "4999580000000000000" + }, + "b961d435c457e205fdbed5442c8614ecfd59616c": { + "balance": "27847452621284000000000" + }, + "b969e9d89f32002cd4f90ef5907bebbbdca6fe6a": { + "balance": "12455448454838000000000" + }, + "b981c9137cfca5389f0123927852278d2d7ff618": { + "balance": "92180707865000000000" + }, + "b98abf0fe91b0d3a16c6ed37aea446baea33fd23": { + "balance": "560454425563614000000000" + }, + "b99ab4e6ae277b9fb04537adbb781e8390b490ad": { + "balance": "32814665223319000000000" + }, + "b99d0a433d7994743dd675894c18ed03164436e1": { + "balance": "16000000000000000000" + }, + "b9d8b6f0a505d217709bb9327f3b9b3f84813e00": { + "balance": "81000000000000000000" + }, + "b9dbd64e3c8e6ad84c9c67c66e678c06ea7bcb91": { + "balance": "1161140466507000000000" + }, + "ba361f7a6dff16a96f957c63e08267dec8f9ecf7": { + "balance": "2170060167590000000000" + }, + "ba47f4136f74b566f62ba373651332b59e74e1db": { + "balance": "906249296535000000000" + }, + "ba5287cf15de91daeaea2465da4d4c1a14dea716": { + "balance": "98978398162000000000" + }, + "ba77d056d52f84e740579aa527792f826591c858": { + "balance": "50000000000000000000000" + }, + "ba895406774ced5fd2e759b58f9ffaed5e04fb14": { + "balance": "10000000000000000000000" + }, + "ba96fab21a4926fd1137558ae996b52ec14538a6": { + "balance": "10000000000000000000000" + }, + "baacc247801eddbf152fd6ec39d659f265935743": { + "balance": "2661902597584000000000" + }, + "bab2eb9fab8e699a958699b15ddc7ada5428d33a": { + "balance": "27006404153000000000" + }, + "babeacd7933c817472875c86bf126e6d11886f8c": { + "balance": "2461234517292000000000" + }, + "baf7021d4d754d4478d3c3624c2376e3f1d4ee5e": { + "balance": "1352066301857000000000" + }, + "bb0760bd1da973d8f70dd0caa6cadfcfd8199231": { + "balance": "177674700430000000000" + }, + "bb278c6a52eebd0b8950e9b78ba211453ccb1b6a": { + "balance": "25000000000000000000" + }, + "bb327e5f260b2dfe25fb180c2d3f4b63211c1dee": { + "balance": "7694972715000000000" + }, + "bb643e768ab20c135e7df3f400284cf04c40a6f7": { + "balance": "385756449779000000000" + }, + "bb73d1d1c289b4953d0033b52d9d2d0d92573d22": { + "balance": "11000000000000000000" + }, + "bb89936d562b19e4c599826ce7cd0c60cb02b512": { + "balance": "725910446589000000000" + }, + "bbc509b7999b0e94534477b98ec8927cba879677": { + "balance": "20000000000000000000000" + }, + "bbcfa9ab62f4eab14d6a1b09c1aa554dae113183": { + "balance": "589417352665000000000" + }, + "bbe78301134249b52b74d73ee3855e7e3d288a40": { + "balance": "4456159000000000" + }, + "bbe7bb4c4f1b506b58f7e3334e6c89011cf2d6a7": { + "balance": "3889127030000000000" + }, + "bc016690596e077273465d1728d18553b185654c": { + "balance": "185932953686000000000" + }, + "bc16b2ab9c7ab309249f93b496b75c6a7392cb10": { + "balance": "5000000000000000000" + }, + "bc254e5405b154b98abb5fe5508d3e7c98663f4e": { + "balance": "144000000000000000000" + }, + "bc258aeb0f18150d3ca253c6bb04f63d657d99ac": { + "balance": "6011905701701000000000" + }, + "bc2620b5ebac12a88b287b625fa5b336568e7869": { + "balance": "534886892259000000000" + }, + "bc318687cfaae2be4c5ece4a18bb9252486a19d0": { + "balance": "147226513970000000000" + }, + "bc32dd123fcc2ef0dc36484c3ab1bae5d9890761": { + "balance": "16000000000000000000" + }, + "bc5c5151be06aaf6180bc9c1058b181a5a30366e": { + "balance": "113865120384000000000" + }, + "bc66241ca430dc31a3e2f44dedba868e16b9a6a1": { + "balance": "50000000000000000000000" + }, + "bc7c371af0688b1c409f4b07662609a1c9efd120": { + "balance": "20000000000000000000000" + }, + "bc9454f7efc86e25d18a8e8b6e230de42a51d967": { + "balance": "148103676062000000000" + }, + "bc9d5456b975bf0b95c161c3355e4ceb28898fd9": { + "balance": "28083912047000000000" + }, + "bce0b47bf13e4517c53bbbe6e51544b99f3147f6": { + "balance": "919711480389000000000" + }, + "bce2d1ec7c41b426f72b352f5f2b7da3edac4157": { + "balance": "908085365725000000000" + }, + "bcf0756789a57f16206dd78bf6e1322ba9b9b85b": { + "balance": "110888224252000000000" + }, + "bd0bc4a0730f9f55a2f65f62662c7553db52238e": { + "balance": "8440290043000000000" + }, + "bd29fda37c2581a3f040c77eead3143cff24a346": { + "balance": "126022762542000000000" + }, + "bd4c1270322a26a1b825040b239008a447c31918": { + "balance": "727012140904000000000" + }, + "bd6a3da2db66dc9fa26fa2b63b14003d26ef91d0": { + "balance": "5492112771780000000000" + }, + "bd80fcccac60078fcf09f5bddd8a25a92fb9cfdf": { + "balance": "10000000000000000000" + }, + "bd92dc94b6e81a3da5dc3ae6bd80782622658196": { + "balance": "10000000000000000000000" + }, + "bdb35c2c595fe7a2864ebe20dd56d6ddaf9d447c": { + "balance": "4346566125000000000" + }, + "bded4718cbad2150c9b6df9ee7356e0f5c713cea": { + "balance": "311694803600000000000" + }, + "be1804630ecd95ac411b935566cecc5a24c6f18a": { + "balance": "85033246331000000000" + }, + "be2318ad50b0a85b95870a81dce5c31029636159": { + "balance": "5185298019030000000000" + }, + "be3de52fc1119f02f4707f353c040b7c4222d847": { + "balance": "25267399461000000000" + }, + "be4feae01d429c872601ae84dfae8fddc3372686": { + "balance": "20000000000000000000000" + }, + "be7c09d704d16e4b2c9e19cc8c07808bb335f926": { + "balance": "25000000000000000000" + }, + "be873a9525899bdad5e4376b0115950e534dea2f": { + "balance": "404116929377000000000" + }, + "be891b1680ad835aab1ac05a30c0813306cf20f2": { + "balance": "144000000000000000000" + }, + "be8ed2d85a5e3f83c6105db1a1f304e9f174bfce": { + "balance": "50000000000000000000" + }, + "beb1cd80c2f8fabc27ee3a3b2a15e35fa52e7879": { + "balance": "11539095431000000000" + }, + "beb67375e46950830906bf281209be133075452f": { + "balance": "1305262446956000000000" + }, + "bebe54437722c6000bc6a8843f159538a2abf613": { + "balance": "41042548942568000000000" + }, + "bef2a05e283ae948efa9b0e3a6ab5d26a57f1de0": { + "balance": "180614450853000000000" + }, + "bf03950f265a4182b4402703723a0311158eef4f": { + "balance": "158997402149000000000" + }, + "bf06393654baa1ad15c2e717e06dbaa61834c214": { + "balance": "34409427774000000000" + }, + "bf2b867313a44bd04aceaa644771d1e95317c881": { + "balance": "10000000000000000000000" + }, + "bf350ccad91a2a2aff4cf27a291323a297a78009": { + "balance": "124593326152000000000" + }, + "bf3d86edfcf52733e91a9c59be606a95bd921885": { + "balance": "20000000000000000000000" + }, + "bf5b21d5e339752b33b180064d0e6047338650a5": { + "balance": "1000000000000000000" + }, + "bf64c2715db8f353600a45b9264e1f22a40ef8c1": { + "balance": "2952972677360000000000" + }, + "bfaff32c8b04a61658ff94f94e4687232b8d2d7a": { + "balance": "1117691379350000000000" + }, + "bfb00182321502e0729d9a0862ec1df1b3e2208e": { + "balance": "500000000000000000000000" + }, + "bfcdfc9f60610f0ca279ca2c89b9af831332aece": { + "balance": "1431082635308000000000" + }, + "bfe14356e86f6b2ad470bc77d250517c8dc03d15": { + "balance": "310115085185000000000" + }, + "c008bd3fb881da9dca4cadcc56b1d99c56db9abd": { + "balance": "12899598792000000000" + }, + "c01efea456d30360a78ee10c790d46bcb889ee61": { + "balance": "103203021492000000000" + }, + "c03d622627bba7d5db1a9f699924e9d5ff5640f2": { + "balance": "95102233308870000000000" + }, + "c0465ed806ce7ee730e5b6eb7b86a754bfd196a9": { + "balance": "1654379359619000000000" + }, + "c061c5b0d0ce7af95ded1805abb23f743e13c455": { + "balance": "500000000000000000000000" + }, + "c074f2024f79cf8d7aab2d858dd110fc2ee89d41": { + "balance": "18382732686000000000" + }, + "c085147a76d0336b4bd6e7d5b60d394bfd3c6f42": { + "balance": "3236912707535000000000" + }, + "c089416d2d679cb2abf44251de227d0a08fa1206": { + "balance": "497124416350000000000" + }, + "c09d8cfd85989397dc723f2df821dbfb2c0c39b3": { + "balance": "833485701262000000000" + }, + "c0aaf130e3b67250d9775d62e7cd3963daf0a627": { + "balance": "1249947125780000000000" + }, + "c0aebdb5c2e8c5ff9870535c738bfe892c9365dd": { + "balance": "360097616959000000000" + }, + "c0db5680ba88052652bfd5a617c4e8a5be188077": { + "balance": "509051625766000000000" + }, + "c0ee350e5e09a2daeff332a66a6e117fad102112": { + "balance": "10000000000000000000000" + }, + "c12c0a3fd42501f8772e4ad5d262eef3f0bc4701": { + "balance": "120398848512531000000000" + }, + "c135b48c7fd11670bbfba923b28767d21d7923ea": { + "balance": "20000000000000000000" + }, + "c1397c66b7f150c0062b0e87c981c107d771b109": { + "balance": "87751498250000000000" + }, + "c1507ee435cf506fc5d8e4cb62515f2ea0f3a7ae": { + "balance": "4935384099000000000" + }, + "c150d185e2cf203054a6e328b72d8c35bfbbcc33": { + "balance": "21044148271000000000" + }, + "c163098f8b8f0736862274860b3842cf14bd2288": { + "balance": "119025568966000000000" + }, + "c1687fbbc7d504b73fe3e71af440b3dec0da88b2": { + "balance": "229520711528000000000" + }, + "c172bf224080d448261b3b66453074b28628daf7": { + "balance": "7903438287958000000000" + }, + "c18e9bc05dfee2a39fe2b6778a24a48d5bf0f141": { + "balance": "500000000000000000000000" + }, + "c198fec4069c95300d34b9c7109d7441b8e62745": { + "balance": "50000000000000000" + }, + "c1b4134f4757d19a687d05bd7087872b5625405f": { + "balance": "20000000000000000000000" + }, + "c1b43ca2af534ac6bcad8f23c30c07ba07e7e8fb": { + "balance": "194999622000000000000" + }, + "c1c2249507d2dcaf4a9103fcea2cfb47aa4957f7": { + "balance": "571416394325000000000" + }, + "c1e90af40fb64427aeb79a13607debbae9270b52": { + "balance": "50000000000000000000" + }, + "c1ffc8938f3412d19d428b8450f17fd394ae539a": { + "balance": "36000000000000000000" + }, + "c20013e25ae53d0d41bf365aa767822bbbe70936": { + "balance": "10000000000000000000000" + }, + "c20e9eadffa5529ce58a39f5898f39906dcd4b78": { + "balance": "757301065305000000000" + }, + "c211fc2623d51846d26952628d140643efa5156c": { + "balance": "865384323985000000000" + }, + "c2546c312570b30ad2ed05edb13b6469494c5b92": { + "balance": "5000000000000000000" + }, + "c25b2280ed0f835538f8ffd9dfc08a3b853f1ccf": { + "balance": "1000000000000000000" + }, + "c260e43b89a7a4e84bcc4c21dc43d4b5e6923f3a": { + "balance": "1000000000000000000" + }, + "c26aeef0e1f382c88bbdb1eb8c01afa7f58218ce": { + "balance": "79774757760000000000" + }, + "c27dd2645254bc30b6cf7bf418803b02ac808b5e": { + "balance": "4419594173874000000000" + }, + "c2b4f6cf92d6d63a20034e409a358df1803159b8": { + "balance": "1630820442000000000" + }, + "c2ba4a7ea6ca2d17231fb17ebd5dd2dfc0964de4": { + "balance": "221662324727000000000" + }, + "c2bc18f24b8097208a8b2418c444ea58beb94281": { + "balance": "1766754009521000000000" + }, + "c2c028dd17f8a89b9131b7daaeae9cb1dddf86e7": { + "balance": "10000000000000000000000" + }, + "c2ed78a0cb850c12ce8e6ff3873e8c18ffc9f4b9": { + "balance": "1017518755567000000000" + }, + "c2fd7296210b7013d476205d2517d51b21c9e76c": { + "balance": "500000000000000000000000" + }, + "c3041d3d650ff6ac3e35b60371b6798360727651": { + "balance": "1011071365226000000000" + }, + "c328ab9ce1fddd5623e0383828714a7e3ff12eff": { + "balance": "285042661579000000000" + }, + "c34ab008ddddf376dd866cccae4a4d6eb88403e2": { + "balance": "2798642711076000000000" + }, + "c3511391c4515cf8f27e9bc0f777a02a4125c8b1": { + "balance": "20000000000000000000000" + }, + "c36916a9fdf656bb1a8c2f7fb752a3489020f6ff": { + "balance": "689483152953000000000" + }, + "c37598a388d6f4e8e046923265ee9256456e40ab": { + "balance": "62865106394696000000000" + }, + "c38813db256eb221a7142d042b81ba2babab2c31": { + "balance": "98477603778000000000" + }, + "c3acd30f0bc3146fc2cab8d54904f98289021374": { + "balance": "17820000000000000000" + }, + "c3ede34dc1cd995fda1c5cb6e9ffd0c0da080587": { + "balance": "1080428143758000000000" + }, + "c3f04dffe2be55a1d6cdaa78e5c09a79d0477e7b": { + "balance": "59747493842929000000000" + }, + "c3f09f681cfb57d3cabc547dc32a71d2a6585c1a": { + "balance": "1757648436173000000000" + }, + "c3f3bb6444d853614f18c04a3c81f7d26e62e96a": { + "balance": "9022830778000000000" + }, + "c3fe4534327a2fc4144e2d3d3392f7b78d2aabc5": { + "balance": "1759225739027000000000" + }, + "c424f5be9490ec7f0f1e2debc3f72bd83e35f587": { + "balance": "1774372626989000000000" + }, + "c434f64eb937207f80e9a02d2f77ca34bfc63aa2": { + "balance": "960850858644000000000" + }, + "c438b6fa5801a4b8dea450530d975f174cdd47ef": { + "balance": "64000000000000000000" + }, + "c446effb984ff3e5ed92280e7b3dcdb1284230b3": { + "balance": "503490303680000000000" + }, + "c453ae9f94253ebdb871e9dac19056b13d1747a3": { + "balance": "1621494076559000000000" + }, + "c4a473b5e3a6bfb51f963d4dcf109bddedf4fb43": { + "balance": "104273242373000000000" + }, + "c4b8058e9e5416e526ea16e37f29dc221d28a003": { + "balance": "1833513486496000000000" + }, + "c4c09f4bbae0ee06f2a52ff0ef0de1978b5305e9": { + "balance": "20000000000000000000000" + }, + "c4c5981f5ac0a9a3701663b887c4aaac3a3a4d1d": { + "balance": "1411640000000000" + }, + "c4f7a493d16aab4d18e88e530e75e3095a3439ee": { + "balance": "191606419322000000000" + }, + "c5259c18bbd8b0485ca83d069d5ac235b28f24ea": { + "balance": "1276479076242000000000" + }, + "c526ef1124c7d0549b117e7b7463539a24209290": { + "balance": "9106523141000000000" + }, + "c5278b9eeff2221604f30f002c307ca2882fba97": { + "balance": "20875716591000000000" + }, + "c527ca73562846de9fca1649fe5144e5068a2f6e": { + "balance": "25000000000000000000" + }, + "c52a960c5df55169ed5d5cb0109a576321ab82fa": { + "balance": "1097338876493000000000" + }, + "c533ab799e5a04e0ba4e4780d632e0044262d216": { + "balance": "200529941482000000000" + }, + "c5389e3ee2f043ac2b6481f254440a97a9cf3bdb": { + "balance": "84047554571000000000" + }, + "c5594292b324c1d63f797c588a589c895c680ed0": { + "balance": "334298857161000000000" + }, + "c55d7ae4f29d857182d5f1ac2a78cbf35a694dc2": { + "balance": "500000000000000000000000" + }, + "c55ead0ece8fcfbecc573666c0170228e089aefb": { + "balance": "438775082956000000000" + }, + "c55f7d73491cdba391b631581029de32755a09b8": { + "balance": "1340000000000000000" + }, + "c56cb4e8308d6462eded0bbc74965ee135e23e11": { + "balance": "568187503785000000000" + }, + "c5b0c5f840f579536d5977a77262458d72ef1490": { + "balance": "5880686297881000000000" + }, + "c5b129c764daac8bfbf023646b9306d817a8ebdd": { + "balance": "10000000000000000000000" + }, + "c5bba43db949e2ed3de3036caf7a6e42558b1ef2": { + "balance": "763947031151000000000" + }, + "c5d57171e5b9cbafaba7d2c13cca3ec9d81bda49": { + "balance": "25000000000000000000" + }, + "c604e6c539c857ae9e60ca20d1906308ba431892": { + "balance": "100000000000000000000" + }, + "c607bdc5ad2f189e9356edb4d7975c7ba9300836": { + "balance": "55828814399000000000" + }, + "c60b0d2341ecada6c3faf1efcc9027125d99e17a": { + "balance": "121000000000000000000" + }, + "c61e1b993c3fd91a1023ba5b92d06a0aa539d92c": { + "balance": "23863993763643000000000" + }, + "c624656ee5298786cb3d0de045b0ac089c5341d6": { + "balance": "2210389938000000000" + }, + "c6573a023d6f4b5e151f266af4ec0045df0d1518": { + "balance": "52505006485983000000000" + }, + "c66b1d84c42018b16dbc4777409bf50a49febba9": { + "balance": "9078953000000000" + }, + "c69e4de93457f251b1e0879b5250b26e57839fec": { + "balance": "500000000000000000000000" + }, + "c6c51205c9f0bcaea05dce8e47e91d94a3f63c2a": { + "balance": "2720612321571000000000" + }, + "c6d237e0936c4714e701823aadb368fdc471451d": { + "balance": "541700595551000000000" + }, + "c6dcac15739872089cb3d23287e8cd546487ecf2": { + "balance": "1023857245227000000000" + }, + "c6f40b81a5860dece34305f53570be61cdf9a8fa": { + "balance": "20000000000000000000000" + }, + "c7147a95cc4f6bedce6292e8f95539caf550e9d6": { + "balance": "20000000000000000000000" + }, + "c7185b1a680d8b0893065d8213de54375d086420": { + "balance": "11564622085000000000" + }, + "c71b3876613c928197aadf3dd7888db3665f28f0": { + "balance": "112276274428000000000" + }, + "c72200bb380db62a3fd741713d332be77bc1a4ed": { + "balance": "6962060809000000000" + }, + "c7345cd5a7eafc9d7ebdc17d674f83e23336538c": { + "balance": "4425703195684000000000" + }, + "c734f9dc3ee2d857ac826b101129eb77a4a22256": { + "balance": "100000000000000000000" + }, + "c736fa9550b73f4a4ca0ac1cd94bf6f42ccbb11b": { + "balance": "449139000000000000" + }, + "c74128ea37f5d1ee016086a38e470bb332eb5270": { + "balance": "40479951869000000000" + }, + "c7647ec91e823cfe57e8a3433ddafd7b4f675b80": { + "balance": "307102062000000000000" + }, + "c76d49334ce25f5fc62841e5a87d4e03ab3edd9f": { + "balance": "109999979000000000000" + }, + "c771093ed5c4df518536b76e013e8142ecc3f9ed": { + "balance": "5247752820195000000000" + }, + "c780dfb4cdcba4dc89245a8be8a93de1a3e82d3c": { + "balance": "205580199482642000000000" + }, + "c79c6c3a0a46052f723a26b1f107a332474df3a1": { + "balance": "50370325181000000000" + }, + "c7a4e02d2c0f00fa56662cc9f323cabeff82759f": { + "balance": "1163435680762000000000" + }, + "c7c0632cff11812130c30163c83746839a625f95": { + "balance": "10000000000000000000000" + }, + "c82238664bedfa8ded51e91969a39f13a8262a37": { + "balance": "10000000000000000000000" + }, + "c877d228c350ec0d8d97802e7d874d3130171813": { + "balance": "199845203467946000000000" + }, + "c88b8a2e498fee366a1290a575a7f09da12ea8b2": { + "balance": "50895598476000000000" + }, + "c8bbd0e52b11ae6a20adc5f6bbe4d34d7440e8ca": { + "balance": "114566193776000000000" + }, + "c8ca2bd1bef02b505f0333996bcb6bf730648390": { + "balance": "1177250974576000000000" + }, + "c92c3358910418fdb3950e1a378af7246553ae38": { + "balance": "81000000000000000000" + }, + "c9325c9b6d2af226bc5ae1cc975e00cc11274cd1": { + "balance": "2927587698197000000000" + }, + "c95ae8dbc8bb075e7dcb2b2c6d9411bedf26244e": { + "balance": "931878010706000000000" + }, + "c98fc33c1d980052d75fee8b34d08796734b6a4d": { + "balance": "8671327034000000000" + }, + "c99fba8321d16cb19c55703b407c54ed106dcdc4": { + "balance": "20000000000000000000000" + }, + "c9a0da2a3be799e751738e61b9cc376eb06e2b00": { + "balance": "50000000000000000000000" + }, + "c9afc551058c32e89bc2d6704d0d00e92f5ef6d7": { + "balance": "11135553563900000000000" + }, + "c9bfa2ad4b3e9c624255c6ede116421b04487d65": { + "balance": "105514983171000000000" + }, + "c9e4b61d8ddeee339e31ba088efb5d608c3464a5": { + "balance": "20000000000000000000000" + }, + "c9e9090d9f95f401c87c7240f3bf88ca9b540f8b": { + "balance": "553735838243000000000" + }, + "c9fd40bb35284e3d7f0dd3b43a1d9e958f7c86e0": { + "balance": "50480449695128000000000" + }, + "ca038c7c9e66531ad79e4d67b42d7920b7f05c26": { + "balance": "64000000000000000000" + }, + "ca0d08f6019884f94f2b5b191ac9bb247150cd13": { + "balance": "25078089364984000000000" + }, + "ca2c6e6ed3d6a1d030807f91e1fd5c79d36af86f": { + "balance": "849454139892000000000" + }, + "ca7c7bbc24cac0f3aabfdccc77df21004672e634": { + "balance": "6952718700000000000" + }, + "ca998c74383b55c8dcddd46b49f95456fb056b7a": { + "balance": "2000000000000000000000" + }, + "caa989e6a1e934532aaae6cad282c18b1a0b9fd6": { + "balance": "2335540529729000000000" + }, + "cab32ee5cce74e0ee88bbd4b505aa587ef2e4bbf": { + "balance": "75914058971000000000" + }, + "cabe9f0d0a18de8d3495dd063b04c6a33584a8c1": { + "balance": "116083536145000000000" + }, + "cacde94daeafc06e46c86b1e20387a23d909ace8": { + "balance": "1521003430346000000000" + }, + "cafbad01b81ad6cc401883773994a9dd6e6ed913": { + "balance": "10000000000000000000" + }, + "cb343b882cfe866f73cd5f0f31fc68cebaddd882": { + "balance": "221801563082000000000" + }, + "cb3a7aa2e97517b6ea8d9ed0ac270a6a9cc6e079": { + "balance": "958830201738000000000" + }, + "cbd2c4916211ab2c234bc8a51e6f680b59aff782": { + "balance": "24279462419000000000" + }, + "cbea4ed5e8d2ffad442e482fa5f8d551ef2a58e6": { + "balance": "26730000000000000000" + }, + "cc001ce4f4417505116486bed9fdf04bf97ca246": { + "balance": "31740534557000000000" + }, + "cc0b53b26b6dee9f8226f25b834085bde13f5eb5": { + "balance": "132440104515963000000000" + }, + "cc174862456f02f349303d1b8328495de8ccd789": { + "balance": "155951512603000000000" + }, + "cc2af3921727d6d2de31d5f656f837a5475de6cf": { + "balance": "10000000000000000000000" + }, + "cc3201749f55f0d7b450110bc11f65b1ce165d2a": { + "balance": "123428947550000000000" + }, + "cc3f37ad6b449e39c544e26bbdf4d7be66b9dab0": { + "balance": "348574664284000000000" + }, + "cc5b36c9ecea12ebfd0721a58ac11b0c340a3f44": { + "balance": "384197170701000000000" + }, + "cc5b410c7797faa05ac4233eb31b468ee4bf279f": { + "balance": "10000000000000000" + }, + "cc60b223554cc6425374c5e2424df7007621368a": { + "balance": "1128118098000000000" + }, + "cc7027381d98c2e883c82bb9c2f85b985e1e7b4c": { + "balance": "1370000000000000000000" + }, + "cca378f16e07258b9c15921233110fb4729645d2": { + "balance": "151974946930000000000" + }, + "cca781d996c3ef985bf7d2b4d68d55f52efe1905": { + "balance": "2217463190039000000000" + }, + "ccd0b9f6ffb0383553c355c6a14be1200966d47d": { + "balance": "12917165349191000000000" + }, + "ccfa4594129bbb9d07cb4ae8dc2b1c8f3bf98508": { + "balance": "524845286088000000000" + }, + "cd19c879df458106d179bbb5b7f44609d68e6e5f": { + "balance": "8601633489844000000000" + }, + "cd1c55037a0570e8f9aaa95ef157ae81a1969250": { + "balance": "10000000000000000000" + }, + "cd1e47695b0fc93b82cffd0326852dc04d8441f0": { + "balance": "144000000000000000000" + }, + "cd1f90c388d76b3aeaf77850f2191f12a2311f51": { + "balance": "1728456799866000000000" + }, + "cd3aecd58de07f80b64044875fa6ad4f18f72789": { + "balance": "2648597880142000000000" + }, + "cd4f39123ece1e0ab52cfa2a5d059b49c4d63c3f": { + "balance": "1661718859439000000000" + }, + "cd6ed2f7ab49515f8fd70aeb4d72bfae8956b5f1": { + "balance": "183807926254000000000" + }, + "cd9d9d07fcf476a8ee7240324a602449606d75f4": { + "balance": "100000000000000000000000" + }, + "cda66d375a10a22f13dff8a9c40b63461daddab3": { + "balance": "1116940051064000000000" + }, + "cdb0832ee5b26da24b1775c4cf0dfd669b94ce00": { + "balance": "23919219542965000000000" + }, + "cdba5805f17df1f3e47647464de978944ed36b62": { + "balance": "4204539000000000" + }, + "cdd1df8bd54941e26ea26eebbd537e751f64f5f7": { + "balance": "5000000000000000000000" + }, + "cddf5b34342200c37ba96eb0dd662ca4c29f89f8": { + "balance": "10000000000000000000000" + }, + "cdf6c838980afd91a600e3fff755a4848d138568": { + "balance": "25000000000000000000" + }, + "cdf7f55a5a16572d2f2bbf7faeffe3c4d64f86ab": { + "balance": "3115969322502000000000" + }, + "ce0f1dbbfa3490a21ee4b28232db612f44bb7bf1": { + "balance": "9227310122000000000" + }, + "ce33184573c33dd859450304984fa63ea4f2b62d": { + "balance": "7055925237496000000000" + }, + "ce33a3db107f01c51d30b24a8db80faf05308bb7": { + "balance": "10996113113089000000000" + }, + "ce4922b3daef62914f0580a55c524e6a02e31d83": { + "balance": "5541295938315000000000" + }, + "ce4ce8a8540678dda16380c211482dd8c8b71092": { + "balance": "6224176337062000000000" + }, + "ce62cfd71abb9979a0acc398c17dbb5cb6da4721": { + "balance": "13448605175000000000" + }, + "ce724bb30c7821a9c847e0a3e9c12843c3471f9d": { + "balance": "252657175031000000000" + }, + "ce8af01494c2c5b4e74bb02dc6de982e7234fed2": { + "balance": "77349533545000000000" + }, + "ce8c774b7f92045faec43e9cc1711224a3b32435": { + "balance": "370287579971000000000" + }, + "ce8c9ed5018559f36ec72e5a9b0701724e498b51": { + "balance": "142866501748000000000" + }, + "ce995c13568a8b1521d4c9721cfc11da4891860b": { + "balance": "1000000000000000000" + }, + "ceab9dddc767a9651e98527fcf51f6e85c9ae402": { + "balance": "5251411770975000000000" + }, + "ceace25f8c7cf853500a461df007f9c9703ac4a5": { + "balance": "1428847332255000000000" + }, + "ceb0c49dad36f6169ec82a2f0d80da36c87e4209": { + "balance": "459821324064000000000" + }, + "cee8083233bcb4d50ddbf2121c90b5c2019ca58d": { + "balance": "557985245088000000000" + }, + "cf0c6bcc66eb75899bc7f8ed4b8d2b29437bfe85": { + "balance": "3252418478000000000" + }, + "cf32c5bf1d7ef0cb0f2f190f8468b01a4f2d93e2": { + "balance": "6593164924646000000000" + }, + "cf6e47463382153fcf0ec6738880925dbc08116a": { + "balance": "1091910654350000000000" + }, + "cf7539096fd0cd97cd316efcfe9d3c87a101a74c": { + "balance": "741847588809000000000" + }, + "cf9439bf2fbab65cecd783e135a37127f585f1e5": { + "balance": "50100000000000000000" + }, + "cf9bdc902604fab070c611ebf6a989ac4a785c82": { + "balance": "1501000000000000000000" + }, + "cfbbefc0e6013fa2caeabc54ac05f45dbf17ca13": { + "balance": "230809632301000000000" + }, + "cfd53f18ac7d94cadd032a0f4cdbdffaf4765d6e": { + "balance": "64000000000000000000" + }, + "cfe66dc4aa9ac9c9f87fdd05c1b2b95da5211703": { + "balance": "1656993051100000000000" + }, + "cff376eef4d69c4a47d6c7916583228fab3b5967": { + "balance": "5904462494391000000000" + }, + "cfffcb819302d05ed763026bdf84b48818938fb0": { + "balance": "289619807900000000000" + }, + "d000aa72a77d55911a5e66c2906da9206db86633": { + "balance": "3008989624945000000000" + }, + "d02d7b42213e873f91e789cbaffc734ffabd1087": { + "balance": "144960809826000000000" + }, + "d02db5279e918b3e93ff81d00d4025cc71dccaf6": { + "balance": "2386625717975000000000" + }, + "d0802cbcca2bb516f251b873eb20bb5e94af7f37": { + "balance": "9287997718210000000000" + }, + "d0c07380308972a36f57d1cd9081d7389d0421cb": { + "balance": "1280367167470000000000" + }, + "d0c131c1b60891b91e58fbed787ee4567e3f2038": { + "balance": "6360752089492000000000" + }, + "d0c71159d46c4d2af7699f682a055c79a1a68a0d": { + "balance": "1527974433762000000000" + }, + "d0d5d9f242f2613079b3b443c359c2e18ed5faab": { + "balance": "637334647476000000000" + }, + "d0dd208ce92da02eee3ee3de335e67f819581a33": { + "balance": "100000000000000000000" + }, + "d0e55ec0ad0f8986dd9fa9d738007c5bdc22f840": { + "balance": "53012893797000000000" + }, + "d0f222cec657ee444e284c07228d585155b82c0a": { + "balance": "7368748129592000000000" + }, + "d11efb07887d8b5b87a77d8fd388190614e8c077": { + "balance": "4703283503278000000000" + }, + "d129f1b89045ebfb4d1df1d9077e9359fd2990f7": { + "balance": "14496053137000000000" + }, + "d15a509424c4e04868bdcf59cbee09882ba04c8d": { + "balance": "65042393236903000000000" + }, + "d162416912b03fa65f3972a63e357ceaa3b621f7": { + "balance": "325650177224000000000" + }, + "d166183164b81bd049b2146a3ccfcc78cc6a0bdd": { + "balance": "1000000000000000000" + }, + "d173d759f0916e61400d56ca690cbf1743fe27b0": { + "balance": "53550838679000000000" + }, + "d18dc883e3881bf4c7db2afaa097bc2d33656724": { + "balance": "5000000000000000000" + }, + "d19dc9b5ae689dea1ccbfea8b44ec6034559e326": { + "balance": "135552499885000000000" + }, + "d1c79160d0b8c1a1546b86db5123e87645a45d13": { + "balance": "10000000000000000000000" + }, + "d1cccaa22259c547993df3c147d5b545f003adb8": { + "balance": "10000000000000000000000" + }, + "d209c9f32f3292ac4d15ef353fbe6f6efcd4e49d": { + "balance": "81000000000000000000" + }, + "d21ac89a20d67e309f96f64adf05fc48f55918a9": { + "balance": "500000000000000000000000" + }, + "d21f6e7adbf480600295af683091f9b9833f5330": { + "balance": "1229445878922000000000" + }, + "d22700a47a0edb137d2f0348aa0f8d4b6dbc5850": { + "balance": "21301422923000000000" + }, + "d258ddc9372e3b70ff53da171252239655ca9886": { + "balance": "16000000000000000000" + }, + "d274c69317dd836df48562455e8f5a7bd2e47d19": { + "balance": "156091832558000000000" + }, + "d286b68a358fcf8a6cec70b83467079664632ae9": { + "balance": "90377010699000000000" + }, + "d29284915d9b924ae5673e8a4a557478f68a7471": { + "balance": "324678197320000000000" + }, + "d297e64ac2bd8e98e6d276d6fe080679c398a26a": { + "balance": "3401930527000000000" + }, + "d2a1e7b51f6b5930a0d9e2ee55736f3d83a1b323": { + "balance": "44578900750000000000" + }, + "d2c9b0b0bbe61de504e4f210c168fa5999c9c23d": { + "balance": "76537483113000000000" + }, + "d2d49f650d222ec3e2cecba163ee92f0e934ca14": { + "balance": "3312486482635000000000" + }, + "d2d803bf10ba18adef5716b4056c1b1d61c45abf": { + "balance": "964679698000000000" + }, + "d2f673b589df7ef5cb32fdeef842d48d66130567": { + "balance": "1079010447581000000000" + }, + "d2ffaceef1af3f1c3e3f35e4062cd9f9abd1da59": { + "balance": "3041453068594000000000" + }, + "d30a74f5041ec6e73d066a375a105116699ce177": { + "balance": "21814020745000000000" + }, + "d30d849a2d8ff5041304014ecf6752dc769bf004": { + "balance": "1247532881540000000000" + }, + "d3113f558c6376321691931c9b21205e31f4a56e": { + "balance": "572224428451000000000" + }, + "d314bac1bf85eedeac0b359dd2106dbae8fc6947": { + "balance": "20000000000000000000000" + }, + "d3283e17112028b324327ef64a238183ba189207": { + "balance": "136000000000000000000" + }, + "d33ce3c3b64d1b3d399651432c15ecb943d16c70": { + "balance": "10000000000000000000000" + }, + "d33e1e4b10a98e82810f6d161df5d35e5677e35f": { + "balance": "10169656674000000000" + }, + "d34699fd152fe38caacd3c096f6abb1cd79e88b2": { + "balance": "25056644550000000000" + }, + "d369c0e01b9a9d519b3b099a98fead19867c019c": { + "balance": "100000000000000000000000" + }, + "d388dcfe55a9b710d05c686f033fdbdd7861ab71": { + "balance": "1439589263065000000000" + }, + "d391a7d45c7b454b743bd867f8f62f56894f9b65": { + "balance": "484904747488000000000" + }, + "d39a75b4831543e1bc99e7a5ca8875c4f69da45b": { + "balance": "10000000000000000000000" + }, + "d39ed6978b6a90fea29e735f8ea3f1d20e0fbd15": { + "balance": "144000000000000000000" + }, + "d3a0a1a00dcbd6bc44c9803ce351a4b36a69c929": { + "balance": "191222401916000000000" + }, + "d3bf1c0a6b0470c30fc49d995025af5e6b639e61": { + "balance": "10000000000000000000000" + }, + "d3cda762bafaf204469f85e6896ec64147a3452c": { + "balance": "468094119213000000000" + }, + "d3d04d78c1ab9e6887a9467b8b1e31b5c9910e5c": { + "balance": "81000000000000000000" + }, + "d3e1bfdd9396aba00d3e78646ddcdaf139a967c0": { + "balance": "833333174120000000000" + }, + "d3e502c42ff0274da12ba87ffd45fa593bba052a": { + "balance": "100409899947269000000000" + }, + "d3e76066c2e32d9a693161de07f2d3b7e6ea07eb": { + "balance": "10000000000000000000000" + }, + "d3e8d577323d97407246b198c4c61f7943c468cd": { + "balance": "10000000000000000000000" + }, + "d3fd4d1b0edbc314b103d350fff023ab75b7d7cd": { + "balance": "84129547428000000000" + }, + "d40087fca8feb72d130bbc9622575d4987f12895": { + "balance": "1000000000000000000" + }, + "d407d4126cbf3619a422c532ccf20c3da1495dbd": { + "balance": "99622000000000000" + }, + "d41a28761c8e5de8c803813667f1dc0918a105be": { + "balance": "157507410260000000000" + }, + "d46ed38228a3c3d78065b2d8b71b325bf0f0e685": { + "balance": "6787045850000000000" + }, + "d4a7463d202e804b39a93bccd77491d8791baf58": { + "balance": "171694163573000000000" + }, + "d4c20716ff7288d811d05fd6f0696a9f5627a11d": { + "balance": "100000000000000000000" + }, + "d4d95059c808cf41e64f7f353246ffae635419d4": { + "balance": "10000000000000000000000" + }, + "d4ef925157c6d0e2d649332f44416b85f8abe69e": { + "balance": "1392945162611000000000" + }, + "d4f0cb25801794f6d803306878763e08209d19f4": { + "balance": "64000000000000000000" + }, + "d55fbebc4dcf2de6341c2325448e9c198f0f06a3": { + "balance": "14206622892000000000" + }, + "d566968c40211fb25114105e36b5a7219cde9d5f": { + "balance": "4898442964000000000" + }, + "d5817b95c6b504a6d07f64faccc9aedf408b0ac4": { + "balance": "54387832478000000000" + }, + "d59679fc40a71897065bf1b3a73f331226cdae72": { + "balance": "20000000000000000000000" + }, + "d5a7deec4a5898f094e1600f9b15768d8aada258": { + "balance": "100000000000000000000000" + }, + "d5b91c29bf772ad3ba04033dfb86b672b245ad77": { + "balance": "100500000000000000000" + }, + "d5c1a9bcc5e68b7547354178fefb3d870572fd67": { + "balance": "2252066779089000000000" + }, + "d5da2a826f5909a221bfd8561dbd7dbf4aca4c35": { + "balance": "13839784966766000000000" + }, + "d5dcc82fa169b4677a3fc26d78f38e27dcc763f3": { + "balance": "10000000000000000000000" + }, + "d5f344ee8a1b954ae5fd8fc7ac702174749bc8a4": { + "balance": "1398836216771000000000" + }, + "d61cd03afbfc1bea186e5a3a51347c2c4ee3a2c3": { + "balance": "109879472702000000000" + }, + "d647fd7ca17203a0049c28ec6759612d767cfcce": { + "balance": "162681136487000000000" + }, + "d656d14acfb2f0fbde2ed2a137a52d852bb6288b": { + "balance": "20000000000000000000000" + }, + "d68130b421b19c193d03a9017b2dc687c7307d26": { + "balance": "128569735484000000000" + }, + "d69a41f7ca76b40ee94b0d04a3780a00c6c651ba": { + "balance": "2801054372864000000000" + }, + "d69af2a796a737a103f12d2f0bcc563a13900e6f": { + "balance": "7412286547000000000" + }, + "d6a5a7e149cbccb72a50b0a3ae00e6756b0a7eda": { + "balance": "1075352201657000000000" + }, + "d6aa9957f141f0dfed77e943c39aeed978834fdf": { + "balance": "20920740110000000000" + }, + "d6e99ccb72d24e8a60f24d47afd4074b1d1fd336": { + "balance": "15415994387186000000000" + }, + "d6ea4a9dda8d5bc832229c916fa45f05f99c093a": { + "balance": "27075799893190000000000" + }, + "d71de419d746ac277baa955761cced4b34c376ec": { + "balance": "1388473506822000000000" + }, + "d71ec6b5e5d4c604f741bafde0974eca49c56156": { + "balance": "61938809628000000000" + }, + "d72f90d9879f6d2d407b4fdf5d128b98d518f1a5": { + "balance": "10000000000000000000000" + }, + "d743d7925a0cfd08150814cce8cd5d3f7099e1c9": { + "balance": "25681376856000000000" + }, + "d7575a09e7498f21cda3e9e7266b7fde91dfe19b": { + "balance": "9841565066000000000" + }, + "d75c2eb5e0a2b2ee72ef4fa7249c1a1ce03f333d": { + "balance": "134491489751000000000" + }, + "d77088329ec1e280ea7a087ad20c5e965721ff4d": { + "balance": "3949070941222000000000" + }, + "d78d564bb79ea19e4a93975a38fe0882018f177c": { + "balance": "992717434142000000000" + }, + "d78efb176b252ce67b5648e04088d12c4668aad1": { + "balance": "10070463674000000000" + }, + "d7a25e43d7d4e23744f0b10e2b4f2911fd3b3bc1": { + "balance": "1000000000000000000" + }, + "d7a941cd82f8aa63c55baa81db44bcb347b8e529": { + "balance": "49000000000000000000" + }, + "d7b34387880daede6cbdad11bb3db67daf942975": { + "balance": "20000000000000000000000" + }, + "d7bca0770e2f890c1e93c3595641241454a31045": { + "balance": "2000000000000000000" + }, + "d7cb675cea1c0dafded44f611c9c344e2a5e053c": { + "balance": "25000000000000000000" + }, + "d7e53a2d8eaefd18e02bbadb7e64906ca8613151": { + "balance": "166599594268000000000" + }, + "d8076b9db0b7496efbd198b73c4bfcf51ac080fd": { + "balance": "210272077089000000000" + }, + "d81dcf5756da397ff1f783ffe5391d1ffd4ff227": { + "balance": "500000000000000000000000" + }, + "d833c6d08f5fff8f77628ab1e86584d052976d1f": { + "balance": "10000000000000000000000" + }, + "d835732e85953baf2af9e49f770bac1caa1dac23": { + "balance": "152211441541000000000" + }, + "d84005fea447e8c6aa0b5436ad79654a75348456": { + "balance": "22563694224690000000000" + }, + "d84d9c59a445911922e88c0f22cc6534f33ca3de": { + "balance": "3054115413381000000000" + }, + "d84e69926216065749e624d87783e90ce3015b82": { + "balance": "1420803164313000000000" + }, + "d884bdbdb7e13cc523e7f192310230c7bdbb4a07": { + "balance": "10000000000000000000000" + }, + "d88eedca1dd9249702f5ffc807c1e439eee1c5e5": { + "balance": "36000000000000000000" + }, + "d8a23fd234bada1c726622925ade62d3021e0037": { + "balance": "1567046607931000000000" + }, + "d8b1aee24264efebd1c677fcab6ada6e0f000cc5": { + "balance": "20000000000000000000000" + }, + "d8ba7afbb8bf2910b983a114aedec626eb7426c1": { + "balance": "275491152435000000000" + }, + "d8c8af55ebf116ba3c3904f8ac39d3a7d31aadc5": { + "balance": "1499999998278000000000000" + }, + "d8d97645f5f62aa89bf0046362dd0f45d40f821f": { + "balance": "25000000000000000000" + }, + "d8ea0e24a7e28285c4454f54181d581324da2583": { + "balance": "53039425000000000" + }, + "d8f5d258164747ccf790f5ed358162c756de49db": { + "balance": "323009990690000000000" + }, + "d9477bb62d3eb668a83a9679f3a7ef43f17c9e4d": { + "balance": "14045557127869000000000" + }, + "d9585e1b03fc86636dde1e64aed3cad77868549a": { + "balance": "1000000000000000000000" + }, + "d975f9ce3fe773fac3f8338a034a757c58f6e11f": { + "balance": "25000000000000000000" + }, + "d97e490faf19de612fb49c041d3f9e7877d3c0bb": { + "balance": "65766847746000000000" + }, + "d98117b74b2f2888d7078d3116d5758e2d09bfca": { + "balance": "1749157484422000000000" + }, + "d990b3f69ec700bdc095c184b3804551c832d612": { + "balance": "509385034698000000000" + }, + "d99b35298e709e5f54e6a5c612a326a83f4268c4": { + "balance": "71963571266000000000" + }, + "d99d9ec76005da26ccc721ec26be4ed9b3b1c586": { + "balance": "469607736824000000000" + }, + "d9bc61075c3201351584a026e5bdfb7cf9a7b6ab": { + "balance": "200000000000000000000" + }, + "d9d07b72f83491b6db26602f6b7039aeebfe6b61": { + "balance": "144000000000000000000" + }, + "d9f6f1ddf03e836b3744d008b62a6424544c67a5": { + "balance": "74347470143000000000" + }, + "d9fceff07ad69bf3b4aef54a7eee541368980cf6": { + "balance": "1143407707495000000000" + }, + "da0285fb7e37fd4be66fb862b248cea94ea8f6db": { + "balance": "80770216661309000000000" + }, + "da05c7aa330fcc5834e19deeb0a808e9ab7f3d99": { + "balance": "169000000000000000000" + }, + "da129e4481bd25450e6c7b42fe417c87ee2ce7a7": { + "balance": "256000000000000000000" + }, + "da32e3ec421993db088c71e256263158f7855b61": { + "balance": "18540215888567000000000" + }, + "da3c99669acd202ccbe6f80902c807588eca0880": { + "balance": "1000000000000000" + }, + "da72a7bec114d43aee6449db830d2d3f16e4d9b6": { + "balance": "744534872932000000000" + }, + "da72ec2cd7b8e3924f8baaea75d5ed23ef39394c": { + "balance": "38646377617204000000000" + }, + "da73078957f491827d62cb3ca0c484c2d1004ba7": { + "balance": "891774109242000000000" + }, + "da828e50c7c8580c6ce81718f11fbd43b2b0541f": { + "balance": "66094097819000000000" + }, + "da91483db6a6a034e068e69a6b46674838c5bc80": { + "balance": "4000000000000000000000" + }, + "da9551b635c3619f81641571e267755b89f7fe1e": { + "balance": "670841942250000000000" + }, + "da9b43a9c1c574580ec43da9f6acb687fc2f8c68": { + "balance": "761695404114000000000" + }, + "daa7f446923f7481115ad285ca468c865147e563": { + "balance": "10000000000000000000000" + }, + "dac6bfd15954efa4c9254e24e5831ab1884f8d67": { + "balance": "960042043423000000000" + }, + "dad85d0b8bb5ebf6ef811d0d35c89f9f343c833c": { + "balance": "37664599958479000000000" + }, + "dad9b01652de5d50bf30f9bcb0c6edc6315139e3": { + "balance": "21500996724000000000" + }, + "dae9c7d6bb0efe3f7ea20442b184f6d99b2a2c12": { + "balance": "937830189066000000000" + }, + "db0d6c28e9b913f611accaab15cc887f9b770f58": { + "balance": "20000000000000000000000" + }, + "db0e5341d64817885721c5abff04c30bd38df40f": { + "balance": "62600679700000000000" + }, + "db387dd404d14478babb60bad2391720d68b92ed": { + "balance": "115096708329000000000" + }, + "db3fb19e8a4a6ace4d8c6c02085d4cbba528b532": { + "balance": "1000000000000000000" + }, + "db4f05a66c0ccf0532ea1ecb931e05a400a6f4a7": { + "balance": "20000000000000000000000" + }, + "db571f1cdf8e83fbff6fb48cc0c81ef95ede12a0": { + "balance": "118317387393000000000" + }, + "db6a6a6db2aef3f43afbfe23027b670ebb3d33bf": { + "balance": "9960755220000000000" + }, + "db8bed34f8f34f45cb83ab19ed33fad76437d217": { + "balance": "21003651205000000000" + }, + "dbeba6a2a7f66c20c6db7b9270a5aee74de3f441": { + "balance": "4086905723945000000000" + }, + "dc04efeac13b2dab3d07833a7e7fa728fc23d18a": { + "balance": "1161834099120000000000" + }, + "dc092386c3a3e28b6b2d7d70db8f3d11e79ef5df": { + "balance": "124362293793000000000" + }, + "dc10be66aa11acbd42a2b1953714f09b5281681b": { + "balance": "20000000000000000000000" + }, + "dc2d58a383ce0bd40bed859ec2f25412b68eca0a": { + "balance": "104917823922000000000" + }, + "dc2e38183dceb2bc82b23e8ccf48dd96ea1c97b6": { + "balance": "2847787376064000000000" + }, + "dc5d9d94530d88451cf081fe7f2ac33667af9d8f": { + "balance": "65321904051000000000000" + }, + "dc993112a8d89136e0e73d67e2f26191583a50ec": { + "balance": "1000000000000000000" + }, + "dc9bb69b295945589a41feb794406558ce65dedc": { + "balance": "104077637254454000000000" + }, + "dcb0109d4fca2dace08ddca5d989a09d470161a0": { + "balance": "28897833222000000000" + }, + "dcce3a4ec516d833f5a9790c40ad0334b0d2dd01": { + "balance": "25000000000000000000" + }, + "dcdb21cc811ab733c2a80a2d5c8e5bb49cb2ddc4": { + "balance": "16000000000000000000" + }, + "dcdf8dd3ce03a2fe0d72835dbbd58725e1ed2c57": { + "balance": "113330414284000000000" + }, + "dd2165839ab95d6b24591307adcde9ee1819927a": { + "balance": "20260199589072000000000" + }, + "dd3015a5fdef66e749a000585d5574f975e3432d": { + "balance": "85465001652000000000" + }, + "dd37c478727f44943c5fd79ace30f21fae5a589a": { + "balance": "108577233510000000000" + }, + "dd3fb5810c31d37652bd17b92497ed479faf123d": { + "balance": "669996966072000000000" + }, + "ddc3bda30f7cf36bd535de4e20c9becb78d159f4": { + "balance": "99998278000000000000" + }, + "ddcce2d2431b67d4157c7ac4bd77f20c24831de6": { + "balance": "36160893899000000000" + }, + "dddcebe609f8b4354a1f27ab1915135e25800344": { + "balance": "1457846339959000000000" + }, + "dde223eb48f81748abde6cbc08cf1e6b0e8e4e5a": { + "balance": "1501921107087000000000" + }, + "ddf4ba402007060d9940a96f8e7c39f0a2c6108a": { + "balance": "377268151287000000000" + }, + "de05d9ada6626a8492acd137c7c7f7080a987cd1": { + "balance": "222144234923000000000" + }, + "de0fab89f79c4edf9766c3b7b1f508cb43c5495e": { + "balance": "8278000000000000" + }, + "de1070f3ff6c47237768fbdead88b2d5184fbe2f": { + "balance": "1000000000000000000" + }, + "de2b16d7f36f630329287822f550ec19415acb3a": { + "balance": "25000000000000000000" + }, + "de3faf6884337a99e54ac5d3f08b34be51b0755b": { + "balance": "51926806905184000000000" + }, + "de4614fd632ddac888d177de0858e62bbbf7dc11": { + "balance": "52506376589000000000" + }, + "de54cabb241dc5def530191f948f67db942a85b0": { + "balance": "9691177060000000000" + }, + "de81e488284acc4f8f6061d3a73bad112efa7a40": { + "balance": "14654060992000000000" + }, + "dea86ac3a661272691c877c1bad8355789382b69": { + "balance": "903877103000000000" + }, + "deadfc79f2a722dbf1c1a92f2824da8874189fea": { + "balance": "98905944986000000000" + }, + "decf1af47e153f6f3749a1b7abadefdcf1607a0f": { + "balance": "529000000000000000000" + }, + "dede5fa984f0def639d5b633f54c60fc5aaa272a": { + "balance": "8193771708654000000000" + }, + "df23607c63b3fd4b5fde6aab093c0c56d1188f95": { + "balance": "14687379916000000000" + }, + "df5b74bf02902e4c466821de798406b663d4d73e": { + "balance": "9000000000000000000" + }, + "df6402ee3f37389e7f65720561b54e26e5f1cbaf": { + "balance": "358266132937000000000" + }, + "df83ea5b770d5abeccac7f0cae803e8bd7b9831d": { + "balance": "25000000000000000000" + }, + "df92802ffe9892c7704875755bdec648914430e6": { + "balance": "20000000000000000000000" + }, + "dfa108bcd80e824a255679a38b2450d428e2f939": { + "balance": "489209553654000000000" + }, + "dfa9f18e859353796afe384d05353dc80b3ffc43": { + "balance": "121000000000000000000" + }, + "dfb0d6580f011e68a39d7727818b0890e70f3036": { + "balance": "537675412560000000000" + }, + "dfdf006abf2293aadc58feea6af6b35db428675e": { + "balance": "9000000000000000000" + }, + "dfdf2ba93bd47d7243b7419413458a947effcf67": { + "balance": "45080282196110000000000" + }, + "dff01277ac23a8cf93383595a80a7c070eafe5c6": { + "balance": "312778552103000000000" + }, + "e0450154c441e52c5e507e8316d4e9376c59c12b": { + "balance": "170163401434000000000" + }, + "e059374d6a7e6c63e609b65642272869fa3b2b3c": { + "balance": "300122497803000000000" + }, + "e0c0d8e739a2f274a43f019a07f7f61d7d8e11a7": { + "balance": "2630310240000000000" + }, + "e0e779e4e3573ea77096daec252ac2b3f1c0013a": { + "balance": "10000000000000000000000" + }, + "e1325eb586180a67873718a2016172afeb03c6a5": { + "balance": "531691399657000000000" + }, + "e13958af480da6443b9ec1067f0f33440634a282": { + "balance": "10000000000000000000000" + }, + "e142daac753b2c4d215372797999e9c88b65dfc9": { + "balance": "585813299366000000000" + }, + "e142ea343bc36ec49989fd43ad5c403c70a40dbe": { + "balance": "656734902975000000000" + }, + "e14d0a3d259db6bfec2fc4ef6e18729e4d93b007": { + "balance": "210234446279000000000" + }, + "e16a5316e3a113f27bafdf3d4fe44fe30ae9c210": { + "balance": "16000000000000000000" + }, + "e1770944aec145a96c9491497eacf7f3fb03c1b2": { + "balance": "335417250470000000000" + }, + "e199ac237661dcac0a4cfab404876abde72ee209": { + "balance": "340000000000000000000" + }, + "e1ad427471023f38cbdf07fdca3728ec343810c4": { + "balance": "343957267368000000000" + }, + "e1ae0223cecd738c8e530a0007ef05e8f3b33769": { + "balance": "950528515289000000000" + }, + "e1d2d4ef39f01a60c3bb5d671af91c5298d87711": { + "balance": "121000000000000000000" + }, + "e1d4a8888cbb383f3671ca96e7b55310b59a2541": { + "balance": "242387826125000000000" + }, + "e1da9039ddfe117e6a0b484fd3962426c112871c": { + "balance": "3710499693813000000000" + }, + "e1da9f16d57c601af8b6d102323c20408af8531a": { + "balance": "3135322588771000000000" + }, + "e1e1c163f391ffad2d0be68641253b0860485a95": { + "balance": "10000000000000000000000" + }, + "e1ec6361df67ad915df9e9661cd0932186db034a": { + "balance": "4279936304854000000000" + }, + "e224050bcd723e63f1fc0567a86942546aaf8d13": { + "balance": "12007628539000000000" + }, + "e2342c7f411d7ca3a86484af59a9c3f3180e2f0f": { + "balance": "16000000000000000000" + }, + "e26f2b026a258ce5801c90bb8fd6f7a152b8d267": { + "balance": "304593714834000000000" + }, + "e2717eb5fd0a1da51272b50ca8d12858009c7016": { + "balance": "506943817535000000000" + }, + "e27546d5620e6398829260e58e8cf4a3a03f4164": { + "balance": "3000000000000000000000" + }, + "e2762bb64e0606a5d635032e15164b01f612a74f": { + "balance": "884716158811000000000" + }, + "e2882066ed0a3c041d09c00c8532850fc42eac06": { + "balance": "42441412728970000000000" + }, + "e294c5d64daf7b7c0994aa9d03669c4b2658c9cf": { + "balance": "6996693830997000000000" + }, + "e2b179f0ed6870a6268aea64b0c7b39d98d97fcf": { + "balance": "334205318353000000000" + }, + "e2d1f6f7e3128340b789565b527bb91de96d54bf": { + "balance": "100000000000000000000" + }, + "e2f136d3693aa0b2346a968a22aca6707fc1d0e5": { + "balance": "10000000000000000000000" + }, + "e2f229054293e32cf3e83f9bb88d9cf1d6acd66b": { + "balance": "20000000000000000000000" + }, + "e33b8f4c9a49554c8b134861f88c8fffc399e456": { + "balance": "83552502198000000000" + }, + "e33cfc7727b1460324b34277dde14cc49bcb273d": { + "balance": "100000000000000000" + }, + "e36af9bfed4f912cae21f3d899f7354e1c902601": { + "balance": "31474316356000000000" + }, + "e36eff7c061dec48446d47675f176b4da3c2e950": { + "balance": "10000000000000000000000" + }, + "e383f3cf431f3cf645f26c7d5e5e2f77348ede6f": { + "balance": "776224304171000000000" + }, + "e398b9f004a4f891cf871a57d9124a97b56e89e9": { + "balance": "84846187740000000000" + }, + "e39ab2415144b46db522e92ed51b8089a5ec01fd": { + "balance": "4158925896363000000000" + }, + "e3aa7ac7e15e9a8a6f54565067234a9d4bf7b569": { + "balance": "1080385576951000000000" + }, + "e3ec5ebd3e822c972d802a0ee4e0ec080b8237ba": { + "balance": "2129139289000000000" + }, + "e3f1fbff8686af23ab95eeeee6a6a03782d72416": { + "balance": "401776848194000000000" + }, + "e4001b830fbd86df257ebab54aec0c66314ef9aa": { + "balance": "518220809325000000000" + }, + "e40790bff894f0b3e534942b5ad6f6592cd6e896": { + "balance": "25000000000000000000" + }, + "e409170a296e46fc96d85a2395e4324212a470ee": { + "balance": "1072528749756000000000" + }, + "e41546f68bbe1771febbdac2a4a5999eef50edf3": { + "balance": "1000000000000000000000000" + }, + "e425d63d711a9996c09d928ba8df94c88163aea9": { + "balance": "10000000000000000000000" + }, + "e4432ff1aee13f97f73a8407e4c7d6e768b8040b": { + "balance": "700508995102000000000" + }, + "e4690f5d024a395355a7cb5238fb7e0dc921b1e8": { + "balance": "1000000000000000000000000" + }, + "e4829684fb36f054766a61fb2a8f6ecdf27c9e87": { + "balance": "73885178137000000000" + }, + "e48a68e1ac007e14ac08c1b3b0df2b5602081ec2": { + "balance": "1389262869176000000000" + }, + "e4d699b3f4117eba7ed27b323048c9ffcb46ed42": { + "balance": "183131036697000000000" + }, + "e4db688c29fdf9a1c16114f99797d8409545955f": { + "balance": "16000000000000000000" + }, + "e535b94d370190d1e0955d3c0d12480e558f00dd": { + "balance": "20000000000000000000000" + }, + "e53966d4bb17fa9b50d29b44ddf3951c9ca67caa": { + "balance": "6400630678000000000" + }, + "e56f2656fdd1a5f7d3716e65dd89a37dd6e42dcc": { + "balance": "1000000000000000000" + }, + "e5a364113076273352e0c31bf505028e0b7edbaa": { + "balance": "10000000000000000000000" + }, + "e5a3c80518fab6a0a721ccbdc3e673680a65f6de": { + "balance": "171727917465000000000" + }, + "e5c71c7170e5c9b07e62cc307d81a4a3053ed64c": { + "balance": "10000000000000000000000" + }, + "e5fb6408db128c55cfb3e7fa1942d6347e34932c": { + "balance": "10000000000000000000" + }, + "e606883236f8b2045393c574153a100675cd4b90": { + "balance": "14005226900000000000" + }, + "e61869d1cf72f25e195898217f5bf5bcec9c9038": { + "balance": "50000000000000000000000" + }, + "e61e2e29c0719457ab1bf7d6d9fe442bd6107b07": { + "balance": "30943034333100000000000" + }, + "e61eb97093e9ee609647bd55f434a27bb30a9401": { + "balance": "200951434577471000000000" + }, + "e62812ad5834747f17c92435d863639e84d132fc": { + "balance": "3017271391299000000000" + }, + "e630b92aa8443eb077e1f6990a2e194d99cf53ec": { + "balance": "1000000000000000000000000" + }, + "e656fd1641c15e1a4b753be41bc4aa438b44b42c": { + "balance": "26972744083000000000" + }, + "e663f0257b98dfa80602a2af1bea1f901c4a7612": { + "balance": "97075813547000000000" + }, + "e66e411a8a9d019b53bf2e0a7e44703e1aa93ac1": { + "balance": "25000000000000000000" + }, + "e6712675d13fff27af43bb1cb3f2f283755bacf5": { + "balance": "227572496234000000000" + }, + "e68e8f04b2cff484da2d41dd639ae8880920f781": { + "balance": "20000000000000000000000" + }, + "e6972b5d7e0fe8c722dec9146b92f89291a0207a": { + "balance": "2115924954211000000000" + }, + "e698b491330cb55ecc4cc4b74015cd94eb927fc4": { + "balance": "1038111785278000000000" + }, + "e6c411e67b90109dbb0fa75f0f07ae8a504e9637": { + "balance": "123792105420000000000" + }, + "e6fb1dabc624edb45b040ad66f30dae010a6b634": { + "balance": "16076893670852000000000" + }, + "e71dac161206e7d3686d13b98fd922ab73587988": { + "balance": "500000000000000000000000" + }, + "e773f9be9b3f4b35ac149b4d759b9e47c8000bdb": { + "balance": "329623043336000000000" + }, + "e781cbbd2dccfdf68595d54fa44104a80d52dd22": { + "balance": "188679476509000000000" + }, + "e793666c7850a409b1d5494f576d122e85cfed9c": { + "balance": "1141845197779000000000" + }, + "e7a5527c6deb922e9f84309c502048f49f0c8f14": { + "balance": "81415566708000000000" + }, + "e7b0f75f9c69ae464b1b63cf295555d0815fc532": { + "balance": "10000000000000000000000" + }, + "e7b43cc673e321e607190a6fde996b71508f4d81": { + "balance": "103958781426000000000" + }, + "e7bfcf3125e37755e57804dfe4479657b212a8ca": { + "balance": "10000000000000000000000" + }, + "e7d33cbbd4eb38365c5be04ce32658a5ac741cfa": { + "balance": "1545192252109000000000" + }, + "e84cfbd7844f6aa3e830258a6b1069b6a7ff5b7e": { + "balance": "543989509107945000000000" + }, + "e8aa0cbc5c1f59fadf3ec122fa8a59ebfc60b5b6": { + "balance": "61271973066000000000" + }, + "e8adb5303c30a8ee044dc09c49818c02a16f4254": { + "balance": "737375689166000000000" + }, + "e8aeef5114e19d467c3064938c5965d04830f2ae": { + "balance": "51130466380000000000" + }, + "e8b5a83497198a513fb2e244bcf05f9d4cf09d62": { + "balance": "10000000000000000000000" + }, + "e8b6818cf0d24bd0e7ded854b3d368662a150dab": { + "balance": "63697741112000000000" + }, + "e8b68b9cb24169fd688db7a626d79d0363777c75": { + "balance": "427222669643000000000" + }, + "e8b8b57b23ea953943da3ef7efaefced9cdbb44c": { + "balance": "16000000000000000000" + }, + "e8f85dca364d26c2149b767904c6c06249c3d88a": { + "balance": "199342917246000000000" + }, + "e916c7801cdcf1b6cf640fcd9dcc1e3148c80105": { + "balance": "9000756000000000000" + }, + "e93cbef13277324caae7816c3d601e2f6bb42589": { + "balance": "121000000000000000000" + }, + "e9415fedcdf8939b551999900128530195a2a5f0": { + "balance": "85165078941891000000000" + }, + "e9a79ade714ce48a07fe88532a20d8f8ed27bac9": { + "balance": "30768493367842000000000" + }, + "e9b35c7ca775661bbd3a4844e2c6bc5effcdea58": { + "balance": "134719523000000000" + }, + "e9b819dffb600373bfd1b1608fc9744cc9167855": { + "balance": "1537634693002000000000" + }, + "e9c5ef50d4a194e53928659b4486a1c456df9e56": { + "balance": "50000000000000000000000" + }, + "e9e21f4523b11567516f6fc525e8967ac707f988": { + "balance": "2498740681000000000" + }, + "ea02821d6c730e061a9947b75188eb8bc0bbf9f1": { + "balance": "12822292582000000000" + }, + "ea3bca3a17c7e724ac0e15acab6442f222cd8688": { + "balance": "2789689549000000000" + }, + "ea4f7923d7045a148d50153f5f4620dbd31a74da": { + "balance": "113595858930000000000" + }, + "ea6d4cbae3cfe49ffd36653bb0d64c01b2bbc0b8": { + "balance": "49325017701000000000" + }, + "ea76cd4cff825301932a5c1d3a1de55a0ff00797": { + "balance": "1282028021000000000" + }, + "ea8e4c8c6500856777e2b41832ff00443db291ce": { + "balance": "553674550359000000000" + }, + "eab52191e5afc804b8685fe13d7ad6f5dc64fc12": { + "balance": "244412435341000000000" + }, + "eac1b0868b710e40d6d5c66a461dfc8f78abbaa9": { + "balance": "10000000000000000000000" + }, + "eacac2c75920b8f6e65f37ad81deb113d526d031": { + "balance": "53028042076000000000" + }, + "eacc9ef8b534143560f420031a8a7f030ff1a36e": { + "balance": "381111853842000000000" + }, + "eaf2cc9fdfe6272de269f32486b2d4c248a05afe": { + "balance": "2793234915237000000000" + }, + "eb0220406832a8a5d4f242538e82c80bd83d0ac6": { + "balance": "10000000000000000000000" + }, + "eb20efc0e0af48c8e6da4b21efa9c9f02d92d29f": { + "balance": "152958793764000000000" + }, + "eb41bce8e3aac2bcf662854a3151e3c83d98c6f3": { + "balance": "219455327737000000000" + }, + "eb44c591306972c29a7084079720d8ee5fb9b0a1": { + "balance": "49000000000000000000" + }, + "eb4b26ab55dc35df2e78d47a90fc43148a6de881": { + "balance": "12139574483030000000000" + }, + "eb4f53510db5edcaad6ea169e521bd094e8da4b1": { + "balance": "100000000000000000" + }, + "eb4fbfb7c0082aa0e7edaed934c5166fee955e5b": { + "balance": "299713748180000000000" + }, + "eb6067ab544af6289a73111e7693dc449d5c2134": { + "balance": "20000000000000000000" + }, + "eb86fea82d10d309b1365237e4855a48684e0e49": { + "balance": "81510415589000000000" + }, + "eb8abbcadeb6e19ab4392cded7a407c8d5df2d5c": { + "balance": "25000000000000000000" + }, + "eba44ca2d6f36df8221a2021bf0644cf6cb59452": { + "balance": "500000000000000000000000" + }, + "ebacbc0eace170f66415df48f74d98eb31828d15": { + "balance": "19046465915296000000000" + }, + "ebc72fb8a1029139d8abdc08da23dc559f87e1a8": { + "balance": "24177703742991000000000" + }, + "ebd561bb9001991cb6b02c8ff9e7ece8a3d73dde": { + "balance": "6684606759000000000" + }, + "ebe1dc3ee857ae4add6fa6636b678af8451d1701": { + "balance": "1485349608007000000000" + }, + "ebe68dc904c737be83aa2ee7f613dd51a6d436e4": { + "balance": "11206782120918000000000" + }, + "ebecf4db55a99f018bf136173ae823528f211380": { + "balance": "191817711082000000000" + }, + "ec15ad0aafe0c0f18089de50b2397509e15a20de": { + "balance": "20000000000000000000000" + }, + "ec2e56973a6cbd8b37d0294b16ef806ab5943ec7": { + "balance": "12031630315394000000000" + }, + "ec432a6a4685ebf6c1e872001d1de246140c8d98": { + "balance": "280056522277000000000" + }, + "ec866ba1bdadb91ca25f5ae035b0f69421ed4377": { + "balance": "431849961155000000000" + }, + "ec9be854224d3d371b79ffc1230fe704ba03be2b": { + "balance": "3692428502391000000000" + }, + "ecc2d6e129c7daa37a93f559c6d4f575171d8386": { + "balance": "20000000000000000000000" + }, + "ecc3aca2a21cb317c5b9debdcb2090f3931d5cd7": { + "balance": "100000000000000000000000" + }, + "eccc9a49ff40aa4b07aa0e1271cfb6713de683dd": { + "balance": "617207728367000000000" + }, + "ecccf24530629033fd6234ae32bde2052ebaa640": { + "balance": "16000000000000000000" + }, + "ed16770d5a56dced87224d4ff68a361a2285fef2": { + "balance": "10000000000000000000000" + }, + "ed23b8e782d5ddf203f9b80e5df83ec32e484fc6": { + "balance": "5000000000000000000" + }, + "ed3244e4168e669ae9d54175173c3f0f0e7c4c7a": { + "balance": "803397672115000000000" + }, + "ed48f39d3f022b321c0864d4955e1cdc8cf54834": { + "balance": "64000000000000000000" + }, + "ed4cb42fa6737cbbbf095f181e1425b3bc3ab4f6": { + "balance": "8974148344000000000" + }, + "ed560f7d83c27a26965f84dcface3930bc447fc5": { + "balance": "2092287996000000000" + }, + "ed6ace91369ec3b06cce474e67d1ce4aba6475a6": { + "balance": "1227081000000000000" + }, + "ed8249dd4a91f70176ffff310e5546e7e0c30b91": { + "balance": "813069034369000000000" + }, + "ed8987fa3d4d42bb8f009c99cda5868633d94f5a": { + "balance": "174952234860000000000" + }, + "ed99b72a58a519ca7aa8f46b8d254c3f1eeea0d6": { + "balance": "10000000000000000000000" + }, + "edb720c9bde4801e204e90282de2a6cf1c44c4ad": { + "balance": "10000000000000000000000" + }, + "edbea23cd0cfde3705d83aada88e78b9f4bb1a50": { + "balance": "4000000000000000000000" + }, + "edc1f174655205bb961ddf94a997cdfd24f1c2ed": { + "balance": "65211537189000000000" + }, + "edd1d2dcba881202bc546943194d64e59bf74bfd": { + "balance": "10000000000000000000000" + }, + "eded28fbd959f2351b4252abc71f0e809562fd4c": { + "balance": "1000000000000000000" + }, + "edfe4d4c83c7db76e5e8a9ccafa34d9841669dac": { + "balance": "2578239411258000000000" + }, + "ee1ef79de869b89334d883ba766e65150f3f6cf5": { + "balance": "779780646165000000000" + }, + "ee27b2da240e862f0848d31116a7b4ed91835c8d": { + "balance": "111637484977461000000000" + }, + "ee3195bdb69e97796911c63fdd3fcebad61ffe9b": { + "balance": "214483035823000000000" + }, + "ee43306530c21793c4fd6039b51cf54fbc912bf0": { + "balance": "374531713769000000000" + }, + "ee4515e30ee1b8dba4779ef213d89e8dfff26ea6": { + "balance": "1166743135013000000000" + }, + "ee591e9ca7948b8485eb210e2a3f706b97e6f9e2": { + "balance": "27793157052774000000000" + }, + "ee5ba6c854d633a04f7656d311817e5104c6de14": { + "balance": "289361919166000000000" + }, + "ee909db4ee48bff3adb9e43db940245a8e5e094d": { + "balance": "582143490064000000000" + }, + "ee94d1afa82de70eb65aad0662f48ef3170495cb": { + "balance": "242490158636000000000" + }, + "ee97e18e09bbb16137a7b4aaae464e97d70e6606": { + "balance": "442709862861000000000" + }, + "eebe957af00050c2841f3ef8768c6a77a5394012": { + "balance": "9000000000000000000" + }, + "eec052f4e2902f7cc496162ca6525997d2b3ede4": { + "balance": "69349303517000000000" + }, + "eed30e1a939d5f0b4a39598967a5f149a7b7cb8c": { + "balance": "1637195595000000000" + }, + "eed7bf1ba39bfdad0ce1b6b8d4c9bb31dc1a9843": { + "balance": "203331701702000000000" + }, + "eee276140ea24e36eccb4fd748f675df1acd3b73": { + "balance": "1000000000000000000000000" + }, + "eefb33b290741c4cded862cea777efe4b14a76da": { + "balance": "64000000000000000000" + }, + "ef17a60d15ecf68a62b4bfd5e3acd6201e1931af": { + "balance": "113292502078000000000" + }, + "ef3f4df42127d3e94b4b5883ca97ee63f90b68b5": { + "balance": "17819622000000000000" + }, + "ef4aa6833a69cf72fbf3eaac57da236970aa4241": { + "balance": "1638520372091000000000" + }, + "ef958a1db06e5b8e12547148f3b01da9a8841aad": { + "balance": "12847752197000000000" + }, + "ef9fa861eefe12a3b4c161a47db5d94b1fa873a9": { + "balance": "49000000000000000000" + }, + "efd9b1ce6bc3932961e41e875edaaa367d318b36": { + "balance": "1626378762077000000000" + }, + "efdce7f577c77f0dac6afc78dcbf5ebadc1c3a73": { + "balance": "627500067619000000000" + }, + "eff3f26bc45638d89f28b3ea7a5471af0b680b72": { + "balance": "1650959950189000000000" + }, + "eff6d78814ddae79d6d09d830dd44de55f3f919d": { + "balance": "44409266093000000000" + }, + "eff739e22b9aeb3781dc301da70761fdd178f08f": { + "balance": "574842224234000000000" + }, + "f0059b3c8a32d3d012b4fcb993431a484b67762f": { + "balance": "516933429840000000000" + }, + "f06747d8e2c76b8827bbd0bf4ea3a68d390ee8f3": { + "balance": "8124594790100000000000" + }, + "f0e29fc0aecc36d1bdd818148878ea7d01957476": { + "balance": "79821431871000000000" + }, + "f0e42acf4e027aa61ac2f56e3d2c171ec0fd6ebf": { + "balance": "672499252575000000000" + }, + "f14338307bc5e6ab71fa202447ce240947568b3c": { + "balance": "13990001528784000000000" + }, + "f14f9a1206eb436a3d2e4ba9b3976137f67a6596": { + "balance": "1086707451000000000" + }, + "f15fcf1772fa5b2a578ce4f9270996430d533000": { + "balance": "496026996898000000000" + }, + "f18c691a5827ff1fdc44b54bd9a64fabd53c1cf4": { + "balance": "3112912699000000000000" + }, + "f1960640b52af75fc71101aec2611499c17cd9c6": { + "balance": "195957678178000000000" + }, + "f1abf01ddd474949713bd7fa67ec81d6b56c87b7": { + "balance": "121000000000000000000" + }, + "f1b93a6cfd4b1c7e0e89ebed119c5fe55af2035e": { + "balance": "1000000000000000000000000" + }, + "f1d14c7659a10ff38f4ea74ff5b07ac035984b6a": { + "balance": "9986323720000000000" + }, + "f1dbf37470a2c4fef98b1023026870ae8f7df2c0": { + "balance": "132757602000000000000" + }, + "f220b958b619d5d848597dd00824ab8b1401ebd2": { + "balance": "1461699635849000000000" + }, + "f2484911e0aa707f88d9dd970db21e8f24b9de2f": { + "balance": "20000000000000000000000" + }, + "f264c15790fd7a36d9ce7a454f6bfbe878708a50": { + "balance": "64000000000000000000" + }, + "f2662356cb3ae7b82efd6c82c3591ee40854892b": { + "balance": "50000000000000000000000" + }, + "f27ae5783b96ef637bde4179080a8f5af63ae692": { + "balance": "784985848611000000000" + }, + "f2a62fc212717e411f72f9a694e30b8da21bb31b": { + "balance": "614971541702000000000" + }, + "f2d0a9594231efb87ac833c365b80944251f29d7": { + "balance": "478622654587000000000" + }, + "f2df99a3df0b9b448d0ea48b9fd5cb1ce9ce50cf": { + "balance": "851116673037000000000" + }, + "f2dff0ae1f5f74808624e4f26fa814e4e19c216a": { + "balance": "404457730686000000000" + }, + "f2ea1ac6282364ad5904c6f058827a4382111d94": { + "balance": "5502482915000000000" + }, + "f2fafdcdb2d887eb13b5362eb76be2a682868643": { + "balance": "6174264174000000000" + }, + "f314adfc2fbf632a6e5d8a261385b6054aca31b6": { + "balance": "1267558242119000000000" + }, + "f31a66a88394ed7dd6609aff07dd26a60a219bd8": { + "balance": "346102834465000000000" + }, + "f3535f2b42d8613363e6d9717cc21a8ec3a74fe0": { + "balance": "35723093185103000000000" + }, + "f36a149466982c030ce3b9717f34b593613804d5": { + "balance": "10000000000000000000000" + }, + "f3828b0eaba4acfbbcf3c58277ceb4616a34b630": { + "balance": "633998941064000000000" + }, + "f38f767eeb8002ef051b32fe2f40193bf0751d92": { + "balance": "50000000000000000000000" + }, + "f39bce177817a7338b1adaf713222e515c0d762b": { + "balance": "1128231726329000000000" + }, + "f3ac7ea27a1cefc7787e5ba54dacfd8385ee4afc": { + "balance": "11364602682758000000000" + }, + "f3d9ea511335ed418b1837766da11832aedf5578": { + "balance": "29188596603509000000000" + }, + "f3ef05ccd19df167e06797d962f6afe16037e134": { + "balance": "144000000000000000000" + }, + "f3f630148eccea0ad7bd67bb806bd5676a4ea4cb": { + "balance": "87187208643000000000" + }, + "f3ff31784e0b8c3cd2f7e18cfd07c682a42d1c8d": { + "balance": "10515373125000000000" + }, + "f40b976e8519a2c97f64783bca495ed3f2e4a7c0": { + "balance": "780184503985000000000" + }, + "f416a3af7f3181ad9c8a916989949d35b0b636ec": { + "balance": "16114504005275000000000" + }, + "f419759927eea6afe77701c4cf4a98791a709ad1": { + "balance": "1032589347112000000000" + }, + "f4368f9c9ad8236b56413f174562d6b6fef21d1c": { + "balance": "5447645343000000000" + }, + "f43c57f984b0e2b7ce4d703e82f41195585504a4": { + "balance": "1135809111749000000000" + }, + "f4449f52895de96a4638c927dc389f010bbd530c": { + "balance": "693196063498000000000" + }, + "f449bd417a674c8bfa1db3a3e09c2b03da0f0c04": { + "balance": "106343287319000000000" + }, + "f44dec8340986c06d64dc98d78772a8a9cdc41ec": { + "balance": "1379381904815000000000" + }, + "f4642be1a7685aea0dc7b362d36f58f15d806b72": { + "balance": "4717509847323000000000" + }, + "f4712925f57391043e0cc2e671f33124a0bc8613": { + "balance": "419736833200000000000" + }, + "f47317fba5927dd8dffc4049d4f3277fcef503d6": { + "balance": "149279442682000000000" + }, + "f47ce4c5aaef82692e47f7a810ba38d1faec0eea": { + "balance": "10000000000000000000000" + }, + "f491ffc412bf142788bb82d48bd4eccbe9e0a286": { + "balance": "77276422315000000000" + }, + "f4a1e27e669c29f15b9f89ac15f702340a135743": { + "balance": "324000000000000000000" + }, + "f4b5cbfa50a6c4f5f7db7a93fa565362cc7aceac": { + "balance": "195951823248000000000" + }, + "f4b949c6e10615b651675016f0d7d6ff64e31aee": { + "balance": "35516207325223000000000" + }, + "f4c5e2f043ef3548a2c1c27d968087bec65e2f7d": { + "balance": "100000000000000000000000" + }, + "f4c79ea9c6f7297e016c39296d86f0304070c31d": { + "balance": "71036374423000000000" + }, + "f4dde3733a72872a7efc095cb412672c50928f1b": { + "balance": "129914864759880000000000" + }, + "f4ed736a413464eb93f8a430e093a64f0bd4222d": { + "balance": "10000000000000000000000" + }, + "f4f07e45560fb63d5207ed7e8d7cf4fe29e06d18": { + "balance": "293103814503448000000000" + }, + "f50eac35eef0a1bfa23ba31020ef60e89bf8e9df": { + "balance": "10000000000000000000000" + }, + "f51236dfd888929ccb2fe1f1fc5554abc5df4ce2": { + "balance": "25000000000000000000" + }, + "f521eb42e9092350f2ad4391ddb42bfe7abb4db9": { + "balance": "217462745186000000000" + }, + "f54e7062b6a9a8b283acf00fcbad58aca0737676": { + "balance": "7327357122437000000000" + }, + "f553301efd81629d0856d9c95c70f4a962e602ed": { + "balance": "1500355826530000000000" + }, + "f55c555b0991b2413f2f2764d8ed6a0d77825965": { + "balance": "1174679810163000000000" + }, + "f56ff110d521ceaec29dbf2842f1e78b24463cea": { + "balance": "20000000000000000000000" + }, + "f573fec366236ab87ba041f7dc6a88d92b1fc9b7": { + "balance": "4659857040000000000" + }, + "f59987743b239379aac9353e17e0e4442aa2c684": { + "balance": "25000000000000000000" + }, + "f5a9ca298e88c5492dd44a66d815b649c2f01d39": { + "balance": "95879585325000000000" + }, + "f5b4933164c55b5ba99db906ecaa52bba4f95164": { + "balance": "25663623936000000000" + }, + "f5d20af68c6fed98144718b6beab82fde00dfedc": { + "balance": "16000000000000000000" + }, + "f5e49ce72be9b17ff39688860e5cf6fd500a886c": { + "balance": "106142276914000000000" + }, + "f5f472405a4530075805fbc11928544770fd61fe": { + "balance": "64000000000000000000" + }, + "f62096c7305eb97b221bb637f4269246fe59262b": { + "balance": "855993602798000000000" + }, + "f622bf9b8f7be2f75d5ed73d318a0e7fa62a587f": { + "balance": "20000000000000000000000" + }, + "f6231f31d524ccc444bd046123ba33bc224bdd52": { + "balance": "97550810879000000000" + }, + "f641b4a721dcefa497274fd06888eb998b9bc038": { + "balance": "39401014566340000000000" + }, + "f64f0c5172c99d74b2450a4685c3ec715b379922": { + "balance": "28337413668000000000" + }, + "f65841061cd55cbf20843d9594bce9ee133aa644": { + "balance": "9064540188290000000000" + }, + "f65f0106f3d148d0660547f0683ded4dffc12fe9": { + "balance": "87334071785367000000000" + }, + "f677961296ed933db9e1dd887711387540c0436d": { + "balance": "3982789899000000000" + }, + "f68ba7530f423b8df1625cee36f8df2363a57c49": { + "balance": "5000000000000000000000" + }, + "f69c6eaf077b795f19a9590ee8b578543558e4c4": { + "balance": "10000000000000000000000" + }, + "f69dfe3f0f76e50e2850e44e9e36b6966e277eaa": { + "balance": "288231750575462000000000" + }, + "f6a73c4b958b4d6044f3f4da7147d0fa80e2ea31": { + "balance": "50000000000000000000000" + }, + "f6b0864be5f7bbc4210a3420aa3ead614a8fe7e2": { + "balance": "880968828000000000" + }, + "f6f43a6d9517471436d2ce5047a2b707580e7149": { + "balance": "20000000000000000000000" + }, + "f6fb414d1ca7c29be35b5f97096c817bbf70b070": { + "balance": "15156317416682000000000" + }, + "f707b491ac27b2d2e5e1f9d4123635ee0af92c5c": { + "balance": "500000000000000000000000" + }, + "f71179583a471767a1b399842d7d29caefe57a5e": { + "balance": "429648186876000000000" + }, + "f71ed909eca6bfd574cd670389bc9250493d686d": { + "balance": "38189267531000000000" + }, + "f72ccdc70b7878cdb94f42ee72ca5b4b35a46238": { + "balance": "86065647347000000000" + }, + "f74035e85dbfdb961037bf689ee7dfdcfaf32d64": { + "balance": "398451682882000000000" + }, + "f77668db085a87b0a0405a275e1c2516d3e02b66": { + "balance": "10000000000000000000000" + }, + "f78990d9e50876b49f933e9d74bda44197e9aa7d": { + "balance": "51984216556000000000" + }, + "f79b9df28b7d94d1b4491fca1cbe50bd36aedb3a": { + "balance": "11546152485156000000000" + }, + "f7c773b89be413848dc4a96f064693a0c3a2eab0": { + "balance": "7084247258755000000000" + }, + "f7e29c20bb0023e9ae079da589346fdfd960dae3": { + "balance": "93132014782000000000" + }, + "f8124428ea619d30a335ecc4c2f64e36500abdcb": { + "balance": "8838170798391000000000" + }, + "f843c9d70226e6c2c8cd4cef78e2db66a8eac027": { + "balance": "498377670361000000000" + }, + "f84bb3c0d872dcdbe99d6abcc57c6b5c2b2e35ad": { + "balance": "1405105232436000000000" + }, + "f8679b915ae94e4668f2e27d1094cbb2d97cf428": { + "balance": "1000000000000000000" + }, + "f86dbb82c634cdfa818e4d0dbcfcc9a5c47a9ddb": { + "balance": "196000000000000000000" + }, + "f88bad7726aa66bc1d0ca5824044072f3551fd15": { + "balance": "37432374800000000000" + }, + "f8ab07d0751a2c283ebe2a7e28c5b6e57867e1d1": { + "balance": "25000000000000000000" + }, + "f8afb4f5684c56ff7ce71b4e4cf7e42062470e08": { + "balance": "10000000000000000000000" + }, + "f8c28df0d1a0982289ddfa2a6d562e5c75a5dd01": { + "balance": "1447386977682000000000" + }, + "f8cca137f9c12b48eafd43f038e55e2d3c481919": { + "balance": "35370515421000000000" + }, + "f8e50d1816a5e5c649756ae208209b03b1ece0c3": { + "balance": "48449640035000000000" + }, + "f8fb33ba1d93112d9c3672806e0939083f09a88e": { + "balance": "419743187776000000000" + }, + "f903bebfcc6a7050fc2c5bd14248af9b300f1600": { + "balance": "473363252199000000000" + }, + "f90ab9078f26dd881fb054b4b6e3b3e17fa94718": { + "balance": "156449634345000000000" + }, + "f93e3f392efc057f0af3a91416858a515c1ed996": { + "balance": "1147663044625000000000" + }, + "f94eac538ca66931869c312acb67721c4337842f": { + "balance": "368103335377000000000" + }, + "f94fda503c3f792491fa77b3702fd465f028810d": { + "balance": "317241487661000000000" + }, + "f95dcedbefee8ed01086c91d91a4c115ad8fc947": { + "balance": "147059838786000000000" + }, + "f961a293bbce366a6fcc98d2ba0342e2ef3c5519": { + "balance": "10000000000000000000000" + }, + "f966fdbc4a42f055f8f52d31c23ad7b6a07a5e22": { + "balance": "10000000000000000000000" + }, + "f9a3a61a2f1469835240bb0641eae40c07451e30": { + "balance": "218000000000000" + }, + "f9adcf232180378b08a46d6c8d9d97f01802e01b": { + "balance": "15658216517944000000000" + }, + "f9c68991ff7ac307e41ea1c673f8ebb1a6afbd99": { + "balance": "10000000000000000000000" + }, + "f9cc0c60431d7bdb0c7581a9ae7f011b0abefeb1": { + "balance": "16000000000000000000" + }, + "f9d43c329b61ca2169600e45c8fad3c94226adb8": { + "balance": "120128558137000000000" + }, + "f9ef5d4e2ca8888216b939d3d938438a34dd9da2": { + "balance": "144000000000000000000" + }, + "f9f3d14cd3bd09e2c4c89035b4f50e93f6175cef": { + "balance": "725000000000000000000" + }, + "fa0f5a03601bd1fc76865cdd69d9671ba6073592": { + "balance": "225298289139000000000" + }, + "fa12f10db0eb552b719194becef20af9f45de8db": { + "balance": "1012484659496000000000" + }, + "fa146c58a0709951bc2e9bccddcd002c5a0bb7dd": { + "balance": "199563276701000000000" + }, + "fa159185c156f35fa450b77c48846c2dab6349b7": { + "balance": "100660066567000000000" + }, + "fa193312655f79c7b0ee7d7ef904486836180026": { + "balance": "48141690266000000000" + }, + "fa2484de744918bd8c91350fbabc0dab8b8a44f0": { + "balance": "36000000000000000000" + }, + "fa36dc463b026d8edfeb8ac4acac43a51d643457": { + "balance": "9608761064478000000000" + }, + "fa84199010be2bf53e803c23771e0d15fd025386": { + "balance": "1474902394742000000000" + }, + "fa958bbfa367a745bcd0904db2c4e30445edaefb": { + "balance": "175679888121000000000" + }, + "fa98bcaeb55285ad7ead12ccaa15cf488f567ede": { + "balance": "136105143781000000000" + }, + "faa1be631da42b41a026774f4166c1b831ef41e9": { + "balance": "86358861589000000000" + }, + "faaa857e7f149968434f313ab8db596e1b0ae75d": { + "balance": "36000000000000000000" + }, + "fac2b85ab274055cf1415d57394e8aca4541857d": { + "balance": "289000000000000000000" + }, + "fb23a508ccdb4e91b252f5c06c465c55ed59b1db": { + "balance": "14698710175236000000000" + }, + "fb24d4e47ba70aa4b984372b4852ad3d082daa24": { + "balance": "4526648424830000000000" + }, + "fb27a7e8b8b4ae43c69ce025b46187e538608769": { + "balance": "121000000000000000000" + }, + "fb2cdb5e85872f52c99985f219b8fb4125c6a8b7": { + "balance": "8568367153000000000" + }, + "fb3d76c8165bcb3c93fd3b2b10c20588d0fa97aa": { + "balance": "500000000000000000000000" + }, + "fb5161b2cc9d48a53f47d66002905f0458e3cd9e": { + "balance": "225000000000000000000" + }, + "fb72756c4845f18ab35d29f632b662c0c0d4b94f": { + "balance": "883095068524000000000" + }, + "fb8b7efb02ea5292304c0f0abc8c555684653587": { + "balance": "10000000000000000000000" + }, + "fb9ee61e337a5c7b57c5140e84919101570e2cb7": { + "balance": "16000000000000000000" + }, + "fbae69f44b116c186a86cb0de79323ca3d6b99eb": { + "balance": "1359504686067000000000" + }, + "fbbd399eb9e5d3dd67efc48927973601dcd84321": { + "balance": "2049018637367000000000" + }, + "fbc9a3c3c429990cc306710b3dd44174dcc72ad4": { + "balance": "55507457947000000000" + }, + "fbce66a6898ecd70893db6b4b8c3d00afef8e20b": { + "balance": "20857164902458000000000" + }, + "fbe8fe04084fc93dff8228861fe100bfeeb057b6": { + "balance": "10000000000000000000000" + }, + "fbfb717f902ad79ef63565f9ab57f041ff5f7626": { + "balance": "16000000000000000000" + }, + "fc0b6c8c6be79bf0c9554f7855dc8c4a617d02c9": { + "balance": "17347593956000000000" + }, + "fc17518d05e605807847bbf6f407da89037bca00": { + "balance": "1796383702108000000000" + }, + "fc2793424c809cc80938a1be1292813adbc8ac8c": { + "balance": "10000000000000000000" + }, + "fc35930abb108ae6cae33fd065dfb799808ea326": { + "balance": "912737460000000000000" + }, + "fc5a9209799e563ae8d958774dc86345a3bc7ed2": { + "balance": "29049176573000000000" + }, + "fc8011850c09c9288e737ea58ca5c15cded6dc8d": { + "balance": "10000000000000000000000" + }, + "fc9183ed137be071ad183d025395a0ebe2674654": { + "balance": "500000000000000000000000" + }, + "fc98c9d88b1fbbb68dbdd6448aa6a32e8282800d": { + "balance": "900000000000000000000" + }, + "fc9f4b9da7a46c2bfcd50cafe1f892b9984be0ee": { + "balance": "21577116424370000000000" + }, + "fca525b732a673b953f1c23083c276cc8cbcb86c": { + "balance": "77653618624000000000" + }, + "fca57b6a4798f33478b6e23622173cda3fe1b9a0": { + "balance": "793368066098000000000" + }, + "fca79b446c513a7bed643603c42f35ff0fa89f49": { + "balance": "998082799053000000000" + }, + "fcab42f7f07735a7b09074c1f1769287069c88c8": { + "balance": "94824830574000000000" + }, + "fcacbbc6810c586522012ad32c3dfac80eb563b4": { + "balance": "10000000000000000000000" + }, + "fcb38809b63810b6673dcb4c947e01f7b49fb1b3": { + "balance": "725937240372000000000" + }, + "fcc0e531d9f6265672aa885af361534464a11015": { + "balance": "22121462657000000000" + }, + "fcc49c62d7738fa1b92aa6a69a12b671e4c7c8d9": { + "balance": "50000000000000000000000" + }, + "fcc95394fd796ca5bd8f3814883b1150d74dd9a5": { + "balance": "144000000000000000000" + }, + "fccdb068dfd599d7d5c290a6ae65eba9151d5b29": { + "balance": "5369426564000000000" + }, + "fcde41ae28bdf9084a28f47a9348d8aac5b3dd43": { + "balance": "409599263197000000000" + }, + "fce5816f066ca32d1fa02e9e8b5eb8a7fa3e4dea": { + "balance": "1193272309645000000000" + }, + "fcf9fb8996d6d9175ade6d6063be0742de20ea1f": { + "balance": "16852526239339000000000" + }, + "fd10488d55e6861cb67f7f50950d78892e7032ad": { + "balance": "165069902909000000000" + }, + "fd23e8263d89256add0dfe93da153d305ad917c7": { + "balance": "26633825496000000000" + }, + "fd3a98cc3b3f1439af35f806de2fb05fef98f279": { + "balance": "1043321187464000000000" + }, + "fd3d79185a91984a117ee6f9fd304725875094e2": { + "balance": "2349991833898000000000" + }, + "fd5e6ac22634f04ec4ace5da8996c2b7b70b22f4": { + "balance": "10000000000000000" + }, + "fd62ed1cf7a535c989fbd742b1660205a2f69dd0": { + "balance": "49000000000000000000" + }, + "fd645043bd4d7b71e63e30409b91e9fdda3a86c0": { + "balance": "362957768837969000000000" + }, + "fd7014fc1c70af482115247ff94ff6bdbd3d364d": { + "balance": "743383172317000000000" + }, + "fda0cfe95df9021497752b04863c3ec44d13e853": { + "balance": "15586809617955000000000" + }, + "fdb5b964808bcb974d3e888cbb45bcd57e57c907": { + "balance": "5549247772273000000000" + }, + "fdbaaa865ec38da13e80554b6d0abc437f60d8a5": { + "balance": "3736861227131000000000" + }, + "fdbb8693b3c20c0eac5fb585e2347d41debbffce": { + "balance": "100000000000000000" + }, + "fdbdaec57829f25ad48e18d94e0b8533f2801818": { + "balance": "6934630922926000000000" + }, + "fdc318ba5b1f8ad33e00528828b93a840592e2fb": { + "balance": "10000000000000000000000" + }, + "fdcf6a997bb10806e4d87eb4222e9f93b4202179": { + "balance": "1000000000000000000" + }, + "fde5a9911a10770d733db4d32ca9a5493478399c": { + "balance": "20000000000000000000000" + }, + "fe39185a6b84378820ee215f630533e658731ca9": { + "balance": "17022202932000000000" + }, + "fe3b1032e524674cba5f329f940c837850fa53ed": { + "balance": "50000000000000000000000" + }, + "fe3bc4ff2c3b66bc582558314b80030407e7de96": { + "balance": "1669870860988000000000" + }, + "fe668dbb1f3de744d16e13e0ed6f5708c2c15d1f": { + "balance": "39974355655263000000000" + }, + "fe95bfb97fa60341f8af2ad621e606b85e3c2e57": { + "balance": "528601649597478000000000" + }, + "fe99cf2a1fbbe7c46e4235b2d135a3a093fcf16c": { + "balance": "7271022106877000000000" + }, + "fec1f6ed4b3ff01e7ebe13fb53f60ee5a3b9e191": { + "balance": "1316316072034000000000" + }, + "fed9bec1b2145452ed5535e4ba29fafac6c35fbb": { + "balance": "10799354586000000000" + }, + "fedced7aa1cf3f3a7eec321cc0274759b154ea8e": { + "balance": "11740927210323000000000" + }, + "fef5063701a93ad02676fe0b99d0f4d2da0ccd67": { + "balance": "10178531012000000000" + }, + "fefd5627a408ca099587892ee2a46fa8cc89be19": { + "balance": "458504035686000000000" + }, + "ff1fc0f6f26188cbe18cf65d8a344d3775aecc6d": { + "balance": "81000000000000000000" + }, + "ff4fe483b3c04ebc8d6705c699ecee3e92071715": { + "balance": "1000000000000000000" + }, + "ff51bfe823394b2bce05947a6068bd5158d4af0e": { + "balance": "692533626783000000000" + }, + "ff6652e4e45f6b0f95ad4c9ec2bc80476e3f7fc6": { + "balance": "46457898024000000000" + }, + "ff68246ac7640091e5e58345736b249e036364fc": { + "balance": "2626125272000000000" + }, + "ff6d4b8a8393a503047ff829dbf2bf8e9172dc6d": { + "balance": "2865001878255000000000" + }, + "ff6fe19e056a7211b7e484c2c540d5aa5f1d83e5": { + "balance": "36000000000000000000" + }, + "ff7fa33529e1781c1b2951e57581780b229e3fda": { + "balance": "10000000000000000000" + }, + "ff82d1052538539d07cf3955476cc9a5027d8e4e": { + "balance": "83572023121000000000" + }, + "ff8acfe75afcc1efb1bc44be9f9bb242a94f73f7": { + "balance": "7556034521000000000" + }, + "ffa2b5f1685de9fcf1af4653cd3a584db1beed64": { + "balance": "114892199805000000000" + }, + "ffb1e9be68ae8be8d7d066c473589921e68825a2": { + "balance": "484660652980000000000" + }, + "ffbf91a9d1a6377b7435e3e734132e7b34188dac": { + "balance": "20000000000000000000000" + }, + "ffbff1fab9f2bc2f387d0cc9cc28f6aac533c813": { + "balance": "10000000000000000000000" + }, + "ffc4ff6433ea35544e7a07fda170e62c451301df": { + "balance": "29238210920000000000" + }, + "ffc7534b64a8fe8760e931a710883119d28ae106": { + "balance": "500000000000000000000000" + }, + "ffda6b8e3de72d7f7c18b892e6a8b80b886d5fa5": { + "balance": "214366938289000000000" + }, + "ffddb1fb7521c9772ea4886aaf022c4375ef904d": { + "balance": "554864446437000000000" + } + } } diff --git a/ethcore/res/ethereum/transition_test.json b/ethcore/res/ethereum/transition_test.json index 7c18fce4e5..9dc00fd5d8 100644 --- a/ethcore/res/ethereum/transition_test.json +++ b/ethcore/res/ethereum/transition_test.json @@ -8,10 +8,6 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "homesteadTransition": "0", - "eip150Transition": "0", - "eip160Transition": "0", - "eip161abcTransition": "0", - "eip161dTransition": "0", "eip649Reward": "0x29A2241AF62C0000", "eip100bTransition": "5", "eip649Transition": "5" @@ -27,6 +23,10 @@ "networkID" : "0x1", "maxCodeSize": 24576, "maxCodeSizeTransition": "0", + "eip150Transition": "0", + "eip160Transition": "0", + "eip161abcTransition": "0", + "eip161dTransition": "0", "eip98Transition": "5", "eip140Transition": "5", "eip211Transition": "5", diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 1bd3805ef3..9c6db25cbc 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -46,14 +46,6 @@ pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]); pub struct EthashExtensions { /// Homestead transition block number. pub homestead_transition: BlockNumber, - /// EIP150 transition block number. - pub eip150_transition: BlockNumber, - /// Number of first block where EIP-160 rules begin. - pub eip160_transition: u64, - /// Number of first block where EIP-161.abc begin. - pub eip161abc_transition: u64, - /// Number of first block where EIP-161.d begins. - pub eip161d_transition: u64, /// DAO hard-fork transition block (X). pub dao_hardfork_transition: u64, /// DAO hard-fork refund contract address (C). @@ -66,10 +58,6 @@ impl From<::ethjson::spec::EthashParams> for EthashExtensions { fn from(p: ::ethjson::spec::EthashParams) -> Self { EthashExtensions { homestead_transition: p.homestead_transition.map_or(0, Into::into), - eip150_transition: p.eip150_transition.map_or(0, Into::into), - eip160_transition: p.eip160_transition.map_or(0, Into::into), - eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into), - eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into), dao_hardfork_transition: p.dao_hardfork_transition.map_or(u64::max_value(), Into::into), dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into), dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or_else(Vec::new).into_iter().map(Into::into).collect(), @@ -267,19 +255,8 @@ impl EthereumMachine { Some(ref ext) => { if block_number < ext.homestead_transition { Schedule::new_frontier() - } else if block_number < ext.eip150_transition { - Schedule::new_homestead() } else { - let max_code_size = self.params.max_code_size(block_number); - let mut schedule = Schedule::new_post_eip150( - max_code_size as _, - block_number >= ext.eip160_transition, - block_number >= ext.eip161abc_transition, - block_number >= ext.eip161d_transition - ); - - self.params.update_schedule(block_number, &mut schedule); - schedule + self.params.schedule(block_number) } } }; @@ -503,10 +480,6 @@ mod tests { fn get_default_ethash_extensions() -> EthashExtensions { EthashExtensions { homestead_transition: 1150000, - eip150_transition: u64::max_value(), - eip160_transition: u64::max_value(), - eip161abc_transition: u64::max_value(), - eip161d_transition: u64::max_value(), dao_hardfork_transition: u64::max_value(), dao_hardfork_beneficiary: "0000000000000000000000000000000000000001".into(), dao_hardfork_accounts: Vec::new(), diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 1ee8cf7032..fa25c8894e 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -78,6 +78,14 @@ pub struct CommonParams { pub min_gas_limit: U256, /// Fork block to check. pub fork_block: Option<(BlockNumber, H256)>, + /// EIP150 transition block number. + pub eip150_transition: BlockNumber, + /// Number of first block where EIP-160 rules begin. + pub eip160_transition: u64, + /// Number of first block where EIP-161.abc begin. + pub eip161abc_transition: u64, + /// Number of first block where EIP-161.d begins. + pub eip161d_transition: u64, /// Number of first block where EIP-98 rules begin. pub eip98_transition: BlockNumber, /// Number of first block where EIP-658 rules begin. @@ -134,9 +142,20 @@ pub struct CommonParams { impl CommonParams { /// Schedule for an EVM in the post-EIP-150-era of the Ethereum main net. pub fn schedule(&self, block_number: u64) -> ::vm::Schedule { - let mut schedule = ::vm::Schedule::new_post_eip150(self.max_code_size(block_number) as _, true, true, true); - self.update_schedule(block_number, &mut schedule); - schedule + if block_number < self.eip150_transition { + ::vm::Schedule::new_homestead() + } else { + let max_code_size = self.max_code_size(block_number); + let mut schedule = ::vm::Schedule::new_post_eip150( + max_code_size as _, + block_number >= self.eip160_transition, + block_number >= self.eip161abc_transition, + block_number >= self.eip161d_transition + ); + + self.update_schedule(block_number, &mut schedule); + schedule + } } /// Returns max code size at given block. @@ -197,6 +216,10 @@ impl From for CommonParams { } else { None }, + eip150_transition: p.eip150_transition.map_or(0, Into::into), + eip160_transition: p.eip160_transition.map_or(0, Into::into), + eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into), + eip161d_transition: p.eip161d_transition.map_or(0, Into::into), eip98_transition: p.eip98_transition.map_or(0, Into::into), eip155_transition: p.eip155_transition.map_or(0, Into::into), validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into), diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs index afa8b59682..66f6913e57 100644 --- a/json/src/spec/ethash.rs +++ b/json/src/spec/ethash.rs @@ -73,21 +73,6 @@ pub struct EthashParams { #[serde(rename="eip100bTransition")] pub eip100b_transition: Option, - /// See main EthashParams docs. - #[serde(rename="eip150Transition")] - pub eip150_transition: Option, - - /// See main EthashParams docs. - #[serde(rename="eip160Transition")] - pub eip160_transition: Option, - - /// See main EthashParams docs. - #[serde(rename="eip161abcTransition")] - pub eip161abc_transition: Option, - /// See main EthashParams docs. - #[serde(rename="eip161dTransition")] - pub eip161d_transition: Option, - /// See main EthashParams docs. #[serde(rename="ecip1010PauseTransition")] pub ecip1010_pause_transition: Option, @@ -190,11 +175,7 @@ mod tests { "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", "bombDefuseTransition": "0x41", - "eip100bTransition": "0x42", - "eip150Transition": "0x43", - "eip160Transition": "0x45", - "eip161abcTransition": "0x46", - "eip161dTransition": "0x47" + "eip100bTransition": "0x42" } }"#; @@ -237,10 +218,6 @@ mod tests { difficulty_hardfork_bound_divisor: Some(Uint(U256::from(0x0200))), bomb_defuse_transition: Some(Uint(U256::from(0x41))), eip100b_transition: Some(Uint(U256::from(0x42))), - eip150_transition: Some(Uint(U256::from(0x43))), - eip160_transition: Some(Uint(U256::from(0x45))), - eip161abc_transition: Some(Uint(U256::from(0x46))), - eip161d_transition: Some(Uint(U256::from(0x47))), ecip1010_pause_transition: None, ecip1010_continue_transition: None, ecip1017_era_rounds: None, @@ -285,10 +262,6 @@ mod tests { difficulty_hardfork_bound_divisor: None, bomb_defuse_transition: None, eip100b_transition: None, - eip150_transition: None, - eip160_transition: None, - eip161abc_transition: None, - eip161d_transition: None, ecip1010_pause_transition: None, ecip1010_continue_transition: None, ecip1017_era_rounds: None, diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 0addf52e4a..f171a88101 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -51,6 +51,21 @@ pub struct Params { #[serde(rename="forkCanonHash")] pub fork_hash: Option, + /// See main EthashParams docs. + #[serde(rename="eip150Transition")] + pub eip150_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip160Transition")] + pub eip160_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip161abcTransition")] + pub eip161abc_transition: Option, + /// See main EthashParams docs. + #[serde(rename="eip161dTransition")] + pub eip161d_transition: Option, + /// See `CommonParams` docs. #[serde(rename="eip98Transition")] pub eip98_transition: Option, -- GitLab From 84ecab0eaf96149be75ee127aef37d0cb0f2c4bb Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 06:32:05 +0200 Subject: [PATCH 174/263] Remove HostInfo::client_version() and secret() (#8677) --- util/network-devp2p/src/handshake.rs | 3 ++- util/network-devp2p/src/host.rs | 14 +++++++------- util/network/src/lib.rs | 4 ---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index a203af5b4b..7aef4d4f0d 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -26,7 +26,8 @@ use node_table::NodeId; use io::{IoContext, StreamToken}; use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; use ethkey::crypto::{ecdh, ecies}; -use network::{Error, ErrorKind, HostInfo}; +use network::{Error, ErrorKind, HostInfo as HostInfoTrait}; +use host::HostInfo; #[derive(PartialEq, Eq, Debug)] enum HandshakeState { diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index f3446845fb..5ccab2e4db 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -215,19 +215,19 @@ impl HostInfo { self.nonce = keccak(&self.nonce); self.nonce } -} -impl HostInfoTrait for HostInfo { - fn id(&self) -> &NodeId { - self.keys.public() + pub(crate) fn client_version(&self) -> &str { + &self.config.client_version } - fn secret(&self) -> &Secret { + pub(crate) fn secret(&self) -> &Secret { self.keys.secret() } +} - fn client_version(&self) -> &str { - &self.config.client_version +impl HostInfoTrait for HostInfo { + fn id(&self) -> &NodeId { + self.keys.public() } } diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 0137543fdd..d16403cd34 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -330,10 +330,6 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { pub trait HostInfo { /// Returns public key fn id(&self) -> &NodeId; - /// Returns secret key - fn secret(&self) -> &Secret; - /// Returns the client version. - fn client_version(&self) -> &str; } /// Network IO protocol handler. This needs to be implemented for each new subprotocol. -- GitLab From ee41fa6f30fe275977265c7e139b4841ab47c725 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 06:34:01 +0200 Subject: [PATCH 175/263] Move connection_filter to the network crate (#8674) --- Cargo.lock | 1 + ethcore/node_filter/Cargo.toml | 1 + ethcore/node_filter/src/lib.rs | 6 ++++-- ethcore/sync/src/api.rs | 5 +++-- ethcore/sync/src/lib.rs | 4 ++-- util/network-devp2p/src/host.rs | 2 +- util/network-devp2p/src/lib.rs | 2 -- util/network-devp2p/src/service.rs | 2 +- util/{network-devp2p => network}/src/connection_filter.rs | 0 util/network/src/lib.rs | 2 ++ 10 files changed, 15 insertions(+), 10 deletions(-) rename util/{network-devp2p => network}/src/connection_filter.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e2fa0a9db8..646bc90645 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,6 +1805,7 @@ dependencies = [ "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", "ethcore-io 1.12.0", + "ethcore-network 1.12.0", "ethcore-network-devp2p 1.12.0", "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index 25b5ec59f4..0d204e29ff 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -8,6 +8,7 @@ authors = ["Parity Technologies "] [dependencies] ethcore = { path = ".."} +ethcore-network = { path = "../../util/network" } ethcore-network-devp2p = { path = "../../util/network-devp2p" } ethereum-types = "0.3" log = "0.3" diff --git a/ethcore/node_filter/src/lib.rs b/ethcore/node_filter/src/lib.rs index 715b7ae3e9..c731ad356a 100644 --- a/ethcore/node_filter/src/lib.rs +++ b/ethcore/node_filter/src/lib.rs @@ -18,7 +18,8 @@ extern crate ethabi; extern crate ethcore; -extern crate ethcore_network_devp2p as network; +extern crate ethcore_network as network; +extern crate ethcore_network_devp2p as devp2p; extern crate ethereum_types; extern crate lru_cache; extern crate parking_lot; @@ -43,7 +44,8 @@ use parking_lot::Mutex; use ethcore::client::{BlockChainClient, BlockId}; use ethereum_types::{H256, Address}; -use network::{NodeId, ConnectionFilter, ConnectionDirection}; +use network::{ConnectionFilter, ConnectionDirection}; +use devp2p::NodeId; use_contract!(peer_set, "PeerSet", "res/peer_set.json"); diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index e901528e41..56ea8526ed 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -19,9 +19,10 @@ use std::collections::{HashMap, BTreeMap}; use std::io; use std::time::Duration; use bytes::Bytes; -use devp2p::{NetworkService, ConnectionFilter}; +use devp2p::NetworkService; use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, ProtocolId, - NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, Error, ErrorKind}; + NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, Error, ErrorKind, + ConnectionFilter}; use ethereum_types::{H256, H512, U256}; use io::{TimerToken}; use ethcore::ethstore::ethkey::Secret; diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index 3eb2e8332b..c00ea5e440 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -74,6 +74,6 @@ mod api; pub use api::*; pub use chain::{SyncStatus, SyncState}; -pub use devp2p::{validate_node_url, ConnectionFilter, ConnectionDirection}; -pub use network::{NonReservedPeerMode, Error, ErrorKind}; +pub use devp2p::validate_node_url; +pub use network::{NonReservedPeerMode, Error, ErrorKind, ConnectionFilter, ConnectionDirection}; pub use private_tx::{PrivateTxHandler, NoopPrivateTxHandler, SimplePrivateTxHandler}; diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 5ccab2e4db..3ab7b7f849 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -45,7 +45,7 @@ use discovery::{Discovery, TableUpdates, NodeEntry}; use ip_utils::{map_external_address, select_public_address}; use path::restrict_permissions_owner; use parking_lot::{Mutex, RwLock}; -use connection_filter::{ConnectionFilter, ConnectionDirection}; +use network::{ConnectionFilter, ConnectionDirection}; type Slab = ::slab::Slab; diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index e5bb95f220..244997a654 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -106,10 +106,8 @@ mod discovery; mod service; mod node_table; mod ip_utils; -mod connection_filter; pub use service::NetworkService; -pub use connection_filter::{ConnectionFilter, ConnectionDirection}; pub use host::NetworkContext; pub use io::TimerToken; diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 10a1e9abc8..3ac1ec7f71 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -21,7 +21,7 @@ use io::*; use parking_lot::RwLock; use std::sync::Arc; use ansi_term::Colour; -use connection_filter::ConnectionFilter; +use network::ConnectionFilter; struct HostHandler { public_url: RwLock> diff --git a/util/network-devp2p/src/connection_filter.rs b/util/network/src/connection_filter.rs similarity index 100% rename from util/network-devp2p/src/connection_filter.rs rename to util/network/src/connection_filter.rs diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index d16403cd34..f3012e4c37 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -27,8 +27,10 @@ extern crate snappy; #[macro_use] extern crate error_chain; +mod connection_filter; mod error; +pub use connection_filter::{ConnectionFilter, ConnectionDirection}; pub use io::TimerToken; pub use error::{Error, ErrorKind, DisconnectReason}; -- GitLab From fe5f5b28d9be6b894545cfbbb42580068e14524b Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 06:35:13 +0200 Subject: [PATCH 176/263] Remove the error when stopping the network (#8671) --- ethcore/sync/src/api.rs | 6 ++---- util/io/src/service_mio.rs | 10 ++++++---- util/network-devp2p/src/host.rs | 5 ++--- util/network-devp2p/src/service.rs | 7 +++---- util/network-devp2p/tests/tests.rs | 2 +- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 56ea8526ed..2f90e410ae 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -475,7 +475,7 @@ impl ChainNotify for EthSync { fn stop(&self) { self.eth_handler.snapshot_service.abort_restore(); - self.network.stop().unwrap_or_else(|e| warn!("Error stopping network: {:?}", e)); + self.network.stop(); } fn broadcast(&self, message_type: ChainMessageType) { @@ -833,9 +833,7 @@ impl ManageNetwork for LightSync { fn stop_network(&self) { self.proto.abort(); - if let Err(e) = self.network.stop() { - warn!("Error stopping network: {}", e); - } + self.network.stop(); } fn network_config(&self) -> NetworkConfiguration { diff --git a/util/io/src/service_mio.rs b/util/io/src/service_mio.rs index f7c9f1976c..2ae3d55e0f 100644 --- a/util/io/src/service_mio.rs +++ b/util/io/src/service_mio.rs @@ -162,11 +162,13 @@ impl IoContext where Message: Send + Sync + 'static { } /// Unregister current IO handler. - pub fn unregister_handler(&self) -> Result<(), IoError> { - self.channel.send_io(IoMessage::RemoveHandler { + pub fn unregister_handler(&self) { + // `send_io` returns an error only if the channel is closed, which means that the + // background thread is no longer running. Therefore the handler is no longer active and + // can be considered as unregistered. + let _ = self.channel.send_io(IoMessage::RemoveHandler { handler_id: self.handler, - })?; - Ok(()) + }); } } diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 3ab7b7f849..fbbeb89ff8 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -396,7 +396,7 @@ impl Host { format!("{}", Node::new(info.id().clone(), info.local_endpoint.clone())) } - pub fn stop(&self, io: &IoContext) -> Result<(), Error> { + pub fn stop(&self, io: &IoContext) { self.stopping.store(true, AtomicOrdering::Release); let mut to_kill = Vec::new(); for e in self.sessions.read().iter() { @@ -408,8 +408,7 @@ impl Host { trace!(target: "network", "Disconnecting on shutdown: {}", p); self.kill_connection(p, io, true); } - io.unregister_handler()?; - Ok(()) + io.unregister_handler(); } /// Get all connected peers. diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 3ac1ec7f71..eb2e9685d4 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -125,15 +125,14 @@ impl NetworkService { Ok(()) } - /// Stop network IO - pub fn stop(&self) -> Result<(), Error> { + /// Stop network IO. + pub fn stop(&self) { let mut host = self.host.write(); if let Some(ref host) = *host { let io = IoContext::new(self.io_service.channel(), 0); //TODO: take token id from host - host.stop(&io)?; + host.stop(&io); } *host = None; - Ok(()) } /// Get a list of all connected peers by id. diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index e8c8eddde4..a1d178d654 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -112,7 +112,7 @@ fn net_start_stop() { let config = NetworkConfiguration::new_local(); let service = NetworkService::new(config, None).unwrap(); service.start().unwrap(); - service.stop().unwrap(); + service.stop(); service.start().unwrap(); } -- GitLab From bd1e3fc606c3bf6337cb5cabcc068a63c4e8a029 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 22 May 2018 19:07:27 +0200 Subject: [PATCH 177/263] Allow making direct RPC queries from the C API (#8588) --- parity-clib-example/main.cpp | 17 +++++++++++++++-- parity-clib/parity.h | 16 ++++++++++++++++ parity-clib/src/lib.rs | 31 ++++++++++++++++++++++++++++++ parity/rpc.rs | 2 +- parity/run.rs | 35 ++++++++++++++++++++++++++++++---- rpc/src/v1/types/provenance.rs | 4 ++++ 6 files changed, 98 insertions(+), 7 deletions(-) diff --git a/parity-clib-example/main.cpp b/parity-clib-example/main.cpp index 1fadf1b5b5..becce8598e 100644 --- a/parity-clib-example/main.cpp +++ b/parity-clib-example/main.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include @@ -8,8 +11,8 @@ int main() { ParityParams cfg = { 0 }; cfg.on_client_restart_cb = on_restart; - const char* args[] = {"--light"}; - size_t str_lens[] = {7}; + const char* args[] = {"--no-ipc"}; + size_t str_lens[] = {8}; if (parity_config_from_cli(args, str_lens, 1, &cfg.configuration) != 0) { return 1; } @@ -19,6 +22,16 @@ int main() { return 1; } + const char* rpc = "{\"method\":\"parity_versionInfo\",\"params\":[],\"id\":1,\"jsonrpc\":\"2.0\"}"; + size_t out_len = 256; + char* out = (char*)malloc(out_len + 1); + if (parity_rpc(parity, rpc, strlen(rpc), out, &out_len)) { + return 1; + } + out[out_len] = '\0'; + printf("RPC output: %s", out); + free(out); + sleep(5); if (parity != NULL) { parity_destroy(parity); diff --git a/parity-clib/parity.h b/parity-clib/parity.h index b61da8e458..f647395ce9 100644 --- a/parity-clib/parity.h +++ b/parity-clib/parity.h @@ -86,6 +86,22 @@ int parity_start(const ParityParams* params, void** out); /// must not call this function. void parity_destroy(void* parity); +/// Performs an RPC request. +/// +/// Blocks the current thread until the request is finished. You are therefore encouraged to spawn +/// a new thread for each RPC request that requires accessing the blockchain. +/// +/// - `rpc` and `len` must contain the JSON string representing the RPC request. +/// - `out_str` and `out_len` point to a buffer where the output JSON result will be stored. If the +/// buffer is not large enough, the function fails. +/// - `out_len` will receive the final length of the string. +/// - On success, the function returns 0. On failure, it returns 1. +/// +/// **Important**: Keep in mind that this function doesn't write any null terminator on the output +/// string. +/// +int parity_rpc(void* parity, const char* rpc, size_t len, char* out_str, size_t* out_len); + #ifdef __cplusplus } #endif diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs index b08d6487d1..fe631ce8a8 100644 --- a/parity-clib/src/lib.rs +++ b/parity-clib/src/lib.rs @@ -23,6 +23,7 @@ use std::os::raw::{c_char, c_void, c_int}; use std::panic; use std::ptr; use std::slice; +use std::str; #[repr(C)] pub struct ParityParams { @@ -131,3 +132,33 @@ pub extern fn parity_destroy(client: *mut c_void) { }); } } + +#[no_mangle] +pub extern fn parity_rpc(client: *mut c_void, query: *const char, len: usize, out_str: *mut c_char, out_len: *mut usize) -> c_int { + unsafe { + panic::catch_unwind(|| { + let client: &mut parity::RunningClient = &mut *(client as *mut parity::RunningClient); + + let query_str = { + let string = slice::from_raw_parts(query as *const u8, len); + match str::from_utf8(string) { + Ok(a) => a, + Err(_) => return 1, + } + }; + + if let Some(output) = client.rpc_query_sync(query_str) { + let q_out_len = output.as_bytes().len(); + if *out_len < q_out_len { + return 1; + } + + ptr::copy_nonoverlapping(output.as_bytes().as_ptr(), out_str as *mut u8, q_out_len); + *out_len = q_out_len; + 0 + } else { + 1 + } + }).unwrap_or(1) + } +} diff --git a/parity/rpc.rs b/parity/rpc.rs index 66a2715d42..21bc9a4096 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -355,7 +355,7 @@ fn with_domain(items: Option>, domain: &str, ui_address: &Option(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler> +pub fn setup_apis(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler> where D: rpc_apis::Dependencies { let mut handler = MetaIoHandler::with_middleware( diff --git a/parity/run.rs b/parity/run.rs index 73113055bb..fd16085c46 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -41,7 +41,7 @@ use miner::external::ExternalMiner; use node_filter::NodeFilter; use node_health; use parity_reactor::EventLoop; -use parity_rpc::{NetworkSettings, informant, is_major_importing}; +use parity_rpc::{Origin, Metadata, NetworkSettings, informant, is_major_importing}; use updater::{UpdatePolicy, Updater}; use parity_version::version; use ethcore_private_tx::{ProviderConfig, EncryptorConfig, SecretStoreEncryptor}; @@ -56,6 +56,7 @@ use cache::CacheConfig; use user_defaults::UserDefaults; use dapps; use ipfs; +use jsonrpc_core; use modules; use rpc; use rpc_apis; @@ -369,6 +370,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: }; // start rpc servers + let rpc_direct = rpc::setup_apis(rpc_apis::ApiSet::All, &dependencies); let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies, dapps_middleware)?; @@ -878,6 +882,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: Ok(RunningClient { inner: RunningClientInner::Full { + rpc: rpc_direct, informant, client, keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), @@ -890,16 +895,18 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: /// Should be destroyed by calling `shutdown()`, otherwise execution will continue in the /// background. pub struct RunningClient { - inner: RunningClientInner + inner: RunningClientInner, } enum RunningClientInner { Light { + rpc: jsonrpc_core::MetaIoHandler>, informant: Arc>, client: Arc, keep_alive: Box, }, Full { + rpc: jsonrpc_core::MetaIoHandler>, informant: Arc>, client: Arc, keep_alive: Box, @@ -907,25 +914,45 @@ enum RunningClientInner { } impl RunningClient { + /// Performs a synchronous RPC query. + /// Blocks execution until the result is ready. + pub fn rpc_query_sync(&self, request: &str) -> Option { + let metadata = Metadata { + origin: Origin::CApi, + session: None, + }; + + match self.inner { + RunningClientInner::Light { ref rpc, .. } => { + rpc.handle_request_sync(request, metadata) + }, + RunningClientInner::Full { ref rpc, .. } => { + rpc.handle_request_sync(request, metadata) + }, + } + } + /// Shuts down the client. pub fn shutdown(self) { match self.inner { - RunningClientInner::Light { informant, client, keep_alive } => { + RunningClientInner::Light { rpc, informant, client, keep_alive } => { // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); + drop(rpc); drop(keep_alive); informant.shutdown(); drop(informant); drop(client); wait_for_drop(weak_client); }, - RunningClientInner::Full { informant, client, keep_alive } => { + RunningClientInner::Full { rpc, informant, client, keep_alive } => { info!("Finishing work, please wait..."); // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); // drop this stuff as soon as exit detected. + drop(rpc); drop(keep_alive); // to make sure timer does not spawn requests while shutdown is in progress informant.shutdown(); diff --git a/rpc/src/v1/types/provenance.rs b/rpc/src/v1/types/provenance.rs index b52f0cb774..6bcd43a21f 100644 --- a/rpc/src/v1/types/provenance.rs +++ b/rpc/src/v1/types/provenance.rs @@ -49,6 +49,9 @@ pub enum Origin { /// Session id session: H256 }, + /// From the C API + #[serde(rename="c-api")] + CApi, /// Unknown #[serde(rename="unknown")] Unknown, @@ -68,6 +71,7 @@ impl fmt::Display for Origin { Origin::Ipc(ref session) => write!(f, "IPC (session: {})", session), Origin::Ws { ref session, ref dapp } => write!(f, "{} via WebSocket (session: {})", dapp, session), Origin::Signer { ref session, ref dapp } => write!(f, "{} via UI (session: {})", dapp, session), + Origin::CApi => write!(f, "C API"), Origin::Unknown => write!(f, "unknown origin"), } } -- GitLab From db9397890efbc551d8ba70c3887ddcb0f6b0e097 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 23 May 2018 10:27:45 +0100 Subject: [PATCH 178/263] Fix cli signer (#8682) * Update ethereum-types so `{:#x}` applies 0x prefix --- Cargo.lock | 102 +++++++++++++++++++-------------------- rpc/Cargo.toml | 2 +- rpc/src/v1/types/uint.rs | 8 +-- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 646bc90645..c0aae6664f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,7 +248,7 @@ name = "common-types" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", @@ -385,7 +385,7 @@ name = "dir" version = "0.1.0" dependencies = [ "app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.1.0", ] @@ -457,7 +457,7 @@ version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -530,7 +530,7 @@ dependencies = [ "ethcore-miner 1.12.0", "ethcore-stratum 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -591,7 +591,7 @@ version = "0.1.0" name = "ethcore-crypto" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.12.1 (git+https://github.com/paritytech/ring)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -628,7 +628,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethcore-network 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -678,7 +678,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -706,7 +706,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -726,7 +726,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethcore-logger 1.12.0", "ethcore-network 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "igd 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -764,7 +764,7 @@ dependencies = [ "ethcore-logger 1.12.0", "ethcore-miner 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "fetch 0.1.0", @@ -798,7 +798,7 @@ dependencies = [ "ethcore-logger 1.12.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -847,7 +847,7 @@ version = "1.12.0" dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -871,7 +871,7 @@ dependencies = [ "ethcore-network-devp2p 1.12.0", "ethcore-private-tx 1.0.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -895,7 +895,7 @@ dependencies = [ name = "ethcore-transaction" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "evm 0.1.0", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "ethereum-types" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -917,7 +917,7 @@ dependencies = [ "fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -932,7 +932,7 @@ dependencies = [ name = "ethjson" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -947,7 +947,7 @@ dependencies = [ "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "ethcore-crypto 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", @@ -979,7 +979,7 @@ version = "0.2.0" dependencies = [ "dir 0.1.0", "ethcore-crypto 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1019,7 +1019,7 @@ name = "evm" version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1038,7 +1038,7 @@ dependencies = [ "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "evm 0.1.0", "panic_hook 0.1.0", @@ -1178,7 +1178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "hardware-wallet" version = "1.12.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", @@ -1194,7 +1194,7 @@ name = "hashdb" version = "0.1.1" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1342,7 +1342,7 @@ version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", @@ -1456,7 +1456,7 @@ dependencies = [ name = "keccak-hash" version = "0.1.2" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1492,7 +1492,7 @@ name = "kvdb-rocksdb" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1644,7 +1644,7 @@ name = "memorydb" version = "0.1.1" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", @@ -1807,7 +1807,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethcore-network 1.12.0", "ethcore-network-devp2p 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1866,7 +1866,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1978,7 +1978,7 @@ dependencies = [ "ethcore-service 0.1.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "fake-fetch 0.0.1", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2044,7 +2044,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-devtools 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2109,7 +2109,7 @@ dependencies = [ "ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "fake-fetch 0.0.1", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2133,7 +2133,7 @@ dependencies = [ "cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2162,7 +2162,7 @@ dependencies = [ name = "parity-machine" version = "0.1.0" dependencies = [ - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2192,7 +2192,7 @@ dependencies = [ "ethcore-private-tx 1.0.0", "ethcore-sync 1.12.0", "ethcore-transaction 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "ethkey 0.3.0", "ethstore 0.2.0", @@ -2331,7 +2331,7 @@ dependencies = [ "ethcore 1.12.0", "ethcore-bytes 0.1.0", "ethcore-sync 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2376,7 +2376,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-network 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -2438,7 +2438,7 @@ dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2494,7 +2494,7 @@ name = "plain_hasher" version = "0.1.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2593,7 +2593,7 @@ version = "0.1.0" dependencies = [ "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2766,7 +2766,7 @@ version = "0.2.1" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2974,7 +2974,7 @@ name = "shell32-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3444,7 +3444,7 @@ name = "transaction-pool" version = "1.12.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", @@ -3471,7 +3471,7 @@ name = "trie-standardmap" version = "0.1.0" dependencies = [ "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "rlp 0.2.1", ] @@ -3481,7 +3481,7 @@ name = "triehash" version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "rlp 0.2.1", "trie-standardmap 0.1.0", @@ -3489,7 +3489,7 @@ dependencies = [ [[package]] name = "uint" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3596,7 +3596,7 @@ name = "util-error" version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3628,7 +3628,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "ethcore-bytes 0.1.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3647,7 +3647,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-logger 1.12.0", - "ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3847,7 +3847,7 @@ dependencies = [ "checksum ethabi-contract 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "210c9e21d164c15b6ef64fe601e0e12a3c84a031d5ef558e38463e53edbd22ed" "checksum ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2bc7099baa147187aedaecd9fe04a6c0541c82bc43ff317cb6900fe2b983d74" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" -"checksum ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3ae691a36ce5d25b433e63128ce5579f4a18457b6a9c849832b2c9e0fec92a" +"checksum ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c48729b8aea8aedb12cf4cb2e5cef439fdfe2dda4a89e47eeebd15778ef53b6" "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" @@ -4045,7 +4045,7 @@ dependencies = [ "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "715254c8f0811be1a79ad3ea5e6fa3c8eddec2b03d7f5ba78cf093e56d79c24f" "checksum trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)" = "" -"checksum uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6477b2716357758c176c36719023e1f9726974d762150e4fc0a9c8c75488c343" +"checksum uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38051a96565903d81c9a9210ce11076b2218f3b352926baa1f5f6abbdfce8273" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 731544a55f..8fdb9ed574 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -47,7 +47,7 @@ ethcore-miner = { path = "../miner" } ethcore-private-tx = { path = "../ethcore/private-tx" } ethcore-sync = { path = "../ethcore/sync" } ethcore-transaction = { path = "../ethcore/transaction" } -ethereum-types = "0.3" +ethereum-types = "0.3.2" ethjson = { path = "../json" } ethkey = { path = "../ethkey" } diff --git a/rpc/src/v1/types/uint.rs b/rpc/src/v1/types/uint.rs index e887322dba..4e2a189a63 100644 --- a/rpc/src/v1/types/uint.rs +++ b/rpc/src/v1/types/uint.rs @@ -55,7 +55,7 @@ macro_rules! impl_uint { impl fmt::LowerHex for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:#x}", self.0) + fmt::LowerHex::fmt(&self.0, f) } } @@ -102,19 +102,19 @@ impl_uint!(U64, u64, 1); impl serde::Serialize for U128 { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(&format!("0x{:x}", self.0)) + serializer.serialize_str(&format!("{:#x}", self)) } } impl serde::Serialize for U256 { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(&format!("0x{:x}", self.0)) + serializer.serialize_str(&format!("{:#x}", self)) } } impl serde::Serialize for U64 { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { - serializer.serialize_str(&format!("0x{:x}", self.0)) + serializer.serialize_str(&format!("{:#x}", self)) } } -- GitLab From 6563576ae9586288516cb614ae0787cb27a8f9f2 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 24 May 2018 04:39:52 +0200 Subject: [PATCH 179/263] Use impl Future in the light client RPC helpers (#8628) --- rpc/src/v1/helpers/light_fetch.rs | 69 +++++++++++++++---------------- rpc/src/v1/impls/eth_pubsub.rs | 2 +- rpc/src/v1/impls/light/eth.rs | 2 +- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index d8a157da21..413670d521 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -25,7 +25,7 @@ use ethcore::ids::BlockId; use ethcore::filter::Filter as EthcoreFilter; use ethcore::receipt::Receipt; -use jsonrpc_core::{BoxFuture, Result}; +use jsonrpc_core::{Result, Error}; use jsonrpc_core::futures::{future, Future}; use jsonrpc_core::futures::future::Either; use jsonrpc_macros::Trailing; @@ -139,58 +139,57 @@ impl LightFetch { } /// Get a block header from the on demand service or client, or error. - pub fn header(&self, id: BlockId) -> BoxFuture { + pub fn header(&self, id: BlockId) -> impl Future + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; - - self.send_requests(reqs, |res| + Either::B(self.send_requests(reqs, |res| extract_header(&res, header_ref) .expect("these responses correspond to requests that header_ref belongs to \ therefore it will not fail; qed") - ) + )) } /// Helper for getting contract code at a given block. - pub fn code(&self, address: Address, id: BlockId) -> BoxFuture> { + pub fn code(&self, address: Address, id: BlockId) -> impl Future, Error = Error> + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::Account { header: header_ref.clone(), address: address }.into()); let account_idx = reqs.len() - 1; reqs.push(request::Code { header: header_ref, code_hash: Field::back_ref(account_idx, 0) }.into()); - self.send_requests(reqs, |mut res| match res.pop() { + Either::B(self.send_requests(reqs, |mut res| match res.pop() { Some(OnDemandResponse::Code(code)) => code, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Helper for getting account info at a given block. /// `None` indicates the account doesn't exist at the given block. - pub fn account(&self, address: Address, id: BlockId) -> BoxFuture> { + pub fn account(&self, address: Address, id: BlockId) -> impl Future, Error = Error> + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::Account { header: header_ref, address: address }.into()); - self.send_requests(reqs, |mut res|match res.pop() { + Either::B(self.send_requests(reqs, |mut res|match res.pop() { Some(OnDemandResponse::Account(acc)) => acc, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Helper for getting proved execution. - pub fn proved_execution(&self, req: CallRequest, num: Trailing) -> BoxFuture { + pub fn proved_execution(&self, req: CallRequest, num: Trailing) -> impl Future + Send { const DEFAULT_GAS_PRICE: u64 = 21_000; // starting gas when gas not provided. const START_GAS: u64 = 50_000; @@ -280,39 +279,39 @@ impl LightFetch { } /// Get a block itself. Fails on unknown block ID. - pub fn block(&self, id: BlockId) -> BoxFuture { + pub fn block(&self, id: BlockId) -> impl Future + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::Body(header_ref).into()); - self.send_requests(reqs, |mut res| match res.pop() { + Either::B(self.send_requests(reqs, |mut res| match res.pop() { Some(OnDemandResponse::Body(b)) => b, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Get the block receipts. Fails on unknown block ID. - pub fn receipts(&self, id: BlockId) -> BoxFuture> { + pub fn receipts(&self, id: BlockId) -> impl Future, Error = Error> + Send { let mut reqs = Vec::new(); let header_ref = match self.make_header_requests(id, &mut reqs) { Ok(r) => r, - Err(e) => return Box::new(future::err(e)), + Err(e) => return Either::A(future::err(e)), }; reqs.push(request::BlockReceipts(header_ref).into()); - self.send_requests(reqs, |mut res| match res.pop() { + Either::B(self.send_requests(reqs, |mut res| match res.pop() { Some(OnDemandResponse::Receipts(b)) => b, _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) + })) } /// Get transaction logs - pub fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { + pub fn logs(&self, filter: EthcoreFilter) -> impl Future, Error = Error> + Send { use std::collections::BTreeMap; use jsonrpc_core::futures::stream::{self, Stream}; @@ -326,9 +325,9 @@ impl LightFetch { }; match (block_number(filter.to_block), block_number(filter.from_block)) { - (Some(to), Some(from)) if to < from => return Box::new(future::ok(Vec::new())), + (Some(to), Some(from)) if to < from => return Either::A(future::ok(Vec::new())), (Some(_), Some(_)) => {}, - _ => return Box::new(future::err(errors::unknown_block())), + _ => return Either::A(future::err(errors::unknown_block())), } let maybe_future = self.sync.with_context(move |ctx| { @@ -362,15 +361,15 @@ impl LightFetch { }); match maybe_future { - Some(fut) => Box::new(fut), - None => Box::new(future::err(errors::network_disabled())), + Some(fut) => Either::B(Either::A(fut)), + None => Either::B(Either::B(future::err(errors::network_disabled()))), } } // Get a transaction by hash. also returns the index in the block. // Only returns transactions in the canonical chain. pub fn transaction_by_hash(&self, tx_hash: H256, eip86_transition: u64) - -> BoxFuture> + -> impl Future, Error = Error> + Send { let params = (self.sync.clone(), self.on_demand.clone()); let fetcher: Self = self.clone(); @@ -426,7 +425,7 @@ impl LightFetch { })) } - fn send_requests(&self, reqs: Vec, parse_response: F) -> BoxFuture where + fn send_requests(&self, reqs: Vec, parse_response: F) -> impl Future + Send where F: FnOnce(Vec) -> T + Send + 'static, T: Send + 'static, { @@ -439,7 +438,7 @@ impl LightFetch { match maybe_future { Some(recv) => recv, - None => Box::new(future::err(errors::network_disabled())) + None => Box::new(future::err(errors::network_disabled())) as Box + Send> } } } @@ -457,7 +456,7 @@ struct ExecuteParams { // has a peer execute the transaction with given params. If `gas_known` is false, // this will double the gas on each `OutOfGas` error. -fn execute_tx(gas_known: bool, params: ExecuteParams) -> BoxFuture { +fn execute_tx(gas_known: bool, params: ExecuteParams) -> impl Future + Send { if !gas_known { Box::new(future::loop_fn(params, |mut params| { execute_tx(true, params.clone()).and_then(move |res| { @@ -480,7 +479,7 @@ fn execute_tx(gas_known: bool, params: ExecuteParams) -> BoxFuture Ok(future::Loop::Break(failed)), } }) - })) + })) as Box + Send> } else { trace!(target: "light_fetch", "Placing execution request for {} gas in on_demand", params.tx.gas); @@ -501,8 +500,8 @@ fn execute_tx(gas_known: bool, params: ExecuteParams) -> BoxFuture Box::new(fut), - None => Box::new(future::err(errors::network_disabled())), + Some(fut) => Box::new(fut) as Box + Send>, + None => Box::new(future::err(errors::network_disabled())) as Box + Send>, } } } diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index 3045959446..c0789910c3 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -199,7 +199,7 @@ impl LightClient for LightFetch { } fn logs(&self, filter: EthFilter) -> BoxFuture> { - LightFetch::logs(self, filter) + Box::new(LightFetch::logs(self, filter)) as BoxFuture<_> } } diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 35f7792b52..10ad024f24 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -538,7 +538,7 @@ impl Filterable for EthClient { } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { - self.fetcher().logs(filter) + Box::new(self.fetcher().logs(filter)) as BoxFuture<_> } fn pending_logs(&self, _block_number: u64, _filter: &EthcoreFilter) -> Vec { -- GitLab From dc8da3743db3855ed86a52a2a36a2826d15917b7 Mon Sep 17 00:00:00 2001 From: Thibaut S <33178835+Tbaut@users.noreply.github.com> Date: Thu, 24 May 2018 10:53:37 +0200 Subject: [PATCH 180/263] Update mod.rs (#8695) - Update interfaces affected by unsafe-expose - replace `{{ }}` as this throws an error in Jekyll (wiki) --- parity/cli/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 34e3bf03a1..a064baeac5 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -315,7 +315,7 @@ usage! { ["Convenience options"] FLAG flag_unsafe_expose: (bool) = false, or |c: &Config| c.misc.as_ref()?.unsafe_expose, "--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!", + "All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --[ws,jsonrpc,ui,ipfs-api,secretstore,stratum,dapps,secretstore-http]-interface=all --*-hosts=all This option is UNSAFE and should be used with great care!", ARG arg_config: (String) = "$BASE/config.toml", or |_| None, "-c, --config=[CONFIG]", -- GitLab From e346f3058ef806ae397571beef5901f8723116d9 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 24 May 2018 13:06:48 +0200 Subject: [PATCH 181/263] remove empty file (#8705) --- ethstore/tests/cli.rs | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 ethstore/tests/cli.rs diff --git a/ethstore/tests/cli.rs b/ethstore/tests/cli.rs deleted file mode 100644 index f90ec463dc..0000000000 --- a/ethstore/tests/cli.rs +++ /dev/null @@ -1,16 +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 . - -- GitLab From 6c24d9897ae63d2fb8f9d132b95fda2871e27ff2 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 24 May 2018 17:29:28 +0200 Subject: [PATCH 182/263] Set the request index to that of the current request (#8683) * Set the request index to that of the current request When setting up the chain of (two) requests to look up a block by hash, the second need to refer to the first. This fixes an issue where the back ref was set to the subsequent request, not the current one. When the requests are executed we loop through them in order and ensure the requests that should produce headers all match up. We do this by index so they better be right. In other words: off by one. --- rpc/src/v1/helpers/light_fetch.rs | 3 +-- rpc/src/v1/tests/eth.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index 413670d521..1baf9a7647 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -129,9 +129,8 @@ impl LightFetch { } } BlockId::Hash(h) => { - reqs.push(request::HeaderByHash(h.into()).into()); - let idx = reqs.len(); + reqs.push(request::HeaderByHash(h.into()).into()); Ok(HeaderRef::Unresolved(idx, h.into())) } _ => Err(errors::unknown_block()) // latest, earliest, and pending will have all already returned. diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 4b83710bc0..26117471ce 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -204,6 +204,18 @@ fn eth_get_block() { assert_eq!(tester.handler.handle_request_sync(req_block).unwrap(), res_block); } +#[test] +fn eth_get_block_by_hash() { + let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test"); + let tester = EthTester::from_chain(&chain); + + // We're looking for block number 4 from "RPC_API_Test_Frontier" + let req_block = r#"{"method":"eth_getBlockByHash","params":["0x9c9bdab4cb53fd834e790b13545597f026494d42112e84c0aca9dd6bcc545295",false],"id":1,"jsonrpc":"2.0"}"#; + + let res_block = r#"{"jsonrpc":"2.0","result":{"author":"0x8888f1f195afa192cfee860698584c030f4c9db1","difficulty":"0x200c0","extraData":"0x","gasLimit":"0x1dd8112","gasUsed":"0x5458","hash":"0x9c9bdab4cb53fd834e790b13545597f026494d42112e84c0aca9dd6bcc545295","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x8888f1f195afa192cfee860698584c030f4c9db1","mixHash":"0xaddea8d25bb0f955fa6c1d58d74ab8a3fec99d37943e2a261e3b12f97d6bff7c","nonce":"0x8e18bed16d5a88da","number":"0x4","parentHash":"0x2cbf4fc930c5b4c87598f43fc8eb26dccdab2f58a7d0d3ca92ec60a5444a330e","receiptsRoot":"0x7ed8026cf72ed0e98e6fd53ab406e51ffd34397d9da0052494ff41376fda7b5f","sealFields":["0xa0addea8d25bb0f955fa6c1d58d74ab8a3fec99d37943e2a261e3b12f97d6bff7c","0x888e18bed16d5a88da"],"sha3Uncles":"0x75cc08a7cb2cf8081446659fecb2633fb6b922d26edd59bd2272b1f5cae1c78b","size":"0x661","stateRoot":"0x68805721294e365020aca15ed56c360d9dc2cf03cbeff84c9b84b8aed023bfb5","timestamp":"0x59d662ff","totalDifficulty":"0xa0180","transactions":["0xb094b9dc356dbb8b256402c6d5709288066ad6a372c90c9c516f14277545fd58"],"transactionsRoot":"0x97a593d8d7e15b57f5c6bb25bc6c325463ef99f874bc08a78656c3ab5cb23262","uncles":["0xa1e9c9ecd2af999e0723aae1dc55dd9789ca618e0b34badcc8ac7d9a3dad3af2","0x81d429b6b6635214a2b0f976cc4b2ed49808140d6bede50129bc10d22ac9249e"]},"id":1}"#; + assert_eq!(tester.handler.handle_request_sync(req_block).unwrap(), res_block); +} + // a frontier-like test with an expanded gas limit and balance on known account. const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{ "name": "Frontier (Test)", -- GitLab From 80528c53445ed958ad6164a49ac1cf28e8f52c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 24 May 2018 19:43:18 +0200 Subject: [PATCH 183/263] parity: trim whitespace when parsing duration strings (#8692) --- parity/helpers.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/parity/helpers.rs b/parity/helpers.rs index 80ade50983..a5ec3c99d4 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -47,11 +47,11 @@ fn to_seconds(s: &str) -> Result { "1minute" | "1 minute" | "minute" => Ok(60), "hourly" | "1hour" | "1 hour" | "hour" => Ok(60 * 60), "daily" | "1day" | "1 day" | "day" => Ok(24 * 60 * 60), - x if x.ends_with("seconds") => x[0..x.len() - 7].parse().map_err(bad), - x if x.ends_with("minutes") => x[0..x.len() - 7].parse::().map_err(bad).map(|x| x * 60), - x if x.ends_with("hours") => x[0..x.len() - 5].parse::().map_err(bad).map(|x| x * 60 * 60), - x if x.ends_with("days") => x[0..x.len() - 4].parse::().map_err(bad).map(|x| x * 24 * 60 * 60), - x => x.parse().map_err(bad), + x if x.ends_with("seconds") => x[0..x.len() - 7].trim().parse().map_err(bad), + x if x.ends_with("minutes") => x[0..x.len() - 7].trim().parse::().map_err(bad).map(|x| x * 60), + x if x.ends_with("hours") => x[0..x.len() - 5].trim().parse::().map_err(bad).map(|x| x * 60 * 60), + x if x.ends_with("days") => x[0..x.len() - 4].trim().parse::().map_err(bad).map(|x| x * 24 * 60 * 60), + x => x.trim().parse().map_err(bad), } } @@ -350,6 +350,8 @@ mod tests { assert_eq!(to_duration("1day").unwrap(), Duration::from_secs(1 * 24 * 60 * 60)); assert_eq!(to_duration("2days").unwrap(), Duration::from_secs(2 * 24 *60 * 60)); assert_eq!(to_duration("15days").unwrap(), Duration::from_secs(15 * 24 * 60 * 60)); + assert_eq!(to_duration("15 days").unwrap(), Duration::from_secs(15 * 24 * 60 * 60)); + assert_eq!(to_duration("2 seconds").unwrap(), Duration::from_secs(2)); } #[test] -- GitLab From 7d7d4822a5087b24b49f2a1ddb111f2daa51a017 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 25 May 2018 13:19:32 +0200 Subject: [PATCH 184/263] Implement recursive Debug for Nodes in patrica_trie::TrieDB (#8697) fixes #8184 --- util/patricia_trie/src/triedb.rs | 228 ++++++++++++++++++++++--------- 1 file changed, 164 insertions(+), 64 deletions(-) diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index aed683117d..259525e2ee 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -78,64 +78,9 @@ impl<'db> TrieDB<'db> { /// Get the data of the root node. fn root_data(&self) -> super::Result { - self.db.get(self.root).ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) - } - - /// Indentation helper for `format_all`. - fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result { - for _ in 0..size { - write!(f, " ")?; - } - Ok(()) - } - - /// Recursion helper for implementation of formatting trait. - fn fmt_all(&self, node: Node, f: &mut fmt::Formatter, deepness: usize) -> fmt::Result { - match node { - Node::Leaf(slice, value) => writeln!(f, "'{:?}: {:?}.", slice, value.pretty())?, - Node::Extension(ref slice, ref item) => { - write!(f, "'{:?} ", slice)?; - if let Ok(node) = self.get_raw_or_lookup(&*item) { - match Node::decoded(&node) { - Ok(n) => self.fmt_all(n, f, deepness)?, - Err(err) => writeln!(f, "ERROR decoding node extension Rlp: {}", err)?, - } - } - }, - Node::Branch(ref nodes, ref value) => { - writeln!(f, "")?; - if let Some(ref v) = *value { - self.fmt_indent(f, deepness + 1)?; - writeln!(f, "=: {:?}", v.pretty())? - } - for i in 0..16 { - let node = self.get_raw_or_lookup(&*nodes[i]); - match node.as_ref() { - Ok(n) => { - match Node::decoded(&*n) { - Ok(Node::Empty) => {}, - Ok(n) => { - self.fmt_indent(f, deepness + 1)?; - write!(f, "'{:x} ", i)?; - self.fmt_all(n, f, deepness + 1)?; - } - Err(e) => { - write!(f, "ERROR decoding node branch Rlp: {}", e)? - } - } - } - Err(e) => { - write!(f, "ERROR: {}", e)?; - } - } - } - }, - // empty - Node::Empty => { - writeln!(f, "")?; - } - }; - Ok(()) + self.db + .get(self.root) + .ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) } /// Given some node-describing data `node`, return the actual node RLP. @@ -174,15 +119,58 @@ impl<'db> Trie for TrieDB<'db> { } } +// This is for pretty debug output only +struct TrieAwareDebugNode<'db, 'a> { + trie: &'db TrieDB<'db>, + key: &'a[u8] +} + +impl<'db, 'a> fmt::Debug for TrieAwareDebugNode<'db, 'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(node) = self.trie.get_raw_or_lookup(self.key) { + match Node::decoded(&node) { + Ok(Node::Leaf(slice, value)) => f.debug_struct("Node::Leaf") + .field("slice", &slice) + .field("value", &value) + .finish(), + Ok(Node::Extension(ref slice, ref item)) => f.debug_struct("Node::Extension") + .field("slice", &slice) + .field("item", &TrieAwareDebugNode{trie: self.trie, key: item}) + .finish(), + Ok(Node::Branch(ref nodes, ref value)) => { + let nodes: Vec = nodes.into_iter().map(|n| TrieAwareDebugNode{trie: self.trie, key: n} ).collect(); + f.debug_struct("Node::Branch") + .field("nodes", &nodes) + .field("value", &value) + .finish() + }, + Ok(Node::Empty) => f.debug_struct("Node::Empty").finish(), + + Err(e) => f.debug_struct("BROKEN_NODE") + .field("key", &self.key) + .field("error", &format!("ERROR decoding node branch Rlp: {}", e)) + .finish() + } + } else { + f.debug_struct("BROKEN_NODE") + .field("key", &self.key) + .field("error", &"Not found") + .finish() + } + } +} + + impl<'db> fmt::Debug for TrieDB<'db> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "c={:?} [", self.hash_count)?; let root_rlp = self.db.get(self.root).expect("Trie root not found!"); - match Node::decoded(&root_rlp) { - Ok(node) => self.fmt_all(node, f, 0)?, - Err(e) => writeln!(f, "ERROR decoding node rlp: {}", e)?, - } - writeln!(f, "]") + f.debug_struct("TrieDB") + .field("hash_count", &self.hash_count) + .field("root", &TrieAwareDebugNode { + trie: self, + key: &root_rlp + }) + .finish() } } @@ -494,6 +482,118 @@ fn get_len() { assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None)); } + +#[test] +fn debug_output_supports_pretty_print() { + use memorydb::*; + use super::TrieMut; + use super::triedbmut::*; + + let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; + + let mut memdb = MemoryDB::new(); + let mut root = H256::new(); + let root = { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + for x in &d { + t.insert(x, x).unwrap(); + } + t.root().clone() + }; + let t = TrieDB::new(&memdb, &root).unwrap(); + + assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }"); + assert_eq!(format!("{:#?}", t), +"TrieDB { + hash_count: 0, + root: Node::Extension { + slice: 4, + item: Node::Branch { + nodes: [ + Node::Empty, + Node::Branch { + nodes: [ + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Branch { + nodes: [ + Node::Empty, + Node::Leaf { + slice: , + value: [ + 65, + 65 + ] + }, + Node::Leaf { + slice: , + value: [ + 65, + 66 + ] + }, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty + ], + value: None + }, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty + ], + value: Some( + [ + 65 + ] + ) + }, + Node::Leaf { + slice: , + value: [ + 66 + ] + }, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty, + Node::Empty + ], + value: None + } + } +}"); +} + // Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking //#[test] //fn test_lookup_with_corrupt_data_returns_decoder_error() { -- GitLab From ed8425b8b907c92ac46a1634e3a4cbda395f934e Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 28 May 2018 16:32:29 +0200 Subject: [PATCH 185/263] Remove unused imports (#8722) --- util/network/src/lib.rs | 2 +- util/patricia_trie/src/triedb.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index f3012e4c37..207a05075d 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -42,7 +42,7 @@ use std::sync::Arc; use std::time::Duration; use ipnetwork::{IpNetwork, IpNetworkError}; use ethkey::Secret; -use ethereum_types::{H256, H512}; +use ethereum_types::H512; use rlp::{Decodable, DecoderError, Rlp}; /// Protocol handler level packet id diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index 259525e2ee..ed2c19e069 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -21,7 +21,7 @@ use super::node::{Node, OwnedNode}; use super::lookup::Lookup; use super::{Trie, TrieItem, TrieError, TrieIterator, Query}; use ethereum_types::H256; -use bytes::{ToPretty, Bytes}; +use bytes::Bytes; /// A `Trie` implementation using a generic `HashDB` backing database. /// @@ -501,7 +501,7 @@ fn debug_output_supports_pretty_print() { t.root().clone() }; let t = TrieDB::new(&memdb, &root).unwrap(); - + assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }"); assert_eq!(format!("{:#?}", t), "TrieDB { -- GitLab From 540044739566a4eaaba82f723eac450388777eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 28 May 2018 16:39:26 +0200 Subject: [PATCH 186/263] Update dev chain (#8717) * Make dev chain more foundation-like and enable wasm. * Fix compilation warnings. --- ethcore/res/instant_seal.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index acd1b49ed0..36832e698e 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -10,10 +10,20 @@ "minGasLimit": "0x1388", "networkID" : "0x11", "registrar" : "0x0000000000000000000000000000000000001337", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip155Transition": "0x0", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff", + "maxCodeSize": 24576, + "maxCodeSizeTransition": "0x0", "eip140Transition": "0x0", "eip211Transition": "0x0", "eip214Transition": "0x0", - "eip658Transition": "0x0" + "eip658Transition": "0x0", + "wasmActivationTransition": "0x0" }, "genesis": { "seal": { -- GitLab From 3b083d545d4f8e39ae6b96eef28f5421775990c1 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 May 2018 16:41:08 +0200 Subject: [PATCH 187/263] Add a test for decoding corrupt data (#8713) --- util/patricia_trie/src/triedb.rs | 50 +++++++++++++++----------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index ed2c19e069..c18e4fce96 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -594,29 +594,27 @@ fn debug_output_supports_pretty_print() { }"); } -// Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking -//#[test] -//fn test_lookup_with_corrupt_data_returns_decoder_error() { -// use memorydb::*; -// use super::TrieMut; -// use super::triedbmut::*; -// use rlp; -// use ethereum_types::H512; -// -// let mut memdb = MemoryDB::new(); -// let mut root = H256::new(); -// { -// let mut t = TrieDBMut::new(&mut memdb, &mut root); -// t.insert(b"A", b"ABC").unwrap(); -// t.insert(b"B", b"ABCBA").unwrap(); -// } -// -// let t = TrieDB::new(&memdb, &root).unwrap(); -// -// // query for an invalid data type to trigger an error -// let q = rlp::decode::; -// let lookup = Lookup{ db: t.db, query: q, hash: root }; -// let query_result = lookup.look_up(NibbleSlice::new(b"A")); -// let expected = Box::new(TrieError::DecoderError(::rlp::DecoderError::RlpIsTooShort)); -// assert_eq!(query_result.unwrap_err(), expected); -//} +#[test] +fn test_lookup_with_corrupt_data_returns_decoder_error() { + use memorydb::*; + use super::TrieMut; + use super::triedbmut::*; + use rlp; + use ethereum_types::H512; + + let mut memdb = MemoryDB::new(); + let mut root = H256::new(); + { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + t.insert(b"A", b"ABC").unwrap(); + t.insert(b"B", b"ABCBA").unwrap(); + } + + let t = TrieDB::new(&memdb, &root).unwrap(); + + // query for an invalid data type to trigger an error + let q = rlp::decode::; + let lookup = Lookup{ db: t.db, query: q, hash: root }; + let query_result = lookup.look_up(NibbleSlice::new(b"A")); + assert_eq!(query_result.unwrap().unwrap().unwrap_err(), rlp::DecoderError::RlpIsTooShort); +} -- GitLab From ec9c6e9783377ba563bdc720708c2a84dc6d14a7 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 28 May 2018 17:10:29 +0200 Subject: [PATCH 188/263] Fix compilation error on nightly rust (#8707) On nightly rust passing `public_url` works but that breaks on stable. This works for both. --- util/network-devp2p/src/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index eb2e9685d4..1b46ca1ae3 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -32,7 +32,7 @@ impl IoHandler for HostHandler { if let NetworkIoMessage::NetworkStarted(ref public_url) = *message { let mut url = self.public_url.write(); if url.as_ref().map_or(true, |uref| uref != public_url) { - info!(target: "network", "Public node URL: {}", Colour::White.bold().paint(public_url.as_ref())); + info!(target: "network", "Public node URL: {}", Colour::White.bold().paint(AsRef::::as_ref(public_url))); } *url = Some(public_url.to_owned()); } -- GitLab From 68d16b723a48ba8d3039b170d109fc3f2ca85b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 29 May 2018 09:16:08 +0200 Subject: [PATCH 189/263] network-devp2p: handle UselessPeer disconnect (#8686) --- util/network-devp2p/src/host.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index fbbeb89ff8..2f577821a7 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -686,14 +686,17 @@ impl Host { Err(e) => { let s = session.lock(); trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); - if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() { - if let Some(id) = s.id() { - if !self.reserved_nodes.read().contains(id) { - let mut nodes = self.nodes.write(); - nodes.note_failure(&id); - nodes.mark_as_useless(id); + match *e.kind() { + ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) | ErrorKind::Disconnect(DisconnectReason::UselessPeer) => { + if let Some(id) = s.id() { + if !self.reserved_nodes.read().contains(id) { + let mut nodes = self.nodes.write(); + nodes.note_failure(&id); + nodes.mark_as_useless(id); + } } - } + }, + _ => {}, } kill = true; break; -- GitLab From 7fcb082cad648ddec96743b8696d59c8b487ad7c Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Tue, 29 May 2018 12:23:15 +0200 Subject: [PATCH 190/263] Shutdown the Snapshot Service early (#8658) * Shutdown the Snapshot Service when shutting down the runner * Rename `service` to `client_service` * Fix tests --- ethcore/service/src/service.rs | 7 ++++++- ethcore/src/snapshot/service.rs | 4 ++++ ethcore/src/snapshot/traits.rs | 3 +++ ethcore/sync/src/tests/snapshot.rs | 4 ++++ parity/run.rs | 9 +++++++-- rpc/src/v1/tests/helpers/snapshot_service.rs | 1 + 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 5f46799796..f703329d61 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -29,7 +29,7 @@ use sync::PrivateTxHandler; use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage}; use ethcore::miner::Miner; use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams}; -use ethcore::snapshot::{RestorationStatus}; +use ethcore::snapshot::{SnapshotService as _SnapshotService, RestorationStatus}; use ethcore::spec::Spec; use ethcore::account_provider::AccountProvider; @@ -168,6 +168,11 @@ impl ClientService { /// Get a handle to the database. pub fn db(&self) -> Arc { self.database.clone() } + + /// Shutdown the Client Service + pub fn shutdown(&self) { + self.snapshot.shutdown(); + } } /// IO interface for the Client handler diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 17c362e044..942015d0f1 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -743,6 +743,10 @@ impl SnapshotService for Service { trace!("Error sending snapshot service message: {:?}", e); } } + + fn shutdown(&self) { + self.abort_restore(); + } } impl Drop for Service { diff --git a/ethcore/src/snapshot/traits.rs b/ethcore/src/snapshot/traits.rs index 2b6ee9df9f..d951f4c534 100644 --- a/ethcore/src/snapshot/traits.rs +++ b/ethcore/src/snapshot/traits.rs @@ -54,4 +54,7 @@ pub trait SnapshotService : Sync + Send { /// Feed a raw block chunk to the service to be processed asynchronously. /// no-op if currently restoring. fn restore_block_chunk(&self, hash: H256, chunk: Bytes); + + /// Shutdown the Snapshot Service by aborting any ongoing restore + fn shutdown(&self); } diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index 864f3d4dc6..ffb71d7a73 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -133,6 +133,10 @@ impl SnapshotService for TestSnapshotService { self.block_restoration_chunks.lock().insert(hash, chunk); } } + + fn shutdown(&self) { + self.abort_restore(); + } } #[test] diff --git a/parity/run.rs b/parity/run.rs index fd16085c46..31f8779c0f 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -885,7 +885,8 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: rpc: rpc_direct, informant, client, - keep_alive: Box::new((watcher, service, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + client_service: Arc::new(service), + keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), } }) } @@ -909,6 +910,7 @@ enum RunningClientInner { rpc: jsonrpc_core::MetaIoHandler>, informant: Arc>, client: Arc, + client_service: Arc, keep_alive: Box, }, } @@ -946,11 +948,14 @@ impl RunningClient { drop(client); wait_for_drop(weak_client); }, - RunningClientInner::Full { rpc, informant, client, keep_alive } => { + RunningClientInner::Full { rpc, informant, client, client_service, keep_alive } => { info!("Finishing work, please wait..."); // Create a weak reference to the client so that we can wait on shutdown // until it is dropped let weak_client = Arc::downgrade(&client); + // Shutdown and drop the ServiceClient + client_service.shutdown(); + drop(client_service); // drop this stuff as soon as exit detected. drop(rpc); drop(keep_alive); diff --git a/rpc/src/v1/tests/helpers/snapshot_service.rs b/rpc/src/v1/tests/helpers/snapshot_service.rs index 099773ab52..91cd14d73f 100644 --- a/rpc/src/v1/tests/helpers/snapshot_service.rs +++ b/rpc/src/v1/tests/helpers/snapshot_service.rs @@ -50,4 +50,5 @@ impl SnapshotService for TestSnapshotService { fn abort_restore(&self) { } fn restore_state_chunk(&self, _hash: H256, _chunk: Bytes) { } fn restore_block_chunk(&self, _hash: H256, _chunk: Bytes) { } + fn shutdown(&self) { } } -- GitLab From 1620eabd9d0dd368ecd350815083ff6adfdd0459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 30 May 2018 11:34:49 +0200 Subject: [PATCH 191/263] Fix local transactions policy. (#8691) --- miner/src/pool/scoring.rs | 33 +++++++++++++++++++++++++++++++++ miner/src/pool/tests/mod.rs | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs index eaf0698332..aedc40e1f2 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -107,6 +107,15 @@ impl txpool::Scoring for NonceAndGasPrice { } } + // Always kick out non-local transactions in favour of local ones. + if new.priority().is_local() && !old.priority().is_local() { + return true; + } + // And never kick out local transactions in favour of external ones. + if !new.priority().is_local() && old.priority.is_local() { + return false; + } + self.choose(old, new) == txpool::scoring::Choice::ReplaceOld } } @@ -119,6 +128,30 @@ mod tests { use pool::tests::tx::{Tx, TxExt}; use txpool::Scoring; + #[test] + fn should_replace_non_local_transaction_with_local_one() { + // given + let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly); + let tx1 = { + let tx = Tx::default().signed().verified(); + txpool::Transaction { + insertion_id: 0, + transaction: Arc::new(tx), + } + }; + let tx2 = { + let mut tx = Tx::default().signed().verified(); + tx.priority = ::pool::Priority::Local; + txpool::Transaction { + insertion_id: 0, + transaction: Arc::new(tx), + } + }; + + assert!(scoring.should_replace(&tx1, &tx2)); + assert!(!scoring.should_replace(&tx2, &tx1)); + } + #[test] fn should_calculate_score_correctly() { // given diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 5d80c2d5bf..85dedaaa45 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -766,4 +766,35 @@ fn should_reject_big_transaction() { verifier::Transaction::Local(PendingTransaction::new(big_tx, transaction::Condition::Timestamp(1000).into())) ]); assert_eq!(res, vec![Err(transaction::Error::TooBig)]); -} \ No newline at end of file +} + +#[test] +fn should_include_local_transaction_to_a_full_pool() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 1, + max_per_sender: 2, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let tx1 = Tx::gas_price(10_000).signed().unverified(); + let tx2 = Tx::gas_price(1).signed().local(); + + let res = txq.import(TestClient::new().with_balance(1_000_000_000), vec![tx1]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + + // when + let res = txq.import(TestClient::new(), vec![tx2]); + assert_eq!(res, vec![Ok(())]); + + // then + assert_eq!(txq.status().status.transaction_count, 1); +} -- GitLab From 93054ef24b590a8d854cd6b2d1de6567667d39da Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Wed, 30 May 2018 16:42:37 +0300 Subject: [PATCH 192/263] Add a deadlock detection thread (#8727) * Add a deadlock detection thread Expose it under a feature flag: `cargo build --features "deadlock_detection"` * Address Nicklas's comments --- Cargo.lock | 36 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + parity/lib.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c0aae6664f..c8e60dce69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1092,6 +1092,11 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fixedbitset" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "flate2" version = "1.0.1" @@ -1939,6 +1944,11 @@ dependencies = [ "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ordermap" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "owning_ref" version = "0.3.3" @@ -2420,10 +2430,13 @@ name = "parking_lot_core" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2454,6 +2467,15 @@ name = "percent-encoding" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "petgraph" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "phf" version = "0.7.21" @@ -3183,6 +3205,16 @@ dependencies = [ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread-id" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.4" @@ -3851,6 +3883,7 @@ dependencies = [ "checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" +"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -3931,6 +3964,7 @@ dependencies = [ "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efa535d5117d3661134dbf1719b6f0ffe06f2375843b13935db186cd094105eb" "checksum ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58d25b6c0e47b20d05226d288ff434940296e7e2f8b877975da32f862152241f" +"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "261c025c67ba416e9fe63aa9b3236520ce3c74cfbe43590c9cdcec4ccc8180e4" "checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "" @@ -3943,6 +3977,7 @@ dependencies = [ "checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" +"checksum petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8b30dc85588cd02b9b76f5e386535db546d21dc68506cff2abebee0b6445e8e4" "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc" "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f" "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" @@ -4021,6 +4056,7 @@ dependencies = [ "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" +"checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" diff --git a/Cargo.toml b/Cargo.toml index de1a78bf4f..24649eff45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ evm-debug-tests = ["ethcore/evm-debug-tests"] slow-blocks = ["ethcore/slow-blocks"] secretstore = ["ethcore-secretstore"] final = ["parity-version/final"] +deadlock_detection = ["parking_lot/deadlock_detection"] [lib] path = "parity/lib.rs" diff --git a/parity/lib.rs b/parity/lib.rs index 4d9d1a2c95..6ef332da65 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -141,6 +141,35 @@ fn print_hash_of(maybe_file: Option) -> Result { } } +#[cfg(feature = "deadlock_detection")] +fn run_deadlock_detection_thread() { + use std::thread; + use std::time::Duration; + use parking_lot::deadlock; + + info!("Starting deadlock detection thread."); + // Create a background thread which checks for deadlocks every 10s + thread::spawn(move || { + loop { + thread::sleep(Duration::from_secs(10)); + let deadlocks = deadlock::check_deadlock(); + if deadlocks.is_empty() { + continue; + } + + warn!("{} {} detected", deadlocks.len(), Style::new().bold().paint("deadlock(s)")); + for (i, threads) in deadlocks.iter().enumerate() { + warn!("{} #{}", Style::new().bold().paint("Deadlock"), i); + for t in threads { + warn!("Thread Id {:#?}", t.thread_id()); + warn!("{:#?}", t.backtrace()); + } + } + } + }); +} + + /// Action that Parity performed when running `start`. pub enum ExecutionAction { /// The execution didn't require starting a node, and thus has finished. @@ -161,6 +190,9 @@ fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res // they want let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed"); + #[cfg(feature = "deadlock_detection")] + run_deadlock_detection_thread(); + match command.cmd { Cmd::Run(run_cmd) => { if run_cmd.ui_conf.enabled && !run_cmd.ui_conf.info_page_only { -- GitLab From 686bf443e6bcca085c897806a7f808fc891c655f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 31 May 2018 15:06:22 +0800 Subject: [PATCH 193/263] Remove unused function new_pow_test_spec (#8735) --- ethcore/src/spec/spec.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index fa25c8894e..98720647d8 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -923,11 +923,6 @@ impl Spec { pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") } - - /// Create a new spec for a PoW chain - pub fn new_pow_test_spec() -> Self { - load_bundled!("ethereum/olympic") - } } #[cfg(test)] -- GitLab From 6b9314eaa9df00b36afae4d7e8ab0f3d65e4fecb Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 31 May 2018 13:36:47 +0200 Subject: [PATCH 194/263] Add 'interface' option to cli (#8699) Additionally as to the port, the new command line option now allows the user to specify the network interface the P2P-Parity listens, too. With support for 'all' and 'local' like in all other versions of this flag. Default is 'all' (aka ). --- parity/cli/mod.rs | 7 +++++++ parity/configuration.rs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index a064baeac5..fea060d593 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -438,6 +438,10 @@ usage! { "--port=[PORT]", "Override the port on which the node should listen.", + ARG arg_interface: (String) = "all", or |c: &Config| c.network.as_ref()?.interface.clone(), + "--interface=[IP]", + "Network interfaces. Valid values are 'all', 'local' or the ip of the interface you want parity to listen to.", + ARG arg_min_peers: (Option) = None, or |c: &Config| c.network.as_ref()?.min_peers.clone(), "--min-peers=[NUM]", "Try to maintain at least NUM peers.", @@ -1119,6 +1123,7 @@ struct Network { warp: Option, warp_barrier: Option, port: Option, + interface: Option, min_peers: Option, max_peers: Option, snapshot_peers: Option, @@ -1567,6 +1572,7 @@ mod tests { // -- Networking Options flag_no_warp: false, arg_port: 30303u16, + arg_interface: "all".into(), arg_min_peers: Some(25u16), arg_max_peers: Some(50u16), arg_max_pending_peers: 64u16, @@ -1823,6 +1829,7 @@ mod tests { warp: Some(false), warp_barrier: None, port: None, + interface: None, min_peers: Some(10), max_peers: Some(20), max_pending_peers: Some(30), diff --git a/parity/configuration.rs b/parity/configuration.rs index 3151621801..6bec636e2c 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -767,7 +767,7 @@ impl Configuration { fn net_addresses(&self) -> Result<(SocketAddr, Option), String> { 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(self.interface(&self.args.arg_interface).parse().unwrap(), port); let public_address = if self.args.arg_nat.starts_with("extip:") { let host = &self.args.arg_nat[6..]; let host = host.parse().map_err(|_| format!("Invalid host given with `--nat extip:{}`", host))?; -- GitLab From 118588ef6ccdfca945fcc5733be3c7a5f857c728 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 31 May 2018 13:38:46 +0200 Subject: [PATCH 195/263] Fix some nits using clippy (#8731) * fix some nits using clippy * fix tests --- util/network-devp2p/src/handshake.rs | 10 +++--- util/network-devp2p/src/host.rs | 30 +++++++++--------- util/network-devp2p/src/ip_utils.rs | 42 ++++++++++++------------- util/network-devp2p/src/node_table.rs | 44 +++++++++++++-------------- util/network-devp2p/src/service.rs | 2 +- util/network-devp2p/src/session.rs | 16 +++++----- whisper/cli/src/main.rs | 3 ++ 7 files changed, 75 insertions(+), 72 deletions(-) diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 7aef4d4f0d..891dd7c257 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -84,12 +84,12 @@ impl Handshake { /// Create a new handshake object pub fn new(token: StreamToken, id: Option<&NodeId>, socket: TcpStream, nonce: &H256) -> Result { Ok(Handshake { - id: if let Some(id) = id { id.clone()} else { NodeId::new() }, + id: if let Some(id) = id { *id } else { NodeId::new() }, connection: Connection::new(token, socket), originated: false, state: HandshakeState::New, ecdhe: Random.generate()?, - nonce: nonce.clone(), + nonce: *nonce, remote_ephemeral: Public::new(), remote_nonce: H256::new(), remote_version: PROTOCOL_VERSION, @@ -166,7 +166,7 @@ impl Handshake { self.remote_version = remote_version; let shared = *ecdh::agree(host_secret, &self.id)?; let signature = H520::from_slice(sig); - self.remote_ephemeral = recover(&signature.into(), &(&shared ^ &self.remote_nonce))?; + self.remote_ephemeral = recover(&signature.into(), &(shared ^ self.remote_nonce))?; Ok(()) } @@ -189,7 +189,7 @@ impl Handshake { } Err(_) => { // Try to interpret as EIP-8 packet - let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + let total = ((u16::from(data[0]) << 8 | (u16::from(data[1]))) as usize) + 2; if total < V4_AUTH_PACKET_SIZE { debug!(target: "network", "Wrong EIP8 auth packet size"); return Err(ErrorKind::BadProtocol.into()); @@ -232,7 +232,7 @@ impl Handshake { } Err(_) => { // Try to interpret as EIP-8 packet - let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + let total = (((u16::from(data[0])) << 8 | (u16::from(data[1]))) as usize) + 2; if total < V4_ACK_PACKET_SIZE { debug!(target: "network", "Wrong EIP8 ack packet size"); return Err(ErrorKind::BadProtocol.into()); diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 2f577821a7..f9180700fe 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -116,11 +116,11 @@ impl<'s> NetworkContext<'s> { ) -> NetworkContext<'s> { let id = session.as_ref().map(|s| s.lock().token()); NetworkContext { - io: io, - protocol: protocol, + io, + protocol, session_id: id, - session: session, - sessions: sessions, + session, + sessions, _reserved_peers: reserved_peers, } } @@ -280,7 +280,7 @@ impl Host { let tcp_listener = TcpListener::bind(&listen_address)?; listen_address = SocketAddr::new(listen_address.ip(), tcp_listener.local_addr()?.port()); debug!(target: "network", "Listening at {:?}", listen_address); - let udp_port = config.udp_port.unwrap_or(listen_address.port()); + let udp_port = config.udp_port.unwrap_or_else(|| listen_address.port()); let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port }; let boot_nodes = config.boot_nodes.clone(); @@ -325,7 +325,7 @@ impl Host { match Node::from_str(id) { Err(e) => { debug!(target: "network", "Could not add node {}: {:?}", id, e); }, Ok(n) => { - let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; + let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id }; self.nodes.write().add_node(n); if let Some(ref mut discovery) = *self.discovery.lock() { @@ -338,9 +338,9 @@ impl Host { pub fn add_reserved_node(&self, id: &str) -> Result<(), Error> { let n = Node::from_str(id)?; - let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; - self.reserved_nodes.write().insert(n.id.clone()); - self.nodes.write().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); + let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id }; + self.reserved_nodes.write().insert(n.id); + self.nodes.write().add_node(Node::new(entry.id, entry.endpoint.clone())); if let Some(ref mut discovery) = *self.discovery.lock() { discovery.add_node(entry); @@ -349,10 +349,10 @@ impl Host { Ok(()) } - pub fn set_non_reserved_mode(&self, mode: NonReservedPeerMode, io: &IoContext) { + pub fn set_non_reserved_mode(&self, mode: &NonReservedPeerMode, io: &IoContext) { let mut info = self.info.write(); - if info.config.non_reserved_mode != mode { + if &info.config.non_reserved_mode != mode { info.config.non_reserved_mode = mode.clone(); drop(info); if let NonReservedPeerMode::Deny = mode { @@ -388,12 +388,12 @@ impl Host { pub fn external_url(&self) -> Option { let info = self.info.read(); - info.public_endpoint.as_ref().map(|e| format!("{}", Node::new(info.id().clone(), e.clone()))) + info.public_endpoint.as_ref().map(|e| format!("{}", Node::new(*info.id(), e.clone()))) } pub fn local_url(&self) -> String { let info = self.info.read(); - format!("{}", Node::new(info.id().clone(), info.local_endpoint.clone())) + format!("{}", Node::new(*info.id(), info.local_endpoint.clone())) } pub fn stop(&self, io: &IoContext) { @@ -554,7 +554,7 @@ impl Host { // iterate over all nodes, reserved ones coming first. // if we are pinned to only reserved nodes, ignore all others. let nodes = reserved_nodes.iter().cloned().chain(if !pin { - self.nodes.read().nodes(allow_ips) + self.nodes.read().nodes(&allow_ips) } else { Vec::new() }); @@ -752,7 +752,7 @@ impl Host { let entry = NodeEntry { id: id, endpoint: endpoint }; let mut nodes = self.nodes.write(); if !nodes.contains(&entry.id) { - nodes.add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); + nodes.add_node(Node::new(entry.id, entry.endpoint.clone())); let mut discovery = self.discovery.lock(); if let Some(ref mut discovery) = *discovery { discovery.add_node(entry); diff --git a/util/network-devp2p/src/ip_utils.rs b/util/network-devp2p/src/ip_utils.rs index 7c3d5c0fd3..3d7d33a066 100644 --- a/util/network-devp2p/src/ip_utils.rs +++ b/util/network-devp2p/src/ip_utils.rs @@ -109,7 +109,7 @@ impl SocketAddrExt for Ipv4Addr { fn is_within(&self, ipnet: &IpNetwork) -> bool { match ipnet { - &IpNetwork::V4(ipnet) => ipnet.contains(*self), + IpNetwork::V4(ipnet) => ipnet.contains(*self), _ => false } } @@ -167,7 +167,7 @@ impl SocketAddrExt for Ipv6Addr { fn is_within(&self, ipnet: &IpNetwork) -> bool { match ipnet { - &IpNetwork::V6(ipnet) => ipnet.contains(*self), + IpNetwork::V6(ipnet) => ipnet.contains(*self), _ => false } } @@ -212,28 +212,28 @@ impl SocketAddrExt for IpAddr { #[cfg(not(any(windows, target_os = "android")))] mod getinterfaces { - use std::{mem, io, ptr}; + use std::{mem, io}; use libc::{AF_INET, AF_INET6}; use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6}; use std::net::{Ipv4Addr, Ipv6Addr, IpAddr}; fn convert_sockaddr(sa: *mut sockaddr) -> Option { - if sa == ptr::null_mut() { return None; } + if sa.is_null() { return None; } - let (addr, _) = match unsafe { *sa }.sa_family as i32 { + let (addr, _) = match i32::from(unsafe { *sa }.sa_family) { AF_INET => { - let sa: *const sockaddr_in = unsafe { mem::transmute(sa) }; - let sa = & unsafe { *sa }; + let sa: *const sockaddr_in = sa as *const sockaddr_in; + let sa = unsafe { &*sa }; let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port); (IpAddr::V4(Ipv4Addr::new( - (addr & 0x000000FF) as u8, - ((addr & 0x0000FF00) >> 8) as u8, - ((addr & 0x00FF0000) >> 16) as u8, - ((addr & 0xFF000000) >> 24) as u8)), + (addr & 0x0000_00FF) as u8, + ((addr & 0x0000_FF00) >> 8) as u8, + ((addr & 0x00FF_0000) >> 16) as u8, + ((addr & 0xFF00_0000) >> 24) as u8)), port) }, AF_INET6 => { - let sa: *const sockaddr_in6 = unsafe { mem::transmute(sa) }; + let sa: *const sockaddr_in6 = sa as *const sockaddr_in6; let sa = & unsafe { *sa }; let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port); let addr: [u16; 8] = unsafe { mem::transmute(addr) }; @@ -266,7 +266,7 @@ mod getinterfaces { let mut ret = Vec::new(); let mut cur: *mut ifaddrs = ifap; - while cur != ptr::null_mut() { + while !cur.is_null() { if let Some(ip_addr) = convert_ifaddrs(cur) { ret.push(ip_addr); } @@ -297,16 +297,16 @@ pub fn select_public_address(port: u16) -> SocketAddr { //prefer IPV4 bindings for addr in &list { //TODO: use better criteria than just the first in the list match addr { - &IpAddr::V4(a) if !a.is_reserved() => { - return SocketAddr::V4(SocketAddrV4::new(a, port)); + IpAddr::V4(a) if !a.is_reserved() => { + return SocketAddr::V4(SocketAddrV4::new(*a, port)); }, _ => {}, } } for addr in &list { match addr { - &IpAddr::V6(a) if !a.is_reserved() => { - return SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)); + IpAddr::V6(a) if !a.is_reserved() => { + return SocketAddr::V6(SocketAddrV6::new(*a, port, 0, 0)); }, _ => {}, } @@ -319,7 +319,7 @@ pub fn select_public_address(port: u16) -> SocketAddr { pub fn map_external_address(local: &NodeEndpoint) -> Option { if let SocketAddr::V4(ref local_addr) = local.address { - match search_gateway_from_timeout(local_addr.ip().clone(), Duration::new(5, 0)) { + match search_gateway_from_timeout(*local_addr.ip(), Duration::new(5, 0)) { Err(ref err) => debug!("Gateway search error: {}", err), Ok(gateway) => { match gateway.get_external_ip() { @@ -327,17 +327,17 @@ pub fn map_external_address(local: &NodeEndpoint) -> Option { debug!("IP request error: {}", err); }, Ok(external_addr) => { - match gateway.add_any_port(PortMappingProtocol::TCP, SocketAddrV4::new(local_addr.ip().clone(), local_addr.port()), 0, "Parity Node/TCP") { + match gateway.add_any_port(PortMappingProtocol::TCP, SocketAddrV4::new(*local_addr.ip(), local_addr.port()), 0, "Parity Node/TCP") { Err(ref err) => { debug!("Port mapping error: {}", err); }, Ok(tcp_port) => { - match gateway.add_any_port(PortMappingProtocol::UDP, SocketAddrV4::new(local_addr.ip().clone(), local.udp_port), 0, "Parity Node/UDP") { + match gateway.add_any_port(PortMappingProtocol::UDP, SocketAddrV4::new(*local_addr.ip(), local.udp_port), 0, "Parity Node/UDP") { Err(ref err) => { debug!("Port mapping error: {}", err); }, Ok(udp_port) => { - return Some(NodeEndpoint { address: SocketAddr::V4(SocketAddrV4::new(external_addr, tcp_port)), udp_port: udp_port }); + return Some(NodeEndpoint { address: SocketAddr::V4(SocketAddrV4::new(external_addr, tcp_port)), udp_port }); }, } }, diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index 8640901cd0..d5d0207ecd 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -26,7 +26,7 @@ use std::hash::{Hash, Hasher}; use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; use std::path::PathBuf; use std::str::FromStr; -use std::{fs, mem, slice}; +use std::{fs, slice}; use std::time::{self, Duration, SystemTime}; use rand::{self, Rng}; @@ -45,8 +45,8 @@ pub struct NodeEndpoint { impl NodeEndpoint { pub fn udp_address(&self) -> SocketAddr { match self.address { - SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)), - SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())), + SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(*a.ip(), self.udp_port)), + SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(*a.ip(), self.udp_port, a.flowinfo(), a.scope_id())), } } @@ -61,10 +61,10 @@ impl NodeEndpoint { pub fn is_allowed_by_predefined(&self, filter: &AllowIP) -> bool { match filter { - &AllowIP::All => true, - &AllowIP::Private => self.address.ip().is_usable_private(), - &AllowIP::Public => self.address.ip().is_usable_public(), - &AllowIP::None => false, + AllowIP::All => true, + AllowIP::Private => self.address.ip().is_usable_private(), + AllowIP::Public => self.address.ip().is_usable_public(), + AllowIP::None => false, } } @@ -75,13 +75,13 @@ impl NodeEndpoint { let address = match addr_bytes.len() { 4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))), 16 => unsafe { - let o: *const u16 = mem::transmute(addr_bytes.as_ptr()); + let o: *const u16 = addr_bytes.as_ptr() as *const u16; let o = slice::from_raw_parts(o, 8); Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0))) }, _ => Err(DecoderError::RlpInconsistentLengthAndData) }?; - Ok(NodeEndpoint { address: address, udp_port: udp_port }) + Ok(NodeEndpoint { address, udp_port }) } pub fn to_rlp(&self, rlp: &mut RlpStream) { @@ -90,7 +90,7 @@ impl NodeEndpoint { rlp.append(&(&a.ip().octets()[..])); } SocketAddr::V6(a) => unsafe { - let o: *const u8 = mem::transmute(a.ip().segments().as_ptr()); + let o: *const u8 = a.ip().segments().as_ptr() as *const u8; rlp.append(&slice::from_raw_parts(o, 16)); } }; @@ -184,8 +184,8 @@ pub struct Node { impl Node { pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { Node { - id: id, - endpoint: endpoint, + id, + endpoint, peer_type: PeerType::Optional, last_contact: None, } @@ -214,8 +214,8 @@ impl FromStr for Node { }; Ok(Node { - id: id, - endpoint: endpoint, + id, + endpoint, peer_type: PeerType::Optional, last_contact: None, }) @@ -258,7 +258,7 @@ impl NodeTable { pub fn add_node(&mut self, mut node: Node) { // preserve node last_contact node.last_contact = self.nodes.get(&node.id).and_then(|n| n.last_contact); - self.nodes.insert(node.id.clone(), node); + self.nodes.insert(node.id, node); } /// Returns a list of ordered nodes according to their most recent contact @@ -315,7 +315,7 @@ impl NodeTable { /// Returns node ids sorted by failure percentage, for nodes with the same failure percentage the absolute number of /// failures is considered. - pub fn nodes(&self, filter: IpFilter) -> Vec { + pub fn nodes(&self, filter: &IpFilter) -> Vec { self.ordered_entries().iter() .filter(|n| n.endpoint.is_allowed(&filter)) .map(|n| n.id) @@ -327,7 +327,7 @@ impl NodeTable { pub fn entries(&self) -> Vec { self.ordered_entries().iter().map(|n| NodeEntry { endpoint: n.endpoint.clone(), - id: n.id.clone(), + id: n.id, }).collect() } @@ -344,7 +344,7 @@ impl NodeTable { /// Apply table changes coming from discovery pub fn update(&mut self, mut update: TableUpdates, reserved: &HashSet) { for (_, node) in update.added.drain() { - let entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone())); + let entry = self.nodes.entry(node.id).or_insert_with(|| Node::new(node.id, node.endpoint.clone())); entry.endpoint = node.endpoint; } for r in update.removed { @@ -389,7 +389,7 @@ impl NodeTable { return; } path.push(NODES_FILE); - let node_ids = self.nodes(IpFilter::default()); + let node_ids = self.nodes(&IpFilter::default()); let nodes = node_ids.into_iter() .map(|id| self.nodes.get(&id).expect("self.nodes() only returns node IDs from self.nodes")) .take(MAX_NODES) @@ -428,7 +428,7 @@ impl NodeTable { Ok(table) => { table.nodes.into_iter() .filter_map(|n| n.into_node()) - .map(|n| (n.id.clone(), n)) + .map(|n| (n.id, n)) .collect() }, Err(e) => { @@ -625,7 +625,7 @@ mod tests { // unknown - node 6 - let r = table.nodes(IpFilter::default()); + let r = table.nodes(&IpFilter::default()); assert_eq!(r[0][..], id4[..]); // most recent success assert_eq!(r[1][..], id3[..]); @@ -662,7 +662,7 @@ mod tests { { let table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned())); - let r = table.nodes(IpFilter::default()); + let r = table.nodes(&IpFilter::default()); assert_eq!(r[0][..], id2[..]); // latest success assert_eq!(r[1][..], id1[..]); // unknown assert_eq!(r[2][..], id3[..]); // oldest failure diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index 1b46ca1ae3..d8105f649c 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -165,7 +165,7 @@ impl NetworkService { let host = self.host.read(); if let Some(ref host) = *host { let io_ctxt = IoContext::new(self.io_service.channel(), 0); - host.set_non_reserved_mode(mode, &io_ctxt); + host.set_non_reserved_mode(&mode, &io_ctxt); } } diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index 47eb2cf728..cd8ef56bd4 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -117,7 +117,7 @@ impl Session { capabilities: Vec::new(), peer_capabilities: Vec::new(), ping: None, - originated: originated, + originated, remote_address: "Handshake".to_owned(), local_address: local_addr, }, @@ -131,7 +131,7 @@ impl Session { fn complete_handshake(&mut self, io: &IoContext, host: &HostInfo) -> Result<(), Error> where Message: Send + Sync + Clone { let connection = if let State::Handshake(ref mut h) = self.state { - self.info.id = Some(h.id.clone()); + self.info.id = Some(h.id); self.info.remote_address = h.connection.remote_addr_str(); EncryptedConnection::new(h)? } else { @@ -204,7 +204,7 @@ impl Session { } } if let Some(data) = packet_data { - return Ok(self.read_packet(io, data, host)?); + return Ok(self.read_packet(io, &data, host)?); } if create_session { self.complete_handshake(io, host)?; @@ -277,7 +277,7 @@ impl Session { None => packet_id }; let mut rlp = RlpStream::new(); - rlp.append(&(pid as u32)); + rlp.append(&(u32::from(pid))); let mut compressed = Vec::new(); let mut payload = data; // create a reference with local lifetime if self.compression { @@ -329,7 +329,7 @@ impl Session { } } - fn read_packet(&mut self, io: &IoContext, packet: Packet, host: &HostInfo) -> Result + fn read_packet(&mut self, io: &IoContext, packet: &Packet, host: &HostInfo) -> Result where Message: Send + Sync + Clone { if packet.data.len() < 2 { return Err(ErrorKind::BadProtocol.into()); @@ -390,7 +390,7 @@ impl Session { match *self.protocol_states.entry(protocol).or_insert_with(|| ProtocolState::Pending(Vec::new())) { ProtocolState::Connected => { trace!(target: "network", "Packet {} mapped to {:?}:{}, i={}, capabilities={:?}", packet_id, protocol, protocol_packet_id, i, self.info.capabilities); - Ok(SessionData::Packet { data: data, protocol: protocol, packet_id: protocol_packet_id } ) + Ok(SessionData::Packet { data, protocol, packet_id: protocol_packet_id } ) } ProtocolState::Pending(ref mut pending) => { trace!(target: "network", "Packet {} deferred until protocol connection event completion", packet_id); @@ -468,11 +468,11 @@ impl Session { self.info.peer_capabilities = peer_caps; if self.info.capabilities.is_empty() { trace!(target: "network", "No common capabilities with peer."); - return Err(From::from(self.disconnect(io, DisconnectReason::UselessPeer))); + return Err(self.disconnect(io, DisconnectReason::UselessPeer)); } if protocol < MIN_PROTOCOL_VERSION { trace!(target: "network", "Peer protocol version mismatch: {}", protocol); - return Err(From::from(self.disconnect(io, DisconnectReason::UselessPeer))); + return Err(self.disconnect(io, DisconnectReason::UselessPeer)); } self.compression = protocol >= MIN_COMPRESSION_PROTOCOL_VERSION; self.send_ping(io)?; diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index f245e99e48..d76c216be4 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -19,6 +19,9 @@ //! Spawns an Ethereum network instance and attaches the Whisper protocol RPCs to it. //! +#![warn(missing_docs)] +#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] + extern crate docopt; extern crate ethcore_network_devp2p as devp2p; extern crate ethcore_network as net; -- GitLab From 1020560af632d6359dcf44c43314dc2df78e2b5b Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 31 May 2018 13:39:25 +0200 Subject: [PATCH 196/263] Remove a couple of unnecessary `transmute()` (#8736) --- ethash/src/compute.rs | 5 ++--- util/plain_hasher/src/lib.rs | 17 +++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index 48906b9ede..de2b57637f 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -25,9 +25,8 @@ use seed_compute::SeedHashCompute; use shared::*; use std::io; -use std::mem; +use std::{mem, ptr}; use std::path::Path; -use std::ptr; const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4; const MIX_NODES: usize = MIX_WORDS / NODE_WORDS; @@ -111,7 +110,7 @@ pub fn quick_get_difficulty(header_hash: &H256, nonce: u64, mix_hash: &H256) -> let mut buf: [u8; 64 + 32] = mem::uninitialized(); ptr::copy_nonoverlapping(header_hash.as_ptr(), buf.as_mut_ptr(), 32); - ptr::copy_nonoverlapping(mem::transmute(&nonce), buf[32..].as_mut_ptr(), 8); + ptr::copy_nonoverlapping(&nonce as *const u64 as *const u8, buf[32..].as_mut_ptr(), 8); keccak_512::unchecked(buf.as_mut_ptr(), 64, buf.as_ptr(), 40); ptr::copy_nonoverlapping(mix_hash.as_ptr(), buf[64..].as_mut_ptr(), 32); diff --git a/util/plain_hasher/src/lib.rs b/util/plain_hasher/src/lib.rs index 54bad92f47..d08d4dd1ab 100644 --- a/util/plain_hasher/src/lib.rs +++ b/util/plain_hasher/src/lib.rs @@ -2,9 +2,9 @@ extern crate crunchy; extern crate ethereum_types; -use std::{hash, mem}; -use std::collections::{HashMap, HashSet}; use ethereum_types::H256; +use std::collections::{HashMap, HashSet}; +use std::hash; /// Specialized version of `HashMap` with H256 keys and fast hashing function. pub type H256FastMap = HashMap>; @@ -28,16 +28,13 @@ impl hash::Hasher for PlainHasher { #[allow(unused_assignments)] fn write(&mut self, bytes: &[u8]) { debug_assert!(bytes.len() == 32); + let mut bytes_ptr = bytes.as_ptr(); + let mut prefix_ptr = &mut self.prefix as *mut u64 as *mut u8; - unsafe { - let mut bytes_ptr = bytes.as_ptr(); - let prefix_u8: &mut [u8; 8] = mem::transmute(&mut self.prefix); - let mut prefix_ptr = prefix_u8.as_mut_ptr(); - - unroll! { - for _i in 0..8 { + unroll! { + for _i in 0..8 { + unsafe { *prefix_ptr ^= (*bytes_ptr ^ *bytes_ptr.offset(8)) ^ (*bytes_ptr.offset(16) ^ *bytes_ptr.offset(24)); - bytes_ptr = bytes_ptr.offset(1); prefix_ptr = prefix_ptr.offset(1); } -- GitLab From d32ce374847ba4ed09101535dfb66356b3a2ffe9 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Thu, 31 May 2018 13:53:09 +0200 Subject: [PATCH 197/263] bump tinykeccak to 1.4 (#8728) --- ethcore/crypto/Cargo.toml | 2 +- ethcore/private-tx/Cargo.toml | 2 +- ethkey/Cargo.toml | 2 +- ethstore/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- secret_store/Cargo.toml | 2 +- util/network-devp2p/Cargo.toml | 2 +- whisper/Cargo.toml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ethcore/crypto/Cargo.toml b/ethcore/crypto/Cargo.toml index 4fe023f25c..b57b8497c0 100644 --- a/ethcore/crypto/Cargo.toml +++ b/ethcore/crypto/Cargo.toml @@ -8,5 +8,5 @@ ethereum-types = "0.3" quick-error = "1.2" ring = "0.12" rust-crypto = "0.2.36" -tiny-keccak = "1.3" +tiny-keccak = "1.4" diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index 0fa11aec84..8283ab314a 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -33,5 +33,5 @@ rustc-hex = "1.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" url = "1" diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index d6698f86d9..952354739d 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -16,4 +16,4 @@ parity-wordlist = "1.2" quick-error = "1.2" rand = "0.4" rustc-hex = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index 6330ce97ce..6108143cb9 100644 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -12,7 +12,7 @@ serde = "1.0" serde_json = "1.0" serde_derive = "1.0" rustc-hex = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" time = "0.1.34" itertools = "0.5" parking_lot = "0.5" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 8fdb9ed574..8a0b689c65 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -23,7 +23,7 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" tempdir = "0.3" -tiny-keccak = "1.3" +tiny-keccak = "1.4" tokio-timer = "0.1" transient-hashmap = "0.4" itertools = "0.5" diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index fee832d069..261658903c 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -16,7 +16,7 @@ serde_derive = "1.0" futures = "0.1" futures-cpupool = "0.1" rustc-hex = "1.0" -tiny-keccak = "1.3" +tiny-keccak = "1.4" tokio = "0.1" tokio-core = "0.1" tokio-io = "0.1" diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index f4889fe26d..4a5d2d942e 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -11,7 +11,7 @@ log = "0.3" mio = "0.6.8" bytes = "0.4" rand = "0.4" -tiny-keccak = "1.3" +tiny-keccak = "1.4" rust-crypto = "0.2.34" slab = "0.2" igd = "0.7" diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index ed370e38a2..e503a74fd6 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -23,7 +23,7 @@ serde_derive = "1.0" serde_json = "1.0" slab = "0.3" smallvec = "0.4" -tiny-keccak = "1.3" +tiny-keccak = "1.4" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } -- GitLab From 9053c0dfd9449ca8a83bac7964cd9d336e6d9f94 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 31 May 2018 15:07:35 +0300 Subject: [PATCH 198/263] ease tiny-keccak version requirements (1.4.1 -> 1.4) (#8726) --- util/hash/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/hash/Cargo.toml b/util/hash/Cargo.toml index e136ada305..4ca503751a 100644 --- a/util/hash/Cargo.toml +++ b/util/hash/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Parity Technologies "] [dependencies] ethereum-types = "0.3" -tiny-keccak = "1.4.1" +tiny-keccak = "1.4" [dev-dependencies] tempdir = "0.3" -- GitLab From 581e510c2d91cfa9008ebf0de93fb4a42be3bd80 Mon Sep 17 00:00:00 2001 From: vrde Date: Thu, 31 May 2018 14:43:06 +0200 Subject: [PATCH 199/263] Remove -k/--insecure option from curl installer (#8719) Piping `curl` to `bash` while **disabling** certificate verification can lead to security problems. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9255d014b6..8cba4205bd 100644 --- a/README.md +++ b/README.md @@ -138,13 +138,13 @@ first. ## Simple one-line installer for Mac and Ubuntu ```bash -bash <(curl https://get.parity.io -Lk) +bash <(curl https://get.parity.io -L) ``` The one-line installer always defaults to the latest beta release. To install a stable release, run: ```bash -bash <(curl https://get.parity.io -Lk) -r stable +bash <(curl https://get.parity.io -L) -r stable ``` ## Start Parity -- GitLab From 00b209a29e96dc6827852de27d8c426189fd2f56 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 31 May 2018 21:28:25 +0800 Subject: [PATCH 200/263] Fix PoW blockchains sealing notifications in chain_new_blocks (#8656) --- ethcore/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 5cfe8fce82..b469cf4518 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2181,7 +2181,7 @@ impl ImportSealedBlock for Client { route }; let route = ChainRoute::from([route].as_ref()); - self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), true); + self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), self.engine.seals_internally().is_some()); self.notify(|notify| { notify.new_blocks( vec![h.clone()], -- GitLab From 799ae29ac490e4bec035a97845a1a44d7610d7bb Mon Sep 17 00:00:00 2001 From: David Date: Fri, 1 Jun 2018 09:38:20 +0200 Subject: [PATCH 201/263] Print warnings when fetching pending blocks (#8711) * Lots of println to figure out what eth_getBlockByNumber does/should do * Remove debugging * Print warnings when fetching pending blocks When calling `eth_getBlockByNumber` with `pending`, we now print a deprecation warning and: * if a pending block is found, use it to respond * if no pending block is found, respond as if if was a request for `Latest` Addresses issue #8703 (not sure if it's enough to close it tbh) --- ethcore/src/miner/miner.rs | 10 ++++++---- rpc/src/v1/impls/eth.rs | 36 +++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 3168ff1a84..4904535a89 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -290,10 +290,12 @@ impl Miner { { self.sealing.lock().queue .peek_last_ref() - .and_then(|b| if b.block().header().number() > latest_block_number { - Some(f(b)) - } else { - None + .and_then(|b| { + if b.block().header().number() > latest_block_number { + Some(f(b)) + } else { + None + } }) } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 389805c176..ae8d611c12 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -108,6 +108,7 @@ pub struct EthClient where eip86_transition: u64, } +#[derive(Debug)] enum BlockNumberOrId { Number(BlockNumber), Id(BlockId), @@ -184,21 +185,30 @@ impl EthClient { let info = self.client.chain_info(); - let pending_block = self.miner.pending_block(info.best_block_number); - let difficulty = { - let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed"); - let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty()); + match self.miner.pending_block(info.best_block_number) { + Some(pending_block) => { + warn!("`Pending` is deprecated and may be removed in future versions."); - if let Some(difficulty) = pending_difficulty { - difficulty + latest_difficulty - } else { - latest_difficulty - } - }; + let difficulty = { + let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed"); + let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty()); + + if let Some(difficulty) = pending_difficulty { + difficulty + latest_difficulty + } else { + latest_difficulty + } + }; - let extra = pending_block.as_ref().map(|b| self.client.engine().extra_info(&b.header)); + let extra = self.client.engine().extra_info(&pending_block.header); - (pending_block.map(|b| encoded::Block::new(b.rlp_bytes())), Some(difficulty), extra, true) + (Some(encoded::Block::new(pending_block.rlp_bytes())), Some(difficulty), Some(extra), true) + }, + None => { + warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`"); + client_query(BlockId::Latest) + } + } }, BlockNumberOrId::Number(num) => { @@ -206,7 +216,7 @@ impl EthClient BlockId::Latest, BlockNumber::Earliest => BlockId::Earliest, BlockNumber::Num(n) => BlockId::Number(n), - BlockNumber::Pending => unreachable!(), // Already covered + BlockNumber::Pending => unreachable!() // Already covered }; client_query(id) -- GitLab From 485d4aa8f3d536f8dca91b51ab4c2e4c22a3e6d5 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 1 Jun 2018 00:42:45 -0700 Subject: [PATCH 202/263] Fix XOR distance calculation in discovery Kademlia impl (#8589) * network-devp2p: Test for discovery bucket insertion. All test values are randomly generated and the assertions are checked manually. Test fails because distance metric is implemented incorrectly. * network-devp2p: Fix discovery distance function. The Kademlia distance function (XOR) was implemented incorrectly as a population count. * network-devp2p: Refactor nearest_node_entries to be on instance. Optimizations are possible with more access to the discovery state. * network-devp2p: Fix loss of precision in nearest_node_entries. * network-devp2p: More efficient nearest node search. The discovery algorithm to identify the nearest k nodes does not need to scan all entries in all buckets. --- util/network-devp2p/src/discovery.rs | 221 +++++++++++++++++++++------ 1 file changed, 172 insertions(+), 49 deletions(-) diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index f14cd5ba6f..af43546a5f 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -16,7 +16,7 @@ use ethcore_bytes::Bytes; use std::net::SocketAddr; -use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; +use std::collections::{HashSet, HashMap, VecDeque}; use std::mem; use std::default::Default; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -34,9 +34,8 @@ use network::IpFilter; use PROTOCOL_VERSION; -const ADDRESS_BYTES_SIZE: u32 = 32; // Size of address type in bytes. -const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademlia]. -const NODE_BINS: u32 = ADDRESS_BITS - 1; // Size of m_state (excludes root, which is us). +const ADDRESS_BYTES_SIZE: usize = 32; // Size of address type in bytes. +const ADDRESS_BITS: usize = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademlia]. const DISCOVERY_MAX_STEPS: u16 = 8; // Max iterations of discovery. (discover) const BUCKET_SIZE: usize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. const ALPHA: usize = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. @@ -119,7 +118,7 @@ impl Discovery { discovery_round: 0, discovery_id: NodeId::new(), discovery_nodes: HashSet::new(), - node_buckets: (0..NODE_BINS).map(|_| NodeBucket::new()).collect(), + node_buckets: (0..ADDRESS_BITS).map(|_| NodeBucket::new()).collect(), udp_socket: socket, send_queue: VecDeque::new(), check_timestamps: true, @@ -155,8 +154,16 @@ impl Discovery { fn update_node(&mut self, e: NodeEntry) { trace!(target: "discovery", "Inserting {:?}", &e); let id_hash = keccak(e.id); + let dist = match Discovery::distance(&self.id_hash, &id_hash) { + Some(dist) => dist, + None => { + warn!(target: "discovery", "Attempted to update own entry: {:?}", e); + return; + } + }; + let ping = { - let bucket = &mut self.node_buckets[Discovery::distance(&self.id_hash, &id_hash) as usize]; + let bucket = &mut self.node_buckets[dist]; let updated = if let Some(node) = bucket.nodes.iter_mut().find(|n| n.address.id == e.id) { node.address = e.clone(); node.timeout = None; @@ -181,7 +188,15 @@ impl Discovery { /// Removes the timeout of a given NodeId if it can be found in one of the discovery buckets fn clear_ping(&mut self, id: &NodeId) { - let bucket = &mut self.node_buckets[Discovery::distance(&self.id_hash, &keccak(id)) as usize]; + let dist = match Discovery::distance(&self.id_hash, &keccak(id)) { + Some(dist) => dist, + None => { + warn!(target: "discovery", "Received ping from self"); + return + } + }; + + let bucket = &mut self.node_buckets[dist]; if let Some(node) = bucket.nodes.iter_mut().find(|n| &n.address.id == id) { node.timeout = None; } @@ -212,7 +227,7 @@ impl Discovery { trace!(target: "discovery", "Starting round {:?}", self.discovery_round); let mut tried_count = 0; { - let nearest = Discovery::nearest_node_entries(&self.discovery_id, &self.node_buckets).into_iter(); + let nearest = self.nearest_node_entries(&self.discovery_id).into_iter(); let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::>(); for r in nearest { let rlp = encode_list(&(&[self.discovery_id.clone()][..])); @@ -233,17 +248,17 @@ impl Discovery { self.discovery_round += 1; } - fn distance(a: &H256, b: &H256) -> u32 { - let d = *a ^ *b; - let mut ret:u32 = 0; - for i in 0..32 { - let mut v: u8 = d[i]; - while v != 0 { - v >>= 1; - ret += 1; + /// The base 2 log of the distance between a and b using the XOR metric. + fn distance(a: &H256, b: &H256) -> Option { + for i in (0..ADDRESS_BYTES_SIZE).rev() { + let byte_index = ADDRESS_BYTES_SIZE - i - 1; + let d: u8 = a[byte_index] ^ b[byte_index]; + if d != 0 { + let high_bit_index = 7 - d.leading_zeros() as usize; + return Some(i * 8 + high_bit_index); } } - ret + None // a and b are equal, so log distance is -inf } fn ping(&mut self, node: &NodeEndpoint) { @@ -286,36 +301,53 @@ impl Discovery { Ok(()) } - fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { - let mut found: BTreeMap> = BTreeMap::new(); - let mut count = 0; + fn nearest_node_entries(&self, target: &NodeId) -> Vec { let target_hash = keccak(target); + let target_distance = self.id_hash ^ target_hash; + + let mut ret = Vec::::with_capacity(BUCKET_SIZE); + + // Sort bucket entries by distance to target and append to end of result vector. + let append_bucket = |results: &mut Vec, bucket: &NodeBucket| -> bool { + let mut sorted_entries: Vec<&BucketEntry> = bucket.nodes.iter().collect(); + sorted_entries.sort_unstable_by_key(|entry| entry.id_hash ^ target_hash); + + let remaining_capacity = results.capacity() - results.len(); + let to_append = if remaining_capacity < sorted_entries.len() { + &sorted_entries[0..remaining_capacity] + } else { + &sorted_entries + }; + for entry in to_append.iter() { + results.push(entry.address.clone()); + } + results.len() == results.capacity() + }; - // Sort nodes by distance to target - for bucket in buckets { - for node in &bucket.nodes { - let distance = Discovery::distance(&target_hash, &node.id_hash); - found.entry(distance).or_insert_with(Vec::new).push(&node.address); - if count == BUCKET_SIZE { - // delete the most distant element - let remove = { - let (key, last) = found.iter_mut().next_back().expect("Last element is always Some when count > 0"); - last.pop(); - if last.is_empty() { Some(key.clone()) } else { None } - }; - if let Some(remove) = remove { - found.remove(&remove); - } - } - else { - count += 1; + // This algorithm leverages the structure of the routing table to efficiently find the + // nearest entries to a target hash. First, we compute the XOR distance from this node to + // the target. On a first pass, we iterate from the MSB of the distance, stopping at any + // buckets where the distance bit is set, and skipping the buckets where it is unset. These + // must be in order the nearest to the target. On a second pass, we traverse from LSB to + // MSB, appending the buckets skipped on the first pass. The reason this works is that all + // entries in bucket i have a common prefix of length exactly 32 - i - 1 with the ID of this + // node. + + for i in 0..ADDRESS_BITS { + if ((target_distance[i / 8] << (i % 8)) & 0x80) != 0 { + let bucket = &self.node_buckets[ADDRESS_BITS - i - 1]; + if !bucket.nodes.is_empty() && append_bucket(&mut ret, bucket) { + return ret; } } } - - let mut ret:Vec = Vec::new(); - for nodes in found.values() { - ret.extend(nodes.iter().map(|&n| n.clone())); + for i in (0..ADDRESS_BITS).rev() { + if ((target_distance[i / 8] << (i % 8)) & 0x80) == 0 { + let bucket = &self.node_buckets[ADDRESS_BITS - i - 1]; + if !bucket.nodes.is_empty() && append_bucket(&mut ret, bucket) { + return ret; + } + } } ret } @@ -453,7 +485,7 @@ impl Discovery { let target: NodeId = rlp.val_at(0)?; let timestamp: u64 = rlp.val_at(1)?; self.check_timestamp(timestamp)?; - let nearest = Discovery::nearest_node_entries(&target, &self.node_buckets); + let nearest = self.nearest_node_entries(&target); if nearest.is_empty() { return Ok(None); } @@ -614,7 +646,7 @@ mod tests { } discovery2.round(); } - assert_eq!(Discovery::nearest_node_entries(&NodeId::new(), &discovery2.node_buckets).len(), 3) + assert_eq!(discovery2.nearest_node_entries(&NodeId::new()).len(), 3) } #[test] @@ -625,7 +657,7 @@ mod tests { for _ in 0..1200 { discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); } - assert!(Discovery::nearest_node_entries(&NodeId::new(), &discovery.node_buckets).len() <= 16); + assert!(discovery.nearest_node_entries(&NodeId::new()).len() <= 16); let removed = discovery.check_expired(true).len(); assert!(removed > 0); } @@ -633,23 +665,114 @@ mod tests { #[test] fn find_nearest_saturated() { use super::*; - let mut buckets: Vec<_> = (0..256).map(|_| NodeBucket::new()).collect(); + + let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + for _ in 0..(16 + 10) { - buckets[0].nodes.push_back(BucketEntry { + discovery.node_buckets[0].nodes.push_back(BucketEntry { address: NodeEntry { id: NodeId::new(), endpoint: ep.clone() }, timeout: None, id_hash: keccak(NodeId::new()), }); } - let nearest = Discovery::nearest_node_entries(&NodeId::new(), &buckets); + let nearest = discovery.nearest_node_entries(&NodeId::new()); assert_eq!(nearest.len(), 16) } + #[test] + fn routing_table_insertions_lookups() { + use super::*; + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40448").unwrap(), udp_port: 40447 }; + let node_ids_hex: [&str; 32] = [ + "22536fa57acc12c4993295cbc26fef4550513496712b301ad2283d356c8108521244a362e64e6d907a0d0b4e65526699c5ae3cfebfc680505fe3b33d50672835", + "22c482f42401546f8dd7ed6b1c0cad976da6630730f1116614579ccb084791a528ff2676bfe94434de80e5d7e479f1ea1d7737077da3bd5e69a0f3e5bf596091", + "234c73e3a8f6835a7f9a9d2a896bff4908d66d21d5433a2c37d94f1fa9a6ca17d02388f31013ff87e3ad86506e76bd1006b9cac3815974a2b47c8d4f2124697e", + "2a5aaf4e2046c521e890dc82313c6151a55078f045a7e3d259f168238d029271cdd9a0943468d45c1e36a34a8a6d4de4b0262e48d3c8cfdd4c2aab5df42926b9", + "341d8c94d9670461186cfc1f66d4246cb12384940e9f621ec8d6c216b5d037cde5f7a41b70474ca36ced4a4f2fe91c9dc5a24a128414672661f78e8611d54bfd", + "3d9fd01851f3ae1bfd06b48e89738f29f9a2b4dce3ab7864df4fccca55d1ac88044956ba47d0c4cb44a19924626a3a3aa5a4de8958365cb7385111ce7b929200", + "406d5507a7fbc194a495800ae8cf408093336febc24d03d6c63756f522274ab02146ceb1b0213291a9a1544680503837519f88f1e8677d921de62c82935b4e6c", + "4c537f00805f320616ee49c7bc36e1d7e52a04a782b0cc00fd3d6b77200b027cef5f875ed38f1167fef4b02d7bd49a661812301d9d680bb62297131204c035f9", + "4fc8e3fdbdd7acad82b283ac52c121b805f3b15ffcaa6b2ca67b9e375aa88e978951ffa3d03ee13be99f0ee987db0bbfc6a7ca02b175e9123d79826025b4089d", + "55b5042a6910bc908a0520966e8cbcc92ac299bdb7efbfbcf703df1506fa0f9b09c5eeb930080de848d2864cca71f885942852c51233db0ee46fe0447306d61f", + "5d24f28b350c4c37fc4dad7f418e029992c9e4ac356bb3d9a1356ba1076339863c05044d7ceba233c65779401f8a3b38fe67b6a592c1be4834dc869f7bb932eb", + "5f6edaf2f2ae3003f4b4ff90b8e71a717c832c71a634d96e77fe046f9a88adc8de5718ff3c47659aea4cead5376df5b731e1b6530e6b0999f56ad75d4dabd3f6", + "6214c04211efe91abd23d65e2dc8e711b06d4fb13dcfd65b691dc51f58455b2145f9b38f523b72a45a12705a28d389308a34455720d774c9b805326df42b5a63", + "69df92573ddbbce88b72a930843dbb70728b2a020e0cc4e8ba805dcf7f19297bfc5def4ca447e9e6ec66971be1815b8f49042720431f698b6a87a185d94fa6c8", + "72ffc23de007cf8b6f4a117f7427b532d05861c314344ffa265175f57ee45dae041a710a4dc74124dba1dabdc0f52dfd21e3154d1d4285aab529810c6161d623", + "80b567f279a9512f3a66ebd8f87a93acd4d50bf66f5eff6d04039c1f5838e37021e981539659b33e0644b243fc9671209a80cbef40d1bcf7c7117d353cb45532", + "9009dc9e3bf50595f84271f46d4c7a5ad6971f7d2ffce1905bfc40a407d34fc5e2dcebd92746eadcd2c5fa4d5aaccb0e01b542d506b361851df3f19e6bc629a3", + "95264f56e091efeba911003fd01eeb2c81f6fc4bb7b10c92e4c7bfaf460b7246d232e61ad8a223d74870981a84e15b2d5134c25d931cb860c6912b20a2d3ac01", + "96013a472a9f7ff9c5c76b5ca958f14ee510d826703aa41d4c88eac51d30d14229b9f19f6e0469c37aaa6d2136a978a4aaa38ca766f48e53e569f84e44252962", + "a513c988cf8480ad2992caa64e3fa059ce07efda260dfeefed78e1d41ea3f97844603b8a9737eb633086fd9ac2f201200cb656cda8a91bf6cc500d6039db6f53", + "ab3311f38e3641c8b3b1fd36dd7f94b148166e267258e840d29d1859537c74f202bd3342359b3623f96c23fa662d1b65182a898bf20343744b37cb265182e500", + "ac8f41dbd637891a08c9cf715c23577bdd431ba40231682a5a9ba7fd6cb6d66c04f63d6d65c7d9f8737e641e05fdbeede57138a174f0d55e7835575dd6cddd98", + "accdad251888d53e4e18efee1e0d749d050216b14896efb657e9c7b1b78dab82a5b6fb3234017aa19a2f50475d73960f352d308b2e0e841cbebaf418362a4f21", + "b138622208f74d2b8e8fc10bcd4cf3302685cd77d339280a939474b92be8b93e441c50709e25c82cc88a2a4207e9f2938912d60600226efe322b43c6ef5e7aef", + "b4f64e1fa6a5cd6198b2515bde63fbdabaf7e7a31dbaf5369babbda4b8cd0bf5025ac4b7d2d6e6e3bc76c890df585d28d4815e464c8792ef677df9206864a12b", + "c1136e08a27c93812ae2dd47201d9e81c82d1995001b88dba9eec700e1d3385dfaf7ae834226c3c90a138f1808cd10b5502f49ee774a2bc707f34bd7d160b7bd", + "c203ae9b5d1953b0ac462e66338800ec26982e2af54bd444fc8978973191633d4f483e31b28233c07bb99f34d57c680fa5f8e093e64f13b235005b7ab6e2d594", + "c2e1067c58a9948e773e0a3637d946e26d95762f89ec9d35e2ad84f770309d94168d4e112c78d62b60efc6216bc5d31475f24307b1b8e0fa8dcbb18a10cb85f5", + "d60ecb1a89e0d5aeff14c9a95da9f5492eb15871c53563b86b7c5ddf0da74b4c29e682fdd22aae2290e0b16ef4b6d707ef55396ca98f755c95b689cf65ce5f80", + "df5ad4ea6242929df86f2162d1cc62b0e0a6f0a03428a39dea98f6a689335b5ceaf1f0696c17b717b141aeb45a29108d95c3a7d2d1d0bb3441219504ae672917", + "e1268f5dd9552a11989df9d4953bb388e7466711b2bd9882a3ed4d0767a21f046c53c20f9a18d66bae1d6a5544492857ddecb0b5b4818bd4557be252ddd66c71", + "e626019dc0b50b9e254461f19d29e69a4669c5256134a6352c6c30d3bc55d201a5b43fc2e006556cfaf29765b683e807e03093798942826244e4ee9e47c75d3f", + ]; + let node_entries = node_ids_hex.iter() + .map(|node_id_hex| NodeId::from_str(node_id_hex).unwrap()) + .map(|node_id| NodeEntry { id: node_id, endpoint: ep.clone() }) + .collect::>(); + + let secret_hex = "6c71d1b8930d29e6371be1081f2c909c64b46440a1716314c3c9df995cb3aed1"; + let key = Secret::from_str(secret_hex) + .and_then(|secret| KeyPair::from_secret(secret)) + .unwrap(); + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + + node_entries.iter().for_each(|entry| discovery.update_node(entry.clone())); + + let expected_bucket_sizes = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7, 8, 12 + ]; + let actual_bucket_sizes = discovery.node_buckets.iter() + .map(|ref bucket| bucket.nodes.len()) + .collect::>(); + assert_eq!(actual_bucket_sizes, expected_bucket_sizes); + + for entry in &node_entries { + let nearest = discovery.nearest_node_entries(&entry.id); + assert_eq!(nearest.len(), 16); + assert_eq!(nearest[0].id, entry.id); + + let mut expected_ids: Vec = node_entries.iter().map(|entry| entry.id).collect(); + expected_ids.sort_unstable_by_key(|id| keccak(id) ^ keccak(entry.id)); + expected_ids.resize(BUCKET_SIZE, NodeId::default()); + + let actual_ids: Vec = nearest.iter().map(|entry| entry.id).collect(); + assert_eq!(actual_ids, expected_ids); + } + } + #[test] fn packets() { let key = Random.generate().unwrap(); - let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40449").unwrap(), udp_port: 40449 }; let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); discovery.check_timestamps = false; let from = SocketAddr::from_str("99.99.99.99:40445").unwrap(); -- GitLab From dab967ace8ad1f4e02c597efda8da8eac874206a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 1 Jun 2018 09:49:46 +0200 Subject: [PATCH 203/263] Remove NetworkService::config() (#8653) --- ethcore/sync/src/api.rs | 49 +++++++++++++++-------- parity/informant.rs | 5 ++- rpc/src/v1/impls/parity.rs | 5 ++- rpc/src/v1/tests/mocked/manage_network.rs | 5 ++- util/network-devp2p/src/service.rs | 28 +++++++++---- whisper/cli/src/main.rs | 2 +- 6 files changed, 62 insertions(+), 32 deletions(-) diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 2f90e410ae..9e6cdafa6e 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use std::collections::{HashMap, BTreeMap}; use std::io; +use std::ops::Range; use std::time::Duration; use bytes::Bytes; use devp2p::NetworkService; @@ -452,11 +453,18 @@ impl ChainNotify for EthSync { } fn start(&self) { - match self.network.start().map_err(Into::into) { - Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), - Err(err) => warn!("Error starting network: {}", err), + match self.network.start() { + Err((err, listen_address)) => { + match err.into() { + ErrorKind::Io(ref e) if e.kind() == io::ErrorKind::AddrInUse => { + warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", listen_address.expect("Listen address is not set.")) + }, + err => warn!("Error starting network: {}", err), + } + }, _ => {}, } + self.network.register_protocol(self.eth_handler.clone(), self.subprotocol_name, &[ETH_PROTOCOL_VERSION_62, ETH_PROTOCOL_VERSION_63]) .unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e)); // register the warp sync subprotocol @@ -520,8 +528,10 @@ pub trait ManageNetwork : Send + Sync { fn start_network(&self); /// Stop network fn stop_network(&self); - /// Query the current configuration of the network - fn network_config(&self) -> NetworkConfiguration; + /// Returns the minimum and maximum peers. + /// Note that `range.end` is *exclusive*. + // TODO: Range should be changed to RangeInclusive once stable (https://github.com/rust-lang/rust/pull/50758) + fn num_peers_range(&self) -> Range; /// Get network context for protocol. fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)); } @@ -561,8 +571,8 @@ impl ManageNetwork for EthSync { self.stop(); } - fn network_config(&self) -> NetworkConfiguration { - NetworkConfiguration::from(self.network.config().clone()) + fn num_peers_range(&self) -> Range { + self.network.num_peers_range() } fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)) { @@ -815,11 +825,15 @@ impl ManageNetwork for LightSync { } fn start_network(&self) { - match self.network.start().map_err(Into::into) { - Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => { - warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")) - } - Err(err) => warn!("Error starting network: {}", err), + match self.network.start() { + Err((err, listen_address)) => { + match err.into() { + ErrorKind::Io(ref e) if e.kind() == io::ErrorKind::AddrInUse => { + warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", listen_address.expect("Listen address is not set.")) + }, + err => warn!("Error starting network: {}", err), + } + }, _ => {}, } @@ -836,8 +850,8 @@ impl ManageNetwork for LightSync { self.network.stop(); } - fn network_config(&self) -> NetworkConfiguration { - NetworkConfiguration::from(self.network.config().clone()) + fn num_peers_range(&self) -> Range { + self.network.num_peers_range() } fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)) { @@ -848,12 +862,13 @@ impl ManageNetwork for LightSync { impl LightSyncProvider for LightSync { fn peer_numbers(&self) -> PeerNumbers { let (connected, active) = self.proto.peer_count(); - let config = self.network_config(); + let peers_range = self.num_peers_range(); + debug_assert!(peers_range.end > peers_range.start); PeerNumbers { connected: connected, active: active, - max: config.max_peers as usize, - min: config.min_peers as usize, + max: peers_range.end as usize - 1, + min: peers_range.start as usize, } } diff --git a/parity/informant.rs b/parity/informant.rs index e2f3960b67..43788bc9d9 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -145,7 +145,8 @@ impl InformantData for FullNodeInformantData { let (importing, sync_info) = match (self.sync.as_ref(), self.net.as_ref()) { (Some(sync), Some(net)) => { let status = sync.status(); - let net_config = net.network_config(); + let num_peers_range = net.num_peers_range(); + debug_assert!(num_peers_range.end > num_peers_range.start); cache_sizes.insert("sync", status.mem_used); @@ -154,7 +155,7 @@ impl InformantData for FullNodeInformantData { last_imported_block_number: status.last_imported_block_number.unwrap_or(chain_info.best_block_number), last_imported_old_block_number: status.last_imported_old_block_number, num_peers: status.num_peers, - max_peers: status.current_max_peers(net_config.min_peers, net_config.max_peers), + max_peers: status.current_max_peers(num_peers_range.start, num_peers_range.end - 1), snapshot_sync: status.is_snapshot_syncing(), })) } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 08d5147202..3fa9cb991b 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -212,13 +212,14 @@ impl Parity for ParityClient where fn net_peers(&self) -> Result { let sync_status = self.sync.status(); - let net_config = self.net.network_config(); + let num_peers_range = self.net.num_peers_range(); + debug_assert!(num_peers_range.end > num_peers_range.start); let peers = self.sync.peers().into_iter().map(Into::into).collect(); Ok(Peers { active: sync_status.num_active_peers, connected: sync_status.num_peers, - max: sync_status.current_max_peers(net_config.min_peers, net_config.max_peers), + max: sync_status.current_max_peers(num_peers_range.start, num_peers_range.end - 1), peers: peers }) } diff --git a/rpc/src/v1/tests/mocked/manage_network.rs b/rpc/src/v1/tests/mocked/manage_network.rs index 3a901c8e9f..da4f1aa511 100644 --- a/rpc/src/v1/tests/mocked/manage_network.rs +++ b/rpc/src/v1/tests/mocked/manage_network.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use sync::{ManageNetwork, NetworkConfiguration}; +use std::ops::Range; +use sync::ManageNetwork; use self::ethcore_network::{ProtocolId, NetworkContext}; extern crate ethcore_network; @@ -29,6 +30,6 @@ impl ManageNetwork for TestManageNetwork { fn add_reserved_peer(&self, _peer: String) -> Result<(), String> { Ok(()) } fn start_network(&self) {} fn stop_network(&self) {} - fn network_config(&self) -> NetworkConfiguration { NetworkConfiguration::new_local() } + fn num_peers_range(&self) -> Range { 25 .. 51 } fn with_proto_context(&self, _: ProtocolId, _: &mut FnMut(&NetworkContext)) { } } diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index d8105f649c..f90c660671 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -19,6 +19,8 @@ use network::{NetworkContext, PeerId, ProtocolId, NetworkIoMessage}; use host::Host; use io::*; use parking_lot::RwLock; +use std::net::SocketAddr; +use std::ops::Range; use std::sync::Arc; use ansi_term::Colour; use network::ConnectionFilter; @@ -92,9 +94,13 @@ impl NetworkService { &self.io_service } - /// Returns network configuration. - pub fn config(&self) -> &NetworkConfiguration { - &self.config + /// Returns the number of peers allowed. + /// + /// Keep in mind that `range.end` is *exclusive*. + pub fn num_peers_range(&self) -> Range { + let start = self.config.min_peers; + let end = self.config.max_peers + 1; + start .. end } /// Returns external url if available. @@ -109,17 +115,23 @@ impl NetworkService { host.as_ref().map(|h| h.local_url()) } - /// Start network IO - pub fn start(&self) -> Result<(), Error> { + /// Start network IO. + /// + /// In case of error, also returns the listening address for better error reporting. + pub fn start(&self) -> Result<(), (Error, Option)> { let mut host = self.host.write(); + let listen_addr = self.config.listen_address.clone(); if host.is_none() { - let h = Arc::new(Host::new(self.config.clone(), self.filter.clone())?); - self.io_service.register_handler(h.clone())?; + let h = Arc::new(Host::new(self.config.clone(), self.filter.clone()) + .map_err(|err| (err.into(), listen_addr))?); + self.io_service.register_handler(h.clone()) + .map_err(|err| (err.into(), listen_addr))?; *host = Some(h); } if self.host_handler.public_url.read().is_none() { - self.io_service.register_handler(self.host_handler.clone())?; + self.io_service.register_handler(self.host_handler.clone()) + .map_err(|err| (err.into(), listen_addr))?; } Ok(()) diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index d76c216be4..6f3aec8594 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -218,7 +218,7 @@ fn execute(command: I) -> Result<(), Error> where I: IntoIterator, let network = devp2p::NetworkService::new(net::NetworkConfiguration::new_local(), None)?; // Start network service - network.start()?; + network.start().map_err(|(err, _)| err)?; // Attach whisper protocol to the network service network.register_protocol(whisper_network_handler.clone(), whisper::net::PROTOCOL_ID, -- GitLab From 27f3f42ce268612083cde19ca8acbbfd54cd8b8e Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Fri, 1 Jun 2018 09:52:30 +0200 Subject: [PATCH 204/263] CI: Fixes for Android Pipeline (#8745) * ci: Remove check for shared libraries in gitlab script * ci: allow android arm build to fail --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 95a7ebcb5e..c615be99ce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -190,9 +190,9 @@ android-armv7: - triggers script: - cargo build --target=armv7-linux-androideabi - - if [ $(arm-linux-androideabi-objdump -x ./target/armv7-linux-androideabi/debug/parity | grep -i 'c++_shared' | wc -l) -ne 0]; then echo "FAIL!!" fi tags: - rust-arm + allow_failure: true artifacts: paths: - parity.zip -- GitLab From 0ebcc200c365a2923fa3e91d4807756ce0be46fc Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 1 Jun 2018 13:37:43 +0200 Subject: [PATCH 205/263] Custom Error Messages on ENFILE and EMFILE IO Errors (#8744) * Custom Error Messages on ENFILE and EMFILE IO Errors Add custom mapping of ENFILE and EMFILE IO Errors (Failure because of missing system resource) right when chaining ioError into ::util::Network::Error to improve Error Messages given to user Note: Adds libc as a dependency to util/network * Use assert-matches for more readable tests * Fix Wording and consistency --- Cargo.lock | 2 ++ util/network/Cargo.toml | 5 ++++ util/network/src/error.rs | 53 ++++++++++++++++++++++++++++++++++++++- util/network/src/lib.rs | 4 +++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c8e60dce69..680b9606ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,12 +703,14 @@ dependencies = [ name = "ethcore-network" version = "1.12.0" dependencies = [ + "assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-crypto 0.1.0", "ethcore-io 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", ] diff --git a/util/network/Cargo.toml b/util/network/Cargo.toml index f7131da038..4ae699098d 100644 --- a/util/network/Cargo.toml +++ b/util/network/Cargo.toml @@ -14,4 +14,9 @@ ethereum-types = "0.3" ethkey = { path = "../../ethkey" } ipnetwork = "0.12.6" rlp = { path = "../rlp" } +libc = "0.2" snappy = { git = "https://github.com/paritytech/rust-snappy" } + + +[dev-dependencies] +assert_matches = "1.2" diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 6104486696..50bd01e9ba 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::{io, net, fmt}; +use libc::{ENFILE, EMFILE}; use io::IoError; use {rlp, ethkey, crypto, snappy}; @@ -83,7 +84,6 @@ impl fmt::Display for DisconnectReason { error_chain! { foreign_links { SocketIo(IoError) #[doc = "Socket IO error."]; - Io(io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."]; Decompression(snappy::InvalidInput) #[doc = "Decompression error."]; } @@ -141,6 +141,34 @@ error_chain! { description("Packet is too large"), display("Packet is too large"), } + + #[doc = "Reached system resource limits for this process"] + ProcessTooManyFiles { + description("Too many open files in process."), + display("Too many open files in this process. Check your resource limits and restart parity"), + } + + #[doc = "Reached system wide resource limits"] + SystemTooManyFiles { + description("Too many open files on system."), + display("Too many open files on system. Consider closing some processes/release some file handlers or increas the system-wide resource limits and restart parity."), + } + + #[doc = "An unknown IO error occurred."] + Io(err: io::Error) { + description("IO Error"), + display("Unexpected IO error: {}", err), + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Self { + match err.raw_os_error() { + Some(ENFILE) => ErrorKind::ProcessTooManyFiles.into(), + Some(EMFILE) => ErrorKind::SystemTooManyFiles.into(), + _ => Error::from_kind(ErrorKind::Io(err)) + } } } @@ -191,3 +219,26 @@ fn test_errors() { _ => panic!("Unexpected error"), } } + +#[test] +fn test_io_errors() { + use libc::{EMFILE, ENFILE}; + + assert_matches!( + >::from( + io::Error::from_raw_os_error(ENFILE) + ).kind(), + ErrorKind::ProcessTooManyFiles); + + assert_matches!( + >::from( + io::Error::from_raw_os_error(EMFILE) + ).kind(), + ErrorKind::SystemTooManyFiles); + + assert_matches!( + >::from( + io::Error::from_raw_os_error(0) + ).kind(), + ErrorKind::Io(_)); +} diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 207a05075d..87d3ed9b0e 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -23,6 +23,10 @@ extern crate ethkey; extern crate rlp; extern crate ipnetwork; extern crate snappy; +extern crate libc; + +#[cfg(test)] #[macro_use] +extern crate assert_matches; #[macro_use] extern crate error_chain; -- GitLab From 79eb8f7ace85720da889b618ed4da35e9e73d608 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 1 Jun 2018 22:49:55 +0800 Subject: [PATCH 206/263] Remove public node settings from cli (#8758) * Remove public node related settings * Fix tests * Unwrap accounts provider in all rpc apis * Unwrap AccountProvider in all cli places * Fix rpc tests --- parity/cli/mod.rs | 14 ++++++----- parity/configuration.rs | 16 ++++--------- parity/rpc_apis.rs | 23 +++++++----------- parity/run.rs | 7 +----- rpc/src/v1/helpers/accounts.rs | 27 ---------------------- rpc/src/v1/helpers/errors.rs | 8 ------- rpc/src/v1/helpers/mod.rs | 1 - rpc/src/v1/impls/eth.rs | 7 +++--- rpc/src/v1/impls/parity.rs | 19 ++++----------- rpc/src/v1/impls/parity_accounts.rs | 7 +++--- rpc/src/v1/impls/personal.rs | 9 ++++---- rpc/src/v1/impls/private.rs | 3 +-- rpc/src/v1/impls/secretstore.rs | 7 +++--- rpc/src/v1/impls/signer.rs | 7 +++--- rpc/src/v1/impls/signing.rs | 7 +++--- rpc/src/v1/impls/signing_unsafe.rs | 7 +++--- rpc/src/v1/tests/eth.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/tests/mocked/parity.rs | 2 +- rpc/src/v1/tests/mocked/parity_accounts.rs | 2 +- rpc/src/v1/tests/mocked/personal.rs | 4 ++-- rpc/src/v1/tests/mocked/secretstore.rs | 2 +- rpc/src/v1/tests/mocked/signer.rs | 2 +- rpc/src/v1/tests/mocked/signing.rs | 2 +- 24 files changed, 57 insertions(+), 130 deletions(-) delete mode 100644 rpc/src/v1/helpers/accounts.rs diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index fea060d593..facd01dbfb 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -240,10 +240,6 @@ usage! { { // Global flags and arguments ["Operating Options"] - FLAG flag_public_node: (bool) = false, or |c: &Config| c.parity.as_ref()?.public_node.clone(), - "--public-node", - "Start Parity as a public web server. Account storage and transaction signing will be delegated to the UI.", - FLAG flag_no_download: (bool) = false, or |c: &Config| c.parity.as_ref()?.no_download.clone(), "--no-download", "Normally new releases will be downloaded ready for updating. This disables it. Not recommended.", @@ -948,6 +944,10 @@ usage! { "--rpc", "Does nothing; JSON-RPC is on by default now.", + FLAG flag_public_node: (bool) = false, or |_| None, + "--public-node", + "Does nothing; Public node is removed from Parity.", + ARG arg_dapps_port: (Option) = None, or |c: &Config| c.dapps.as_ref()?.port.clone(), "--dapps-port=[PORT]", "Dapps server is merged with RPC server. Use --jsonrpc-port.", @@ -1070,7 +1070,6 @@ struct Operating { auto_update_delay: Option, auto_update_check_frequency: Option, release_track: Option, - public_node: Option, no_download: Option, no_consensus: Option, chain: Option, @@ -1081,6 +1080,9 @@ struct Operating { light: Option, no_persistent_txqueue: Option, no_hardcoded_sync: Option, + + #[serde(rename="public_node")] + _legacy_public_node: Option, } #[derive(Default, Debug, PartialEq, Deserialize)] @@ -1797,7 +1799,6 @@ mod tests { auto_update_delay: None, auto_update_check_frequency: None, release_track: None, - public_node: None, no_download: None, no_consensus: None, chain: Some("./chain.json".into()), @@ -1808,6 +1809,7 @@ mod tests { light: None, no_hardcoded_sync: None, no_persistent_txqueue: None, + _legacy_public_node: None, }), account: Some(Account { unlock: Some(vec!["0x1".into(), "0x2".into(), "0x3".into()]), diff --git a/parity/configuration.rs b/parity/configuration.rs index 6bec636e2c..426b651015 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -35,7 +35,6 @@ use ethcore::verification::queue::VerifierSettings; use miner::pool; use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}; -use rpc_apis::ApiSet; use parity_rpc::NetworkSettings; use cache::CacheConfig; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files}; @@ -138,7 +137,6 @@ impl Configuration { let fat_db = self.args.arg_fat_db.parse()?; let compaction = self.args.arg_db_compaction.parse()?; let wal = !self.args.flag_fast_and_loose; - let public_node = self.args.flag_public_node; let warp_sync = !self.args.flag_no_warp; let geth_compatibility = self.args.flag_geth; let dapps_conf = self.dapps_config(); @@ -379,7 +377,6 @@ impl Configuration { vm_type: vm_type, warp_sync: warp_sync, warp_barrier: self.args.arg_warp_barrier, - public_node: public_node, geth_compatibility: geth_compatibility, net_settings: self.network_settings()?, dapps_conf: dapps_conf, @@ -914,10 +911,7 @@ impl Configuration { enabled: self.rpc_enabled(), interface: self.rpc_interface(), port: self.args.arg_ports_shift + self.args.arg_rpcport.unwrap_or(self.args.arg_jsonrpc_port), - apis: match self.args.flag_public_node { - false => self.rpc_apis().parse()?, - true => self.rpc_apis().parse::()?.retain(ApiSet::PublicContext), - }, + apis: self.rpc_apis().parse()?, hosts: self.rpc_hosts(), cors: self.rpc_cors(), server_threads: match self.args.arg_jsonrpc_server_threads { @@ -935,10 +929,8 @@ impl Configuration { let http = self.http_config()?; let support_token_api = - // never enabled for public node - !self.args.flag_public_node - // enabled when not unlocking unless the ui is forced - && (self.args.arg_unlock.is_none() || ui.enabled); + // enabled when not unlocking + self.args.arg_unlock.is_none(); let conf = WsConfiguration { enabled: self.ws_enabled(), @@ -1263,6 +1255,7 @@ mod tests { use params::SpecType; use presale::ImportWallet; use rpc::{WsConfiguration, UiConfiguration}; + use rpc_apis::ApiSet; use run::RunCmd; use network::{AllowIP, IpFilter}; @@ -1499,7 +1492,6 @@ mod tests { ipc_conf: Default::default(), net_conf: default_network_config(), network_id: None, - public_node: false, warp_sync: true, warp_barrier: None, acc_conf: Default::default(), diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 7b914f2860..855f917b13 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -116,8 +116,6 @@ pub enum ApiSet { SafeContext, // Unsafe context (like jsonrpc over http) UnsafeContext, - // Public context (like public jsonrpc over http) - PublicContext, // All possible APIs All, // Local "unsafe" context and accounts access @@ -219,7 +217,7 @@ pub struct FullDependencies { pub snapshot: Arc, pub sync: Arc, pub net: Arc, - pub secret_store: Option>, + pub secret_store: Arc, pub private_tx_service: Option>, pub miner: Arc, pub external_miner: Arc, @@ -316,7 +314,7 @@ impl FullDependencies { } }, Api::Personal => { - handler.extend_with(PersonalClient::new(self.secret_store.clone(), dispatcher.clone(), self.geth_compatibility).to_delegate()); + handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility).to_delegate()); }, Api::Signer => { handler.extend_with(SignerClient::new(&self.secret_store, dispatcher.clone(), &self.signer_service, self.remote.clone()).to_delegate()); @@ -475,7 +473,7 @@ impl LightDependencies { { let deps = &$deps; let dispatcher = dispatcher.clone(); - let secret_store = Some(deps.secret_store.clone()); + let secret_store = deps.secret_store.clone(); if deps.signer_service.is_enabled() { $handler.extend_with($namespace::to_delegate( SigningQueueClient::new(&deps.signer_service, dispatcher, deps.remote.clone(), &secret_store) @@ -533,12 +531,10 @@ impl LightDependencies { handler.extend_with(EthPubSub::to_delegate(client)); }, Api::Personal => { - let secret_store = Some(self.secret_store.clone()); - handler.extend_with(PersonalClient::new(secret_store, dispatcher.clone(), self.geth_compatibility).to_delegate()); + handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility).to_delegate()); }, Api::Signer => { - let secret_store = Some(self.secret_store.clone()); - handler.extend_with(SignerClient::new(&secret_store, dispatcher.clone(), &self.signer_service, self.remote.clone()).to_delegate()); + handler.extend_with(SignerClient::new(&self.secret_store, dispatcher.clone(), &self.signer_service, self.remote.clone()).to_delegate()); }, Api::Parity => { let signer = match self.signer_service.is_enabled() { @@ -571,8 +567,7 @@ impl LightDependencies { } }, Api::ParityAccounts => { - let secret_store = Some(self.secret_store.clone()); - handler.extend_with(ParityAccountsClient::new(&secret_store).to_delegate()); + handler.extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate()); }, Api::ParitySet => { handler.extend_with(light::ParitySetClient::new( @@ -590,8 +585,7 @@ impl LightDependencies { handler.extend_with(RpcClient::new(modules).to_delegate()); }, Api::SecretStore => { - let secret_store = Some(self.secret_store.clone()); - handler.extend_with(SecretStoreClient::new(&secret_store).to_delegate()); + handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate()); }, Api::Whisper => { if let Some(ref whisper_rpc) = self.whisper_rpc { @@ -637,7 +631,7 @@ impl ApiSet { } pub fn list_apis(&self) -> HashSet { - let mut public_list = [ + let mut public_list: HashSet = [ Api::Web3, Api::Net, Api::Eth, @@ -651,7 +645,6 @@ impl ApiSet { match *self { ApiSet::List(ref apis) => apis.clone(), - ApiSet::PublicContext => public_list, ApiSet::UnsafeContext => { public_list.insert(Api::Traces); public_list.insert(Api::ParityPubSub); diff --git a/parity/run.rs b/parity/run.rs index 31f8779c0f..bd8d4fb4a8 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -98,7 +98,6 @@ pub struct RunCmd { pub network_id: Option, pub warp_sync: bool, pub warp_barrier: Option, - pub public_node: bool, pub acc_conf: AccountsConfig, pub gas_pricer_conf: GasPricerConfig, pub miner_extras: MinerExtras, @@ -721,11 +720,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // set up dependencies for rpc servers let rpc_stats = Arc::new(informant::RpcStats::default()); - let secret_store = match cmd.public_node { - true => None, - false => Some(account_provider.clone()) - }; - + let secret_store = account_provider.clone(); let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.logger_config)); // the dapps server diff --git a/rpc/src/v1/helpers/accounts.rs b/rpc/src/v1/helpers/accounts.rs deleted file mode 100644 index 9706039355..0000000000 --- a/rpc/src/v1/helpers/accounts.rs +++ /dev/null @@ -1,27 +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 . - -use std::sync::Arc; -use ethcore::account_provider::AccountProvider; -use jsonrpc_core::Error; -use v1::helpers::errors; - -pub fn unwrap_provider(provider: &Option>) -> Result, Error> { - match *provider { - Some(ref arc) => Ok(arc.clone()), - None => Err(errors::public_unsupported(None)), - } -} diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index c85beef7d5..0d36a926e9 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -68,14 +68,6 @@ pub fn light_unimplemented(details: Option) -> Error { } } -pub fn public_unsupported(details: Option) -> Error { - Error { - code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), - message: "Method disallowed when running parity as a public node.".into(), - data: details.map(Value::String), - } -} - pub fn unsupported>(msg: T, details: Option) -> Error { Error { code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index 7cd4e6f60a..9adb5d68d4 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -17,7 +17,6 @@ #[macro_use] pub mod errors; -pub mod accounts; pub mod block_import; pub mod dapps; pub mod dispatch; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index ae8d611c12..32ba36deb8 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -45,7 +45,6 @@ use jsonrpc_macros::Trailing; use v1::helpers::{errors, limit_logs, fake_sign}; use v1::helpers::dispatch::{FullDispatcher, default_gas_price}; use v1::helpers::block_import::is_major_importing; -use v1::helpers::accounts::unwrap_provider; use v1::traits::Eth; use v1::types::{ RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, @@ -100,7 +99,7 @@ pub struct EthClient where client: Arc, snapshot: Arc, sync: Arc, - accounts: Option>, + accounts: Arc, miner: Arc, external_miner: Arc, seed_compute: Mutex, @@ -153,7 +152,7 @@ impl EthClient, snapshot: &Arc, sync: &Arc, - accounts: &Option>, + accounts: &Arc, miner: &Arc, em: &Arc, options: EthClientOptions @@ -174,7 +173,7 @@ impl EthClient`, errors if provider was not /// set. fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } fn rich_block(&self, id: BlockNumberOrId, include_txs: bool) -> Result> { diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 3fa9cb991b..f5d4a58949 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -40,7 +40,6 @@ use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_core::futures::{future, Future}; use jsonrpc_macros::Trailing; use v1::helpers::{self, errors, fake_sign, ipfs, SigningQueue, SignerService, NetworkSettings}; -use v1::helpers::accounts::unwrap_provider; use v1::metadata::Metadata; use v1::traits::Parity; use v1::types::{ @@ -62,7 +61,7 @@ pub struct ParityClient { sync: Arc, net: Arc, health: NodeHealth, - accounts: Option>, + accounts: Arc, logger: Arc, settings: Arc, signer: Option>, @@ -82,7 +81,7 @@ impl ParityClient where updater: Arc, net: Arc, health: NodeHealth, - accounts: Option>, + accounts: Arc, logger: Arc, settings: Arc, signer: Option>, @@ -110,7 +109,7 @@ impl ParityClient where /// Attempt to get the `Arc`, errors if provider was not /// set. fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } } @@ -349,11 +348,6 @@ impl Parity for ParityClient where } fn local_transactions(&self) -> Result> { - // Return nothing if accounts are disabled (running as public node) - if self.accounts.is_none() { - return Ok(BTreeMap::new()); - } - let transactions = self.miner.local_transactions(); let block_number = self.client.chain_info().best_block_number; Ok(transactions @@ -418,13 +412,8 @@ impl Parity for ParityClient where fn node_kind(&self) -> Result<::v1::types::NodeKind> { use ::v1::types::{NodeKind, Availability, Capability}; - let availability = match self.accounts { - Some(_) => Availability::Personal, - None => Availability::Public - }; - Ok(NodeKind { - availability: availability, + availability: Availability::Personal, capability: Capability::Full, }) } diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index 8de8fea900..adb97db28d 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -25,18 +25,17 @@ use ethcore::account_provider::AccountProvider; use jsonrpc_core::Result; use v1::helpers::errors; -use v1::helpers::accounts::unwrap_provider; use v1::traits::ParityAccounts; use v1::types::{H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, DappId, Derive, DeriveHierarchical, DeriveHash, ExtAccountInfo}; /// Account management (personal) rpc implementation. pub struct ParityAccountsClient { - accounts: Option>, + accounts: Arc, } impl ParityAccountsClient { /// Creates new PersonalClient - pub fn new(store: &Option>) -> Self { + pub fn new(store: &Arc) -> Self { ParityAccountsClient { accounts: store.clone(), } @@ -45,7 +44,7 @@ impl ParityAccountsClient { /// Attempt to get the `Arc`, errors if provider was not /// set. fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 03495fd37f..da5ef983a2 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -28,7 +28,6 @@ use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_core::futures::{future, Future}; use v1::helpers::errors; use v1::helpers::dispatch::{self, eth_data_hash, Dispatcher, SignWith}; -use v1::helpers::accounts::unwrap_provider; use v1::traits::Personal; use v1::types::{ H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U128 as RpcU128, @@ -42,23 +41,23 @@ use v1::metadata::Metadata; /// Account management (personal) rpc implementation. pub struct PersonalClient { - accounts: Option>, + accounts: Arc, dispatcher: D, allow_perm_unlock: bool, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(accounts: Option>, dispatcher: D, allow_perm_unlock: bool) -> Self { + pub fn new(accounts: &Arc, dispatcher: D, allow_perm_unlock: bool) -> Self { PersonalClient { - accounts, + accounts: accounts.clone(), dispatcher, allow_perm_unlock, } } fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } } diff --git a/rpc/src/v1/impls/private.rs b/rpc/src/v1/impls/private.rs index ab5866e4a7..4034d2b9a1 100644 --- a/rpc/src/v1/impls/private.rs +++ b/rpc/src/v1/impls/private.rs @@ -47,7 +47,7 @@ impl PrivateClient { fn unwrap_manager(&self) -> Result<&PrivateTransactionManager, Error> { match self.private { Some(ref arc) => Ok(&**arc), - None => Err(errors::public_unsupported(None)), + None => Err(errors::light_unimplemented(None)), } } } @@ -119,4 +119,3 @@ impl Private for PrivateClient { Ok(key.into()) } } - diff --git a/rpc/src/v1/impls/secretstore.rs b/rpc/src/v1/impls/secretstore.rs index 5a60192e8a..f85fa6f584 100644 --- a/rpc/src/v1/impls/secretstore.rs +++ b/rpc/src/v1/impls/secretstore.rs @@ -25,7 +25,6 @@ use ethcore::account_provider::AccountProvider; use jsonrpc_core::Result; use v1::helpers::errors; -use v1::helpers::accounts::unwrap_provider; use v1::helpers::secretstore::{generate_document_key, encrypt_document, decrypt_document, decrypt_document_with_shadow, ordered_servers_keccak}; use v1::traits::SecretStore; @@ -33,12 +32,12 @@ use v1::types::{H160, H256, H512, Bytes, EncryptedDocumentKey}; /// Parity implementation. pub struct SecretStoreClient { - accounts: Option>, + accounts: Arc, } impl SecretStoreClient { /// Creates new SecretStoreClient - pub fn new(store: &Option>) -> Self { + pub fn new(store: &Arc) -> Self { SecretStoreClient { accounts: store.clone(), } @@ -47,7 +46,7 @@ impl SecretStoreClient { /// Attempt to get the `Arc`, errors if provider was not /// set. fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } /// Decrypt public key using account' private key diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index 2e8d41c4ac..eafa07ad4d 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -30,7 +30,6 @@ use jsonrpc_core::futures::{future, Future, IntoFuture}; use jsonrpc_core::futures::future::Either; use jsonrpc_pubsub::SubscriptionId; use jsonrpc_macros::pubsub::{Sink, Subscriber}; -use v1::helpers::accounts::unwrap_provider; use v1::helpers::dispatch::{self, Dispatcher, WithToken, eth_data_hash}; use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload, FilledTransactionRequest, Subscribers}; use v1::metadata::Metadata; @@ -40,7 +39,7 @@ use v1::types::{TransactionModification, ConfirmationRequest, ConfirmationRespon /// Transactions confirmation (personal) rpc implementation. pub struct SignerClient { signer: Arc, - accounts: Option>, + accounts: Arc, dispatcher: D, subscribers: Arc>>>>, } @@ -48,7 +47,7 @@ pub struct SignerClient { impl SignerClient { /// Create new instance of signer client. pub fn new( - store: &Option>, + store: &Arc, dispatcher: D, signer: &Arc, remote: Remote, @@ -79,7 +78,7 @@ impl SignerClient { } fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } fn confirm_internal(&self, id: U256, modification: TransactionModification, f: F) -> BoxFuture> where diff --git a/rpc/src/v1/impls/signing.rs b/rpc/src/v1/impls/signing.rs index d8a27e9526..71cf18a06b 100644 --- a/rpc/src/v1/impls/signing.rs +++ b/rpc/src/v1/impls/signing.rs @@ -32,7 +32,6 @@ use v1::helpers::{ ConfirmationResult as RpcConfirmationResult, }; use v1::helpers::dispatch::{self, Dispatcher}; -use v1::helpers::accounts::unwrap_provider; use v1::metadata::Metadata; use v1::traits::{EthSigning, ParitySigning}; use v1::types::{ @@ -90,7 +89,7 @@ fn schedule(remote: Remote, /// Implementation of functions that require signing when no trusted signer is used. pub struct SigningQueueClient { signer: Arc, - accounts: Option>, + accounts: Arc, dispatcher: D, remote: Remote, // None here means that the request hasn't yet been confirmed @@ -99,7 +98,7 @@ pub struct SigningQueueClient { impl SigningQueueClient { /// Creates a new signing queue client given shared signing queue. - pub fn new(signer: &Arc, dispatcher: D, remote: Remote, accounts: &Option>) -> Self { + pub fn new(signer: &Arc, dispatcher: D, remote: Remote, accounts: &Arc) -> Self { SigningQueueClient { signer: signer.clone(), accounts: accounts.clone(), @@ -110,7 +109,7 @@ impl SigningQueueClient { } fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount, origin: Origin) -> BoxFuture { diff --git a/rpc/src/v1/impls/signing_unsafe.rs b/rpc/src/v1/impls/signing_unsafe.rs index ddac36a61e..75f5f5e2bf 100644 --- a/rpc/src/v1/impls/signing_unsafe.rs +++ b/rpc/src/v1/impls/signing_unsafe.rs @@ -24,7 +24,6 @@ use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_core::futures::{future, Future}; use v1::helpers::{errors, DefaultAccount}; use v1::helpers::dispatch::{self, Dispatcher}; -use v1::helpers::accounts::unwrap_provider; use v1::metadata::Metadata; use v1::traits::{EthSigning, ParitySigning}; use v1::types::{ @@ -39,13 +38,13 @@ use v1::types::{ /// Implementation of functions that require signing when no trusted signer is used. pub struct SigningUnsafeClient { - accounts: Option>, + accounts: Arc, dispatcher: D, } impl SigningUnsafeClient { /// Creates new SigningUnsafeClient. - pub fn new(accounts: &Option>, dispatcher: D) -> Self { + pub fn new(accounts: &Arc, dispatcher: D) -> Self { SigningUnsafeClient { accounts: accounts.clone(), dispatcher: dispatcher, @@ -53,7 +52,7 @@ impl SigningUnsafeClient { } fn account_provider(&self) -> Result> { - unwrap_provider(&self.accounts) + Ok(self.accounts.clone()) } fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> BoxFuture { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 26117471ce..e0931ae6bf 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -101,7 +101,7 @@ impl EthTester { fn from_spec(spec: Spec) -> Self { let account_provider = account_provider(); - let opt_account_provider = Some(account_provider.clone()); + let opt_account_provider = account_provider.clone(); let miner_service = miner_service(&spec, account_provider.clone()); let snapshot_service = snapshot_service(); diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 39a2e842db..a6c8772439 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -86,7 +86,7 @@ impl EthTester { let client = blockchain_client(); let sync = sync_provider(); let ap = accounts_provider(); - let opt_ap = Some(ap.clone()); + let opt_ap = ap.clone(); let miner = miner_service(); let snapshot = snapshot_service(); let hashrates = Arc::new(Mutex::new(HashMap::new())); diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 5835e2e82c..c27615a589 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -81,7 +81,7 @@ impl Dependencies { } pub fn client(&self, signer: Option>) -> TestParityClient { - let opt_accounts = Some(self.accounts.clone()); + let opt_accounts = self.accounts.clone(); ParityClient::new( self.client.clone(), diff --git a/rpc/src/v1/tests/mocked/parity_accounts.rs b/rpc/src/v1/tests/mocked/parity_accounts.rs index 258310b85a..c30b4b9ced 100644 --- a/rpc/src/v1/tests/mocked/parity_accounts.rs +++ b/rpc/src/v1/tests/mocked/parity_accounts.rs @@ -40,7 +40,7 @@ fn accounts_provider_with_vaults_support(temp_path: &str) -> Arc) -> ParityAccountsTester { - let opt_ap = Some(accounts_provider.clone()); + let opt_ap = accounts_provider.clone(); let parity_accounts = ParityAccountsClient::new(&opt_ap); let mut io = IoHandler::default(); io.extend_with(parity_accounts.to_delegate()); diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index c11aca42fb..323f9fe137 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -52,13 +52,13 @@ fn miner_service() -> Arc { fn setup() -> PersonalTester { let accounts = accounts_provider(); - let opt_accounts = Some(accounts.clone()); + let opt_accounts = accounts.clone(); let client = blockchain_client(); let miner = miner_service(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); let dispatcher = FullDispatcher::new(client, miner.clone(), reservations, 50); - let personal = PersonalClient::new(opt_accounts, dispatcher, false); + let personal = PersonalClient::new(&opt_accounts, dispatcher, false); let mut io = IoHandler::default(); io.extend_with(personal.to_delegate()); diff --git a/rpc/src/v1/tests/mocked/secretstore.rs b/rpc/src/v1/tests/mocked/secretstore.rs index d3ab781bcf..6ee9b6c245 100644 --- a/rpc/src/v1/tests/mocked/secretstore.rs +++ b/rpc/src/v1/tests/mocked/secretstore.rs @@ -40,7 +40,7 @@ impl Dependencies { } pub fn client(&self) -> SecretStoreClient { - SecretStoreClient::new(&Some(self.accounts.clone())) + SecretStoreClient::new(&self.accounts) } fn default_client(&self) -> IoHandler { diff --git a/rpc/src/v1/tests/mocked/signer.rs b/rpc/src/v1/tests/mocked/signer.rs index bee28b35ec..8881dc41c3 100644 --- a/rpc/src/v1/tests/mocked/signer.rs +++ b/rpc/src/v1/tests/mocked/signer.rs @@ -58,7 +58,7 @@ fn miner_service() -> Arc { fn signer_tester() -> SignerTester { let signer = Arc::new(SignerService::new_test(false)); let accounts = accounts_provider(); - let opt_accounts = Some(accounts.clone()); + let opt_accounts = accounts.clone(); let client = blockchain_client(); let miner = miner_service(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 3a56c5a0d3..84cf2e376e 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -56,7 +56,7 @@ impl Default for SigningTester { let client = Arc::new(TestBlockChainClient::default()); let miner = Arc::new(TestMinerService::default()); let accounts = Arc::new(AccountProvider::transient_provider()); - let opt_accounts = Some(accounts.clone()); + let opt_accounts = accounts.clone(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); let mut io = IoHandler::default(); -- GitLab From 2060ea5de388f7b3b515ba5c2d58425585a8ac1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Sat, 2 Jun 2018 09:29:44 +0100 Subject: [PATCH 207/263] ethcore-sync: fix connection to peers behind chain fork block (#8710) --- ethcore/sync/src/chain/handler.rs | 43 ++++++++++++++----------------- ethcore/sync/src/chain/mod.rs | 2 ++ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index 7668a64594..75111a4d4a 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -332,14 +332,6 @@ impl SyncHandler { Ok(()) } - fn on_peer_confirmed(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId) { - { - let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); - peer.confirmation = ForkConfirmation::Confirmed; - } - sync.sync_peer(io, peer_id, false); - } - fn on_peer_fork_header(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), PacketDecodeError> { { let peer = sync.peers.get_mut(&peer_id).expect("Is only called when peer is present in peers"); @@ -349,24 +341,27 @@ impl SyncHandler { if item_count == 0 || item_count != 1 { trace!(target: "sync", "{}: Chain is too short to confirm the block", peer_id); - io.disable_peer(peer_id); - return Ok(()); - } + peer.confirmation = ForkConfirmation::TooShort; - let header = r.at(0)?.as_raw(); - if keccak(&header) != fork_hash { - trace!(target: "sync", "{}: Fork mismatch", peer_id); - io.disable_peer(peer_id); - return Ok(()); - } + } else { + let header = r.at(0)?.as_raw(); + if keccak(&header) != fork_hash { + trace!(target: "sync", "{}: Fork mismatch", peer_id); + io.disable_peer(peer_id); + return Ok(()); + } + + trace!(target: "sync", "{}: Confirmed peer", peer_id); + peer.confirmation = ForkConfirmation::Confirmed; - trace!(target: "sync", "{}: Confirmed peer", peer_id); - if !io.chain_overlay().read().contains_key(&fork_number) { - trace!(target: "sync", "Inserting (fork) block {} header", fork_number); - io.chain_overlay().write().insert(fork_number, header.to_vec()); + if !io.chain_overlay().read().contains_key(&fork_number) { + trace!(target: "sync", "Inserting (fork) block {} header", fork_number); + io.chain_overlay().write().insert(fork_number, header.to_vec()); + } } } - SyncHandler::on_peer_confirmed(sync, io, peer_id); + + sync.sync_peer(io, peer_id, false); return Ok(()); } @@ -686,7 +681,9 @@ impl SyncHandler { SyncRequester::request_fork_header(sync, io, peer_id, fork_block); }, _ => { - SyncHandler::on_peer_confirmed(sync, io, peer_id); + // when there's no `fork_block` defined we initialize the peer with + // `confirmation: ForkConfirmation::Confirmed`. + sync.sync_peer(io, peer_id, false); } } diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 5af2892549..c0ee8299b8 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -294,6 +294,8 @@ pub enum BlockSet { pub enum ForkConfirmation { /// Fork block confirmation pending. Unconfirmed, + /// Peer's chain is too short to confirm the fork. + TooShort, /// Fork is confirmed. Confirmed, } -- GitLab From 3d76417353a0dfe24517815fedb0ad646e6a3add Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 2 Jun 2018 11:05:11 +0200 Subject: [PATCH 208/263] Remove HostTrait altogether (#8681) --- ethcore/light/src/net/mod.rs | 4 ++-- ethcore/sync/src/api.rs | 4 ++-- util/network-devp2p/src/handshake.rs | 2 +- util/network-devp2p/src/host.rs | 6 +----- util/network-devp2p/src/lib.rs | 2 +- util/network-devp2p/src/session.rs | 2 +- util/network-devp2p/tests/tests.rs | 2 +- util/network/src/lib.rs | 7 +------ whisper/src/net/mod.rs | 10 +++------- 9 files changed, 13 insertions(+), 26 deletions(-) diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 27d5c12a5f..d8a975dc3f 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -21,7 +21,7 @@ use transaction::UnverifiedTransaction; use io::TimerToken; -use network::{HostInfo, NetworkProtocolHandler, NetworkContext, PeerId}; +use network::{NetworkProtocolHandler, NetworkContext, PeerId}; use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; use kvdb::DBValue; @@ -1082,7 +1082,7 @@ fn punish(peer: PeerId, io: &IoContext, e: Error) { } impl NetworkProtocolHandler for LightProtocol { - fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { io.register_timer(TIMEOUT, TIMEOUT_INTERVAL) .expect("Error registering sync timer."); io.register_timer(TICK_TIMEOUT, TICK_TIMEOUT_INTERVAL) diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 9e6cdafa6e..8419fccd7a 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -21,7 +21,7 @@ use std::ops::Range; use std::time::Duration; use bytes::Bytes; use devp2p::NetworkService; -use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, ProtocolId, +use network::{NetworkProtocolHandler, NetworkContext, PeerId, ProtocolId, NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, Error, ErrorKind, ConnectionFilter}; use ethereum_types::{H256, H512, U256}; @@ -371,7 +371,7 @@ struct SyncProtocolHandler { } impl NetworkProtocolHandler for SyncProtocolHandler { - fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { if io.subprotocol_name() != WARP_SYNC_PROTOCOL_ID { io.register_timer(0, Duration::from_secs(1)).expect("Error registering sync timer"); } diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index 891dd7c257..ffe0276d97 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -26,7 +26,7 @@ use node_table::NodeId; use io::{IoContext, StreamToken}; use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random}; use ethkey::crypto::{ecdh, ecies}; -use network::{Error, ErrorKind, HostInfo as HostInfoTrait}; +use network::{Error, ErrorKind}; use host::HostInfo; #[derive(PartialEq, Eq, Debug)] diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index f9180700fe..245492de80 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -39,7 +39,6 @@ use PROTOCOL_VERSION; use node_table::*; use network::{NetworkConfiguration, NetworkIoMessage, ProtocolId, PeerId, PacketId}; use network::{NonReservedPeerMode, NetworkContext as NetworkContextTrait}; -use network::HostInfo as HostInfoTrait; use network::{SessionInfo, Error, ErrorKind, DisconnectReason, NetworkProtocolHandler}; use discovery::{Discovery, TableUpdates, NodeEntry}; use ip_utils::{map_external_address, select_public_address}; @@ -223,10 +222,8 @@ impl HostInfo { pub(crate) fn secret(&self) -> &Secret { self.keys.secret() } -} -impl HostInfoTrait for HostInfo { - fn id(&self) -> &NodeId { + pub(crate) fn id(&self) -> &NodeId { self.keys.public() } } @@ -997,7 +994,6 @@ impl IoHandler for Host { let reserved = self.reserved_nodes.read(); h.initialize( &NetworkContext::new(io, *protocol, None, self.sessions.clone(), &reserved), - &*self.info.read(), ); self.handlers.write().insert(*protocol, h); let mut info = self.info.write(); diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 244997a654..12383fdbee 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -29,7 +29,7 @@ //! struct MyHandler; //! //! impl NetworkProtocolHandler for MyHandler { -//! fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { +//! fn initialize(&self, io: &NetworkContext) { //! io.register_timer(0, Duration::from_secs(1)); //! } //! diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index cd8ef56bd4..f830dcc0d7 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -28,7 +28,7 @@ use connection::{EncryptedConnection, Packet, Connection, MAX_PAYLOAD_SIZE}; use handshake::Handshake; use io::{IoContext, StreamToken}; use network::{Error, ErrorKind, DisconnectReason, SessionInfo, ProtocolId, PeerCapabilityInfo}; -use network::{SessionCapabilityInfo, HostInfo as HostInfoTrait}; +use network::SessionCapabilityInfo; use host::*; use node_table::NodeId; use snappy; diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index a1d178d654..3c2333cd10 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -70,7 +70,7 @@ impl TestProtocol { } impl NetworkProtocolHandler for TestProtocol { - fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { io.register_timer(0, Duration::from_millis(10)).unwrap(); } diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index 87d3ed9b0e..a04eb04880 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -333,17 +333,12 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { } } -pub trait HostInfo { - /// Returns public key - fn id(&self) -> &NodeId; -} - /// Network IO protocol handler. This needs to be implemented for each new subprotocol. /// All the handler function are called from within IO event loop. /// `Message` is the type for message data. pub trait NetworkProtocolHandler: Sync + Send { /// Initialize the handler - fn initialize(&self, _io: &NetworkContext, _host_info: &HostInfo) {} + fn initialize(&self, _io: &NetworkContext) {} /// Called when new network packet received. fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]); /// Called when new peer is connected. Only called when peer supports the same protocol. diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index c462baa9d7..1115b17d4f 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -23,7 +23,7 @@ use std::time::{Duration, SystemTime}; use std::sync::Arc; use ethereum_types::{H256, H512}; -use network::{self, HostInfo, NetworkContext, NodeId, PeerId, ProtocolId, TimerToken}; +use network::{self, NetworkContext, NodeId, PeerId, ProtocolId, TimerToken}; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock}; use rlp::{DecoderError, RlpStream, Rlp}; @@ -423,7 +423,6 @@ pub struct Network { messages: Arc>, handler: T, peers: RwLock>>, - node_key: RwLock, } // public API. @@ -434,7 +433,6 @@ impl Network { messages: Arc::new(RwLock::new(Messages::new(messages_size_bytes))), handler: handler, peers: RwLock::new(HashMap::new()), - node_key: RwLock::new(Default::default()), } } @@ -685,12 +683,10 @@ impl Network { } impl ::network::NetworkProtocolHandler for Network { - fn initialize(&self, io: &NetworkContext, host_info: &HostInfo) { + fn initialize(&self, io: &NetworkContext) { // set up broadcast timer (< 1s) io.register_timer(RALLY_TOKEN, RALLY_TIMEOUT) .expect("Failed to initialize message rally timer"); - - *self.node_key.write() = host_info.id().clone(); } fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { @@ -720,7 +716,7 @@ impl ::network::NetworkProtocolHandler for Network { pub struct ParityExtensions; impl ::network::NetworkProtocolHandler for ParityExtensions { - fn initialize(&self, _io: &NetworkContext, _host_info: &HostInfo) { } + fn initialize(&self, _io: &NetworkContext) { } fn read(&self, _io: &NetworkContext, _peer: &PeerId, _id: u8, _msg: &[u8]) { } -- GitLab From 98b7c07171cd320f32877dfa5aa528f585dc9a72 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Jun 2018 10:19:50 +0200 Subject: [PATCH 209/263] Update `license header` and `scripts` (#8666) * Update `add_license` script * run script * add `remove duplicate lines script` and run it * Revert changes `English spaces` * strip whitespaces * Revert `GPL` in files with `apache/mit license` * don't append `gpl license` in files with other lic * Don't append `gpl header` in files with other lic. * re-ran script * include c and cpp files too * remove duplicate header * rebase nit --- chainspec/src/main.rs | 16 +++++++++++ dapps/js-glue/build.rs | 3 +-- dapps/js-glue/src/build.rs | 15 +++++++++++ dapps/js-glue/src/codegen.rs | 2 +- dapps/js-glue/src/js.rs | 2 +- dapps/js-glue/src/lib.rs | 3 +-- dapps/js-glue/src/lib.rs.in | 7 ++--- dapps/node-health/src/health.rs | 2 +- dapps/node-health/src/lib.rs | 2 +- dapps/node-health/src/time.rs | 2 +- dapps/node-health/src/types.rs | 2 +- dapps/src/api/api.rs | 2 +- dapps/src/api/mod.rs | 2 +- dapps/src/api/response.rs | 2 +- dapps/src/api/types.rs | 2 +- dapps/src/apps/app.rs | 2 +- dapps/src/apps/cache.rs | 2 +- dapps/src/apps/fetcher/installers.rs | 2 +- dapps/src/apps/fetcher/mod.rs | 2 +- dapps/src/apps/fs.rs | 4 +-- dapps/src/apps/manifest.rs | 2 +- dapps/src/apps/mod.rs | 2 +- dapps/src/apps/ui.rs | 2 +- dapps/src/endpoint.rs | 2 +- dapps/src/handlers/content.rs | 2 +- dapps/src/handlers/echo.rs | 2 +- dapps/src/handlers/fetch.rs | 3 +-- dapps/src/handlers/mod.rs | 2 +- dapps/src/handlers/reader.rs | 2 +- dapps/src/handlers/redirect.rs | 2 +- dapps/src/handlers/streaming.rs | 2 +- dapps/src/lib.rs | 3 +-- dapps/src/page/builtin.rs | 3 +-- dapps/src/page/handler.rs | 2 +- dapps/src/page/local.rs | 3 +-- dapps/src/page/mod.rs | 4 +-- dapps/src/proxypac.rs | 4 +-- dapps/src/router.rs | 2 +- dapps/src/tests/api.rs | 3 +-- dapps/src/tests/fetch.rs | 3 +-- dapps/src/tests/helpers/fetch.rs | 2 +- dapps/src/tests/helpers/mod.rs | 3 +-- dapps/src/tests/helpers/registrar.rs | 2 +- dapps/src/tests/home.rs | 2 +- dapps/src/tests/mod.rs | 3 +-- dapps/src/tests/redirection.rs | 3 +-- dapps/src/tests/rpc.rs | 2 +- dapps/src/tests/validation.rs | 2 +- dapps/src/web.rs | 3 +-- dapps/ui/src/lib.rs | 3 +-- devtools/src/http_client.rs | 2 +- devtools/src/lib.rs | 2 +- ethash/src/cache.rs | 2 +- ethash/src/compute.rs | 2 +- ethash/src/keccak.rs | 2 +- ethash/src/lib.rs | 2 +- ethash/src/seed_compute.rs | 2 +- ethash/src/shared.rs | 2 +- ethcore/benches/evm.rs | 4 +-- ethcore/crypto/src/aes.rs | 3 +-- ethcore/crypto/src/aes_gcm.rs | 3 +-- ethcore/crypto/src/digest.rs | 2 +- ethcore/crypto/src/error.rs | 3 +-- ethcore/crypto/src/hmac.rs | 3 +-- ethcore/crypto/src/lib.rs | 3 +-- ethcore/crypto/src/pbkdf2.rs | 3 +-- ethcore/crypto/src/scrypt.rs | 3 +-- ethcore/evm/src/benches/mod.rs | 2 +- ethcore/evm/src/evm.rs | 2 +- ethcore/evm/src/factory.rs | 2 +- ethcore/evm/src/instructions.rs | 2 +- ethcore/evm/src/interpreter/gasometer.rs | 4 +-- ethcore/evm/src/interpreter/informant.rs | 2 +- ethcore/evm/src/interpreter/memory.rs | 2 +- ethcore/evm/src/interpreter/mod.rs | 4 +-- ethcore/evm/src/interpreter/shared_cache.rs | 3 +-- ethcore/evm/src/interpreter/stack.rs | 3 +-- ethcore/evm/src/lib.rs | 2 +- ethcore/evm/src/tests.rs | 2 +- ethcore/evm/src/vmtype.rs | 2 +- ethcore/light/src/cache.rs | 2 +- ethcore/light/src/cht.rs | 5 +++- ethcore/light/src/client/fetch.rs | 2 +- ethcore/light/src/client/header_chain.rs | 2 +- ethcore/light/src/client/mod.rs | 3 +-- ethcore/light/src/client/service.rs | 2 +- ethcore/light/src/lib.rs | 2 +- ethcore/light/src/net/context.rs | 5 ++-- ethcore/light/src/net/error.rs | 2 +- ethcore/light/src/net/load_timer.rs | 2 +- ethcore/light/src/net/mod.rs | 3 +-- ethcore/light/src/net/request_credits.rs | 2 +- ethcore/light/src/net/request_set.rs | 2 +- ethcore/light/src/net/status.rs | 2 +- ethcore/light/src/net/tests/mod.rs | 2 +- ethcore/light/src/on_demand/mod.rs | 2 +- ethcore/light/src/on_demand/request.rs | 3 +-- ethcore/light/src/on_demand/tests.rs | 2 +- ethcore/light/src/provider.rs | 2 +- ethcore/light/src/transaction_queue.rs | 2 +- ethcore/light/src/types/mod.rs | 2 +- ethcore/light/src/types/request/batch.rs | 2 +- ethcore/light/src/types/request/mod.rs | 4 +-- ethcore/node_filter/src/lib.rs | 3 +-- ethcore/private-tx/src/encryptor.rs | 2 +- ethcore/private-tx/src/error.rs | 3 +-- ethcore/private-tx/src/lib.rs | 2 +- ethcore/private-tx/src/messages.rs | 2 +- .../private-tx/src/private_transactions.rs | 2 +- ethcore/private-tx/tests/private_contract.rs | 2 +- ethcore/service/src/service.rs | 2 +- ethcore/src/account_db.rs | 2 +- ethcore/src/account_provider/mod.rs | 2 +- ethcore/src/account_provider/stores.rs | 2 +- ethcore/src/block.rs | 2 +- ethcore/src/blockchain/best_block.rs | 2 +- ethcore/src/blockchain/block_info.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 2 +- ethcore/src/blockchain/cache.rs | 2 +- ethcore/src/blockchain/config.rs | 2 +- ethcore/src/blockchain/extras.rs | 2 +- ethcore/src/blockchain/generator.rs | 2 +- ethcore/src/blockchain/import_route.rs | 2 +- ethcore/src/blockchain/mod.rs | 2 +- ethcore/src/blockchain/update.rs | 16 +++++++++++ ethcore/src/blooms/bloom_group.rs | 2 +- ethcore/src/blooms/group_position.rs | 2 +- ethcore/src/blooms/mod.rs | 2 +- ethcore/src/builtin.rs | 5 +--- ethcore/src/cache_manager.rs | 2 +- ethcore/src/client/ancient_import.rs | 2 +- ethcore/src/client/chain_notify.rs | 2 +- ethcore/src/client/client.rs | 6 +---- ethcore/src/client/config.rs | 3 +-- ethcore/src/client/error.rs | 2 +- ethcore/src/client/evm_test_client.rs | 2 +- ethcore/src/client/io_message.rs | 1 - ethcore/src/client/mod.rs | 2 +- ethcore/src/client/private_notify.rs | 2 +- ethcore/src/client/test_client.rs | 3 +-- ethcore/src/client/trace.rs | 15 +++++++++++ ethcore/src/client/traits.rs | 2 +- ethcore/src/db.rs | 2 +- ethcore/src/encoded.rs | 2 +- .../src/engines/authority_round/finality.rs | 2 +- ethcore/src/engines/authority_round/mod.rs | 3 +-- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/epoch.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 2 +- ethcore/src/engines/null_engine.rs | 2 +- ethcore/src/engines/signer.rs | 2 +- ethcore/src/engines/tendermint/message.rs | 3 +-- ethcore/src/engines/tendermint/mod.rs | 3 +-- ethcore/src/engines/tendermint/params.rs | 2 +- ethcore/src/engines/transition.rs | 2 +- ethcore/src/engines/validator_set/contract.rs | 2 +- ethcore/src/engines/validator_set/mod.rs | 2 +- ethcore/src/engines/validator_set/multi.rs | 2 +- .../engines/validator_set/safe_contract.rs | 2 +- .../src/engines/validator_set/simple_list.rs | 2 +- ethcore/src/engines/validator_set/test.rs | 2 +- ethcore/src/engines/vote_collector.rs | 2 +- ethcore/src/error.rs | 3 +-- ethcore/src/ethereum/denominations.rs | 3 +-- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/ethereum/mod.rs | 2 +- ethcore/src/executed.rs | 2 +- ethcore/src/executive.rs | 2 +- ethcore/src/externalities.rs | 2 +- ethcore/src/factory.rs | 2 +- ethcore/src/header.rs | 3 +-- ethcore/src/json_tests/chain.rs | 3 +-- ethcore/src/json_tests/difficulty.rs | 6 +---- ethcore/src/json_tests/executive.rs | 2 +- ethcore/src/json_tests/mod.rs | 2 +- ethcore/src/json_tests/state.rs | 3 +-- ethcore/src/json_tests/test_common.rs | 2 +- ethcore/src/json_tests/transaction.rs | 2 +- ethcore/src/json_tests/trie.rs | 2 +- ethcore/src/lib.rs | 2 +- ethcore/src/machine.rs | 3 +-- ethcore/src/miner/miner.rs | 4 +-- ethcore/src/miner/mod.rs | 4 +-- ethcore/src/miner/pool_client.rs | 2 +- .../src/miner/service_transaction_checker.rs | 4 +-- ethcore/src/miner/stratum.rs | 3 +-- ethcore/src/pod_account.rs | 3 +-- ethcore/src/pod_state.rs | 2 +- ethcore/src/snapshot/account.rs | 2 +- ethcore/src/snapshot/block.rs | 2 +- ethcore/src/snapshot/consensus/authority.rs | 2 +- ethcore/src/snapshot/consensus/mod.rs | 3 +-- ethcore/src/snapshot/consensus/work.rs | 2 +- ethcore/src/snapshot/error.rs | 2 +- ethcore/src/snapshot/io.rs | 3 +-- ethcore/src/snapshot/mod.rs | 2 +- ethcore/src/snapshot/service.rs | 2 +- ethcore/src/snapshot/tests/helpers.rs | 2 +- ethcore/src/snapshot/tests/mod.rs | 2 +- .../src/snapshot/tests/proof_of_authority.rs | 3 +-- ethcore/src/snapshot/tests/proof_of_work.rs | 2 +- ethcore/src/snapshot/tests/service.rs | 2 +- ethcore/src/snapshot/tests/state.rs | 2 +- ethcore/src/snapshot/traits.rs | 2 +- ethcore/src/snapshot/watcher.rs | 2 +- ethcore/src/spec/genesis.rs | 2 +- ethcore/src/spec/mod.rs | 2 +- ethcore/src/spec/seal.rs | 2 +- ethcore/src/spec/spec.rs | 4 +-- ethcore/src/state/account.rs | 2 +- ethcore/src/state/backend.rs | 2 +- ethcore/src/state/mod.rs | 3 +-- ethcore/src/state/substate.rs | 2 +- ethcore/src/state_db.rs | 2 +- ethcore/src/test_helpers.rs | 3 +-- ethcore/src/test_helpers_internal.rs | 2 +- ethcore/src/tests/client.rs | 4 +-- ethcore/src/tests/mod.rs | 2 +- ethcore/src/tests/trace.rs | 2 +- ethcore/src/trace/config.rs | 2 +- ethcore/src/trace/db.rs | 3 +-- ethcore/src/trace/executive_tracer.rs | 2 +- ethcore/src/trace/import.rs | 2 +- ethcore/src/trace/mod.rs | 2 +- ethcore/src/trace/noop_tracer.rs | 2 +- ethcore/src/trace/types/error.rs | 2 +- ethcore/src/trace/types/filter.rs | 2 +- ethcore/src/trace/types/flat.rs | 2 +- ethcore/src/trace/types/localized.rs | 2 +- ethcore/src/trace/types/mod.rs | 2 +- ethcore/src/trace/types/trace.rs | 3 +-- ethcore/src/tx_filter.rs | 3 +-- ethcore/src/verification/canon_verifier.rs | 2 +- ethcore/src/verification/mod.rs | 2 +- ethcore/src/verification/noop_verifier.rs | 2 +- ethcore/src/verification/queue/kind.rs | 2 +- ethcore/src/verification/queue/mod.rs | 2 +- ethcore/src/verification/verification.rs | 2 +- ethcore/src/verification/verifier.rs | 2 +- ethcore/src/views/block.rs | 2 +- ethcore/src/views/body.rs | 2 +- ethcore/src/views/header.rs | 2 +- ethcore/src/views/mod.rs | 4 +-- ethcore/src/views/transaction.rs | 2 +- ethcore/src/views/view_rlp.rs | 4 +-- ethcore/stratum/src/lib.rs | 2 +- ethcore/stratum/src/traits.rs | 2 +- ethcore/sync/src/api.rs | 3 +-- ethcore/sync/src/block_sync.rs | 2 +- ethcore/sync/src/blocks.rs | 4 +-- ethcore/sync/src/chain/mod.rs | 3 +-- ethcore/sync/src/lib.rs | 2 +- ethcore/sync/src/light_sync/mod.rs | 2 +- ethcore/sync/src/light_sync/response.rs | 2 +- ethcore/sync/src/light_sync/sync_round.rs | 2 +- ethcore/sync/src/light_sync/tests/mod.rs | 2 +- ethcore/sync/src/light_sync/tests/test_net.rs | 2 +- ethcore/sync/src/private_tx.rs | 2 +- ethcore/sync/src/snapshot.rs | 3 +-- ethcore/sync/src/sync_io.rs | 4 +-- ethcore/sync/src/tests/chain.rs | 4 +-- ethcore/sync/src/tests/consensus.rs | 2 +- ethcore/sync/src/tests/helpers.rs | 2 +- ethcore/sync/src/tests/mod.rs | 2 +- ethcore/sync/src/tests/private.rs | 2 +- ethcore/sync/src/tests/rpc.rs | 2 +- ethcore/sync/src/tests/snapshot.rs | 3 +-- ethcore/sync/src/transactions_stats.rs | 2 +- ethcore/transaction/src/error.rs | 3 +-- ethcore/transaction/src/lib.rs | 2 +- ethcore/transaction/src/transaction.rs | 2 +- ethcore/types/src/account_diff.rs | 3 +-- ethcore/types/src/basic_account.rs | 2 +- ethcore/types/src/block_status.rs | 2 +- ethcore/types/src/blockchain_info.rs | 2 +- ethcore/types/src/call_analytics.rs | 2 +- ethcore/types/src/filter.rs | 2 +- ethcore/types/src/ids.rs | 2 +- ethcore/types/src/lib.rs | 2 +- ethcore/types/src/log_entry.rs | 2 +- ethcore/types/src/mode.rs | 2 +- ethcore/types/src/pruning_info.rs | 2 +- ethcore/types/src/receipt.rs | 2 +- ethcore/types/src/restoration_status.rs | 3 +-- ethcore/types/src/security_level.rs | 2 +- ethcore/types/src/snapshot_manifest.rs | 3 +-- ethcore/types/src/state_diff.rs | 2 +- ethcore/types/src/trace_filter.rs | 2 +- ethcore/types/src/tree_route.rs | 2 +- ethcore/types/src/verification_queue_info.rs | 2 +- ethcore/vm/src/action_params.rs | 2 +- ethcore/vm/src/call_type.rs | 16 +++++++++++ ethcore/vm/src/env_info.rs | 2 +- ethcore/vm/src/error.rs | 3 +-- ethcore/vm/src/ext.rs | 2 +- ethcore/vm/src/lib.rs | 2 +- ethcore/vm/src/return_data.rs | 2 ++ ethcore/vm/src/schedule.rs | 2 +- ethcore/vm/src/tests.rs | 2 +- ethcore/wasm/run/src/fixture.rs | 18 ++++++++++++- ethcore/wasm/run/src/main.rs | 16 +++++++++++ ethcore/wasm/run/src/runner.rs | 16 +++++++++++ ethcore/wasm/src/env.rs | 4 +-- ethcore/wasm/src/lib.rs | 2 +- ethcore/wasm/src/panic_payload.rs | 2 +- ethcore/wasm/src/parser.rs | 4 +-- ethcore/wasm/src/tests.rs | 2 +- ethkey/cli/src/main.rs | 2 +- ethkey/src/brain.rs | 2 +- ethkey/src/brain_prefix.rs | 2 +- ethkey/src/brain_recover.rs | 4 +-- ethkey/src/crypto.rs | 2 +- ethkey/src/error.rs | 2 +- ethkey/src/extended.rs | 2 +- ethkey/src/keccak.rs | 2 +- ethkey/src/keypair.rs | 2 +- ethkey/src/lib.rs | 2 +- ethkey/src/math.rs | 2 +- ethkey/src/prefix.rs | 2 +- ethkey/src/random.rs | 2 +- ethkey/src/secret.rs | 2 +- ethkey/src/signature.rs | 2 +- ethstore/cli/src/crack.rs | 16 +++++++++++ ethstore/cli/src/main.rs | 2 +- ethstore/cli/tests/cli.rs | 3 +-- ethstore/src/account/cipher.rs | 2 +- ethstore/src/account/crypto.rs | 2 +- ethstore/src/account/kdf.rs | 2 +- ethstore/src/account/mod.rs | 3 +-- ethstore/src/account/safe_account.rs | 2 +- ethstore/src/account/version.rs | 2 +- ethstore/src/accounts_dir/disk.rs | 3 +-- ethstore/src/accounts_dir/memory.rs | 3 +-- ethstore/src/accounts_dir/mod.rs | 2 +- ethstore/src/accounts_dir/vault.rs | 2 +- ethstore/src/error.rs | 2 +- ethstore/src/ethkey.rs | 2 +- ethstore/src/ethstore.rs | 2 +- ethstore/src/import.rs | 2 +- ethstore/src/json/bytes.rs | 3 +-- ethstore/src/json/cipher.rs | 2 +- ethstore/src/json/crypto.rs | 2 +- ethstore/src/json/error.rs | 2 +- ethstore/src/json/hash.rs | 2 +- ethstore/src/json/id.rs | 2 +- ethstore/src/json/kdf.rs | 2 +- ethstore/src/json/key_file.rs | 3 +-- ethstore/src/json/mod.rs | 2 +- ethstore/src/json/presale.rs | 16 +++++++++++ ethstore/src/json/vault_file.rs | 2 +- ethstore/src/json/vault_key_file.rs | 2 +- ethstore/src/json/version.rs | 3 +-- ethstore/src/lib.rs | 2 +- ethstore/src/presale.rs | 16 +++++++++++ ethstore/src/random.rs | 3 +-- ethstore/src/secret_store.rs | 2 +- ethstore/tests/api.rs | 2 +- ethstore/tests/util/mod.rs | 2 +- ethstore/tests/util/transient_dir.rs | 2 +- evmbin/benches/mod.rs | 3 +-- evmbin/src/display/json.rs | 3 +-- evmbin/src/display/mod.rs | 2 +- evmbin/src/display/simple.rs | 2 +- evmbin/src/display/std_json.rs | 2 +- evmbin/src/info.rs | 2 +- evmbin/src/main.rs | 3 +-- hash-fetch/src/client.rs | 2 +- hash-fetch/src/lib.rs | 2 +- hash-fetch/src/urlhint.rs | 5 +--- hw/src/ledger.rs | 2 +- hw/src/lib.rs | 3 +-- hw/src/trezor.rs | 3 +-- ipfs/src/error.rs | 2 +- ipfs/src/lib.rs | 2 +- ipfs/src/route.rs | 2 +- json/src/blockchain/account.rs | 2 +- json/src/blockchain/block.rs | 2 +- json/src/blockchain/blockchain.rs | 2 +- json/src/blockchain/header.rs | 2 +- json/src/blockchain/mod.rs | 2 +- json/src/blockchain/state.rs | 2 +- json/src/blockchain/test.rs | 2 +- json/src/blockchain/transaction.rs | 2 +- json/src/bytes.rs | 2 +- json/src/hash.rs | 3 +-- json/src/lib.rs | 2 +- json/src/maybe.rs | 15 +++++++++++ json/src/misc/account_meta.rs | 2 +- json/src/misc/dapps_settings.rs | 2 +- json/src/misc/mod.rs | 2 +- json/src/spec/account.rs | 2 +- json/src/spec/authority_round.rs | 2 +- json/src/spec/basic_authority.rs | 2 +- json/src/spec/builtin.rs | 2 +- json/src/spec/engine.rs | 3 +-- json/src/spec/ethash.rs | 2 +- json/src/spec/genesis.rs | 2 +- json/src/spec/hardcoded_sync.rs | 2 +- json/src/spec/mod.rs | 2 +- json/src/spec/null_engine.rs | 2 +- json/src/spec/params.rs | 2 +- json/src/spec/seal.rs | 2 +- json/src/spec/spec.rs | 2 +- json/src/spec/state.rs | 2 +- json/src/spec/tendermint.rs | 2 +- json/src/spec/validator_set.rs | 2 +- json/src/state/log.rs | 2 +- json/src/state/mod.rs | 2 +- json/src/state/state.rs | 2 +- json/src/state/test.rs | 2 +- json/src/state/transaction.rs | 2 +- json/src/test/mod.rs | 3 +-- json/src/transaction/mod.rs | 2 +- json/src/transaction/test.rs | 2 +- json/src/transaction/transaction.rs | 2 +- json/src/transaction/txtest.rs | 2 +- json/src/trie/input.rs | 2 +- json/src/trie/mod.rs | 2 +- json/src/trie/test.rs | 2 +- json/src/trie/trie.rs | 2 +- json/src/uint.rs | 2 +- json/src/vm/call.rs | 2 +- json/src/vm/env.rs | 2 +- json/src/vm/mod.rs | 2 +- json/src/vm/test.rs | 2 +- json/src/vm/transaction.rs | 2 +- json/src/vm/vm.rs | 2 +- license_header | 2 +- local-store/src/lib.rs | 2 +- logger/src/lib.rs | 2 +- logger/src/rotating.rs | 3 +-- machine/src/lib.rs | 2 +- miner/src/external.rs | 3 +-- miner/src/gas_pricer.rs | 2 +- miner/src/lib.rs | 2 +- miner/src/pool/client.rs | 2 +- miner/src/pool/listener.rs | 4 +-- miner/src/pool/local_transactions.rs | 3 +-- miner/src/pool/mod.rs | 2 +- miner/src/pool/queue.rs | 3 +-- miner/src/pool/ready.rs | 3 +-- miner/src/pool/scoring.rs | 2 +- miner/src/pool/tests/client.rs | 2 +- miner/src/pool/tests/mod.rs | 4 +-- miner/src/pool/tests/tx.rs | 3 +-- miner/src/pool/verifier.rs | 3 +-- miner/src/work_notify.rs | 2 +- parity-clib-example/main.cpp | 16 +++++++++++ parity-clib/src/lib.rs | 2 +- parity/account.rs | 2 +- parity/blockchain.rs | 2 +- parity/cache.rs | 2 +- parity/cli/presets/mod.rs | 4 +-- parity/cli/usage.rs | 2 +- parity/configuration.rs | 3 +-- parity/dapps.rs | 2 +- parity/db/rocksdb/migration.rs | 3 +-- parity/deprecated.rs | 3 +-- parity/export_hardcoded_sync.rs | 2 +- parity/helpers.rs | 2 +- parity/ipfs.rs | 2 +- parity/light_helpers/epoch_fetch.rs | 2 +- parity/light_helpers/mod.rs | 2 +- parity/light_helpers/queue_cull.rs | 2 +- parity/modules.rs | 2 +- parity/params.rs | 2 +- parity/presale.rs | 2 +- parity/rpc.rs | 3 +-- parity/rpc_apis.rs | 2 +- parity/run.rs | 2 +- parity/secretstore.rs | 2 +- parity/signer.rs | 2 +- parity/snapshot.rs | 2 +- parity/stratum.rs | 2 +- parity/upgrade.rs | 2 +- parity/url.rs | 2 +- parity/user_defaults.rs | 2 +- parity/whisper.rs | 2 +- price-info/src/lib.rs | 2 +- registrar/src/lib.rs | 2 +- registrar/src/registrar.rs | 3 +-- rpc/src/authcodes.rs | 2 +- rpc/src/http_common.rs | 2 +- rpc/src/lib.rs | 2 +- rpc/src/tests/helpers.rs | 2 +- rpc/src/tests/mod.rs | 2 +- rpc/src/tests/rpc.rs | 2 +- rpc/src/tests/ws.rs | 3 +-- rpc/src/v1/extractors.rs | 2 +- rpc/src/v1/helpers/accounts.rs | 27 +++++++++++++++++++ rpc/src/v1/helpers/block_import.rs | 3 +-- rpc/src/v1/helpers/dapps.rs | 2 +- rpc/src/v1/helpers/dispatch.rs | 2 +- rpc/src/v1/helpers/errors.rs | 2 +- rpc/src/v1/helpers/fake_sign.rs | 2 +- rpc/src/v1/helpers/ipfs.rs | 2 +- rpc/src/v1/helpers/light_fetch.rs | 3 +-- rpc/src/v1/helpers/mod.rs | 2 +- rpc/src/v1/helpers/network_settings.rs | 3 ++- rpc/src/v1/helpers/nonce.rs | 2 +- rpc/src/v1/helpers/oneshot.rs | 2 +- rpc/src/v1/helpers/poll_filter.rs | 16 +++++++++++ rpc/src/v1/helpers/poll_manager.rs | 2 +- rpc/src/v1/helpers/requests.rs | 2 +- rpc/src/v1/helpers/secretstore.rs | 2 +- rpc/src/v1/helpers/signer.rs | 3 +-- rpc/src/v1/helpers/signing_queue.rs | 3 +-- rpc/src/v1/helpers/subscribers.rs | 3 +-- rpc/src/v1/helpers/subscription_manager.rs | 2 +- rpc/src/v1/impls/eth.rs | 3 +-- rpc/src/v1/impls/eth_filter.rs | 4 +-- rpc/src/v1/impls/eth_pubsub.rs | 2 +- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/mod.rs | 2 +- rpc/src/v1/impls/light/net.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 2 +- rpc/src/v1/impls/light/parity_set.rs | 2 +- rpc/src/v1/impls/light/trace.rs | 2 +- rpc/src/v1/impls/mod.rs | 2 +- rpc/src/v1/impls/net.rs | 2 +- rpc/src/v1/impls/parity.rs | 2 +- rpc/src/v1/impls/parity_accounts.rs | 2 +- rpc/src/v1/impls/parity_set.rs | 2 +- rpc/src/v1/impls/personal.rs | 2 +- rpc/src/v1/impls/private.rs | 2 +- rpc/src/v1/impls/pubsub.rs | 2 +- rpc/src/v1/impls/rpc.rs | 2 +- rpc/src/v1/impls/secretstore.rs | 2 +- rpc/src/v1/impls/signer.rs | 2 +- rpc/src/v1/impls/signing.rs | 2 +- rpc/src/v1/impls/signing_unsafe.rs | 2 +- rpc/src/v1/impls/traces.rs | 2 +- rpc/src/v1/impls/web3.rs | 2 +- rpc/src/v1/informant.rs | 2 +- rpc/src/v1/metadata.rs | 2 +- rpc/src/v1/mod.rs | 2 +- rpc/src/v1/tests/eth.rs | 2 +- rpc/src/v1/tests/helpers/dapps.rs | 2 +- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- rpc/src/v1/tests/helpers/mod.rs | 2 +- rpc/src/v1/tests/helpers/snapshot_service.rs | 2 +- rpc/src/v1/tests/helpers/sync_provider.rs | 3 +-- rpc/src/v1/tests/helpers/update_service.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 6 +---- rpc/src/v1/tests/mocked/eth_pubsub.rs | 4 +-- rpc/src/v1/tests/mocked/manage_network.rs | 2 +- rpc/src/v1/tests/mocked/mod.rs | 2 +- rpc/src/v1/tests/mocked/net.rs | 2 +- rpc/src/v1/tests/mocked/parity.rs | 3 +-- rpc/src/v1/tests/mocked/parity_accounts.rs | 4 +-- rpc/src/v1/tests/mocked/parity_set.rs | 3 +-- rpc/src/v1/tests/mocked/personal.rs | 2 +- rpc/src/v1/tests/mocked/pubsub.rs | 3 +-- rpc/src/v1/tests/mocked/rpc.rs | 3 +-- rpc/src/v1/tests/mocked/secretstore.rs | 2 +- rpc/src/v1/tests/mocked/signer.rs | 4 +-- rpc/src/v1/tests/mocked/signing.rs | 4 +-- rpc/src/v1/tests/mocked/traces.rs | 2 +- rpc/src/v1/tests/mocked/web3.rs | 2 +- rpc/src/v1/tests/mod.rs | 16 +++++++++++ rpc/src/v1/traits/eth.rs | 2 +- rpc/src/v1/traits/eth_pubsub.rs | 2 +- rpc/src/v1/traits/eth_signing.rs | 2 +- rpc/src/v1/traits/mod.rs | 2 +- rpc/src/v1/traits/net.rs | 2 +- rpc/src/v1/traits/parity.rs | 2 +- rpc/src/v1/traits/parity_accounts.rs | 2 +- rpc/src/v1/traits/parity_set.rs | 2 +- rpc/src/v1/traits/parity_signing.rs | 2 +- rpc/src/v1/traits/personal.rs | 2 +- rpc/src/v1/traits/private.rs | 2 +- rpc/src/v1/traits/pubsub.rs | 2 +- rpc/src/v1/traits/rpc.rs | 2 +- rpc/src/v1/traits/secretstore.rs | 2 +- rpc/src/v1/traits/signer.rs | 2 +- rpc/src/v1/traits/traces.rs | 2 +- rpc/src/v1/traits/web3.rs | 2 +- rpc/src/v1/types/account_info.rs | 3 +-- rpc/src/v1/types/block.rs | 2 +- rpc/src/v1/types/block_number.rs | 3 +-- rpc/src/v1/types/bytes.rs | 4 +-- rpc/src/v1/types/call_request.rs | 2 +- rpc/src/v1/types/confirmations.rs | 2 +- rpc/src/v1/types/consensus_status.rs | 2 +- rpc/src/v1/types/dapps.rs | 2 +- rpc/src/v1/types/derivation.rs | 2 +- rpc/src/v1/types/filter.rs | 2 +- rpc/src/v1/types/hash.rs | 2 +- rpc/src/v1/types/histogram.rs | 4 +-- rpc/src/v1/types/index.rs | 3 +-- rpc/src/v1/types/log.rs | 2 +- rpc/src/v1/types/mod.rs | 3 +-- rpc/src/v1/types/node_kind.rs | 2 +- rpc/src/v1/types/private_receipt.rs | 3 +-- rpc/src/v1/types/provenance.rs | 2 +- rpc/src/v1/types/pubsub.rs | 2 +- rpc/src/v1/types/receipt.rs | 3 +-- rpc/src/v1/types/rpc_settings.rs | 4 +-- rpc/src/v1/types/secretstore.rs | 2 +- rpc/src/v1/types/sync.rs | 2 +- rpc/src/v1/types/trace.rs | 3 +-- rpc/src/v1/types/trace_filter.rs | 2 +- rpc/src/v1/types/transaction.rs | 3 +-- rpc/src/v1/types/transaction_condition.rs | 3 +-- rpc/src/v1/types/transaction_request.rs | 3 +-- rpc/src/v1/types/uint.rs | 2 +- rpc/src/v1/types/work.rs | 3 +-- rpc_cli/src/lib.rs | 16 +++++++++++ rpc_client/src/client.rs | 16 +++++++++++ rpc_client/src/lib.rs | 16 +++++++++++ rpc_client/src/signer_client.rs | 16 +++++++++++ scripts/add_license.sh | 22 ++++++++++++--- scripts/remove_duplicate_empty_lines.sh | 6 +++++ secret_store/src/acl_storage.rs | 2 +- secret_store/src/key_server.rs | 2 +- .../key_version_negotiation_session.rs | 2 +- .../key_server_cluster/admin_sessions/mod.rs | 2 +- .../servers_set_change_session.rs | 2 +- .../admin_sessions/sessions_queue.rs | 2 +- .../admin_sessions/share_add_session.rs | 2 +- .../admin_sessions/share_change_session.rs | 2 +- .../client_sessions/decryption_session.rs | 2 +- .../client_sessions/encryption_session.rs | 2 +- .../client_sessions/generation_session.rs | 3 +-- .../key_server_cluster/client_sessions/mod.rs | 2 +- .../client_sessions/signing_session_ecdsa.rs | 3 +-- .../signing_session_schnorr.rs | 4 +-- .../src/key_server_cluster/cluster.rs | 2 +- .../key_server_cluster/cluster_sessions.rs | 2 +- .../cluster_sessions_creator.rs | 2 +- .../key_server_cluster/connection_trigger.rs | 2 +- .../connection_trigger_with_migration.rs | 2 +- .../src/key_server_cluster/io/deadline.rs | 2 +- .../src/key_server_cluster/io/handshake.rs | 2 +- .../src/key_server_cluster/io/message.rs | 2 +- secret_store/src/key_server_cluster/io/mod.rs | 2 +- .../src/key_server_cluster/io/read_header.rs | 2 +- .../src/key_server_cluster/io/read_message.rs | 2 +- .../src/key_server_cluster/io/read_payload.rs | 2 +- .../io/shared_tcp_stream.rs | 2 +- .../key_server_cluster/io/write_message.rs | 2 +- .../jobs/consensus_session.rs | 2 +- .../key_server_cluster/jobs/decryption_job.rs | 2 +- .../src/key_server_cluster/jobs/dummy_job.rs | 2 +- .../key_server_cluster/jobs/job_session.rs | 2 +- .../key_server_cluster/jobs/key_access_job.rs | 2 +- .../src/key_server_cluster/jobs/mod.rs | 2 +- .../jobs/servers_set_change_access_job.rs | 2 +- .../jobs/signing_job_ecdsa.rs | 2 +- .../jobs/signing_job_schnorr.rs | 4 +-- .../jobs/unknown_sessions_job.rs | 2 +- secret_store/src/key_server_cluster/math.rs | 2 +- .../src/key_server_cluster/message.rs | 2 +- secret_store/src/key_server_cluster/mod.rs | 2 +- .../net/accept_connection.rs | 2 +- .../src/key_server_cluster/net/connect.rs | 2 +- .../src/key_server_cluster/net/connection.rs | 2 +- .../src/key_server_cluster/net/mod.rs | 2 +- secret_store/src/key_server_set.rs | 2 +- secret_store/src/key_storage.rs | 3 +-- secret_store/src/lib.rs | 2 +- secret_store/src/listener/http_listener.rs | 2 +- secret_store/src/listener/mod.rs | 2 +- secret_store/src/listener/service_contract.rs | 2 +- .../listener/service_contract_aggregate.rs | 2 +- .../src/listener/service_contract_listener.rs | 2 +- secret_store/src/listener/tasks_queue.rs | 2 +- secret_store/src/node_key_pair.rs | 2 +- secret_store/src/serialization.rs | 2 +- secret_store/src/traits.rs | 2 +- secret_store/src/trusted_client.rs | 2 +- secret_store/src/types/all.rs | 2 +- secret_store/src/types/error.rs | 2 +- secret_store/src/types/mod.rs | 2 +- transaction-pool/src/error.rs | 2 +- transaction-pool/src/lib.rs | 2 +- transaction-pool/src/listener.rs | 2 +- transaction-pool/src/options.rs | 2 +- transaction-pool/src/pool.rs | 3 +-- transaction-pool/src/ready.rs | 2 +- transaction-pool/src/scoring.rs | 2 +- transaction-pool/src/status.rs | 2 +- transaction-pool/src/tests/helpers.rs | 2 +- transaction-pool/src/tests/mod.rs | 3 +-- transaction-pool/src/tests/tx_builder.rs | 2 +- transaction-pool/src/transactions.rs | 2 +- transaction-pool/src/verifier.rs | 2 +- updater/src/lib.rs | 2 +- updater/src/service.rs | 3 +-- updater/src/types/all.rs | 2 +- updater/src/types/mod.rs | 3 +-- updater/src/types/release_track.rs | 3 +-- updater/src/types/version_info.rs | 2 +- updater/src/updater.rs | 2 +- util/bloom/src/lib.rs | 4 +-- util/bloomchain/src/chain.rs | 16 +++++++++++ util/bloomchain/src/config.rs | 16 +++++++++++ util/bloomchain/src/database.rs | 16 +++++++++++ util/bloomchain/src/filter.rs | 16 +++++++++++ util/bloomchain/src/group/bridge.rs | 16 +++++++++++ util/bloomchain/src/group/chain.rs | 16 +++++++++++ util/bloomchain/src/group/database.rs | 16 +++++++++++ util/bloomchain/src/group/group.rs | 16 +++++++++++ util/bloomchain/src/group/mod.rs | 16 +++++++++++ util/bloomchain/src/group/position/manager.rs | 16 +++++++++++ util/bloomchain/src/group/position/mod.rs | 16 +++++++++++ .../bloomchain/src/group/position/position.rs | 16 +++++++++++ util/bloomchain/src/lib.rs | 16 +++++++++++ util/bloomchain/src/number.rs | 16 +++++++++++ util/bloomchain/src/position/manager.rs | 16 +++++++++++ util/bloomchain/src/position/mod.rs | 16 +++++++++++ util/bloomchain/src/position/position.rs | 16 +++++++++++ util/bloomchain/tests/bloomchain.rs | 18 +++++++++++-- util/bloomchain/tests/groupchain.rs | 19 ++++++++++--- util/bloomchain/tests/util/db.rs | 16 +++++++++++ util/bloomchain/tests/util/each.rs | 16 +++++++++++ util/bloomchain/tests/util/from_hex.rs | 16 +++++++++++ util/bloomchain/tests/util/mod.rs | 16 +++++++++++ util/bloomchain/tests/util/random.rs | 16 +++++++++++ util/bytes/src/lib.rs | 2 +- util/dir/src/helpers.rs | 2 +- util/dir/src/lib.rs | 2 +- util/error/src/lib.rs | 3 +-- util/fetch/src/client.rs | 2 +- util/fetch/src/lib.rs | 2 +- util/hash/benches/keccak_256.rs | 18 ++++++++++++- util/hash/src/lib.rs | 3 +-- util/hashdb/src/lib.rs | 2 +- util/io/src/lib.rs | 2 +- util/io/src/service_mio.rs | 2 +- util/io/src/service_non_mio.rs | 2 +- util/io/src/worker.rs | 2 +- util/journaldb/src/archivedb.rs | 2 +- util/journaldb/src/earlymergedb.rs | 3 +-- util/journaldb/src/lib.rs | 2 +- util/journaldb/src/overlaydb.rs | 2 +- util/journaldb/src/overlayrecentdb.rs | 2 +- util/journaldb/src/refcounteddb.rs | 2 +- util/journaldb/src/traits.rs | 2 +- util/kvdb-memorydb/src/lib.rs | 2 +- util/kvdb-rocksdb/src/lib.rs | 3 +-- util/kvdb/src/lib.rs | 2 +- util/macros/src/lib.rs | 2 +- util/mem/src/lib.rs | 3 +-- util/memory_cache/src/lib.rs | 2 +- util/memorydb/src/lib.rs | 2 +- util/migration-rocksdb/src/lib.rs | 2 +- util/migration-rocksdb/tests/tests.rs | 3 +-- util/network-devp2p/src/connection.rs | 2 +- util/network-devp2p/src/discovery.rs | 2 +- util/network-devp2p/src/handshake.rs | 3 +-- util/network-devp2p/src/host.rs | 3 +-- util/network-devp2p/src/ip_utils.rs | 4 +-- util/network-devp2p/src/lib.rs | 2 +- util/network-devp2p/src/node_table.rs | 2 +- util/network-devp2p/src/service.rs | 2 +- util/network-devp2p/src/session.rs | 3 +-- util/network-devp2p/tests/tests.rs | 3 +-- util/network/src/connection_filter.rs | 2 +- util/network/src/error.rs | 2 +- util/network/src/lib.rs | 2 +- util/panic_hook/src/lib.rs | 4 +-- util/path/src/lib.rs | 3 +-- util/patricia_trie/src/fatdb.rs | 2 +- util/patricia_trie/src/fatdbmut.rs | 2 +- util/patricia_trie/src/lib.rs | 2 +- util/patricia_trie/src/lookup.rs | 2 +- util/patricia_trie/src/nibbleslice.rs | 2 +- util/patricia_trie/src/nibblevec.rs | 2 +- util/patricia_trie/src/node.rs | 2 +- util/patricia_trie/src/recorder.rs | 2 +- util/patricia_trie/src/sectriedb.rs | 2 +- util/patricia_trie/src/sectriedbmut.rs | 2 +- util/patricia_trie/src/triedb.rs | 2 +- util/patricia_trie/src/triedbmut.rs | 3 +-- util/plain_hasher/benches/bench.rs | 16 +++++++++++ util/plain_hasher/src/lib.rs | 16 +++++++++++ util/reactor/src/lib.rs | 4 +-- util/rlp/src/rlpin.rs | 1 - util/rlp/src/stream.rs | 2 -- util/rlp_compress/src/lib.rs | 1 - util/rlp_compress/tests/compress.rs | 16 +++++++++++ util/rlp_derive/src/de.rs | 18 +++++++++++-- util/rlp_derive/src/en.rs | 17 +++++++++++- util/rlp_derive/src/lib.rs | 16 +++++++++++ util/rlp_derive/tests/rlp.rs | 17 +++++++++++- util/stats/src/lib.rs | 3 +-- util/stop-guard/src/lib.rs | 2 +- util/trace-time/src/lib.rs | 2 +- util/trie-standardmap/src/lib.rs | 2 +- util/triehash/src/lib.rs | 4 +-- util/unexpected/src/lib.rs | 2 +- util/using_queue/src/lib.rs | 2 +- util/version/build.rs | 2 +- util/version/src/lib.rs | 2 +- whisper/src/lib.rs | 2 +- whisper/src/message.rs | 2 +- whisper/src/net/mod.rs | 2 +- whisper/src/net/tests.rs | 2 +- whisper/src/rpc/crypto.rs | 2 +- whisper/src/rpc/filter.rs | 2 +- whisper/src/rpc/key_store.rs | 2 +- whisper/src/rpc/mod.rs | 2 +- whisper/src/rpc/payload.rs | 3 +-- whisper/src/rpc/types.rs | 2 +- windows/ptray/ptray.cpp | 3 +-- 807 files changed, 1635 insertions(+), 986 deletions(-) create mode 100644 rpc/src/v1/helpers/accounts.rs create mode 100755 scripts/remove_duplicate_empty_lines.sh diff --git a/chainspec/src/main.rs b/chainspec/src/main.rs index bcef53f3f0..708d74b503 100644 --- a/chainspec/src/main.rs +++ b/chainspec/src/main.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate serde_json; extern crate serde_ignored; extern crate ethjson; diff --git a/dapps/js-glue/build.rs b/dapps/js-glue/build.rs index 442abf7dfb..19d422ab23 100644 --- a/dapps/js-glue/build.rs +++ b/dapps/js-glue/build.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - #[cfg(feature = "with-syntex")] mod inner { extern crate syntex; diff --git a/dapps/js-glue/src/build.rs b/dapps/js-glue/src/build.rs index 31f27306a9..76b0a8714c 100644 --- a/dapps/js-glue/src/build.rs +++ b/dapps/js-glue/src/build.rs @@ -1,3 +1,18 @@ +// Copyright 2015-2018 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 . #[cfg(feature = "with-syntex")] pub mod inner { diff --git a/dapps/js-glue/src/codegen.rs b/dapps/js-glue/src/codegen.rs index c6e948820f..4b6c4445d7 100644 --- a/dapps/js-glue/src/codegen.rs +++ b/dapps/js-glue/src/codegen.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/js-glue/src/js.rs b/dapps/js-glue/src/js.rs index d1d1cdda91..f89fcefc76 100644 --- a/dapps/js-glue/src/js.rs +++ b/dapps/js-glue/src/js.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/js-glue/src/lib.rs b/dapps/js-glue/src/lib.rs index 143dd1fc8b..f8ada2541e 100644 --- a/dapps/js-glue/src/lib.rs +++ b/dapps/js-glue/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - #![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))] #![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))] diff --git a/dapps/js-glue/src/lib.rs.in b/dapps/js-glue/src/lib.rs.in index 99a253013d..b78eae1098 100644 --- a/dapps/js-glue/src/lib.rs.in +++ b/dapps/js-glue/src/lib.rs.in @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -8,11 +8,12 @@ // 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 +// 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 . +// along with Parity. If not, see . + extern crate quasi; diff --git a/dapps/node-health/src/health.rs b/dapps/node-health/src/health.rs index ab300a4a77..430061ea2b 100644 --- a/dapps/node-health/src/health.rs +++ b/dapps/node-health/src/health.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/node-health/src/lib.rs b/dapps/node-health/src/lib.rs index b0eb133ee3..13529004a6 100644 --- a/dapps/node-health/src/lib.rs +++ b/dapps/node-health/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/node-health/src/time.rs b/dapps/node-health/src/time.rs index c3da050a47..9dfb3aa87f 100644 --- a/dapps/node-health/src/time.rs +++ b/dapps/node-health/src/time.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/node-health/src/types.rs b/dapps/node-health/src/types.rs index ae883a626b..76fd3682f9 100644 --- a/dapps/node-health/src/types.rs +++ b/dapps/node-health/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/api/api.rs b/dapps/src/api/api.rs index a9f9af293b..e6bba899f9 100644 --- a/dapps/src/api/api.rs +++ b/dapps/src/api/api.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/api/mod.rs b/dapps/src/api/mod.rs index 4ffb9f791a..c18eb189ea 100644 --- a/dapps/src/api/mod.rs +++ b/dapps/src/api/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/api/response.rs b/dapps/src/api/response.rs index c8d25c1445..5fe81eaa19 100644 --- a/dapps/src/api/response.rs +++ b/dapps/src/api/response.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/api/types.rs b/dapps/src/api/types.rs index 6beca3b586..8bc451a849 100644 --- a/dapps/src/api/types.rs +++ b/dapps/src/api/types.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/apps/app.rs b/dapps/src/apps/app.rs index c75346124c..15468b4f1d 100644 --- a/dapps/src/apps/app.rs +++ b/dapps/src/apps/app.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/apps/cache.rs b/dapps/src/apps/cache.rs index c81d4d9af9..b93acfaece 100644 --- a/dapps/src/apps/cache.rs +++ b/dapps/src/apps/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/apps/fetcher/installers.rs b/dapps/src/apps/fetcher/installers.rs index 5bde5cf999..99b6be218b 100644 --- a/dapps/src/apps/fetcher/installers.rs +++ b/dapps/src/apps/fetcher/installers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/apps/fetcher/mod.rs b/dapps/src/apps/fetcher/mod.rs index 8ed3024fdf..78be4f4cb3 100644 --- a/dapps/src/apps/fetcher/mod.rs +++ b/dapps/src/apps/fetcher/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/apps/fs.rs b/dapps/src/apps/fs.rs index 3d93a2fae1..0139e0ec52 100644 --- a/dapps/src/apps/fs.rs +++ b/dapps/src/apps/fs.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -78,7 +78,6 @@ pub fn local_endpoint>(path: P, embeddable: Embeddable, pool: Cpu }) } - fn local_dapp(name: String, path: PathBuf) -> LocalDapp { // try to get manifest file let info = read_manifest(&name, path.clone()); @@ -102,7 +101,6 @@ pub fn local_endpoints>(dapps_path: P, embeddable: Embeddable, po pages } - fn local_dapps(dapps_path: &Path) -> Vec { let files = fs::read_dir(dapps_path); if let Err(e) = files { diff --git a/dapps/src/apps/manifest.rs b/dapps/src/apps/manifest.rs index e320482195..4d71af40fe 100644 --- a/dapps/src/apps/manifest.rs +++ b/dapps/src/apps/manifest.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/apps/mod.rs b/dapps/src/apps/mod.rs index 21947b928b..32bd7ee0fd 100644 --- a/dapps/src/apps/mod.rs +++ b/dapps/src/apps/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/apps/ui.rs b/dapps/src/apps/ui.rs index 39da14e5b9..696ed2523d 100644 --- a/dapps/src/apps/ui.rs +++ b/dapps/src/apps/ui.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/endpoint.rs b/dapps/src/endpoint.rs index fd05445c2a..948f412b38 100644 --- a/dapps/src/endpoint.rs +++ b/dapps/src/endpoint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/handlers/content.rs b/dapps/src/handlers/content.rs index c7eccf474e..ec4d4f2eff 100644 --- a/dapps/src/handlers/content.rs +++ b/dapps/src/handlers/content.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/handlers/echo.rs b/dapps/src/handlers/echo.rs index 375f047906..d7484b6d15 100644 --- a/dapps/src/handlers/echo.rs +++ b/dapps/src/handlers/echo.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/handlers/fetch.rs b/dapps/src/handlers/fetch.rs index 1408d634db..860fe998c4 100644 --- a/dapps/src/handlers/fetch.rs +++ b/dapps/src/handlers/fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -102,7 +102,6 @@ impl FetchControl { } } - enum WaitState { Waiting(oneshot::Receiver), Done(endpoint::Response), diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs index f78f46c764..fad9c40416 100644 --- a/dapps/src/handlers/mod.rs +++ b/dapps/src/handlers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/handlers/reader.rs b/dapps/src/handlers/reader.rs index 85a351c7b0..3b0aa5449b 100644 --- a/dapps/src/handlers/reader.rs +++ b/dapps/src/handlers/reader.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/handlers/redirect.rs b/dapps/src/handlers/redirect.rs index cb1eda2dd5..c8bf837d85 100644 --- a/dapps/src/handlers/redirect.rs +++ b/dapps/src/handlers/redirect.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/handlers/streaming.rs b/dapps/src/handlers/streaming.rs index 269e4c5d2a..4dfd2c4afa 100644 --- a/dapps/src/handlers/streaming.rs +++ b/dapps/src/handlers/streaming.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index c4e244b251..255560e422 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -85,7 +85,6 @@ use node_health::NodeHealth; pub use registrar::{RegistrarClient, Asynchronous}; pub use node_health::SyncStatus; - /// Validates Web Proxy tokens pub trait WebProxyTokens: Send + Sync { /// Should return a domain allowed to be accessed by this token or `None` if the token is not valid diff --git a/dapps/src/page/builtin.rs b/dapps/src/page/builtin.rs index 150cfe8642..b9f2fcdac5 100644 --- a/dapps/src/page/builtin.rs +++ b/dapps/src/page/builtin.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -146,7 +146,6 @@ impl From for EndpointInfo { } } - struct BuiltinFile { content_type: Mime, content: io::Cursor<&'static [u8]>, diff --git a/dapps/src/page/handler.rs b/dapps/src/page/handler.rs index 687c8e1e52..15e2b10c50 100644 --- a/dapps/src/page/handler.rs +++ b/dapps/src/page/handler.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/page/local.rs b/dapps/src/page/local.rs index a1746efcd2..f30af45237 100644 --- a/dapps/src/page/local.rs +++ b/dapps/src/page/local.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -92,7 +92,6 @@ impl Dapp { LocalFile::from_path(&file_path, mime) } - pub fn to_response(&self, path: &EndpointPath) -> Response { let (reader, response) = handler::PageHandler { file: self.get_file(path), diff --git a/dapps/src/page/mod.rs b/dapps/src/page/mod.rs index 420707bfe1..65385320c4 100644 --- a/dapps/src/page/mod.rs +++ b/dapps/src/page/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,10 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - pub mod builtin; pub mod local; mod handler; pub use self::handler::PageCache; - diff --git a/dapps/src/proxypac.rs b/dapps/src/proxypac.rs index 85ac11423a..4e11f3ea6b 100644 --- a/dapps/src/proxypac.rs +++ b/dapps/src/proxypac.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,5 +64,3 @@ function FindProxyForURL(url, host) {{ )) } } - - diff --git a/dapps/src/router.rs b/dapps/src/router.rs index d5f4647049..565874f6a8 100644 --- a/dapps/src/router.rs +++ b/dapps/src/router.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/tests/api.rs b/dapps/src/tests/api.rs index 3ae3f7cbbf..d31f796d57 100644 --- a/dapps/src/tests/api.rs +++ b/dapps/src/tests/api.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -63,7 +63,6 @@ fn should_handle_ping() { assert_security_headers(&response.headers); } - #[test] fn should_try_to_resolve_dapp() { // given diff --git a/dapps/src/tests/fetch.rs b/dapps/src/tests/fetch.rs index 59eeaf8d66..bbd766a552 100644 --- a/dapps/src/tests/fetch.rs +++ b/dapps/src/tests/fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -383,7 +383,6 @@ fn should_correctly_handle_long_label_when_splitted() { fetch.assert_no_more_requests(); } - #[test] fn should_support_base32_encoded_web_urls_as_path() { // given diff --git a/dapps/src/tests/helpers/fetch.rs b/dapps/src/tests/helpers/fetch.rs index 51c98db531..4affffe6ef 100644 --- a/dapps/src/tests/helpers/fetch.rs +++ b/dapps/src/tests/helpers/fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/tests/helpers/mod.rs b/dapps/src/tests/helpers/mod.rs index 41df0db61b..aa76089794 100644 --- a/dapps/src/tests/helpers/mod.rs +++ b/dapps/src/tests/helpers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -140,7 +140,6 @@ pub fn assert_security_headers_for_embed(headers: &[String]) { http_client::assert_security_headers_present(headers, Some(SIGNER_PORT)) } - /// Webapps HTTP+RPC server build. pub struct ServerBuilder { dapps_path: PathBuf, diff --git a/dapps/src/tests/helpers/registrar.rs b/dapps/src/tests/helpers/registrar.rs index e770146f5a..b9acb1afc3 100644 --- a/dapps/src/tests/helpers/registrar.rs +++ b/dapps/src/tests/helpers/registrar.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/tests/home.rs b/dapps/src/tests/home.rs index fa5c5b4c46..024261d5df 100644 --- a/dapps/src/tests/home.rs +++ b/dapps/src/tests/home.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/tests/mod.rs b/dapps/src/tests/mod.rs index a47294392e..38a1d6f17a 100644 --- a/dapps/src/tests/mod.rs +++ b/dapps/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -24,4 +24,3 @@ mod home; mod redirection; mod rpc; mod validation; - diff --git a/dapps/src/tests/redirection.rs b/dapps/src/tests/redirection.rs index b7f72009f7..722ade25b9 100644 --- a/dapps/src/tests/redirection.rs +++ b/dapps/src/tests/redirection.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -160,7 +160,6 @@ fn should_serve_rpc_at_slash_rpc() { assert_eq!(response.body, format!("4C\n{}\n\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#)); } - #[test] fn should_serve_proxy_pac() { // given diff --git a/dapps/src/tests/rpc.rs b/dapps/src/tests/rpc.rs index 0cfc2c5a81..326fcd72a6 100644 --- a/dapps/src/tests/rpc.rs +++ b/dapps/src/tests/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/tests/validation.rs b/dapps/src/tests/validation.rs index bd97c940a0..ed4a3dc2f0 100644 --- a/dapps/src/tests/validation.rs +++ b/dapps/src/tests/validation.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/dapps/src/web.rs b/dapps/src/web.rs index 86c0ac28d6..14f215ca45 100644 --- a/dapps/src/web.rs +++ b/dapps/src/web.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -168,4 +168,3 @@ impl ContentValidator for WebInstaller { Ok(ValidatorResponse::Streaming(handler)) } } - diff --git a/dapps/ui/src/lib.rs b/dapps/ui/src/lib.rs index aa1c867366..f04f755a99 100644 --- a/dapps/ui/src/lib.rs +++ b/dapps/ui/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - #[cfg(feature = "parity-ui-dev")] mod inner { extern crate parity_ui_dev; diff --git a/devtools/src/http_client.rs b/devtools/src/http_client.rs index ab23410592..e2f33d4257 100644 --- a/devtools/src/http_client.rs +++ b/devtools/src/http_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs index efaf4b9351..6fdbc8d890 100644 --- a/devtools/src/lib.rs +++ b/devtools/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/cache.rs b/ethash/src/cache.rs index eef426bcf1..21bd0e231e 100644 --- a/ethash/src/cache.rs +++ b/ethash/src/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index de2b57637f..fa95038d18 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/keccak.rs b/ethash/src/keccak.rs index 36fb173547..ab6be94dca 100644 --- a/ethash/src/keccak.rs +++ b/ethash/src/keccak.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index 9d0c669d9c..69b5a1d115 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/seed_compute.rs b/ethash/src/seed_compute.rs index 04774b3e39..bc6f1d51e1 100644 --- a/ethash/src/seed_compute.rs +++ b/ethash/src/seed_compute.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethash/src/shared.rs b/ethash/src/shared.rs index 39e1c8eb88..90969c5222 100644 --- a/ethash/src/shared.rs +++ b/ethash/src/shared.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/benches/evm.rs b/ethcore/benches/evm.rs index 9fe2657d61..c68adc9878 100644 --- a/ethcore/benches/evm.rs +++ b/ethcore/benches/evm.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -28,7 +28,6 @@ extern crate ethcore_bigint; use self::test::{Bencher}; use rand::{StdRng}; - #[bench] fn bn_128_pairing(b: &mut Bencher) { use bn::{pairing, G1, G2, Fr, Group}; @@ -92,4 +91,3 @@ fn ecrecover(b: &mut Bencher) { let _ = ec_recover(&s, &hash); }); } - diff --git a/ethcore/crypto/src/aes.rs b/ethcore/crypto/src/aes.rs index 79a8dcc86d..42a26fad0d 100644 --- a/ethcore/crypto/src/aes.rs +++ b/ethcore/crypto/src/aes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -51,4 +51,3 @@ pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; Ok(len - buffer.remaining()) } - diff --git a/ethcore/crypto/src/aes_gcm.rs b/ethcore/crypto/src/aes_gcm.rs index 178b5d1e12..819c613197 100644 --- a/ethcore/crypto/src/aes_gcm.rs +++ b/ethcore/crypto/src/aes_gcm.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -196,4 +196,3 @@ mod tests { assert_eq!(plaintext, &message[..]) } } - diff --git a/ethcore/crypto/src/digest.rs b/ethcore/crypto/src/digest.rs index 095a8ca262..b2be0b8ed1 100644 --- a/ethcore/crypto/src/digest.rs +++ b/ethcore/crypto/src/digest.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/crypto/src/error.rs b/ethcore/crypto/src/error.rs index 4de3b80036..4e5582e196 100644 --- a/ethcore/crypto/src/error.rs +++ b/ethcore/crypto/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -80,4 +80,3 @@ impl From for SymmError { SymmError(PrivSymmErr::RustCrypto(e)) } } - diff --git a/ethcore/crypto/src/hmac.rs b/ethcore/crypto/src/hmac.rs index 7327250442..ff337ed024 100644 --- a/ethcore/crypto/src/hmac.rs +++ b/ethcore/crypto/src/hmac.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -86,4 +86,3 @@ impl VerifyKey { pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { hmac::verify(&k.0, data, sig).is_ok() } - diff --git a/ethcore/crypto/src/lib.rs b/ethcore/crypto/src/lib.rs index 0ee42e3599..459c790319 100644 --- a/ethcore/crypto/src/lib.rs +++ b/ethcore/crypto/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -74,4 +74,3 @@ pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { pub fn is_equal(a: &[u8], b: &[u8]) -> bool { ring::constant_time::verify_slices_are_equal(a, b).is_ok() } - diff --git a/ethcore/crypto/src/pbkdf2.rs b/ethcore/crypto/src/pbkdf2.rs index b4c993c513..d210f6f659 100644 --- a/ethcore/crypto/src/pbkdf2.rs +++ b/ethcore/crypto/src/pbkdf2.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -26,4 +26,3 @@ pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..]) } - diff --git a/ethcore/crypto/src/scrypt.rs b/ethcore/crypto/src/scrypt.rs index 684ab2c572..de3cd55553 100644 --- a/ethcore/crypto/src/scrypt.rs +++ b/ethcore/crypto/src/scrypt.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -36,4 +36,3 @@ pub fn derive_key(pass: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) } - diff --git a/ethcore/evm/src/benches/mod.rs b/ethcore/evm/src/benches/mod.rs index c87fda7bbf..244c26985a 100644 --- a/ethcore/evm/src/benches/mod.rs +++ b/ethcore/evm/src/benches/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/evm.rs b/ethcore/evm/src/evm.rs index 16dffe77c5..4c85b37028 100644 --- a/ethcore/evm/src/evm.rs +++ b/ethcore/evm/src/evm.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index af38afede3..65a683cd4a 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/instructions.rs b/ethcore/evm/src/instructions.rs index 6ecfc7f673..76f99a9333 100644 --- a/ethcore/evm/src/instructions.rs +++ b/ethcore/evm/src/instructions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/interpreter/gasometer.rs b/ethcore/evm/src/interpreter/gasometer.rs index beb22447fe..85ea8ee487 100644 --- a/ethcore/evm/src/interpreter/gasometer.rs +++ b/ethcore/evm/src/interpreter/gasometer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -316,7 +316,6 @@ impl Gasometer { } } - #[inline] fn mem_needed_const(mem: &U256, add: usize) -> vm::Result { Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add)))) @@ -369,4 +368,3 @@ fn test_calculate_mem_cost() { assert_eq!(new_mem_gas, 3); assert_eq!(mem_size, 32); } - diff --git a/ethcore/evm/src/interpreter/informant.rs b/ethcore/evm/src/interpreter/informant.rs index f07d11ff7a..ca04be844f 100644 --- a/ethcore/evm/src/interpreter/informant.rs +++ b/ethcore/evm/src/interpreter/informant.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/interpreter/memory.rs b/ethcore/evm/src/interpreter/memory.rs index f646d01985..843aeef3b5 100644 --- a/ethcore/evm/src/interpreter/memory.rs +++ b/ethcore/evm/src/interpreter/memory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 160a2e5b1d..ef9b3fb973 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -103,7 +103,6 @@ enum InstructionResult { StopExecution, } - /// Intepreter EVM implementation pub struct Interpreter { mem: Vec, @@ -959,7 +958,6 @@ fn address_to_u256(value: Address) -> U256 { U256::from(&*H256::from(value)) } - #[cfg(test)] mod tests { use std::sync::Arc; diff --git a/ethcore/evm/src/interpreter/shared_cache.rs b/ethcore/evm/src/interpreter/shared_cache.rs index 30bc5b677d..d4e992c90e 100644 --- a/ethcore/evm/src/interpreter/shared_cache.rs +++ b/ethcore/evm/src/interpreter/shared_cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -91,7 +91,6 @@ impl Default for SharedCache { } } - #[test] fn test_find_jump_destinations() { use rustc_hex::FromHex; diff --git a/ethcore/evm/src/interpreter/stack.rs b/ethcore/evm/src/interpreter/stack.rs index cbe40fb67f..3902b8ff76 100644 --- a/ethcore/evm/src/interpreter/stack.rs +++ b/ethcore/evm/src/interpreter/stack.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -95,4 +95,3 @@ impl Stack for VecStack { &self.stack[self.stack.len() - no_from_top .. self.stack.len()] } } - diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index 263a11d682..1b5610cef5 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index 9058d073e8..b62faf87d7 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/evm/src/vmtype.rs b/ethcore/evm/src/vmtype.rs index b3a8aaf3e9..feb567b73d 100644 --- a/ethcore/evm/src/vmtype.rs +++ b/ethcore/evm/src/vmtype.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/cache.rs b/ethcore/light/src/cache.rs index b63fd07576..7b6324a991 100644 --- a/ethcore/light/src/cache.rs +++ b/ethcore/light/src/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/cht.rs b/ethcore/light/src/cht.rs index ffb7841f45..805cca3cbc 100644 --- a/ethcore/light/src/cht.rs +++ b/ethcore/light/src/cht.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -11,6 +11,9 @@ // 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 . + //! Canonical hash trie definitions and helper functions. //! //! Each CHT is a trie mapping block numbers to canonical hashes and total difficulty. diff --git a/ethcore/light/src/client/fetch.rs b/ethcore/light/src/client/fetch.rs index 86269c695f..b0f7353496 100644 --- a/ethcore/light/src/client/fetch.rs +++ b/ethcore/light/src/client/fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 60c7d288a7..cb370da2a7 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 82b424cc83..a1625b0e8f 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -463,7 +463,6 @@ impl Client { loop { - let is_signal = { let auxiliary = AuxiliaryData { bytes: block.as_ref().map(|x| &x[..]), diff --git a/ethcore/light/src/client/service.rs b/ethcore/light/src/client/service.rs index a3ec8a3686..d1645cfe7e 100644 --- a/ethcore/light/src/client/service.rs +++ b/ethcore/light/src/client/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index 9723854b8d..d7469fdcee 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/context.rs b/ethcore/light/src/net/context.rs index 613e26b1f1..a49ef79dc2 100644 --- a/ethcore/light/src/net/context.rs +++ b/ethcore/light/src/net/context.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! I/O and event context generalizations. @@ -46,7 +46,6 @@ pub trait IoContext { fn persistent_peer_id(&self, peer: PeerId) -> Option; } - impl IoContext for T where T: ?Sized + NetworkContext { fn send(&self, peer: PeerId, packet_id: u8, packet_body: Vec) { if let Err(e) = self.send(peer, packet_id, packet_body) { diff --git a/ethcore/light/src/net/error.rs b/ethcore/light/src/net/error.rs index 35349c5539..ec2a7f91c5 100644 --- a/ethcore/light/src/net/error.rs +++ b/ethcore/light/src/net/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/load_timer.rs b/ethcore/light/src/net/load_timer.rs index 2846a57384..0ad9627021 100644 --- a/ethcore/light/src/net/load_timer.rs +++ b/ethcore/light/src/net/load_timer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index d8a975dc3f..39f53445ad 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -86,7 +86,6 @@ pub const PROTOCOL_VERSIONS: &'static [(u8, u8)] = &[ /// Max protocol version. pub const MAX_PROTOCOL_VERSION: u8 = 1; - // packet ID definitions. mod packet { // the status packet. diff --git a/ethcore/light/src/net/request_credits.rs b/ethcore/light/src/net/request_credits.rs index 29570b613c..e97e1aad58 100644 --- a/ethcore/light/src/net/request_credits.rs +++ b/ethcore/light/src/net/request_credits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/request_set.rs b/ethcore/light/src/net/request_set.rs index 27e6c28bc2..4170f8e632 100644 --- a/ethcore/light/src/net/request_set.rs +++ b/ethcore/light/src/net/request_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/status.rs b/ethcore/light/src/net/status.rs index c9ee3d760f..d89db173cb 100644 --- a/ethcore/light/src/net/status.rs +++ b/ethcore/light/src/net/status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index 3c04c0ffba..305ef9b354 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/on_demand/mod.rs b/ethcore/light/src/on_demand/mod.rs index 64794d49e7..c7cc5ef5e7 100644 --- a/ethcore/light/src/on_demand/mod.rs +++ b/ethcore/light/src/on_demand/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 18a309ae96..4cac6b629d 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -520,7 +520,6 @@ impl IncompleteRequest for CheckedRequest { } } - fn adjust_refs(&mut self, mapping: F) where F: FnMut(usize) -> usize { match_me!(*self, (_, ref mut req) => req.adjust_refs(mapping)) } diff --git a/ethcore/light/src/on_demand/tests.rs b/ethcore/light/src/on_demand/tests.rs index 95aec273f8..d3cd137ec0 100644 --- a/ethcore/light/src/on_demand/tests.rs +++ b/ethcore/light/src/on_demand/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/provider.rs b/ethcore/light/src/provider.rs index aaa6f5858a..0e518ea772 100644 --- a/ethcore/light/src/provider.rs +++ b/ethcore/light/src/provider.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/transaction_queue.rs b/ethcore/light/src/transaction_queue.rs index ae3dc26915..e8880037a1 100644 --- a/ethcore/light/src/transaction_queue.rs +++ b/ethcore/light/src/transaction_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/types/mod.rs b/ethcore/light/src/types/mod.rs index eba551b533..67e54141b2 100644 --- a/ethcore/light/src/types/mod.rs +++ b/ethcore/light/src/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/types/request/batch.rs b/ethcore/light/src/types/request/batch.rs index 21f1264672..16843ae02c 100644 --- a/ethcore/light/src/types/request/batch.rs +++ b/ethcore/light/src/types/request/batch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index bda992df97..538aa0c6bf 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -124,8 +124,6 @@ impl Field { } } - - // attempt conversion into scalar value. fn into_scalar(self) -> Result { match self { diff --git a/ethcore/node_filter/src/lib.rs b/ethcore/node_filter/src/lib.rs index c731ad356a..76f6fd18ff 100644 --- a/ethcore/node_filter/src/lib.rs +++ b/ethcore/node_filter/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -90,7 +90,6 @@ impl ConnectionFilter for NodeFilter { return *res; } - let address = self.contract_address; let own_low = H256::from_slice(&own_id[0..32]); let own_high = H256::from_slice(&own_id[32..64]); diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs index b15acbee71..e171e3e606 100644 --- a/ethcore/private-tx/src/encryptor.rs +++ b/ethcore/private-tx/src/encryptor.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/private-tx/src/error.rs b/ethcore/private-tx/src/error.rs index 3b3c881a94..0456b33053 100644 --- a/ethcore/private-tx/src/error.rs +++ b/ethcore/private-tx/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -205,4 +205,3 @@ impl From> for Error where Error: From { Error::from(*err) } } - diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 7aca4c85dc..31abdb1eca 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/private-tx/src/messages.rs b/ethcore/private-tx/src/messages.rs index f465f752be..57362e7ce6 100644 --- a/ethcore/private-tx/src/messages.rs +++ b/ethcore/private-tx/src/messages.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/private-tx/src/private_transactions.rs b/ethcore/private-tx/src/private_transactions.rs index 1a018d927a..fcc6da514e 100644 --- a/ethcore/private-tx/src/private_transactions.rs +++ b/ethcore/private-tx/src/private_transactions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs index e7e608c2b6..bc678b1ab5 100644 --- a/ethcore/private-tx/tests/private_contract.rs +++ b/ethcore/private-tx/tests/private_contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index f703329d61..7248d97229 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index 4e715766d7..8fc4b95c6e 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 9d6b814c6f..2ebefc988b 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/account_provider/stores.rs b/ethcore/src/account_provider/stores.rs index 1563d21bc6..d7725deb7e 100644 --- a/ethcore/src/account_provider/stores.rs +++ b/ethcore/src/account_provider/stores.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 4c47089677..682171170e 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index 017c4f86ea..adfaf68aad 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index ee8a50d09d..6a48e92447 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index f2621d00e1..ee781ebe53 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs index 999be423df..0717011ae6 100644 --- a/ethcore/src/blockchain/cache.rs +++ b/ethcore/src/blockchain/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/config.rs b/ethcore/src/blockchain/config.rs index 312289b060..632f978ac5 100644 --- a/ethcore/src/blockchain/config.rs +++ b/ethcore/src/blockchain/config.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 3fb25e7b1b..30dbec707e 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/generator.rs b/ethcore/src/blockchain/generator.rs index e767f2211c..5a97f37f98 100644 --- a/ethcore/src/blockchain/generator.rs +++ b/ethcore/src/blockchain/generator.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs index 080d3b0682..d8b38e6335 100644 --- a/ethcore/src/blockchain/import_route.rs +++ b/ethcore/src/blockchain/import_route.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index f991692ded..6389f308aa 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index b695b9236b..8960d795aa 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::collections::HashMap; use ethereum_types::H256; use header::BlockNumber; diff --git a/ethcore/src/blooms/bloom_group.rs b/ethcore/src/blooms/bloom_group.rs index 4b47b1ad94..0eb1e9c529 100644 --- a/ethcore/src/blooms/bloom_group.rs +++ b/ethcore/src/blooms/bloom_group.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blooms/group_position.rs b/ethcore/src/blooms/group_position.rs index b1ea827926..1f9ddca7e0 100644 --- a/ethcore/src/blooms/group_position.rs +++ b/ethcore/src/blooms/group_position.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/blooms/mod.rs b/ethcore/src/blooms/mod.rs index a66485782b..7658446c74 100644 --- a/ethcore/src/blooms/mod.rs +++ b/ethcore/src/blooms/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index a0833cfb5e..61739c7b1d 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -703,7 +703,6 @@ mod tests { assert_eq!(f.cost(&input[..]), expected_cost.into()); } - // test for potential exp len overflow { let input = FromHex::from_hex("\ @@ -827,7 +826,6 @@ mod tests { assert_eq!(output, expected); } - // no input, should not fail { let mut empty = [0u8; 0]; @@ -859,7 +857,6 @@ mod tests { } } - #[test] fn bn128_mul() { diff --git a/ethcore/src/cache_manager.rs b/ethcore/src/cache_manager.rs index 7d91dcc0d0..4199cb1d59 100644 --- a/ethcore/src/cache_manager.rs +++ b/ethcore/src/cache_manager.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/ancient_import.rs b/ethcore/src/client/ancient_import.rs index c2523a13a5..4586a04eed 100644 --- a/ethcore/src/client/ancient_import.rs +++ b/ethcore/src/client/ancient_import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index 8330fb40d9..62de03591d 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b469cf4518..9e2cfeff40 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -425,7 +425,6 @@ impl Importer { Ok(locked_block) } - /// Import a block with transaction receipts. /// /// The block is guaranteed to be the next best blocks in the @@ -918,7 +917,6 @@ impl Client { Arc::new(last_hashes) } - /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self) -> usize { self.importer.import_verified_blocks(self) @@ -1566,7 +1564,6 @@ impl BlockChainClient for Client { }))) } - fn mode(&self) -> IpcMode { let r = self.mode.lock().clone().into(); trace!(target: "mode", "Asked for mode = {:?}. returning {:?}", &*self.mode.lock(), r); @@ -2280,7 +2277,6 @@ impl ProvingBlockChainClient for Client { ) } - fn epoch_signal(&self, hash: H256) -> Option> { // pending transitions are never deleted, and do not contain // finality proofs by definition. diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 9787f822a4..288de25e4b 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -110,7 +110,6 @@ impl From for Mode { } } - /// Client configuration. Includes configs for all sub-systems. #[derive(Debug, PartialEq, Default)] pub struct ClientConfig { diff --git a/ethcore/src/client/error.rs b/ethcore/src/client/error.rs index d2af13a3b2..0e6608c0ff 100644 --- a/ethcore/src/client/error.rs +++ b/ethcore/src/client/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index b91414ca8f..fbf57cbdc7 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/io_message.rs b/ethcore/src/client/io_message.rs index 817c726020..d388f5ed44 100644 --- a/ethcore/src/client/io_message.rs +++ b/ethcore/src/client/io_message.rs @@ -54,4 +54,3 @@ impl fmt::Debug for Callback { write!(fmt, "") } } - diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 4c410d3011..6e12c03052 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/private_notify.rs b/ethcore/src/client/private_notify.rs index 2b865a9e2c..d1fde555c9 100644 --- a/ethcore/src/client/private_notify.rs +++ b/ethcore/src/client/private_notify.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index fab3234657..8acbde4f97 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -704,7 +704,6 @@ impl BlockChainClient for TestBlockChainClient { .map(|header| self.spec.engine.extra_info(&header)) } - fn block_status(&self, id: BlockId) -> BlockStatus { match id { BlockId::Number(number) if (number as usize) < self.blocks.read().len() => BlockStatus::InChain, diff --git a/ethcore/src/client/trace.rs b/ethcore/src/client/trace.rs index 75e0fe34a1..5f1b6c4f4d 100644 --- a/ethcore/src/client/trace.rs +++ b/ethcore/src/client/trace.rs @@ -1,3 +1,18 @@ +// Copyright 2015-2018 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 . //! Bridge between Tracedb and Blockchain. diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 358e24fa90..f0fae4b498 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/db.rs b/ethcore/src/db.rs index a1c7d6b0f5..39c30e9637 100644 --- a/ethcore/src/db.rs +++ b/ethcore/src/db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/encoded.rs b/ethcore/src/encoded.rs index 5a2d376a2a..5bd723f0e2 100644 --- a/ethcore/src/encoded.rs +++ b/ethcore/src/encoded.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/authority_round/finality.rs b/ethcore/src/engines/authority_round/finality.rs index 61f1c18229..3745cde96c 100644 --- a/ethcore/src/engines/authority_round/finality.rs +++ b/ethcore/src/engines/authority_round/finality.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 02bb88c51f..067c754c7f 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -655,7 +655,6 @@ impl AuthorityRound { }).cloned().collect() } - fn clear_empty_steps(&self, step: U256) { // clear old `empty_steps` messages self.empty_steps.lock().retain(|e| U256::from(e.step) > step); diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index e99fd88dcb..dde0af2d96 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/epoch.rs b/ethcore/src/engines/epoch.rs index 6975e8898b..53b540cabd 100644 --- a/ethcore/src/engines/epoch.rs +++ b/ethcore/src/engines/epoch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index c16203f105..a35dea5219 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 0878b4595f..54a9dde2e6 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index c6025e6247..f9e698307d 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/signer.rs b/ethcore/src/engines/signer.rs index d9e97fee06..965b619c7d 100644 --- a/ethcore/src/engines/signer.rs +++ b/ethcore/src/engines/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index 17b79a80b8..ba8e4390ec 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -43,7 +43,6 @@ pub struct VoteStep { pub step: Step, } - impl VoteStep { pub fn new(height: Height, view: View, step: Step) -> Self { VoteStep { height: height, view: view, step: step } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 52bf5ff67b..967ef482a6 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -359,7 +359,6 @@ impl Tendermint { && lock_change_view < self.view.load(AtomicOrdering::SeqCst) } - fn has_enough_any_votes(&self) -> bool { let step_votes = self.votes.count_round_votes(&VoteStep::new(self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst), *self.step.read())); self.check_above_threshold(step_votes).is_ok() diff --git a/ethcore/src/engines/tendermint/params.rs b/ethcore/src/engines/tendermint/params.rs index c1fd39eb1c..fbd3839cad 100644 --- a/ethcore/src/engines/tendermint/params.rs +++ b/ethcore/src/engines/tendermint/params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/transition.rs b/ethcore/src/engines/transition.rs index a0469b6249..ddc9a70628 100644 --- a/ethcore/src/engines/transition.rs +++ b/ethcore/src/engines/transition.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index 00f74fd2eb..c44f2ab303 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/validator_set/mod.rs b/ethcore/src/engines/validator_set/mod.rs index d439c69c2e..26b57d78f2 100644 --- a/ethcore/src/engines/validator_set/mod.rs +++ b/ethcore/src/engines/validator_set/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/validator_set/multi.rs b/ethcore/src/engines/validator_set/multi.rs index 89a33abc74..3ac58cd4dc 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index f132a0bf9d..e55a0e3e36 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/validator_set/simple_list.rs b/ethcore/src/engines/validator_set/simple_list.rs index bb67c9778b..e1339250ef 100644 --- a/ethcore/src/engines/validator_set/simple_list.rs +++ b/ethcore/src/engines/validator_set/simple_list.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/validator_set/test.rs b/ethcore/src/engines/validator_set/test.rs index a6b8930454..6459803d19 100644 --- a/ethcore/src/engines/validator_set/test.rs +++ b/ethcore/src/engines/validator_set/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/engines/vote_collector.rs b/ethcore/src/engines/vote_collector.rs index 7af66b30c5..f416d0c3f7 100644 --- a/ethcore/src/engines/vote_collector.rs +++ b/ethcore/src/engines/vote_collector.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index bec749297c..ba53b9f93e 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -299,7 +299,6 @@ error_chain! { } } - /// Result of import block operation. pub type ImportResult = EthcoreResult; diff --git a/ethcore/src/ethereum/denominations.rs b/ethcore/src/ethereum/denominations.rs index 4892770df1..4c51932543 100644 --- a/ethcore/src/ethereum/denominations.rs +++ b/ethcore/src/ethereum/denominations.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -35,4 +35,3 @@ pub fn shannon() -> U256 { U256::exp10(9) } #[inline] /// 1 Wei in Wei pub fn wei() -> U256 { U256::exp10(0) } - diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 9b3945e38b..b51da58fec 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 5cf6462686..6456440759 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/executed.rs b/ethcore/src/executed.rs index 9ffd673154..3d0b9767c4 100644 --- a/ethcore/src/executed.rs +++ b/ethcore/src/executed.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index e29da093c7..f375f3c2e8 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 5d35d1109a..65d130c342 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index 68a15f164a..b429073b30 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 3e9675aa35..5aa4be3237 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -338,7 +338,6 @@ fn change_field(hash: &mut Option, field: &mut T, value: T) where T: Pa } } - impl Decodable for Header { fn decode(r: &Rlp) -> Result { let mut blockheader = Header { diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 89b8df4a26..814538cdbd 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -152,4 +152,3 @@ mod block_tests { declare_test!{BlockchainTests_TransitionTests_bcHomesteadToDao, "BlockchainTests/TransitionTests/bcHomesteadToDao/"} declare_test!{BlockchainTests_TransitionTests_bcHomesteadToEIP150, "BlockchainTests/TransitionTests/bcHomesteadToEIP150/"} } - diff --git a/ethcore/src/json_tests/difficulty.rs b/ethcore/src/json_tests/difficulty.rs index c0d03c810b..d111f0890d 100644 --- a/ethcore/src/json_tests/difficulty.rs +++ b/ethcore/src/json_tests/difficulty.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -56,7 +56,6 @@ mod difficulty_test_byzantium { declare_test!{DifficultyTests_difficultyByzantium, "BasicTests/difficultyByzantium.json"} } - mod difficulty_test_foundation { use super::json_difficulty_test; use tempdir::TempDir; @@ -68,6 +67,3 @@ mod difficulty_test_foundation { declare_test!{DifficultyTests_difficultyMainNetwork, "BasicTests/difficultyMainNetwork.json"} } - - - diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 404b1c25e6..5bda6c55a3 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs index a0966a2d29..65cc6d2134 100644 --- a/ethcore/src/json_tests/mod.rs +++ b/ethcore/src/json_tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index a55ab18443..45ec6f3fb0 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -135,4 +135,3 @@ mod state_tests { declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"} declare_test!{GeneralStateTest_stZeroKnowledge, "GeneralStateTests/stZeroKnowledge/"} } - diff --git a/ethcore/src/json_tests/test_common.rs b/ethcore/src/json_tests/test_common.rs index 83f6b55272..6ce38b27a0 100644 --- a/ethcore/src/json_tests/test_common.rs +++ b/ethcore/src/json_tests/test_common.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index 1be4900b12..295093305d 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/json_tests/trie.rs b/ethcore/src/json_tests/trie.rs index f5803d2d37..fae7cc7380 100644 --- a/ethcore/src/json_tests/trie.rs +++ b/ethcore/src/json_tests/trie.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index b1782cb1d6..00113f7303 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 9c6db25cbc..d54dd2e292 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -472,7 +472,6 @@ fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256) } } - #[cfg(test)] mod tests { use super::*; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 4904535a89..bf51d0b135 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -121,7 +121,6 @@ pub struct MinerOptions { /// will be invalid if mined. pub infinite_pending_block: bool, - /// Strategy to use for prioritizing transactions in the queue. pub tx_queue_strategy: PrioritizationStrategy, /// Simple senders penalization. @@ -506,7 +505,6 @@ impl Miner { || self.engine.seals_internally() == Some(true) || had_requests; - let should_disable_sealing = !sealing_enabled; trace!(target: "miner", "requires_reseal: should_disable_sealing={}; forced={:?}, has_local={:?}, internal={:?}, had_requests={:?}", diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index fbf4f11b7a..dd5f28feb6 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -81,7 +81,6 @@ pub trait MinerService : Send + Sync { fn update_sealing(&self, chain: &C) where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; - // Notifications /// Called when blocks are imported to chain, updates transactions queue. @@ -90,7 +89,6 @@ pub trait MinerService : Send + Sync { fn chain_new_blocks(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256], is_internal_import: bool) where C: BlockChainClient; - // Pending block /// Get a list of all pending receipts from pending block. diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs index dfcdec684f..226fe21e29 100644 --- a/ethcore/src/miner/pool_client.rs +++ b/ethcore/src/miner/pool_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/miner/service_transaction_checker.rs b/ethcore/src/miner/service_transaction_checker.rs index f085564d22..adae0c36ea 100644 --- a/ethcore/src/miner/service_transaction_checker.rs +++ b/ethcore/src/miner/service_transaction_checker.rs @@ -1,4 +1,4 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! A service transactions contract checker. diff --git a/ethcore/src/miner/stratum.rs b/ethcore/src/miner/stratum.rs index c63124dcd0..0fd892bf50 100644 --- a/ethcore/src/miner/stratum.rs +++ b/ethcore/src/miner/stratum.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -111,7 +111,6 @@ pub struct StratumJobDispatcher { miner: Weak, } - impl JobDispatcher for StratumJobDispatcher { fn initial(&self) -> Option { // initial payload may contain additional data, not in this case diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 027e2765ff..281299b3b2 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -165,7 +165,6 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option u64; } - /// Restore from secondary snapshot chunks. pub trait Rebuilder: Send { /// Feed a chunk, potentially out of order. diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index b71f7b9d1d..31c7b51ec5 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/error.rs b/ethcore/src/snapshot/error.rs index 2741f648a2..36fb0927a6 100644 --- a/ethcore/src/snapshot/error.rs +++ b/ethcore/src/snapshot/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/io.rs b/ethcore/src/snapshot/io.rs index 84faa19b48..7d2cbcf92c 100644 --- a/ethcore/src/snapshot/io.rs +++ b/ethcore/src/snapshot/io.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -214,7 +214,6 @@ impl PackedReader { return Ok(None); } - file.seek(SeekFrom::End(-8))?; let mut off_bytes = [0u8; 8]; diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 8871ced26f..30a61b779c 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 942015d0f1..b76a703675 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/tests/helpers.rs b/ethcore/src/snapshot/tests/helpers.rs index 067a3abab0..516e438abd 100644 --- a/ethcore/src/snapshot/tests/helpers.rs +++ b/ethcore/src/snapshot/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/tests/mod.rs b/ethcore/src/snapshot/tests/mod.rs index 6e9398356a..c09f2b965c 100644 --- a/ethcore/src/snapshot/tests/mod.rs +++ b/ethcore/src/snapshot/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index 4b1b3d6ad0..d26ecfc404 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -52,7 +52,6 @@ lazy_static! { static ref RICH_SECRET: Secret = secret!("1"); } - /// Contract code used here: https://gist.github.com/anonymous/2a43783647e0f0dfcc359bd6fd81d6d9 /// Account with secrets keccak("1") is initially the validator. /// Transitions to the contract at block 2, initially same validator set. diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index 3c3b47ce9c..e689edf80f 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/tests/service.rs b/ethcore/src/snapshot/tests/service.rs index 3fcb0addfa..55cb0e8338 100644 --- a/ethcore/src/snapshot/tests/service.rs +++ b/ethcore/src/snapshot/tests/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index 05926a7e66..12f19e8c27 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/traits.rs b/ethcore/src/snapshot/traits.rs index d951f4c534..eec629ba6e 100644 --- a/ethcore/src/snapshot/traits.rs +++ b/ethcore/src/snapshot/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/snapshot/watcher.rs b/ethcore/src/snapshot/watcher.rs index 6e04fe6d16..6805679627 100644 --- a/ethcore/src/snapshot/watcher.rs +++ b/ethcore/src/snapshot/watcher.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/genesis.rs b/ethcore/src/spec/genesis.rs index 937d7ed873..fbfd2cbc42 100644 --- a/ethcore/src/spec/genesis.rs +++ b/ethcore/src/spec/genesis.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/mod.rs b/ethcore/src/spec/mod.rs index fb60e1cc85..35705f4a8e 100644 --- a/ethcore/src/spec/mod.rs +++ b/ethcore/src/spec/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/seal.rs b/ethcore/src/spec/seal.rs index 2a07e69c43..0ed41acc84 100644 --- a/ethcore/src/spec/seal.rs +++ b/ethcore/src/spec/seal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 98720647d8..a8ab757549 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -320,7 +320,6 @@ impl<'a, T: AsRef> From<&'a T> for SpecParams<'a> { } } - /// Parameters for a block chain; includes both those intrinsic to the design of the /// chain and those to be interpreted by the active chain engine. pub struct Spec { @@ -848,7 +847,6 @@ impl Spec { /// Create the EthereumMachine corresponding to Spec::new_test. pub fn new_test_machine() -> EthereumMachine { load_machine_bundled!("null_morden") } - /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus with applying reward on block close. pub fn new_test_with_reward() -> Spec { load_bundled!("null_morden_with_reward") } diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index 5c1dd40396..a7a40e6a3b 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/state/backend.rs b/ethcore/src/state/backend.rs index 1e761506d9..6b2e21cb46 100644 --- a/ethcore/src/state/backend.rs +++ b/ethcore/src/state/backend.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 5b969bccb9..ccca20b71e 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -51,7 +51,6 @@ use trie; use trie::{Trie, TrieError, TrieDB}; use trie::recorder::Recorder; - mod account; mod substate; diff --git a/ethcore/src/state/substate.rs b/ethcore/src/state/substate.rs index e70178a362..c2f3c62dcb 100644 --- a/ethcore/src/state/substate.rs +++ b/ethcore/src/state/substate.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 3b00a42ee6..c3704828c2 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index e57d16a654..4a83752c04 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -283,7 +283,6 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); - let mut batch = db.transaction(); for block_order in 1..block_number { // Total difficulty is always 0 here. diff --git a/ethcore/src/test_helpers_internal.rs b/ethcore/src/test_helpers_internal.rs index ef98c7c85b..7319d2d763 100644 --- a/ethcore/src/test_helpers_internal.rs +++ b/ethcore/src/test_helpers_internal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 6dcad9ba62..ccafcf6613 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -130,7 +130,6 @@ fn fails_to_import_block_with_invalid_rlp() { } } - #[test] fn query_none_block() { let tempdir = TempDir::new("").unwrap(); @@ -221,7 +220,6 @@ fn can_collect_garbage() { assert!(client.blockchain_cache_info().blocks < 100 * 1024); } - #[test] fn can_generate_gas_price_median() { let client = generate_dummy_client_with_data(3, 1, slice_into![1, 2, 3]); diff --git a/ethcore/src/tests/mod.rs b/ethcore/src/tests/mod.rs index 8b509d2afc..d1d5b6ef7f 100644 --- a/ethcore/src/tests/mod.rs +++ b/ethcore/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index a98667b142..7071ef1486 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/config.rs b/ethcore/src/trace/config.rs index dbd8a97aff..e9b003adf9 100644 --- a/ethcore/src/trace/config.rs +++ b/ethcore/src/trace/config.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs index 45b9ebc150..29f294062c 100644 --- a/ethcore/src/trace/db.rs +++ b/ethcore/src/trace/db.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -590,7 +590,6 @@ mod tests { assert!(tracedb.traces(&block_0).is_some(), "Traces should be available even if block is non-canon."); } - #[test] fn test_import() { let db = new_db(); diff --git a/ethcore/src/trace/executive_tracer.rs b/ethcore/src/trace/executive_tracer.rs index b1d116d69d..1bae15d595 100644 --- a/ethcore/src/trace/executive_tracer.rs +++ b/ethcore/src/trace/executive_tracer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/import.rs b/ethcore/src/trace/import.rs index fb72e220e4..b720b0b86a 100644 --- a/ethcore/src/trace/import.rs +++ b/ethcore/src/trace/import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 381dcd9f0d..569b2a6791 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/noop_tracer.rs b/ethcore/src/trace/noop_tracer.rs index ab0bf77ff1..8312de58f8 100644 --- a/ethcore/src/trace/noop_tracer.rs +++ b/ethcore/src/trace/noop_tracer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/error.rs b/ethcore/src/trace/types/error.rs index f2fa192d33..a934443c5d 100644 --- a/ethcore/src/trace/types/error.rs +++ b/ethcore/src/trace/types/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/filter.rs b/ethcore/src/trace/types/filter.rs index 308eb72da7..b3a5de58cd 100644 --- a/ethcore/src/trace/types/filter.rs +++ b/ethcore/src/trace/types/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index 00cf517df8..8610692200 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/localized.rs b/ethcore/src/trace/types/localized.rs index f649e16997..816eccc937 100644 --- a/ethcore/src/trace/types/localized.rs +++ b/ethcore/src/trace/types/localized.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/mod.rs b/ethcore/src/trace/types/mod.rs index a9be2865b0..0e019ac552 100644 --- a/ethcore/src/trace/types/mod.rs +++ b/ethcore/src/trace/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index cdb00a5229..1dde16e23b 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -210,7 +210,6 @@ impl Decodable for Reward { } } - /// Suicide action. #[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] pub struct Suicide { diff --git a/ethcore/src/tx_filter.rs b/ethcore/src/tx_filter.rs index 8bbb499052..a20ff8e60c 100644 --- a/ethcore/src/tx_filter.rs +++ b/ethcore/src/tx_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -198,4 +198,3 @@ mod test { assert!(!filter.transaction_allowed(&genesis, &call_tx.clone().sign(key4.secret(), None), &*client)); } } - diff --git a/ethcore/src/verification/canon_verifier.rs b/ethcore/src/verification/canon_verifier.rs index 3d0fd77c6e..0ace8987e0 100644 --- a/ethcore/src/verification/canon_verifier.rs +++ b/ethcore/src/verification/canon_verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs index d5fd4e8476..ed4227ee21 100644 --- a/ethcore/src/verification/mod.rs +++ b/ethcore/src/verification/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/noop_verifier.rs b/ethcore/src/verification/noop_verifier.rs index 24b117bbc1..d04eec9b11 100644 --- a/ethcore/src/verification/noop_verifier.rs +++ b/ethcore/src/verification/noop_verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index ce9bddf4ef..2d89f11a33 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index f7a558f33d..5ae4f7c8fc 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index de2f6c7195..3b9104f0e1 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/verification/verifier.rs b/ethcore/src/verification/verifier.rs index a9ca22a4c8..188254b431 100644 --- a/ethcore/src/verification/verifier.rs +++ b/ethcore/src/verification/verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index 3bed1818f2..2a7c2ebd53 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/body.rs b/ethcore/src/views/body.rs index d2864b9725..6560140cad 100644 --- a/ethcore/src/views/body.rs +++ b/ethcore/src/views/body.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/header.rs b/ethcore/src/views/header.rs index 8d407f0a1b..4b7b1225d0 100644 --- a/ethcore/src/views/header.rs +++ b/ethcore/src/views/header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/mod.rs b/ethcore/src/views/mod.rs index b9cbad8889..6d32649382 100644 --- a/ethcore/src/views/mod.rs +++ b/ethcore/src/views/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -38,4 +38,4 @@ mod tests { fn should_include_file_line_number_in_panic_for_invalid_rlp() { let _ = view!(HeaderView, &[]).parent_hash(); } -} \ No newline at end of file +} diff --git a/ethcore/src/views/transaction.rs b/ethcore/src/views/transaction.rs index 5607482b30..911fde944e 100644 --- a/ethcore/src/views/transaction.rs +++ b/ethcore/src/views/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/src/views/view_rlp.rs b/ethcore/src/views/view_rlp.rs index 6afdb3af8c..2ecc4dbdd3 100644 --- a/ethcore/src/views/view_rlp.rs +++ b/ethcore/src/views/view_rlp.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -127,4 +127,4 @@ macro_rules! view { ($view: ident, $bytes: expr) => { $view::new($crate::views::ViewRlp::new($bytes, file!(), line!())) }; -} \ No newline at end of file +} diff --git a/ethcore/stratum/src/lib.rs b/ethcore/stratum/src/lib.rs index a4abeffd73..0e9de9b43c 100644 --- a/ethcore/stratum/src/lib.rs +++ b/ethcore/stratum/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/stratum/src/traits.rs b/ethcore/stratum/src/traits.rs index 431d338a42..d1bb9a4da7 100644 --- a/ethcore/stratum/src/traits.rs +++ b/ethcore/stratum/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 8419fccd7a..b759fb734a 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -536,7 +536,6 @@ pub trait ManageNetwork : Send + Sync { fn with_proto_context(&self, proto: ProtocolId, f: &mut FnMut(&NetworkContext)); } - impl ManageNetwork for EthSync { fn accept_unreserved_peers(&self) { self.network.set_non_reserved_mode(NonReservedPeerMode::Accept); diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index 7411fa30cc..bff9bb071a 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs index 283f4ed610..8485b1d75e 100644 --- a/ethcore/sync/src/blocks.rs +++ b/ethcore/sync/src/blocks.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -194,7 +194,6 @@ impl BlockCollection { needed_bodies } - /// Returns a set of block hashes that require a receipt download. The returned set is marked as being downloaded. pub fn needed_receipts(&mut self, count: usize, _ignore_downloading: bool) -> Vec { if self.head.is_none() || !self.need_receipts { @@ -616,4 +615,3 @@ mod test { assert_eq!(bc.drain().len(), 2); } } - diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index c0ee8299b8..8f0aff7514 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -1348,7 +1348,6 @@ pub mod tests { client.set_nonce(sender, U256::from(0)); } - // when { let queue = RwLock::new(VecDeque::new()); diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index c00ea5e440..35483f4ec3 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/mod.rs b/ethcore/sync/src/light_sync/mod.rs index 9fa669817a..32e3a0dbfd 100644 --- a/ethcore/sync/src/light_sync/mod.rs +++ b/ethcore/sync/src/light_sync/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs index 3629613224..161461c2a5 100644 --- a/ethcore/sync/src/light_sync/response.rs +++ b/ethcore/sync/src/light_sync/response.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/sync_round.rs b/ethcore/sync/src/light_sync/sync_round.rs index d477ecc815..79684efe53 100644 --- a/ethcore/sync/src/light_sync/sync_round.rs +++ b/ethcore/sync/src/light_sync/sync_round.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/tests/mod.rs b/ethcore/sync/src/light_sync/tests/mod.rs index 3fee1c7170..e3d46188a6 100644 --- a/ethcore/sync/src/light_sync/tests/mod.rs +++ b/ethcore/sync/src/light_sync/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/light_sync/tests/test_net.rs b/ethcore/sync/src/light_sync/tests/test_net.rs index badd35668b..5995bd7c6c 100644 --- a/ethcore/sync/src/light_sync/tests/test_net.rs +++ b/ethcore/sync/src/light_sync/tests/test_net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/private_tx.rs b/ethcore/sync/src/private_tx.rs index ded5de2d86..d7434c8bd5 100644 --- a/ethcore/sync/src/private_tx.rs +++ b/ethcore/sync/src/private_tx.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/snapshot.rs b/ethcore/sync/src/snapshot.rs index b603a2a007..e5632e652b 100644 --- a/ethcore/sync/src/snapshot.rs +++ b/ethcore/sync/src/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -274,4 +274,3 @@ mod test { assert_eq!(snapshot.is_known_bad(&hash), true); } } - diff --git a/ethcore/sync/src/sync_io.rs b/ethcore/sync/src/sync_io.rs index 76f323e826..c7704724c6 100644 --- a/ethcore/sync/src/sync_io.rs +++ b/ethcore/sync/src/sync_io.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -136,5 +136,3 @@ impl<'s> SyncIo for NetSyncIo<'s> { self.network.peer_client_version(peer_id) } } - - diff --git a/ethcore/sync/src/tests/chain.rs b/ethcore/sync/src/tests/chain.rs index 6b5ef65da1..0d9c83f2fb 100644 --- a/ethcore/sync/src/tests/chain.rs +++ b/ethcore/sync/src/tests/chain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -253,7 +253,6 @@ fn high_td_attach() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5); } - #[test] fn disconnect_on_unrelated_chain() { ::env_logger::init().ok(); @@ -267,4 +266,3 @@ fn disconnect_on_unrelated_chain() { net.sync(); assert_eq!(net.disconnect_events, vec![(0, 0)]); } - diff --git a/ethcore/sync/src/tests/consensus.rs b/ethcore/sync/src/tests/consensus.rs index 8825bad2c8..6b2502f4a6 100644 --- a/ethcore/sync/src/tests/consensus.rs +++ b/ethcore/sync/src/tests/consensus.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/tests/helpers.rs b/ethcore/sync/src/tests/helpers.rs index 407f699e0e..112dab8a98 100644 --- a/ethcore/sync/src/tests/helpers.rs +++ b/ethcore/sync/src/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/tests/mod.rs b/ethcore/sync/src/tests/mod.rs index eb01108286..0168913aa1 100644 --- a/ethcore/sync/src/tests/mod.rs +++ b/ethcore/sync/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/tests/private.rs b/ethcore/sync/src/tests/private.rs index b54240bfb8..120dc8fc9c 100644 --- a/ethcore/sync/src/tests/private.rs +++ b/ethcore/sync/src/tests/private.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/tests/rpc.rs b/ethcore/sync/src/tests/rpc.rs index 5806fbbd8d..99e95959be 100644 --- a/ethcore/sync/src/tests/rpc.rs +++ b/ethcore/sync/src/tests/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/sync/src/tests/snapshot.rs b/ethcore/sync/src/tests/snapshot.rs index ffb71d7a73..e6636c02f4 100644 --- a/ethcore/sync/src/tests/snapshot.rs +++ b/ethcore/sync/src/tests/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -154,4 +154,3 @@ fn snapshot_sync() { assert_eq!(net.peer(4).snapshot_service.state_restoration_chunks.lock().len(), net.peer(0).snapshot_service.manifest.as_ref().unwrap().state_hashes.len()); assert_eq!(net.peer(4).snapshot_service.block_restoration_chunks.lock().len(), net.peer(0).snapshot_service.manifest.as_ref().unwrap().block_hashes.len()); } - diff --git a/ethcore/sync/src/transactions_stats.rs b/ethcore/sync/src/transactions_stats.rs index 4d33008621..c45b1ad8b3 100644 --- a/ethcore/sync/src/transactions_stats.rs +++ b/ethcore/sync/src/transactions_stats.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/transaction/src/error.rs b/ethcore/transaction/src/error.rs index eeeba4e53a..0efd18ae6b 100644 --- a/ethcore/transaction/src/error.rs +++ b/ethcore/transaction/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -130,4 +130,3 @@ impl error::Error for Error { "Transaction error" } } - diff --git a/ethcore/transaction/src/lib.rs b/ethcore/transaction/src/lib.rs index 6a478b9463..829613cf9c 100644 --- a/ethcore/transaction/src/lib.rs +++ b/ethcore/transaction/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 6152e61acb..dd1e8ca2cc 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/account_diff.rs b/ethcore/types/src/account_diff.rs index c3edb1fb1e..521ed8ab1f 100644 --- a/ethcore/types/src/account_diff.rs +++ b/ethcore/types/src/account_diff.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -138,4 +138,3 @@ impl fmt::Display for AccountDiff { Ok(()) } } - diff --git a/ethcore/types/src/basic_account.rs b/ethcore/types/src/basic_account.rs index 79e75dfc01..94157977bc 100644 --- a/ethcore/types/src/basic_account.rs +++ b/ethcore/types/src/basic_account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/block_status.rs b/ethcore/types/src/block_status.rs index d330b9ed1b..5455f1d40f 100644 --- a/ethcore/types/src/block_status.rs +++ b/ethcore/types/src/block_status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/blockchain_info.rs b/ethcore/types/src/blockchain_info.rs index 836ee7618b..ddd91623d1 100644 --- a/ethcore/types/src/blockchain_info.rs +++ b/ethcore/types/src/blockchain_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/call_analytics.rs b/ethcore/types/src/call_analytics.rs index b0520a0d3f..ae53e6911e 100644 --- a/ethcore/types/src/call_analytics.rs +++ b/ethcore/types/src/call_analytics.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/filter.rs b/ethcore/types/src/filter.rs index 0a37482b94..c32551473d 100644 --- a/ethcore/types/src/filter.rs +++ b/ethcore/types/src/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/ids.rs b/ethcore/types/src/ids.rs index e304698a4c..d1457832c0 100644 --- a/ethcore/types/src/ids.rs +++ b/ethcore/types/src/ids.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 18e0dde86a..8db6163bbf 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/log_entry.rs b/ethcore/types/src/log_entry.rs index 951a7389f2..0b7455df49 100644 --- a/ethcore/types/src/log_entry.rs +++ b/ethcore/types/src/log_entry.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/mode.rs b/ethcore/types/src/mode.rs index 539ebcdbd8..ee4f9fbf2c 100644 --- a/ethcore/types/src/mode.rs +++ b/ethcore/types/src/mode.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/pruning_info.rs b/ethcore/types/src/pruning_info.rs index 8a47fdd8b9..fcf4a774a2 100644 --- a/ethcore/types/src/pruning_info.rs +++ b/ethcore/types/src/pruning_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index 8846d27c02..b4f105afab 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/restoration_status.rs b/ethcore/types/src/restoration_status.rs index 51f5b8aa0a..ec15bf4809 100644 --- a/ethcore/types/src/restoration_status.rs +++ b/ethcore/types/src/restoration_status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -40,4 +40,3 @@ pub enum RestorationStatus { /// Failed restoration. Failed, } - diff --git a/ethcore/types/src/security_level.rs b/ethcore/types/src/security_level.rs index ea39dc3280..5917584704 100644 --- a/ethcore/types/src/security_level.rs +++ b/ethcore/types/src/security_level.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/snapshot_manifest.rs b/ethcore/types/src/snapshot_manifest.rs index c59402023a..40ff4c532f 100644 --- a/ethcore/types/src/snapshot_manifest.rs +++ b/ethcore/types/src/snapshot_manifest.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -76,4 +76,3 @@ impl ManifestData { }) } } - diff --git a/ethcore/types/src/state_diff.rs b/ethcore/types/src/state_diff.rs index dd976eb36c..4cc85fff93 100644 --- a/ethcore/types/src/state_diff.rs +++ b/ethcore/types/src/state_diff.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/trace_filter.rs b/ethcore/types/src/trace_filter.rs index 2afa752ccb..69a3787027 100644 --- a/ethcore/types/src/trace_filter.rs +++ b/ethcore/types/src/trace_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/tree_route.rs b/ethcore/types/src/tree_route.rs index 5d1bddd87b..9c84052be3 100644 --- a/ethcore/types/src/tree_route.rs +++ b/ethcore/types/src/tree_route.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/types/src/verification_queue_info.rs b/ethcore/types/src/verification_queue_info.rs index db818590af..bc280b15bf 100644 --- a/ethcore/types/src/verification_queue_info.rs +++ b/ethcore/types/src/verification_queue_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/action_params.rs b/ethcore/vm/src/action_params.rs index 9e9a35528c..481f637310 100644 --- a/ethcore/vm/src/action_params.rs +++ b/ethcore/vm/src/action_params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/call_type.rs b/ethcore/vm/src/call_type.rs index dc00b2b839..0e58d76bbd 100644 --- a/ethcore/vm/src/call_type.rs +++ b/ethcore/vm/src/call_type.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + //! EVM call types. use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; diff --git a/ethcore/vm/src/env_info.rs b/ethcore/vm/src/env_info.rs index 71bb48eeb7..bb1c9ecd91 100644 --- a/ethcore/vm/src/env_info.rs +++ b/ethcore/vm/src/env_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/error.rs b/ethcore/vm/src/error.rs index fe8d7054cf..ad23e3e020 100644 --- a/ethcore/vm/src/error.rs +++ b/ethcore/vm/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -71,7 +71,6 @@ pub enum Error { Reverted, } - impl From> for Error { fn from(err: Box) -> Self { Error::Internal(format!("Internal error: {}", err)) diff --git a/ethcore/vm/src/ext.rs b/ethcore/vm/src/ext.rs index 98661e47e2..166e8712aa 100644 --- a/ethcore/vm/src/ext.rs +++ b/ethcore/vm/src/ext.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs index 67fc59bab5..0dc1b79954 100644 --- a/ethcore/vm/src/lib.rs +++ b/ethcore/vm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/return_data.rs b/ethcore/vm/src/return_data.rs index 067a26e35e..24191ec55f 100644 --- a/ethcore/vm/src/return_data.rs +++ b/ethcore/vm/src/return_data.rs @@ -1,3 +1,5 @@ +// Copyright 2015-2018 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 diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index a0085ef1ec..960821e72c 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index daf46be0f0..9a17e0d3dc 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/wasm/run/src/fixture.rs b/ethcore/wasm/run/src/fixture.rs index ba2da06706..9fc1ca6fef 100644 --- a/ethcore/wasm/run/src/fixture.rs +++ b/ethcore/wasm/run/src/fixture.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::borrow::Cow; use ethjson::uint::Uint; use ethjson::hash::{Address, H256}; @@ -67,4 +83,4 @@ pub enum Assert { HasStorage(StorageAssert), UsedGas(u64), Return(Bytes), -} \ No newline at end of file +} diff --git a/ethcore/wasm/run/src/main.rs b/ethcore/wasm/run/src/main.rs index ab8ac631df..d2a3a0ff50 100644 --- a/ethcore/wasm/run/src/main.rs +++ b/ethcore/wasm/run/src/main.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate serde; extern crate serde_json; #[macro_use] extern crate serde_derive; diff --git a/ethcore/wasm/run/src/runner.rs b/ethcore/wasm/run/src/runner.rs index 5ae0f941a4..3e24ced5db 100644 --- a/ethcore/wasm/run/src/runner.rs +++ b/ethcore/wasm/run/src/runner.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use fixture::{Fixture, Assert, CallLocator, Source}; use wasm::WasmInterpreter; use vm::{self, Vm, GasLeft, ActionParams, ActionValue, ParamsType}; diff --git a/ethcore/wasm/src/env.rs b/ethcore/wasm/src/env.rs index 7ffaaf98ab..9bcbee63fb 100644 --- a/ethcore/wasm/src/env.rs +++ b/ethcore/wasm/src/env.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -295,4 +295,4 @@ impl wasmi::ModuleImportResolver for ImportResolver { Err(Error::Instantiation("Memory imported under unknown name".to_owned())) } } -} \ No newline at end of file +} diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index 5605a7ea18..f1290318e0 100644 --- a/ethcore/wasm/src/lib.rs +++ b/ethcore/wasm/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/wasm/src/panic_payload.rs b/ethcore/wasm/src/panic_payload.rs index dc95f53fbf..36aa6c5f58 100644 --- a/ethcore/wasm/src/panic_payload.rs +++ b/ethcore/wasm/src/panic_payload.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethcore/wasm/src/parser.rs b/ethcore/wasm/src/parser.rs index 62cd66cb98..1efb89e1bd 100644 --- a/ethcore/wasm/src/parser.rs +++ b/ethcore/wasm/src/parser.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -95,4 +95,4 @@ pub fn payload<'a>(params: &'a vm::ActionParams, wasm_costs: &vm::WasmCosts) }; Ok((contract_module, data)) -} \ No newline at end of file +} diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 2b71a1768e..b32ca75ae9 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/cli/src/main.rs b/ethkey/cli/src/main.rs index 0dfc8aecde..c8f5e2e64e 100644 --- a/ethkey/cli/src/main.rs +++ b/ethkey/cli/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/brain.rs b/ethkey/src/brain.rs index fffae0bed8..55b525e2a4 100644 --- a/ethkey/src/brain.rs +++ b/ethkey/src/brain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/brain_prefix.rs b/ethkey/src/brain_prefix.rs index a4e31e989c..accf947370 100644 --- a/ethkey/src/brain_prefix.rs +++ b/ethkey/src/brain_prefix.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/brain_recover.rs b/ethkey/src/brain_recover.rs index f064c6fd0e..5133193232 100644 --- a/ethkey/src/brain_recover.rs +++ b/ethkey/src/brain_recover.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -21,7 +21,6 @@ use parity_wordlist; use super::{Address, Brain, Generator}; - /// Tries to find a phrase for address, given the number /// of expected words and a partial phrase. /// @@ -150,7 +149,6 @@ impl Iterator for PhrasesIterator { mod tests { use super::PhrasesIterator; - #[test] fn should_generate_possible_combinations() { let mut it = PhrasesIterator::new(vec![ diff --git a/ethkey/src/crypto.rs b/ethkey/src/crypto.rs index 739a463c07..3ff809614e 100644 --- a/ethkey/src/crypto.rs +++ b/ethkey/src/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/error.rs b/ethkey/src/error.rs index c7faf67788..7cba375d0f 100644 --- a/ethkey/src/error.rs +++ b/ethkey/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/extended.rs b/ethkey/src/extended.rs index d41ae54c53..89a4bb26a0 100644 --- a/ethkey/src/extended.rs +++ b/ethkey/src/extended.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/keccak.rs b/ethkey/src/keccak.rs index 002f20d946..3801d841ab 100644 --- a/ethkey/src/keccak.rs +++ b/ethkey/src/keccak.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/keypair.rs b/ethkey/src/keypair.rs index 5a13d476bb..610c14524f 100644 --- a/ethkey/src/keypair.rs +++ b/ethkey/src/keypair.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/lib.rs b/ethkey/src/lib.rs index b5cf984530..7aec015c47 100644 --- a/ethkey/src/lib.rs +++ b/ethkey/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/math.rs b/ethkey/src/math.rs index e2426b4fbd..6b1d4013bd 100644 --- a/ethkey/src/math.rs +++ b/ethkey/src/math.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/prefix.rs b/ethkey/src/prefix.rs index f2ef0f0ffb..2668050ef8 100644 --- a/ethkey/src/prefix.rs +++ b/ethkey/src/prefix.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/random.rs b/ethkey/src/random.rs index b44a4b2ca8..d42bb4ea4d 100644 --- a/ethkey/src/random.rs +++ b/ethkey/src/random.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index c3bf2a12ba..a3560698af 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethkey/src/signature.rs b/ethkey/src/signature.rs index ec225ec011..cd6d88fe18 100644 --- a/ethkey/src/signature.rs +++ b/ethkey/src/signature.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/cli/src/crack.rs b/ethstore/cli/src/crack.rs index 64eda66e56..3e767a6084 100644 --- a/ethstore/cli/src/crack.rs +++ b/ethstore/cli/src/crack.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::{cmp, thread}; use std::sync::Arc; use std::collections::VecDeque; diff --git a/ethstore/cli/src/main.rs b/ethstore/cli/src/main.rs index 8ebb206a0b..416b64d43e 100644 --- a/ethstore/cli/src/main.rs +++ b/ethstore/cli/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/cli/tests/cli.rs b/ethstore/cli/tests/cli.rs index a740b95c28..1b899f7082 100644 --- a/ethstore/cli/tests/cli.rs +++ b/ethstore/cli/tests/cli.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -74,7 +74,6 @@ fn cli_cmd() { "--vault-pwd", test_password]); assert_eq!(output, "0x54ab6e5cf0c5cb40043fdca5d15d611a3a94285414a076dafecc8dc9c04183f413296a3defff61092c0bb478dc9887ec01070e1275234211208fb8f4be4a9b0101\n"); - let output = run(&["public", &address[2..], test_vault_addr, "--dir", dir_str, "--vault", "test-vault", diff --git a/ethstore/src/account/cipher.rs b/ethstore/src/account/cipher.rs index 427ccafc4a..92a5304edb 100644 --- a/ethstore/src/account/cipher.rs +++ b/ethstore/src/account/cipher.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs index bd65bc927b..3143958a12 100644 --- a/ethstore/src/account/crypto.rs +++ b/ethstore/src/account/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/account/kdf.rs b/ethstore/src/account/kdf.rs index 31b8f304ca..4d6d7cd956 100644 --- a/ethstore/src/account/kdf.rs +++ b/ethstore/src/account/kdf.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/account/mod.rs b/ethstore/src/account/mod.rs index c352ffe78f..e13237d827 100644 --- a/ethstore/src/account/mod.rs +++ b/ethstore/src/account/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,4 +25,3 @@ pub use self::crypto::Crypto; pub use self::kdf::{Kdf, Pbkdf2, Scrypt, Prf}; pub use self::safe_account::SafeAccount; pub use self::version::Version; - diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 069c997e10..0bda99d02c 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/account/version.rs b/ethstore/src/account/version.rs index 2ba0848a68..d206a2c12d 100644 --- a/ethstore/src/account/version.rs +++ b/ethstore/src/account/version.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/accounts_dir/disk.rs b/ethstore/src/accounts_dir/disk.rs index 29b7e52466..79e8c0f4c3 100644 --- a/ethstore/src/accounts_dir/disk.rs +++ b/ethstore/src/accounts_dir/disk.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -153,7 +153,6 @@ impl DiskDirectory where T: KeyFileManager { ) } - /// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to /// true, a random suffix is appended to the filename. pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result { diff --git a/ethstore/src/accounts_dir/memory.rs b/ethstore/src/accounts_dir/memory.rs index 5cfdba0e5c..71ddfa536e 100644 --- a/ethstore/src/accounts_dir/memory.rs +++ b/ethstore/src/accounts_dir/memory.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -72,4 +72,3 @@ impl KeyDirectory for MemoryDirectory { Ok(val) } } - diff --git a/ethstore/src/accounts_dir/mod.rs b/ethstore/src/accounts_dir/mod.rs index ec72d05da3..b8dd313d26 100644 --- a/ethstore/src/accounts_dir/mod.rs +++ b/ethstore/src/accounts_dir/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/accounts_dir/vault.rs b/ethstore/src/accounts_dir/vault.rs index 2705262666..b2f6ce6160 100644 --- a/ethstore/src/accounts_dir/vault.rs +++ b/ethstore/src/accounts_dir/vault.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/error.rs b/ethstore/src/error.rs index 7c89473280..6a2c257633 100644 --- a/ethstore/src/error.rs +++ b/ethstore/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/ethkey.rs b/ethstore/src/ethkey.rs index 4821263910..34e89a4fb5 100644 --- a/ethstore/src/ethkey.rs +++ b/ethstore/src/ethkey.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 46c81153c7..13780f7f63 100644 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/import.rs b/ethstore/src/import.rs index 2aaef51f50..876119fd50 100644 --- a/ethstore/src/import.rs +++ b/ethstore/src/import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/bytes.rs b/ethstore/src/json/bytes.rs index de2c645636..b5aae19222 100644 --- a/ethstore/src/json/bytes.rs +++ b/ethstore/src/json/bytes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -72,4 +72,3 @@ impl From for Vec { b.0 } } - diff --git a/ethstore/src/json/cipher.rs b/ethstore/src/json/cipher.rs index 33f4ec5721..6fffdde9e2 100644 --- a/ethstore/src/json/cipher.rs +++ b/ethstore/src/json/cipher.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/crypto.rs b/ethstore/src/json/crypto.rs index 03f72e576e..0a926cc83f 100644 --- a/ethstore/src/json/crypto.rs +++ b/ethstore/src/json/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/error.rs b/ethstore/src/json/error.rs index 8a5029642d..81b805bfe2 100644 --- a/ethstore/src/json/error.rs +++ b/ethstore/src/json/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/hash.rs b/ethstore/src/json/hash.rs index 13564c95d1..c2ad547734 100644 --- a/ethstore/src/json/hash.rs +++ b/ethstore/src/json/hash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/id.rs b/ethstore/src/json/id.rs index aa90a4d7a4..7df5c8f7e5 100644 --- a/ethstore/src/json/id.rs +++ b/ethstore/src/json/id.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/kdf.rs b/ethstore/src/json/kdf.rs index 6498323be2..f8df3c2285 100644 --- a/ethstore/src/json/kdf.rs +++ b/ethstore/src/json/kdf.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/key_file.rs b/ethstore/src/json/key_file.rs index 60b34681e2..2c3cf3fdd5 100644 --- a/ethstore/src/json/key_file.rs +++ b/ethstore/src/json/key_file.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -102,7 +102,6 @@ impl<'a> Deserialize<'a> for KeyFile { } } - fn none_if_empty<'a, T>(v: Option) -> Option where T: DeserializeOwned { diff --git a/ethstore/src/json/mod.rs b/ethstore/src/json/mod.rs index 865b75dea6..e39bff651e 100644 --- a/ethstore/src/json/mod.rs +++ b/ethstore/src/json/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/presale.rs b/ethstore/src/json/presale.rs index d1cffcb6ad..478f328a43 100644 --- a/ethstore/src/json/presale.rs +++ b/ethstore/src/json/presale.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::io::Read; use serde_json; use super::{H160, Bytes}; diff --git a/ethstore/src/json/vault_file.rs b/ethstore/src/json/vault_file.rs index d11e71451f..e962044227 100644 --- a/ethstore/src/json/vault_file.rs +++ b/ethstore/src/json/vault_file.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/vault_key_file.rs b/ethstore/src/json/vault_key_file.rs index 76c59b3808..818487d52b 100644 --- a/ethstore/src/json/vault_key_file.rs +++ b/ethstore/src/json/vault_key_file.rs @@ -1,4 +1,4 @@ -// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/json/version.rs b/ethstore/src/json/version.rs index 0eb8450f14..683d4a520f 100644 --- a/ethstore/src/json/version.rs +++ b/ethstore/src/json/version.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -56,4 +56,3 @@ impl<'a> Visitor<'a> for VersionVisitor { } } } - diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index b558126ada..67e636dd5c 100644 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index 555d00c1e9..d7b80d240c 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::fs; use std::path::Path; use json; diff --git a/ethstore/src/random.rs b/ethstore/src/random.rs index af754471e1..b8b7a71fa8 100644 --- a/ethstore/src/random.rs +++ b/ethstore/src/random.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -43,4 +43,3 @@ pub fn random_string(length: usize) -> String { let mut rng = OsRng::new().expect("Not able to operate without random source."); rng.gen_ascii_chars().take(length).collect() } - diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs index ebac2f9922..fd37267a74 100644 --- a/ethstore/src/secret_store.rs +++ b/ethstore/src/secret_store.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/tests/api.rs b/ethstore/tests/api.rs index fb24ff3367..5e4eaab817 100644 --- a/ethstore/tests/api.rs +++ b/ethstore/tests/api.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/tests/util/mod.rs b/ethstore/tests/util/mod.rs index c0002d4e13..1a7abc93ef 100644 --- a/ethstore/tests/util/mod.rs +++ b/ethstore/tests/util/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ethstore/tests/util/transient_dir.rs b/ethstore/tests/util/transient_dir.rs index dcc65ec698..c0969418d8 100644 --- a/ethstore/tests/util/transient_dir.rs +++ b/ethstore/tests/util/transient_dir.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/benches/mod.rs b/evmbin/benches/mod.rs index 6b6746e747..8fdd5e9cfe 100644 --- a/evmbin/benches/mod.rs +++ b/evmbin/benches/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -83,4 +83,3 @@ fn rng(gas: U256, b: &mut Bencher) { run_vm(params) }); } - diff --git a/evmbin/src/display/json.rs b/evmbin/src/display/json.rs index 00ca91b94f..ccee9c3717 100644 --- a/evmbin/src/display/json.rs +++ b/evmbin/src/display/json.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -156,7 +156,6 @@ impl trace::VMTracer for Informant { self.storage.insert(pos.into(), val.into()); } - if !self.subtraces.is_empty() { self.traces.extend(mem::replace(&mut self.subtraces, vec![])); } diff --git a/evmbin/src/display/mod.rs b/evmbin/src/display/mod.rs index b9390058b6..a8eb20d9e6 100644 --- a/evmbin/src/display/mod.rs +++ b/evmbin/src/display/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/src/display/simple.rs b/evmbin/src/display/simple.rs index 30bb8ffcf7..8ff863cfa9 100644 --- a/evmbin/src/display/simple.rs +++ b/evmbin/src/display/simple.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/src/display/std_json.rs b/evmbin/src/display/std_json.rs index 3d8f52dbd1..6c4dac1626 100644 --- a/evmbin/src/display/std_json.rs +++ b/evmbin/src/display/std_json.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/src/info.rs b/evmbin/src/info.rs index 1be81d9132..d1cd3cf6fc 100644 --- a/evmbin/src/info.rs +++ b/evmbin/src/info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/evmbin/src/main.rs b/evmbin/src/main.rs index bddb40ecd2..4620143f76 100644 --- a/evmbin/src/main.rs +++ b/evmbin/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -83,7 +83,6 @@ General options: -h, --help Display this message and exit. "#; - fn main() { panic_hook::set(); diff --git a/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index 1c7d417758..ebdab681a4 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/hash-fetch/src/lib.rs b/hash-fetch/src/lib.rs index 18176be500..bdbb0e3505 100644 --- a/hash-fetch/src/lib.rs +++ b/hash-fetch/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/hash-fetch/src/urlhint.rs b/hash-fetch/src/urlhint.rs index d05dd40a22..d80566ea62 100644 --- a/hash-fetch/src/urlhint.rs +++ b/hash-fetch/src/urlhint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -265,8 +265,6 @@ pub mod tests { let calls = registrar.calls.clone(); let urlhint = URLHintContract::new(Arc::new(registrar)); - - // when let res = urlhint.resolve("test".as_bytes().into()).wait().unwrap(); let calls = calls.lock(); @@ -353,7 +351,6 @@ pub mod tests { let url4 = "https://parity.io/parity.png#content-type=image/jpeg"; let url5 = "https://parity.io/parity.png"; - assert_eq!(guess_mime_type(url1), None); assert_eq!(guess_mime_type(url2), Some(mime::IMAGE_PNG)); assert_eq!(guess_mime_type(url3), Some(mime::IMAGE_PNG)); diff --git a/hw/src/ledger.rs b/hw/src/ledger.rs index e31d49f130..992a565d5a 100644 --- a/hw/src/ledger.rs +++ b/hw/src/ledger.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/hw/src/lib.rs b/hw/src/lib.rs index f51be356ae..4cc0d30856 100644 --- a/hw/src/lib.rs +++ b/hw/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -92,7 +92,6 @@ pub trait Wallet<'a> { where F: Fn() -> Result; } - /// Hardware wallet error. #[derive(Debug)] pub enum Error { diff --git a/hw/src/trezor.rs b/hw/src/trezor.rs index 044e5487b4..21dcd9c9fd 100644 --- a/hw/src/trezor.rs +++ b/hw/src/trezor.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -164,7 +164,6 @@ impl Manager { unlocked } - fn u256_to_be_vec(&self, val: &U256) -> Vec { let mut buf = [0u8; 32]; val.to_big_endian(&mut buf); diff --git a/ipfs/src/error.rs b/ipfs/src/error.rs index fadd75b9b4..1ff2829553 100644 --- a/ipfs/src/error.rs +++ b/ipfs/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ipfs/src/lib.rs b/ipfs/src/lib.rs index bb7d0c3897..7f6ebe77c4 100644 --- a/ipfs/src/lib.rs +++ b/ipfs/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/ipfs/src/route.rs b/ipfs/src/route.rs index 2beb4ccc37..8f57fc4d10 100644 --- a/ipfs/src/route.rs +++ b/ipfs/src/route.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs index 66b5f9b844..38a0b1fa9c 100644 --- a/json/src/blockchain/account.rs +++ b/json/src/blockchain/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs index 503230f09e..5a6c995658 100644 --- a/json/src/blockchain/block.rs +++ b/json/src/blockchain/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 9edd753130..9e4d650b85 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index 667a36bb1b..ee79a928ea 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/mod.rs b/json/src/blockchain/mod.rs index e1faa07880..0d8e7ff78f 100644 --- a/json/src/blockchain/mod.rs +++ b/json/src/blockchain/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs index a64887572b..e23a31efa0 100644 --- a/json/src/blockchain/state.rs +++ b/json/src/blockchain/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs index 018ae767dd..792303dc7e 100644 --- a/json/src/blockchain/test.rs +++ b/json/src/blockchain/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/blockchain/transaction.rs b/json/src/blockchain/transaction.rs index 6b3550fd78..f14dd5e336 100644 --- a/json/src/blockchain/transaction.rs +++ b/json/src/blockchain/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 79ba4f896b..3eb1f54152 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/hash.rs b/json/src/hash.rs index 54aea04365..8dac3f6e73 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,7 +23,6 @@ use serde::de::{Error, Visitor}; use rustc_hex::ToHex; use ethereum_types::{H64 as Hash64, H160 as Hash160, H256 as Hash256, H520 as Hash520, Bloom as Hash2048}; - macro_rules! impl_hash { ($name: ident, $inner: ident) => { /// Lenient hash json deserialization for test json files. diff --git a/json/src/lib.rs b/json/src/lib.rs index 3cb1e49f57..5d31cd6c97 100644 --- a/json/src/lib.rs +++ b/json/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/maybe.rs b/json/src/maybe.rs index 8b74b22c48..1f77a98ef1 100644 --- a/json/src/maybe.rs +++ b/json/src/maybe.rs @@ -1,3 +1,18 @@ +// Copyright 2015-2018 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 . //! Deserializer of empty string values into optionals. diff --git a/json/src/misc/account_meta.rs b/json/src/misc/account_meta.rs index 9c4d67286e..cb6ed1c877 100644 --- a/json/src/misc/account_meta.rs +++ b/json/src/misc/account_meta.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/misc/dapps_settings.rs b/json/src/misc/dapps_settings.rs index 5081c62b28..f59f5f1cf6 100644 --- a/json/src/misc/dapps_settings.rs +++ b/json/src/misc/dapps_settings.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/misc/mod.rs b/json/src/misc/mod.rs index d587f2f157..836094f0c0 100644 --- a/json/src/misc/mod.rs +++ b/json/src/misc/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/account.rs b/json/src/spec/account.rs index fb41137aa9..acc6d96b58 100644 --- a/json/src/spec/account.rs +++ b/json/src/spec/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/authority_round.rs b/json/src/spec/authority_round.rs index 4ef9368362..e355c6fe95 100644 --- a/json/src/spec/authority_round.rs +++ b/json/src/spec/authority_round.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/basic_authority.rs b/json/src/spec/basic_authority.rs index 0a257f134b..1e5c6b8456 100644 --- a/json/src/spec/basic_authority.rs +++ b/json/src/spec/basic_authority.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/builtin.rs b/json/src/spec/builtin.rs index 34e9a2df1c..850867d095 100644 --- a/json/src/spec/builtin.rs +++ b/json/src/spec/builtin.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/engine.rs b/json/src/spec/engine.rs index e2545a5f90..55b9c1b2af 100644 --- a/json/src/spec/engine.rs +++ b/json/src/spec/engine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -142,4 +142,3 @@ mod tests { }; } } - diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs index 66f6913e57..19fd096627 100644 --- a/json/src/spec/ethash.rs +++ b/json/src/spec/ethash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/genesis.rs b/json/src/spec/genesis.rs index f595e7750f..d8e2ad5357 100644 --- a/json/src/spec/genesis.rs +++ b/json/src/spec/genesis.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/hardcoded_sync.rs b/json/src/spec/hardcoded_sync.rs index 548fd66f0f..8b00b5413b 100644 --- a/json/src/spec/hardcoded_sync.rs +++ b/json/src/spec/hardcoded_sync.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/mod.rs b/json/src/spec/mod.rs index 285596f14a..26965c887d 100644 --- a/json/src/spec/mod.rs +++ b/json/src/spec/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/null_engine.rs b/json/src/spec/null_engine.rs index cfd3d6ce63..87827bd5b9 100644 --- a/json/src/spec/null_engine.rs +++ b/json/src/spec/null_engine.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index f171a88101..e03fe7081b 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/seal.rs b/json/src/spec/seal.rs index 6654a309a3..b61d141d64 100644 --- a/json/src/spec/seal.rs +++ b/json/src/spec/seal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs index 7003cb4cfc..2be695689e 100644 --- a/json/src/spec/spec.rs +++ b/json/src/spec/spec.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/state.rs b/json/src/spec/state.rs index ad6f2e548d..d15ad540ce 100644 --- a/json/src/spec/state.rs +++ b/json/src/spec/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/tendermint.rs b/json/src/spec/tendermint.rs index 8f3d4c2248..e0a6568aa9 100644 --- a/json/src/spec/tendermint.rs +++ b/json/src/spec/tendermint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/spec/validator_set.rs b/json/src/spec/validator_set.rs index 9c6b4e79a1..41fa60961a 100644 --- a/json/src/spec/validator_set.rs +++ b/json/src/spec/validator_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/log.rs b/json/src/state/log.rs index 823979f627..1e07d9ed1e 100644 --- a/json/src/state/log.rs +++ b/json/src/state/log.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/mod.rs b/json/src/state/mod.rs index 316744983c..6037ca514d 100644 --- a/json/src/state/mod.rs +++ b/json/src/state/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/state.rs b/json/src/state/state.rs index 9daecaed8e..c6837d1fd6 100644 --- a/json/src/state/state.rs +++ b/json/src/state/state.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/test.rs b/json/src/state/test.rs index 3a25c007df..528a49b5a6 100644 --- a/json/src/state/test.rs +++ b/json/src/state/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/state/transaction.rs b/json/src/state/transaction.rs index 606c40f21f..89edb08692 100644 --- a/json/src/state/transaction.rs +++ b/json/src/state/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/test/mod.rs b/json/src/test/mod.rs index 1a6e4db7da..8f95a9aec4 100644 --- a/json/src/test/mod.rs +++ b/json/src/test/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,4 +64,3 @@ impl DifficultyTest { serde_json::from_reader(reader) } } - diff --git a/json/src/transaction/mod.rs b/json/src/transaction/mod.rs index 5cde3eff40..8ebab3f1c2 100644 --- a/json/src/transaction/mod.rs +++ b/json/src/transaction/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/transaction/test.rs b/json/src/transaction/test.rs index a2ef9ad36a..e1bd588de3 100644 --- a/json/src/transaction/test.rs +++ b/json/src/transaction/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/transaction/transaction.rs b/json/src/transaction/transaction.rs index d9b6abb14e..13b342b3f6 100644 --- a/json/src/transaction/transaction.rs +++ b/json/src/transaction/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/transaction/txtest.rs b/json/src/transaction/txtest.rs index 33bc0152f2..60d65e70d6 100644 --- a/json/src/transaction/txtest.rs +++ b/json/src/transaction/txtest.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/input.rs b/json/src/trie/input.rs index c84f1aa1e1..e1c46ac537 100644 --- a/json/src/trie/input.rs +++ b/json/src/trie/input.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/mod.rs b/json/src/trie/mod.rs index ce19922058..5dc52cb21d 100644 --- a/json/src/trie/mod.rs +++ b/json/src/trie/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/test.rs b/json/src/trie/test.rs index 30811ca661..c6cd99c25e 100644 --- a/json/src/trie/test.rs +++ b/json/src/trie/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/trie/trie.rs b/json/src/trie/trie.rs index e4951f8141..ca18de7daa 100644 --- a/json/src/trie/trie.rs +++ b/json/src/trie/trie.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/uint.rs b/json/src/uint.rs index 70e0390a34..25c5049c45 100644 --- a/json/src/uint.rs +++ b/json/src/uint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/call.rs b/json/src/vm/call.rs index 39d5a828eb..026951c028 100644 --- a/json/src/vm/call.rs +++ b/json/src/vm/call.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/env.rs b/json/src/vm/env.rs index c7f0ccd725..f4af8119c3 100644 --- a/json/src/vm/env.rs +++ b/json/src/vm/env.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/mod.rs b/json/src/vm/mod.rs index a2588e37c7..29b12d4805 100644 --- a/json/src/vm/mod.rs +++ b/json/src/vm/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/test.rs b/json/src/vm/test.rs index 68112e6015..10b4aae54f 100644 --- a/json/src/vm/test.rs +++ b/json/src/vm/test.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/transaction.rs b/json/src/vm/transaction.rs index efdad0f9cc..44b79e8622 100644 --- a/json/src/vm/transaction.rs +++ b/json/src/vm/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/json/src/vm/vm.rs b/json/src/vm/vm.rs index 8cc01e3bac..7fd101da83 100644 --- a/json/src/vm/vm.rs +++ b/json/src/vm/vm.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/license_header b/license_header index f90ec463dc..4738554f91 100644 --- a/license_header +++ b/license_header @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/local-store/src/lib.rs b/local-store/src/lib.rs index 078dff36ed..83bc07b901 100644 --- a/local-store/src/lib.rs +++ b/local-store/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/logger/src/lib.rs b/logger/src/lib.rs index 863075a0e5..2a50969802 100644 --- a/logger/src/lib.rs +++ b/logger/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/logger/src/rotating.rs b/logger/src/rotating.rs index e67bdfaad0..ddc24792ae 100644 --- a/logger/src/rotating.rs +++ b/logger/src/rotating.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -121,4 +121,3 @@ mod test { assert_eq!(logs.len(), 2); } } - diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 075a42d731..6d152851da 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/external.rs b/miner/src/external.rs index b49a9a4e2c..a56be42f02 100644 --- a/miner/src/external.rs +++ b/miner/src/external.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -106,7 +106,6 @@ mod tests { m.submit_hashrate(U256::from(15), H256::from(1)); m.submit_hashrate(U256::from(20), H256::from(2)); - // then assert_eq!(m.hashrate(), U256::from(35)); } diff --git a/miner/src/gas_pricer.rs b/miner/src/gas_pricer.rs index f826ccf77d..ecb69ba572 100644 --- a/miner/src/gas_pricer.rs +++ b/miner/src/gas_pricer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 08ea7d204f..107b9b22b5 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/pool/client.rs b/miner/src/pool/client.rs index 622e9a8492..bdf57312ee 100644 --- a/miner/src/pool/client.rs +++ b/miner/src/pool/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/pool/listener.rs b/miner/src/pool/listener.rs index 3f42372e84..e881a2ba29 100644 --- a/miner/src/pool/listener.rs +++ b/miner/src/pool/listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,7 +64,6 @@ impl txpool::Listener for Notifier { } } - /// Transaction pool logger. #[derive(Default, Debug)] pub struct Logger; @@ -113,7 +112,6 @@ impl txpool::Listener for Logger { } } - #[cfg(test)] mod tests { use super::*; diff --git a/miner/src/pool/local_transactions.rs b/miner/src/pool/local_transactions.rs index 12ffa84c19..d69da3347a 100644 --- a/miner/src/pool/local_transactions.rs +++ b/miner/src/pool/local_transactions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -190,7 +190,6 @@ impl txpool::Listener for LocalTransactionsList { self.clear_old(); } - /// The transaction has been mined. fn mined(&mut self, tx: &Arc) { if !tx.priority().is_local() { diff --git a/miner/src/pool/mod.rs b/miner/src/pool/mod.rs index 45d28f3c12..57f813157b 100644 --- a/miner/src/pool/mod.rs +++ b/miner/src/pool/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index 8cf4534b76..bd5a98edc7 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -412,7 +412,6 @@ impl TransactionQueue { } } - fn convert_error(err: txpool::Error) -> transaction::Error { use self::txpool::ErrorKind; diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs index c2829b34a9..0b4d27f7f2 100644 --- a/miner/src/pool/ready.rs +++ b/miner/src/pool/ready.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -83,7 +83,6 @@ impl txpool::Ready for State { _ => {}, } - let sender = tx.sender(); let state = &self.state; let state_nonce = || state.account_nonce(sender); diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs index aedc40e1f2..e7551ed6a3 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/pool/tests/client.rs b/miner/src/pool/tests/client.rs index a00cc541eb..101b6cdc21 100644 --- a/miner/src/pool/tests/client.rs +++ b/miner/src/pool/tests/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 85dedaaa45..552903a4bb 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -491,7 +491,6 @@ fn should_accept_same_transaction_twice_if_removed() { let (tx1, _) = txs.clone(); let (hash, _) = txs.hash(); - let res = txq.import(TestClient::new(), txs.local().into_vec()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); @@ -731,7 +730,6 @@ fn should_not_return_transactions_over_nonce_cap() { // This should invalidate the cache! let limited = txq.pending(TestClient::new(), 0, 0, Some(123.into())); - // then assert_eq!(all.len(), 3); assert_eq!(limited.len(), 1); diff --git a/miner/src/pool/tests/tx.rs b/miner/src/pool/tests/tx.rs index c0f8751ebb..a8b06f5436 100644 --- a/miner/src/pool/tests/tx.rs +++ b/miner/src/pool/tests/tx.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,7 +64,6 @@ impl Tx { self.nonce += 1; let tx3 = self.unsigned().sign(keypair.secret(), None); - (tx1, tx2, tx3) } diff --git a/miner/src/pool/verifier.rs b/miner/src/pool/verifier.rs index 0a89a784b1..4675303928 100644 --- a/miner/src/pool/verifier.rs +++ b/miner/src/pool/verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -91,7 +91,6 @@ impl Transaction { } } - fn gas_price(&self) -> &U256 { match *self { Transaction::Unverified(ref tx) => &tx.gas_price, diff --git a/miner/src/work_notify.rs b/miner/src/work_notify.rs index 3436938097..8825fd4b65 100644 --- a/miner/src/work_notify.rs +++ b/miner/src/work_notify.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity-clib-example/main.cpp b/parity-clib-example/main.cpp index becce8598e..c5e83d0649 100644 --- a/parity-clib-example/main.cpp +++ b/parity-clib-example/main.cpp @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + #include #include #include diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs index fe631ce8a8..f7a98f811d 100644 --- a/parity-clib/src/lib.rs +++ b/parity-clib/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/account.rs b/parity/account.rs index 676cf93e73..c2f15546e6 100644 --- a/parity/account.rs +++ b/parity/account.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 027814f245..d33ac1eacb 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/cache.rs b/parity/cache.rs index 0bf0717a30..5848e404c2 100644 --- a/parity/cache.rs +++ b/parity/cache.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/cli/presets/mod.rs b/parity/cli/presets/mod.rs index ca1ad4559b..125ab510c3 100644 --- a/parity/cli/presets/mod.rs +++ b/parity/cli/presets/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -25,4 +25,4 @@ pub fn preset_config_string(arg: &str) -> Result<&'static str, Error> { "dev-insecure" => Ok(include_str!("./config.dev-insecure.toml")), _ => Err(Error::new(ErrorKind::InvalidInput, "Config doesn't match any presets [dev, mining, non-standard-ports, insecure, dev-insecure]")) } -} \ No newline at end of file +} diff --git a/parity/cli/usage.rs b/parity/cli/usage.rs index ce138fdff3..9a892c0091 100644 --- a/parity/cli/usage.rs +++ b/parity/cli/usage.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/configuration.rs b/parity/configuration.rs index 426b651015..6f475aa83c 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -1982,7 +1982,6 @@ mod tests { assert_eq!(conf0.ipfs_config().port, 5002); assert_eq!(conf0.stratum_options().unwrap().unwrap().port, 8009); - assert_eq!(conf1.net_addresses().unwrap().0.port(), 30304); assert_eq!(conf1.network_settings().unwrap().network_port, 30304); assert_eq!(conf1.network_settings().unwrap().rpc_port, 8545); diff --git a/parity/dapps.rs b/parity/dapps.rs index 2219f7cbee..427bfa53b3 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/db/rocksdb/migration.rs b/parity/db/rocksdb/migration.rs index df6a4b5dc9..e92a9db035 100644 --- a/parity/db/rocksdb/migration.rs +++ b/parity/db/rocksdb/migration.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -40,7 +40,6 @@ pub const TO_V12: ChangeColumns = ChangeColumns { version: 12, }; - /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; /// Current version of database models. diff --git a/parity/deprecated.rs b/parity/deprecated.rs index b41475d9db..f3e433d138 100644 --- a/parity/deprecated.rs +++ b/parity/deprecated.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -160,4 +160,3 @@ mod tests { ]); } } - diff --git a/parity/export_hardcoded_sync.rs b/parity/export_hardcoded_sync.rs index 3aa2b56149..008a5b9ecd 100644 --- a/parity/export_hardcoded_sync.rs +++ b/parity/export_hardcoded_sync.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/helpers.rs b/parity/helpers.rs index a5ec3c99d4..8de3728c3a 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/ipfs.rs b/parity/ipfs.rs index ac9a4662b2..2cc2effca5 100644 --- a/parity/ipfs.rs +++ b/parity/ipfs.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/light_helpers/epoch_fetch.rs b/parity/light_helpers/epoch_fetch.rs index 1b9ae86484..a7d8f4171f 100644 --- a/parity/light_helpers/epoch_fetch.rs +++ b/parity/light_helpers/epoch_fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/light_helpers/mod.rs b/parity/light_helpers/mod.rs index 5fc9c516b4..c30b62da55 100644 --- a/parity/light_helpers/mod.rs +++ b/parity/light_helpers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index b6be59e2ce..03ec2efe74 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/modules.rs b/parity/modules.rs index cf46149b8e..e12e8ee458 100644 --- a/parity/modules.rs +++ b/parity/modules.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/params.rs b/parity/params.rs index 957b280193..9ceac1e4f0 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/presale.rs b/parity/presale.rs index 216ff66a84..4106ad8992 100644 --- a/parity/presale.rs +++ b/parity/presale.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/rpc.rs b/parity/rpc.rs index 21bc9a4096..cdc8e7ca5b 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -212,7 +212,6 @@ pub fn new_ws( let url = format!("{}:{}", conf.interface, conf.port); let addr = url.parse().map_err(|_| format!("Invalid WebSockets listen host/port given: {}", url))?; - let full_handler = setup_apis(rpc_apis::ApiSet::SafeContext, deps); let handler = { let mut handler = MetaIoHandler::with_middleware(( diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 855f917b13..ce30f3cd85 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/run.rs b/parity/run.rs index bd8d4fb4a8..b1bf67f022 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 168a9b3fcf..3b4a4e468c 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/signer.rs b/parity/signer.rs index ab476ef9d7..4388e11aa8 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 3c0dadedaa..90ae8327a6 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/stratum.rs b/parity/stratum.rs index 043ba50622..efaa6b307c 100644 --- a/parity/stratum.rs +++ b/parity/stratum.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/upgrade.rs b/parity/upgrade.rs index c5c2e1ed48..d98123ce13 100644 --- a/parity/upgrade.rs +++ b/parity/upgrade.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/url.rs b/parity/url.rs index 4f547c28f0..d9eb2c9d3c 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/user_defaults.rs b/parity/user_defaults.rs index be91e302eb..cb4a0a40a4 100644 --- a/parity/user_defaults.rs +++ b/parity/user_defaults.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/parity/whisper.rs b/parity/whisper.rs index bb9aebf0b9..c3c8854dcb 100644 --- a/parity/whisper.rs +++ b/parity/whisper.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/price-info/src/lib.rs b/price-info/src/lib.rs index e3594ad2ae..93dacca338 100644 --- a/price-info/src/lib.rs +++ b/price-info/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/registrar/src/lib.rs b/registrar/src/lib.rs index 961fbb17ee..aad33765ef 100644 --- a/registrar/src/lib.rs +++ b/registrar/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/registrar/src/registrar.rs b/registrar/src/registrar.rs index c4128660d2..0a17de499a 100644 --- a/registrar/src/registrar.rs +++ b/registrar/src/registrar.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -74,4 +74,3 @@ pub trait RegistrarClient: Send + Sync { /// Call Contract fn call_contract(&self, address: Address, data: Bytes) -> Self::Call; } - diff --git a/rpc/src/authcodes.rs b/rpc/src/authcodes.rs index d18d0741fd..5b7309a317 100644 --- a/rpc/src/authcodes.rs +++ b/rpc/src/authcodes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/http_common.rs b/rpc/src/http_common.rs index 72af6e4697..8296720b20 100644 --- a/rpc/src/http_common.rs +++ b/rpc/src/http_common.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 1fc3d0e242..2d49a8c771 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/tests/helpers.rs b/rpc/src/tests/helpers.rs index db61353d53..602648d063 100644 --- a/rpc/src/tests/helpers.rs +++ b/rpc/src/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/tests/mod.rs b/rpc/src/tests/mod.rs index d4d9538dca..6ecab3299a 100644 --- a/rpc/src/tests/mod.rs +++ b/rpc/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/tests/rpc.rs b/rpc/src/tests/rpc.rs index 6e2900c8b7..015c2764a6 100644 --- a/rpc/src/tests/rpc.rs +++ b/rpc/src/tests/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/tests/ws.rs b/rpc/src/tests/ws.rs index 429ff6d3c4..91f10e6475 100644 --- a/rpc/src/tests/ws.rs +++ b/rpc/src/tests/ws.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -177,7 +177,6 @@ mod testing { ) ); - // then assert_eq!(response1.status, "HTTP/1.1 101 Switching Protocols".to_owned()); assert_eq!(response2.status, "HTTP/1.1 403 Forbidden".to_owned()); diff --git a/rpc/src/v1/extractors.rs b/rpc/src/v1/extractors.rs index 071e57dae4..c69c41dddf 100644 --- a/rpc/src/v1/extractors.rs +++ b/rpc/src/v1/extractors.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/accounts.rs b/rpc/src/v1/helpers/accounts.rs new file mode 100644 index 0000000000..4268bf2f99 --- /dev/null +++ b/rpc/src/v1/helpers/accounts.rs @@ -0,0 +1,27 @@ +// Copyright 2015-2018 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 . + +use std::sync::Arc; +use ethcore::account_provider::AccountProvider; +use jsonrpc_core::Error; +use v1::helpers::errors; + +pub fn unwrap_provider(provider: &Option>) -> Result, Error> { + match *provider { + Some(ref arc) => Ok(arc.clone()), + None => Err(errors::public_unsupported(None)), + } +} diff --git a/rpc/src/v1/helpers/block_import.rs b/rpc/src/v1/helpers/block_import.rs index 1246faa658..9e947e5baa 100644 --- a/rpc/src/v1/helpers/block_import.rs +++ b/rpc/src/v1/helpers/block_import.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -35,7 +35,6 @@ mod tests { use sync::SyncState; use super::is_major_importing; - fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo { BlockQueueInfo { unverified_queue_size: unverified, diff --git a/rpc/src/v1/helpers/dapps.rs b/rpc/src/v1/helpers/dapps.rs index 391a12c824..88a9cce6fb 100644 --- a/rpc/src/v1/helpers/dapps.rs +++ b/rpc/src/v1/helpers/dapps.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 1f43ef008e..9bec8e1d31 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 0d36a926e9..6207d4542f 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/fake_sign.rs b/rpc/src/v1/helpers/fake_sign.rs index 84a225d814..eca8a5abbd 100644 --- a/rpc/src/v1/helpers/fake_sign.rs +++ b/rpc/src/v1/helpers/fake_sign.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/ipfs.rs b/rpc/src/v1/helpers/ipfs.rs index da51f1fd54..12980d3f41 100644 --- a/rpc/src/v1/helpers/ipfs.rs +++ b/rpc/src/v1/helpers/ipfs.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index 1baf9a7647..c11f47a456 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -86,7 +86,6 @@ pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_t .map(|tx| Transaction::from_localized(tx, eip86_transition)) } - /// Type alias for convenience. pub type ExecutionResult = ::std::result::Result; diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index 9adb5d68d4..97b96675e4 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/network_settings.rs b/rpc/src/v1/helpers/network_settings.rs index a798286244..d011d2394f 100644 --- a/rpc/src/v1/helpers/network_settings.rs +++ b/rpc/src/v1/helpers/network_settings.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -13,6 +13,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . + //! Structure to hold network settings configured from CLI /// Networking & RPC settings diff --git a/rpc/src/v1/helpers/nonce.rs b/rpc/src/v1/helpers/nonce.rs index 06f38a8589..12dfd3d520 100644 --- a/rpc/src/v1/helpers/nonce.rs +++ b/rpc/src/v1/helpers/nonce.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 harity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/oneshot.rs b/rpc/src/v1/helpers/oneshot.rs index 89e90dbd18..5ede0ae912 100644 --- a/rpc/src/v1/helpers/oneshot.rs +++ b/rpc/src/v1/helpers/oneshot.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index 7ef8db0f15..c7284d6651 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + //! Helper type with all filter state data. use std::collections::HashSet; diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index f367f669fd..e176ed440e 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/requests.rs b/rpc/src/v1/helpers/requests.rs index 13bfbb1b38..478f6785b4 100644 --- a/rpc/src/v1/helpers/requests.rs +++ b/rpc/src/v1/helpers/requests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/secretstore.rs b/rpc/src/v1/helpers/secretstore.rs index 019d2b1051..f23222824f 100644 --- a/rpc/src/v1/helpers/secretstore.rs +++ b/rpc/src/v1/helpers/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/helpers/signer.rs b/rpc/src/v1/helpers/signer.rs index 6d9606f878..0ee14bad1b 100644 --- a/rpc/src/v1/helpers/signer.rs +++ b/rpc/src/v1/helpers/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -88,4 +88,3 @@ impl Deref for SignerService { &self.queue } } - diff --git a/rpc/src/v1/helpers/signing_queue.rs b/rpc/src/v1/helpers/signing_queue.rs index b73535ba4f..c6a8048825 100644 --- a/rpc/src/v1/helpers/signing_queue.rs +++ b/rpc/src/v1/helpers/signing_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -227,7 +227,6 @@ impl SigningQueue for ConfirmationsQueue { } } - #[cfg(test)] mod test { use std::sync::Arc; diff --git a/rpc/src/v1/helpers/subscribers.rs b/rpc/src/v1/helpers/subscribers.rs index 11dd45d11b..6871207643 100644 --- a/rpc/src/v1/helpers/subscribers.rs +++ b/rpc/src/v1/helpers/subscribers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -22,7 +22,6 @@ use jsonrpc_macros::pubsub::{Subscriber, Sink, SubscriptionId}; use rand::{Rng, StdRng}; use v1::types::H64; - #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub struct Id(H64); impl str::FromStr for Id { diff --git a/rpc/src/v1/helpers/subscription_manager.rs b/rpc/src/v1/helpers/subscription_manager.rs index 5988824b6a..5f6d77d883 100644 --- a/rpc/src/v1/helpers/subscription_manager.rs +++ b/rpc/src/v1/helpers/subscription_manager.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 32ba36deb8..38e36cf11c 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -495,7 +495,6 @@ impl Eth for EthClient< _ => (false, None, None), }; - if warping || is_major_importing(Some(status.state), client.queue_info()) { let chain_info = client.chain_info(); let current_block = U256::from(chain_info.best_block_number); diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 6ca1c355f3..bbad2fe27d 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -102,8 +102,6 @@ impl Filterable for EthFilterClient where fn polls(&self) -> &Mutex> { &self.polls } } - - impl EthFilter for T { fn new_filter(&self, filter: Filter) -> Result { let mut polls = self.polls().lock(); diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index c0789910c3..11fef2e0bd 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 10ad024f24..68afe649b8 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/mod.rs b/rpc/src/v1/impls/light/mod.rs index 38ba2438e2..40f1df8990 100644 --- a/rpc/src/v1/impls/light/mod.rs +++ b/rpc/src/v1/impls/light/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/net.rs b/rpc/src/v1/impls/light/net.rs index 1b374247a3..4dbc9d1908 100644 --- a/rpc/src/v1/impls/light/net.rs +++ b/rpc/src/v1/impls/light/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 025538fc42..91db00ca30 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index 76c33cf458..4e907deaf1 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/light/trace.rs b/rpc/src/v1/impls/light/trace.rs index 1d2c7fcaa0..d1e99fb9a1 100644 --- a/rpc/src/v1/impls/light/trace.rs +++ b/rpc/src/v1/impls/light/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 4edaf6bcd2..1349147207 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 3f42f01b94..74521d8135 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index f5d4a58949..e3ad5a3b1b 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index adb97db28d..eb069cf27f 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 612e6aa78b..4ba9ab658e 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index da5ef983a2..045496fc95 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/private.rs b/rpc/src/v1/impls/private.rs index 4034d2b9a1..a1110eed11 100644 --- a/rpc/src/v1/impls/private.rs +++ b/rpc/src/v1/impls/private.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/pubsub.rs b/rpc/src/v1/impls/pubsub.rs index 59eef19533..564c8b90d5 100644 --- a/rpc/src/v1/impls/pubsub.rs +++ b/rpc/src/v1/impls/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/rpc.rs b/rpc/src/v1/impls/rpc.rs index 3c76a31646..9f15cc1a38 100644 --- a/rpc/src/v1/impls/rpc.rs +++ b/rpc/src/v1/impls/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/secretstore.rs b/rpc/src/v1/impls/secretstore.rs index f85fa6f584..52404a58d0 100644 --- a/rpc/src/v1/impls/secretstore.rs +++ b/rpc/src/v1/impls/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index eafa07ad4d..14fd6a33a4 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/signing.rs b/rpc/src/v1/impls/signing.rs index 71cf18a06b..6229a54c84 100644 --- a/rpc/src/v1/impls/signing.rs +++ b/rpc/src/v1/impls/signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/signing_unsafe.rs b/rpc/src/v1/impls/signing_unsafe.rs index 75f5f5e2bf..f14d1e028d 100644 --- a/rpc/src/v1/impls/signing_unsafe.rs +++ b/rpc/src/v1/impls/signing_unsafe.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 0130b3b9c1..0e43d8c11a 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index 6fd6ff7a46..aa30447285 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/informant.rs b/rpc/src/v1/informant.rs index 9a9cde3837..07a70eeb10 100644 --- a/rpc/src/v1/informant.rs +++ b/rpc/src/v1/informant.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/metadata.rs b/rpc/src/v1/metadata.rs index f0644d455c..970ec60e48 100644 --- a/rpc/src/v1/metadata.rs +++ b/rpc/src/v1/metadata.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 154317eb2f..cb510ae294 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index e0931ae6bf..7354eb18b0 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2016 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/helpers/dapps.rs b/rpc/src/v1/tests/helpers/dapps.rs index 10c54cf4c2..70f42a29e5 100644 --- a/rpc/src/v1/tests/helpers/dapps.rs +++ b/rpc/src/v1/tests/helpers/dapps.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 6781d10b95..90201e346a 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index 8e1aeeb147..a2782eec60 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/helpers/snapshot_service.rs b/rpc/src/v1/tests/helpers/snapshot_service.rs index 91cd14d73f..4e45488dbe 100644 --- a/rpc/src/v1/tests/helpers/snapshot_service.rs +++ b/rpc/src/v1/tests/helpers/snapshot_service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index a5ca4a4b36..7cb0acffef 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -123,4 +123,3 @@ impl SyncProvider for TestSyncProvider { ] } } - diff --git a/rpc/src/v1/tests/helpers/update_service.rs b/rpc/src/v1/tests/helpers/update_service.rs index eaa3b06fbe..3c4d0b1d7d 100644 --- a/rpc/src/v1/tests/helpers/update_service.rs +++ b/rpc/src/v1/tests/helpers/update_service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index a6c8772439..a8875a3354 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -149,7 +149,6 @@ fn rpc_eth_syncing() { // causes TestBlockChainClient to return 1000 for its best block number. tester.add_blocks(1000, EachBlockWith::Nothing); - let true_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x3e8","highestBlock":"0x9c4","startingBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null},"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(true_res.to_owned())); @@ -221,7 +220,6 @@ fn rpc_eth_logs() { log_index: 1, }]); - let request1 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{}], "id": 1}"#; let request2 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":1}], "id": 1}"#; let request3 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":0}], "id": 1}"#; @@ -582,7 +580,6 @@ fn rpc_eth_pending_transaction_by_hash() { assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } - #[test] fn rpc_eth_uncle_count_by_block_hash() { let request = r#"{ @@ -933,7 +930,6 @@ fn rpc_eth_send_transaction_with_bad_to() { assert_eq!(tester.io.handle_request_sync(&request), Some(response.into())); } - #[test] fn rpc_eth_send_transaction_error() { let tester = EthTester::default(); diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index 936695a9a1..0d886fe2f1 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -144,7 +144,6 @@ fn should_subscribe_to_logs() { + r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"removed"},"subscription":"0x416d77337e24399d"}}"#; assert_eq!(res, Some(response.into())); - // And unsubscribe let request = r#"{"jsonrpc": "2.0", "method": "eth_unsubscribe", "params": ["0x416d77337e24399d"], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; @@ -154,7 +153,6 @@ fn should_subscribe_to_logs() { assert_eq!(res, None); } - #[test] fn should_subscribe_to_pending_transactions() { // given diff --git a/rpc/src/v1/tests/mocked/manage_network.rs b/rpc/src/v1/tests/mocked/manage_network.rs index da4f1aa511..a742f03c2f 100644 --- a/rpc/src/v1/tests/mocked/manage_network.rs +++ b/rpc/src/v1/tests/mocked/manage_network.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs index ae51c2be67..a3de3b3b71 100644 --- a/rpc/src/v1/tests/mocked/mod.rs +++ b/rpc/src/v1/tests/mocked/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/net.rs b/rpc/src/v1/tests/mocked/net.rs index 0f77dfb11a..b94bf2b113 100644 --- a/rpc/src/v1/tests/mocked/net.rs +++ b/rpc/src/v1/tests/mocked/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index c27615a589..c9dd50a3c6 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -150,7 +150,6 @@ fn rpc_parity_default_account() { let deps = Dependencies::new(); let io = deps.default_client(); - // Check empty let address = Address::default(); let request = r#"{"jsonrpc": "2.0", "method": "parity_defaultAccount", "params": [], "id": 1}"#; diff --git a/rpc/src/v1/tests/mocked/parity_accounts.rs b/rpc/src/v1/tests/mocked/parity_accounts.rs index c30b4b9ced..8342641d6c 100644 --- a/rpc/src/v1/tests/mocked/parity_accounts.rs +++ b/rpc/src/v1/tests/mocked/parity_accounts.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -206,7 +206,6 @@ fn rpc_parity_set_and_get_new_dapps_default_address() { assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } - #[test] fn rpc_parity_recent_dapps() { // given @@ -474,7 +473,6 @@ fn derive_key_index() { assert_eq!(res, Some(response.into())); } - #[test] fn should_export_account() { // given diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index 78c73f9479..bc9f04de7c 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -181,7 +181,6 @@ fn rpc_parity_set_engine_signer() { assert_eq!(*miner.password.read(), "password".to_string()); } - #[test] fn rpc_parity_set_transactions_limit() { let miner = miner_service(); diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 323f9fe137..131a865da7 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/pubsub.rs b/rpc/src/v1/tests/mocked/pubsub.rs index 99b34366c8..a21f8a4903 100644 --- a/rpc/src/v1/tests/mocked/pubsub.rs +++ b/rpc/src/v1/tests/mocked/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -75,4 +75,3 @@ fn should_subscribe_to_a_method() { let (res, _receiver) = receiver.into_future().wait().unwrap(); assert_eq!(res, None); } - diff --git a/rpc/src/v1/tests/mocked/rpc.rs b/rpc/src/v1/tests/mocked/rpc.rs index d0a6d2fab4..ed6503cea5 100644 --- a/rpc/src/v1/tests/mocked/rpc.rs +++ b/rpc/src/v1/tests/mocked/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -18,7 +18,6 @@ use std::collections::BTreeMap; use jsonrpc_core::IoHandler; use v1::{Rpc, RpcClient}; - fn rpc_client() -> RpcClient { let mut modules = BTreeMap::new(); modules.insert("rpc".to_owned(), "1.0".to_owned()); diff --git a/rpc/src/v1/tests/mocked/secretstore.rs b/rpc/src/v1/tests/mocked/secretstore.rs index 6ee9b6c245..33592a4883 100644 --- a/rpc/src/v1/tests/mocked/secretstore.rs +++ b/rpc/src/v1/tests/mocked/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/signer.rs b/rpc/src/v1/tests/mocked/signer.rs index 8881dc41c3..8bbb590c06 100644 --- a/rpc/src/v1/tests/mocked/signer.rs +++ b/rpc/src/v1/tests/mocked/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -76,7 +76,6 @@ fn signer_tester() -> SignerTester { } } - #[test] fn should_return_list_of_items_to_confirm() { // given @@ -107,7 +106,6 @@ fn should_return_list_of_items_to_confirm() { assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); } - #[test] fn should_reject_transaction_from_queue_without_dispatching() { // given diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 84cf2e376e..2dc80f066c 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -393,7 +393,6 @@ fn should_decrypt_message_if_account_is_unlocked() { let (address, public) = tester.accounts.new_account_and_public("test").unwrap(); tester.accounts.unlock_account_permanently(address, "test".into()).unwrap(); - // First encrypt message let request = format!("{}0x{:x}{}", r#"{"jsonrpc": "2.0", "method": "parity_encryptMessage", "params":[""#, @@ -473,7 +472,6 @@ fn should_compose_transaction() { + &from + r#"","gas":"0x5208","gasPrice":"0x4a817c800","nonce":"0x0","to":null,"value":"0x5"},"id":1}"#; - // then let res = tester.io.handle_request(&request).wait().unwrap(); assert_eq!(res, Some(response.to_owned())); diff --git a/rpc/src/v1/tests/mocked/traces.rs b/rpc/src/v1/tests/mocked/traces.rs index 0b2e7d5ccb..70a862d332 100644 --- a/rpc/src/v1/tests/mocked/traces.rs +++ b/rpc/src/v1/tests/mocked/traces.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mocked/web3.rs b/rpc/src/v1/tests/mocked/web3.rs index 3c78d67ad3..e16c5f4926 100644 --- a/rpc/src/v1/tests/mocked/web3.rs +++ b/rpc/src/v1/tests/mocked/web3.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 31ac1c5410..471569e523 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + //! RPC unit test moduleS pub mod helpers; diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index f4ea1e10d6..48e315ce7e 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/eth_pubsub.rs b/rpc/src/v1/traits/eth_pubsub.rs index cfbe4c54bc..38babeef42 100644 --- a/rpc/src/v1/traits/eth_pubsub.rs +++ b/rpc/src/v1/traits/eth_pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/eth_signing.rs b/rpc/src/v1/traits/eth_signing.rs index 9830ac54d8..27657475ba 100644 --- a/rpc/src/v1/traits/eth_signing.rs +++ b/rpc/src/v1/traits/eth_signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index 26a43fa3f8..62edac8ed6 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/net.rs b/rpc/src/v1/traits/net.rs index bc2068ff9a..d70a4653a6 100644 --- a/rpc/src/v1/traits/net.rs +++ b/rpc/src/v1/traits/net.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 83d8b19811..f78cf8052e 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/parity_accounts.rs b/rpc/src/v1/traits/parity_accounts.rs index 494f1576cb..977593d44e 100644 --- a/rpc/src/v1/traits/parity_accounts.rs +++ b/rpc/src/v1/traits/parity_accounts.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index 40aad1a4bd..8cfffb50c7 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/parity_signing.rs b/rpc/src/v1/traits/parity_signing.rs index 8015b04317..208422222e 100644 --- a/rpc/src/v1/traits/parity_signing.rs +++ b/rpc/src/v1/traits/parity_signing.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/personal.rs b/rpc/src/v1/traits/personal.rs index 7c187fcffe..7187219105 100644 --- a/rpc/src/v1/traits/personal.rs +++ b/rpc/src/v1/traits/personal.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/private.rs b/rpc/src/v1/traits/private.rs index 7106e0bf43..b7b1aa20a7 100644 --- a/rpc/src/v1/traits/private.rs +++ b/rpc/src/v1/traits/private.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/pubsub.rs b/rpc/src/v1/traits/pubsub.rs index 0b77fc64d6..840de8d4b0 100644 --- a/rpc/src/v1/traits/pubsub.rs +++ b/rpc/src/v1/traits/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/rpc.rs b/rpc/src/v1/traits/rpc.rs index a813aa94e6..8c0b3c2c90 100644 --- a/rpc/src/v1/traits/rpc.rs +++ b/rpc/src/v1/traits/rpc.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/secretstore.rs b/rpc/src/v1/traits/secretstore.rs index 6d2e5669c0..e15d71a72f 100644 --- a/rpc/src/v1/traits/secretstore.rs +++ b/rpc/src/v1/traits/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/signer.rs b/rpc/src/v1/traits/signer.rs index b7f60619e8..4ede0ce534 100644 --- a/rpc/src/v1/traits/signer.rs +++ b/rpc/src/v1/traits/signer.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/traces.rs b/rpc/src/v1/traits/traces.rs index 1fe01f47ef..2d3665f6bc 100644 --- a/rpc/src/v1/traits/traces.rs +++ b/rpc/src/v1/traits/traces.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/traits/web3.rs b/rpc/src/v1/traits/web3.rs index e4fb8b0d1f..713cd9a32d 100644 --- a/rpc/src/v1/traits/web3.rs +++ b/rpc/src/v1/traits/web3.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/account_info.rs b/rpc/src/v1/types/account_info.rs index f9cabb450b..5a0e2952a1 100644 --- a/rpc/src/v1/types/account_info.rs +++ b/rpc/src/v1/types/account_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -41,4 +41,3 @@ pub struct HwAccountInfo { /// Device manufacturer. pub manufacturer: String, } - diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 486e3b9c14..9ae870dc55 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index b6c1860f5b..b92a0d4a3f 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -135,4 +135,3 @@ mod tests { block_number_to_id(BlockNumber::Pending); } } - diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index fdbcb729bb..0bd62c601c 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -86,7 +86,6 @@ impl<'a> Visitor<'a> for BytesVisitor { } } - #[cfg(test)] mod tests { use super::*; @@ -118,4 +117,3 @@ mod tests { assert_eq!(bytes6, Bytes(vec![0x1, 0x23])); } } - diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs index 71b562e45a..39d4d17b78 100644 --- a/rpc/src/v1/types/call_request.rs +++ b/rpc/src/v1/types/call_request.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/confirmations.rs b/rpc/src/v1/types/confirmations.rs index 5dcb11316c..7f4f3ad106 100644 --- a/rpc/src/v1/types/confirmations.rs +++ b/rpc/src/v1/types/confirmations.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/consensus_status.rs b/rpc/src/v1/types/consensus_status.rs index 96657adbc9..0cbdf1f007 100644 --- a/rpc/src/v1/types/consensus_status.rs +++ b/rpc/src/v1/types/consensus_status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/dapps.rs b/rpc/src/v1/types/dapps.rs index 418717fccf..81339fb1dc 100644 --- a/rpc/src/v1/types/dapps.rs +++ b/rpc/src/v1/types/dapps.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/derivation.rs b/rpc/src/v1/types/derivation.rs index 76becbaebe..0e39b65322 100644 --- a/rpc/src/v1/types/derivation.rs +++ b/rpc/src/v1/types/derivation.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index 52217459c1..dd8b823e87 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/hash.rs b/rpc/src/v1/types/hash.rs index e3cc73e272..07c7ef24f4 100644 --- a/rpc/src/v1/types/hash.rs +++ b/rpc/src/v1/types/hash.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/histogram.rs b/rpc/src/v1/types/histogram.rs index 26bbc7d2de..2b71b88bf6 100644 --- a/rpc/src/v1/types/histogram.rs +++ b/rpc/src/v1/types/histogram.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! Gas prices histogram. diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs index 4e44ce49ce..4c8af60004 100644 --- a/rpc/src/v1/types/index.rs +++ b/rpc/src/v1/types/index.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -73,4 +73,3 @@ mod tests { assert_eq!(deserialized, vec![Index(10), Index(10)]); } } - diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index e178516d6d..1d3335bcad 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index e7f764b8b1..4a0ccee906 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - //! RPC types mod account_info; diff --git a/rpc/src/v1/types/node_kind.rs b/rpc/src/v1/types/node_kind.rs index 5c96fafc63..8061d82808 100644 --- a/rpc/src/v1/types/node_kind.rs +++ b/rpc/src/v1/types/node_kind.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/private_receipt.rs b/rpc/src/v1/types/private_receipt.rs index 328013d7f6..7e758af3a5 100644 --- a/rpc/src/v1/types/private_receipt.rs +++ b/rpc/src/v1/types/private_receipt.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -51,4 +51,3 @@ pub struct PrivateTransactionReceiptAndTransaction { #[serde(rename="transaction")] pub transaction: TransactionRequest, } - diff --git a/rpc/src/v1/types/provenance.rs b/rpc/src/v1/types/provenance.rs index 6bcd43a21f..328f2ded3e 100644 --- a/rpc/src/v1/types/provenance.rs +++ b/rpc/src/v1/types/provenance.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/pubsub.rs b/rpc/src/v1/types/pubsub.rs index dfac5a0abb..ea01d6427b 100644 --- a/rpc/src/v1/types/pubsub.rs +++ b/rpc/src/v1/types/pubsub.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index e20856b822..f8d111887a 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -165,4 +165,3 @@ mod tests { assert_eq!(serialized, s); } } - diff --git a/rpc/src/v1/types/rpc_settings.rs b/rpc/src/v1/types/rpc_settings.rs index bc5bf72171..3be781f206 100644 --- a/rpc/src/v1/types/rpc_settings.rs +++ b/rpc/src/v1/types/rpc_settings.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -12,7 +12,7 @@ // 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 . +// along with Parity. If not, see . //! RPC Settings data. diff --git a/rpc/src/v1/types/secretstore.rs b/rpc/src/v1/types/secretstore.rs index 4388b308ba..22b61b5e15 100644 --- a/rpc/src/v1/types/secretstore.rs +++ b/rpc/src/v1/types/secretstore.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index cbac3e1bbb..ec43fb27d6 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index 6eb222f5e6..08ddfb2767 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -327,7 +327,6 @@ impl From for RewardType { } } - /// Reward action #[derive(Debug, Serialize)] pub struct Reward { diff --git a/rpc/src/v1/types/trace_filter.rs b/rpc/src/v1/types/trace_filter.rs index 3a64f52488..83247dade0 100644 --- a/rpc/src/v1/types/trace_filter.rs +++ b/rpc/src/v1/types/trace_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 0ac3e37454..d41fc84e00 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -327,4 +327,3 @@ mod tests { ); } } - diff --git a/rpc/src/v1/types/transaction_condition.rs b/rpc/src/v1/types/transaction_condition.rs index 541bd364a3..65642224c2 100644 --- a/rpc/src/v1/types/transaction_condition.rs +++ b/rpc/src/v1/types/transaction_condition.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -64,4 +64,3 @@ mod tests { assert_eq!(transaction::Condition::Timestamp(100), TransactionCondition::Timestamp(100).into()); } } - diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index 2d4c86c7e7..7fed6f681a 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -127,7 +127,6 @@ impl Into for TransactionRequest { } } - #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/rpc/src/v1/types/uint.rs b/rpc/src/v1/types/uint.rs index 4e2a189a63..cb6dd5d3fd 100644 --- a/rpc/src/v1/types/uint.rs +++ b/rpc/src/v1/types/uint.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/rpc/src/v1/types/work.rs b/rpc/src/v1/types/work.rs index 3664892df7..5fdc117a20 100644 --- a/rpc/src/v1/types/work.rs +++ b/rpc/src/v1/types/work.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -40,4 +40,3 @@ impl Serialize for Work { } } } - diff --git a/rpc_cli/src/lib.rs b/rpc_cli/src/lib.rs index f322129d1c..e4554d6ed5 100644 --- a/rpc_cli/src/lib.rs +++ b/rpc_cli/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate futures; extern crate rpassword; diff --git a/rpc_client/src/client.rs b/rpc_client/src/client.rs index 17a8d9d724..93abdac88e 100644 --- a/rpc_client/src/client.rs +++ b/rpc_client/src/client.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::fmt::{Debug, Formatter, Error as FmtError}; use std::io::{BufReader, BufRead}; use std::sync::Arc; diff --git a/rpc_client/src/lib.rs b/rpc_client/src/lib.rs index 49f537708e..98614bd763 100644 --- a/rpc_client/src/lib.rs +++ b/rpc_client/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + pub mod client; pub mod signer_client; diff --git a/rpc_client/src/signer_client.rs b/rpc_client/src/signer_client.rs index cee063109b..e7a241137f 100644 --- a/rpc_client/src/signer_client.rs +++ b/rpc_client/src/signer_client.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use client::{Rpc, RpcError}; use rpc::signer::{ConfirmationRequest, TransactionModification, U256, TransactionCondition}; use serde; diff --git a/scripts/add_license.sh b/scripts/add_license.sh index 1d916f4279..2b283590b0 100755 --- a/scripts/add_license.sh +++ b/scripts/add_license.sh @@ -1,6 +1,20 @@ -#!/bin/sh +#!/usr/bin/env sh -for f in $(find . -name '*.rs'); do - cat license_header $f > $f.new - mv $f.new $f +PAT_GPL="^// Copyright.*If not, see \.$" +PAT_OTHER="^// Copyright" + +for f in $(find . -type f | egrep '\.(c|cpp|rs)$'); do + HEADER=$(head -16 $f) + if [[ $HEADER =~ $PAT_GPL ]]; then + BODY=$(tail -n +17 $f) + cat license_header > temp + echo "$BODY" >> temp + mv temp $f + elif [[ $HEADER =~ $PAT_OTHER ]]; then + echo "Other license was found do nothing" + else + echo "$f was missing header" + cat license_header $f > temp + mv temp $f + fi done diff --git a/scripts/remove_duplicate_empty_lines.sh b/scripts/remove_duplicate_empty_lines.sh new file mode 100755 index 0000000000..0df265ab9f --- /dev/null +++ b/scripts/remove_duplicate_empty_lines.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +for f in $(find . -name '*.rs'); do + cat -s $f > $f.temp + mv $f.temp $f +done diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index bc75cfec44..10b58a9c74 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server.rs b/secret_store/src/key_server.rs index b06be2422e..099d8aa451 100644 --- a/secret_store/src/key_server.rs +++ b/secret_store/src/key_server.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs index 6c39fd8e7e..9aeb5ca34d 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/key_version_negotiation_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/mod.rs b/secret_store/src/key_server_cluster/admin_sessions/mod.rs index 11c01cac53..1fedc1db40 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/mod.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs index 698872aadc..01cb03131e 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/servers_set_change_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs b/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs index 35adaab68c..7657dfc826 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/sessions_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs index abe34edeab..4b79473b56 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/share_add_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs b/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs index 1e408ee52e..af16ef2f6d 100644 --- a/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs +++ b/secret_store/src/key_server_cluster/admin_sessions/share_change_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs index f852451b43..724d2fe49f 100644 --- a/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/decryption_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs index 3c863d1cb9..70532b6905 100644 --- a/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/encryption_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs index c2effe6c26..7001ccf69e 100644 --- a/secret_store/src/key_server_cluster/client_sessions/generation_session.rs +++ b/secret_store/src/key_server_cluster/client_sessions/generation_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -1299,7 +1299,6 @@ pub mod tests { }).unwrap_err(), Error::InvalidMessage); } - #[test] fn encryption_fails_on_session_timeout() { let (_, _, _, l) = make_simple_cluster(0, 2).unwrap(); diff --git a/secret_store/src/key_server_cluster/client_sessions/mod.rs b/secret_store/src/key_server_cluster/client_sessions/mod.rs index ba2fbd5350..133edcffbb 100644 --- a/secret_store/src/key_server_cluster/client_sessions/mod.rs +++ b/secret_store/src/key_server_cluster/client_sessions/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs index b0d465343b..670fa138f2 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_ecdsa.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -644,7 +644,6 @@ impl SessionImpl { Self::compute_inversed_nonce_coeff(&self.core, &*data)? }; - let version = data.version.as_ref().ok_or(Error::InvalidMessage)?.clone(); let message_hash = data.message_hash .expect("we are on master node; on master node message_hash is filled in initialize(); on_generation_message follows initialize; qed"); diff --git a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs index 013748827c..376eab26b4 100644 --- a/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs +++ b/secret_store/src/key_server_cluster/client_sessions/signing_session_schnorr.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -1289,4 +1289,4 @@ mod tests { _ => unreachable!(), } } -} \ No newline at end of file +} diff --git a/secret_store/src/key_server_cluster/cluster.rs b/secret_store/src/key_server_cluster/cluster.rs index d782ccd035..86de005b77 100644 --- a/secret_store/src/key_server_cluster/cluster.rs +++ b/secret_store/src/key_server_cluster/cluster.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/cluster_sessions.rs b/secret_store/src/key_server_cluster/cluster_sessions.rs index 780c947fc3..4dcfd3f881 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs index a56f51f8fb..e1b5125ac4 100644 --- a/secret_store/src/key_server_cluster/cluster_sessions_creator.rs +++ b/secret_store/src/key_server_cluster/cluster_sessions_creator.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/connection_trigger.rs b/secret_store/src/key_server_cluster/connection_trigger.rs index 66612f044b..71f17313fe 100644 --- a/secret_store/src/key_server_cluster/connection_trigger.rs +++ b/secret_store/src/key_server_cluster/connection_trigger.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs index 40a4b5028e..cc8db3e665 100644 --- a/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs +++ b/secret_store/src/key_server_cluster/connection_trigger_with_migration.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/deadline.rs b/secret_store/src/key_server_cluster/io/deadline.rs index 1088f4f337..94a1895227 100644 --- a/secret_store/src/key_server_cluster/io/deadline.rs +++ b/secret_store/src/key_server_cluster/io/deadline.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/handshake.rs b/secret_store/src/key_server_cluster/io/handshake.rs index af64295632..5081004d0b 100644 --- a/secret_store/src/key_server_cluster/io/handshake.rs +++ b/secret_store/src/key_server_cluster/io/handshake.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/message.rs b/secret_store/src/key_server_cluster/io/message.rs index 9925b789d2..e8e01a91f5 100644 --- a/secret_store/src/key_server_cluster/io/message.rs +++ b/secret_store/src/key_server_cluster/io/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/mod.rs b/secret_store/src/key_server_cluster/io/mod.rs index dfea336830..02adb72ad7 100644 --- a/secret_store/src/key_server_cluster/io/mod.rs +++ b/secret_store/src/key_server_cluster/io/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/read_header.rs b/secret_store/src/key_server_cluster/io/read_header.rs index 2fd8960e30..803e01b95b 100644 --- a/secret_store/src/key_server_cluster/io/read_header.rs +++ b/secret_store/src/key_server_cluster/io/read_header.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/read_message.rs b/secret_store/src/key_server_cluster/io/read_message.rs index 1ffb98792a..b1d0395d57 100644 --- a/secret_store/src/key_server_cluster/io/read_message.rs +++ b/secret_store/src/key_server_cluster/io/read_message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/read_payload.rs b/secret_store/src/key_server_cluster/io/read_payload.rs index 1246092e90..da4f4d3c01 100644 --- a/secret_store/src/key_server_cluster/io/read_payload.rs +++ b/secret_store/src/key_server_cluster/io/read_payload.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs b/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs index a847b14280..64afbbe82f 100644 --- a/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs +++ b/secret_store/src/key_server_cluster/io/shared_tcp_stream.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/io/write_message.rs b/secret_store/src/key_server_cluster/io/write_message.rs index 8a89cf4552..d337a3705a 100644 --- a/secret_store/src/key_server_cluster/io/write_message.rs +++ b/secret_store/src/key_server_cluster/io/write_message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/consensus_session.rs b/secret_store/src/key_server_cluster/jobs/consensus_session.rs index 5d780a48eb..6d2866750e 100644 --- a/secret_store/src/key_server_cluster/jobs/consensus_session.rs +++ b/secret_store/src/key_server_cluster/jobs/consensus_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/decryption_job.rs b/secret_store/src/key_server_cluster/jobs/decryption_job.rs index 2c11fe0ab3..debffa25e0 100644 --- a/secret_store/src/key_server_cluster/jobs/decryption_job.rs +++ b/secret_store/src/key_server_cluster/jobs/decryption_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/dummy_job.rs b/secret_store/src/key_server_cluster/jobs/dummy_job.rs index 3e84c0d49d..f7e771d155 100644 --- a/secret_store/src/key_server_cluster/jobs/dummy_job.rs +++ b/secret_store/src/key_server_cluster/jobs/dummy_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/job_session.rs b/secret_store/src/key_server_cluster/jobs/job_session.rs index d3a765bf5b..ab0300db36 100644 --- a/secret_store/src/key_server_cluster/jobs/job_session.rs +++ b/secret_store/src/key_server_cluster/jobs/job_session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/key_access_job.rs b/secret_store/src/key_server_cluster/jobs/key_access_job.rs index a47385b5ae..6a0577f022 100644 --- a/secret_store/src/key_server_cluster/jobs/key_access_job.rs +++ b/secret_store/src/key_server_cluster/jobs/key_access_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/mod.rs b/secret_store/src/key_server_cluster/jobs/mod.rs index 817f09b71d..75d07e313b 100644 --- a/secret_store/src/key_server_cluster/jobs/mod.rs +++ b/secret_store/src/key_server_cluster/jobs/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs b/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs index 1d16286926..6c142d2a2f 100644 --- a/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs +++ b/secret_store/src/key_server_cluster/jobs/servers_set_change_access_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs index 8f4ab1d68e..6349c2e7db 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs index 54225a6cf5..4d1a0e7d90 100644 --- a/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs +++ b/secret_store/src/key_server_cluster/jobs/signing_job_schnorr.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -148,4 +148,4 @@ impl JobExecutor for SchnorrSigningJob { Ok((signature_c, signature_s)) } -} \ No newline at end of file +} diff --git a/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs b/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs index 13f2f8b8bb..908afa1ecc 100644 --- a/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs +++ b/secret_store/src/key_server_cluster/jobs/unknown_sessions_job.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/math.rs b/secret_store/src/key_server_cluster/math.rs index ef6d88f67c..66f26b5086 100644 --- a/secret_store/src/key_server_cluster/math.rs +++ b/secret_store/src/key_server_cluster/math.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/message.rs b/secret_store/src/key_server_cluster/message.rs index cc49e56fdb..8aecdc9dd6 100644 --- a/secret_store/src/key_server_cluster/message.rs +++ b/secret_store/src/key_server_cluster/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/mod.rs b/secret_store/src/key_server_cluster/mod.rs index d5ac85b3de..018d70d305 100644 --- a/secret_store/src/key_server_cluster/mod.rs +++ b/secret_store/src/key_server_cluster/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/accept_connection.rs b/secret_store/src/key_server_cluster/net/accept_connection.rs index d85e492dd7..3565ea3d0f 100644 --- a/secret_store/src/key_server_cluster/net/accept_connection.rs +++ b/secret_store/src/key_server_cluster/net/accept_connection.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/connect.rs b/secret_store/src/key_server_cluster/net/connect.rs index 7515494e44..8b93479f97 100644 --- a/secret_store/src/key_server_cluster/net/connect.rs +++ b/secret_store/src/key_server_cluster/net/connect.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/connection.rs b/secret_store/src/key_server_cluster/net/connection.rs index 577f5828f6..7776e97a74 100644 --- a/secret_store/src/key_server_cluster/net/connection.rs +++ b/secret_store/src/key_server_cluster/net/connection.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_cluster/net/mod.rs b/secret_store/src/key_server_cluster/net/mod.rs index 6abf83ceb8..e76f4f476c 100644 --- a/secret_store/src/key_server_cluster/net/mod.rs +++ b/secret_store/src/key_server_cluster/net/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs index 8a0d786af9..cf95e917ae 100644 --- a/secret_store/src/key_server_set.rs +++ b/secret_store/src/key_server_set.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index 848e6bf2a5..f5d6df8010 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -348,7 +348,6 @@ impl DocumentKeyShareVersion { } } - /// Calculate hash of given version data. pub fn data_hash<'a, I>(id_numbers: I) -> H256 where I: Iterator { let mut nodes_keccak = Keccak::new_keccak256(); diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 80b15318a9..404c278d53 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/http_listener.rs b/secret_store/src/listener/http_listener.rs index 074052fae4..5aa82a1cbd 100644 --- a/secret_store/src/listener/http_listener.rs +++ b/secret_store/src/listener/http_listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/mod.rs b/secret_store/src/listener/mod.rs index 0d1f3f2675..8837e7ffd6 100644 --- a/secret_store/src/listener/mod.rs +++ b/secret_store/src/listener/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/service_contract.rs b/secret_store/src/listener/service_contract.rs index eac3cfa9da..72c23b86b5 100644 --- a/secret_store/src/listener/service_contract.rs +++ b/secret_store/src/listener/service_contract.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/service_contract_aggregate.rs b/secret_store/src/listener/service_contract_aggregate.rs index 9ec467fea4..cc2e97b8d4 100644 --- a/secret_store/src/listener/service_contract_aggregate.rs +++ b/secret_store/src/listener/service_contract_aggregate.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/service_contract_listener.rs b/secret_store/src/listener/service_contract_listener.rs index 214235210f..724c902d12 100644 --- a/secret_store/src/listener/service_contract_listener.rs +++ b/secret_store/src/listener/service_contract_listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/listener/tasks_queue.rs b/secret_store/src/listener/tasks_queue.rs index e228d12cef..934459940a 100644 --- a/secret_store/src/listener/tasks_queue.rs +++ b/secret_store/src/listener/tasks_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/node_key_pair.rs b/secret_store/src/node_key_pair.rs index 428dba6c1a..93cf285b2f 100644 --- a/secret_store/src/node_key_pair.rs +++ b/secret_store/src/node_key_pair.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/serialization.rs b/secret_store/src/serialization.rs index f3e9aa1d76..7ae5e8f269 100644 --- a/secret_store/src/serialization.rs +++ b/secret_store/src/serialization.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/traits.rs b/secret_store/src/traits.rs index 704be1c254..d92983fe8d 100644 --- a/secret_store/src/traits.rs +++ b/secret_store/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/trusted_client.rs b/secret_store/src/trusted_client.rs index 94b1c0174d..cf9c987be3 100644 --- a/secret_store/src/trusted_client.rs +++ b/secret_store/src/trusted_client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index ab0aea1b13..f0e0388104 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/types/error.rs b/secret_store/src/types/error.rs index eae914ec86..74e6bb9e3c 100644 --- a/secret_store/src/types/error.rs +++ b/secret_store/src/types/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/secret_store/src/types/mod.rs b/secret_store/src/types/mod.rs index 9da7f6ef98..443f4acb3a 100644 --- a/secret_store/src/types/mod.rs +++ b/secret_store/src/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/error.rs b/transaction-pool/src/error.rs index 4cf221a71e..c7666841a2 100644 --- a/transaction-pool/src/error.rs +++ b/transaction-pool/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/lib.rs b/transaction-pool/src/lib.rs index 4a1bdcde14..ea77debfa2 100644 --- a/transaction-pool/src/lib.rs +++ b/transaction-pool/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/listener.rs b/transaction-pool/src/listener.rs index 728a035e31..3339a7730d 100644 --- a/transaction-pool/src/listener.rs +++ b/transaction-pool/src/listener.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/options.rs b/transaction-pool/src/options.rs index 8ccf8adfd1..291001a202 100644 --- a/transaction-pool/src/options.rs +++ b/transaction-pool/src/options.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index 5cb6e479b8..dcd52a3e7e 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -95,7 +95,6 @@ impl> Pool { } } - const INITIAL_NUMBER_OF_SENDERS: usize = 16; impl Pool where diff --git a/transaction-pool/src/ready.rs b/transaction-pool/src/ready.rs index aa913a9eb5..0bee5188df 100644 --- a/transaction-pool/src/ready.rs +++ b/transaction-pool/src/ready.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index 2acfb33748..462b708651 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/status.rs b/transaction-pool/src/status.rs index a03bc6b062..b9e7656d44 100644 --- a/transaction-pool/src/status.rs +++ b/transaction-pool/src/status.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index cfc6641b5e..b71959b08e 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index b21ea31807..6edd60e60e 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -578,4 +578,3 @@ mod listener { assert_eq!(*results.borrow(), &["added", "added", "mined", "mined"]); } } - diff --git a/transaction-pool/src/tests/tx_builder.rs b/transaction-pool/src/tests/tx_builder.rs index 88a881aca8..9478d417a2 100644 --- a/transaction-pool/src/tests/tx_builder.rs +++ b/transaction-pool/src/tests/tx_builder.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/transactions.rs b/transaction-pool/src/transactions.rs index f1a91ff4f8..edc26b69f4 100644 --- a/transaction-pool/src/transactions.rs +++ b/transaction-pool/src/transactions.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/transaction-pool/src/verifier.rs b/transaction-pool/src/verifier.rs index e55a17e911..312a3eae3c 100644 --- a/transaction-pool/src/verifier.rs +++ b/transaction-pool/src/verifier.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/updater/src/lib.rs b/updater/src/lib.rs index 67525aa4b2..f27d74e7d7 100644 --- a/updater/src/lib.rs +++ b/updater/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/updater/src/service.rs b/updater/src/service.rs index b025eb42ea..604c01ec76 100644 --- a/updater/src/service.rs +++ b/updater/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -35,4 +35,3 @@ pub trait Service: Send + Sync { /// Information gathered concerning the release. fn info(&self) -> Option; } - diff --git a/updater/src/types/all.rs b/updater/src/types/all.rs index 7079fb8ded..9dd782683d 100644 --- a/updater/src/types/all.rs +++ b/updater/src/types/all.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/updater/src/types/mod.rs b/updater/src/types/mod.rs index b6d3c60254..8fdbcf169d 100644 --- a/updater/src/types/mod.rs +++ b/updater/src/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -23,4 +23,3 @@ mod version_info; pub use self::all::{ReleaseInfo, OperationsInfo, CapState}; pub use self::release_track::ReleaseTrack; pub use self::version_info::VersionInfo; - diff --git a/updater/src/types/release_track.rs b/updater/src/types/release_track.rs index a1f646805a..eefe18d9f2 100644 --- a/updater/src/types/release_track.rs +++ b/updater/src/types/release_track.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -70,7 +70,6 @@ impl From for ReleaseTrack { } } - impl From for u8 { fn from(rt: ReleaseTrack) -> Self { rt as u8 diff --git a/updater/src/types/version_info.rs b/updater/src/types/version_info.rs index 4409153e2a..955be05660 100644 --- a/updater/src/types/version_info.rs +++ b/updater/src/types/version_info.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/updater/src/updater.rs b/updater/src/updater.rs index f8a98f3b0f..8e9efa0aa1 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/bloom/src/lib.rs b/util/bloom/src/lib.rs index 22a2cbc2aa..32aad24bf2 100644 --- a/util/bloom/src/lib.rs +++ b/util/bloom/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - extern crate siphasher; use std::cmp; @@ -208,7 +207,6 @@ pub struct BloomJournal { pub entries: Vec<(usize, u64)>, } - #[cfg(test)] mod tests { use super::Bloom; diff --git a/util/bloomchain/src/chain.rs b/util/bloomchain/src/chain.rs index ba7bc21b35..1017c874e4 100644 --- a/util/bloomchain/src/chain.rs +++ b/util/bloomchain/src/chain.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::collections::{HashMap, HashSet}; use std::ops::Range; use number::Number; diff --git a/util/bloomchain/src/config.rs b/util/bloomchain/src/config.rs index 3e729922a1..58a600e1a1 100644 --- a/util/bloomchain/src/config.rs +++ b/util/bloomchain/src/config.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + /// `BloomChain` configuration. #[derive(Debug, PartialEq, Clone, Copy)] pub struct Config { diff --git a/util/bloomchain/src/database.rs b/util/bloomchain/src/database.rs index 9aba41e7c6..b6dc77a199 100644 --- a/util/bloomchain/src/database.rs +++ b/util/bloomchain/src/database.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use position::Position; use bloom::Bloom; diff --git a/util/bloomchain/src/filter.rs b/util/bloomchain/src/filter.rs index 06d657ba44..83edd95a72 100644 --- a/util/bloomchain/src/filter.rs +++ b/util/bloomchain/src/filter.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::ops::Range; use bloom::Bloom; use number::Number; diff --git a/util/bloomchain/src/group/bridge.rs b/util/bloomchain/src/group/bridge.rs index b01650157c..4efbec6274 100644 --- a/util/bloomchain/src/group/bridge.rs +++ b/util/bloomchain/src/group/bridge.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use bloom::Bloom; use config::Config; use database::BloomDatabase; diff --git a/util/bloomchain/src/group/chain.rs b/util/bloomchain/src/group/chain.rs index cfd7796f4d..3108ba649b 100644 --- a/util/bloomchain/src/group/chain.rs +++ b/util/bloomchain/src/group/chain.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::collections::HashMap; use std::ops::Range; use bloom::Bloom; diff --git a/util/bloomchain/src/group/database.rs b/util/bloomchain/src/group/database.rs index 494184f3eb..a3d0847b65 100644 --- a/util/bloomchain/src/group/database.rs +++ b/util/bloomchain/src/group/database.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use group::{GroupPosition, BloomGroup}; /// Readonly `BloomGroup` database. diff --git a/util/bloomchain/src/group/group.rs b/util/bloomchain/src/group/group.rs index 084c8f8e48..dc19926c58 100644 --- a/util/bloomchain/src/group/group.rs +++ b/util/bloomchain/src/group/group.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use bloom::Bloom; /// Group of blooms that are in the same index. diff --git a/util/bloomchain/src/group/mod.rs b/util/bloomchain/src/group/mod.rs index b6cabf628f..9123037ec6 100644 --- a/util/bloomchain/src/group/mod.rs +++ b/util/bloomchain/src/group/mod.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + //! Bloom grouping. //! //! Optimization gathering together blooms that are in the same index and are likely to be retrived together. diff --git a/util/bloomchain/src/group/position/manager.rs b/util/bloomchain/src/group/position/manager.rs index 611a5bb784..fc5656537a 100644 --- a/util/bloomchain/src/group/position/manager.rs +++ b/util/bloomchain/src/group/position/manager.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use super::{Position, GroupPosition}; use position::Position as BloomPosition; diff --git a/util/bloomchain/src/group/position/mod.rs b/util/bloomchain/src/group/position/mod.rs index fc95de4dd0..7173d1d9bb 100644 --- a/util/bloomchain/src/group/position/mod.rs +++ b/util/bloomchain/src/group/position/mod.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + mod position; mod manager; diff --git a/util/bloomchain/src/group/position/position.rs b/util/bloomchain/src/group/position/position.rs index 88f26d69ab..1d8f89af54 100644 --- a/util/bloomchain/src/group/position/position.rs +++ b/util/bloomchain/src/group/position/position.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + /// Uniquely identifies bloom group position. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct GroupPosition { diff --git a/util/bloomchain/src/lib.rs b/util/bloomchain/src/lib.rs index 997ae08391..a82b898caf 100644 --- a/util/bloomchain/src/lib.rs +++ b/util/bloomchain/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate ethbloom as bloom; mod chain; diff --git a/util/bloomchain/src/number.rs b/util/bloomchain/src/number.rs index 3ff82f1957..6c5af2e25d 100644 --- a/util/bloomchain/src/number.rs +++ b/util/bloomchain/src/number.rs @@ -1,2 +1,18 @@ +// Copyright 2015-2018 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 . + /// Represents block number. pub type Number = usize; diff --git a/util/bloomchain/src/position/manager.rs b/util/bloomchain/src/position/manager.rs index a405878ab5..707afb667c 100644 --- a/util/bloomchain/src/position/manager.rs +++ b/util/bloomchain/src/position/manager.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + //! Simplifies working with bloom indexes. use super::Position; diff --git a/util/bloomchain/src/position/mod.rs b/util/bloomchain/src/position/mod.rs index 4fa736a163..623e9784e3 100644 --- a/util/bloomchain/src/position/mod.rs +++ b/util/bloomchain/src/position/mod.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + pub mod position; pub mod manager; diff --git a/util/bloomchain/src/position/position.rs b/util/bloomchain/src/position/position.rs index 32845cbcc5..c822d03e00 100644 --- a/util/bloomchain/src/position/position.rs +++ b/util/bloomchain/src/position/position.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + /// Uniquely identifies bloom position. #[derive(Debug, PartialEq, Eq, Hash)] pub struct Position { diff --git a/util/bloomchain/tests/bloomchain.rs b/util/bloomchain/tests/bloomchain.rs index 4a77407a7a..f1e260bfdd 100644 --- a/util/bloomchain/tests/bloomchain.rs +++ b/util/bloomchain/tests/bloomchain.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate bloomchain; extern crate rustc_hex; @@ -53,7 +69,6 @@ fn partly_matching_bloom_searach() { db.insert_blooms(modified_blooms_1); - let chain = BloomChain::new(config, &db); assert_eq!(chain.with_bloom(&(0..100), &bloom2), vec![14, 15]); } @@ -101,7 +116,6 @@ fn bloom_replace() { db.insert_blooms(modified_blooms_3); - let reset_modified_blooms = { let chain = BloomChain::new(config, &db); chain.replace(&(15..17), vec![bloom4.clone(), bloom5.clone()]) diff --git a/util/bloomchain/tests/groupchain.rs b/util/bloomchain/tests/groupchain.rs index ec396346ac..048edc03ce 100644 --- a/util/bloomchain/tests/groupchain.rs +++ b/util/bloomchain/tests/groupchain.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate bloomchain; extern crate rustc_hex; @@ -23,7 +39,6 @@ fn simple_bloom_group_search() { assert_eq!(modified_blooms.len(), config.levels); db.insert_blooms(modified_blooms); - let chain = BloomGroupChain::new(config, &db); assert_eq!(chain.with_bloom(&(0..100), &bloom), vec![23]); assert_eq!(chain.with_bloom(&(0..22), &bloom), vec![]); @@ -55,7 +70,6 @@ fn partly_matching_bloom_group_searach() { db.insert_blooms(modified_blooms_1); - let chain = BloomGroupChain::new(config, &db); assert_eq!(chain.with_bloom(&(0..100), &bloom2), vec![14, 15]); } @@ -103,7 +117,6 @@ fn bloom_group_replace() { db.insert_blooms(modified_blooms_3); - let reset_modified_blooms = { let chain = BloomGroupChain::new(config, &db); chain.replace(&(15..17), vec![bloom4.clone(), bloom5.clone()]) diff --git a/util/bloomchain/tests/util/db.rs b/util/bloomchain/tests/util/db.rs index 8101b37848..b28e7b524b 100644 --- a/util/bloomchain/tests/util/db.rs +++ b/util/bloomchain/tests/util/db.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::collections::HashMap; use bloomchain::{Position, Bloom, BloomDatabase}; use bloomchain::group::{GroupPosition, BloomGroup, BloomGroupDatabase}; diff --git a/util/bloomchain/tests/util/each.rs b/util/bloomchain/tests/util/each.rs index 19ca1b67cf..1d8fc9a1d4 100644 --- a/util/bloomchain/tests/util/each.rs +++ b/util/bloomchain/tests/util/each.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use std::io::{BufReader, Read, BufRead}; use bloomchain::Bloom; use super::FromHex; diff --git a/util/bloomchain/tests/util/from_hex.rs b/util/bloomchain/tests/util/from_hex.rs index 9152d304fd..20c59333ae 100644 --- a/util/bloomchain/tests/util/from_hex.rs +++ b/util/bloomchain/tests/util/from_hex.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use rustc_hex::FromHex as RustcFromHex; use bloomchain::Bloom; diff --git a/util/bloomchain/tests/util/mod.rs b/util/bloomchain/tests/util/mod.rs index 2a1e55af9a..998e7c9520 100644 --- a/util/bloomchain/tests/util/mod.rs +++ b/util/bloomchain/tests/util/mod.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + mod db; mod each; mod from_hex; diff --git a/util/bloomchain/tests/util/random.rs b/util/bloomchain/tests/util/random.rs index 3d50b5ac10..06e3d13520 100644 --- a/util/bloomchain/tests/util/random.rs +++ b/util/bloomchain/tests/util/random.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate rand; use self::rand::random; diff --git a/util/bytes/src/lib.rs b/util/bytes/src/lib.rs index 4303f70150..03b4745598 100644 --- a/util/bytes/src/lib.rs +++ b/util/bytes/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/dir/src/helpers.rs b/util/dir/src/helpers.rs index 95f8090c87..820b9dc5af 100644 --- a/util/dir/src/helpers.rs +++ b/util/dir/src/helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index bb36a46a83..7404a2cbca 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/error/src/lib.rs b/util/error/src/lib.rs index 9a1ab87536..bacc66c283 100644 --- a/util/error/src/lib.rs +++ b/util/error/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -74,4 +74,3 @@ error_chain! { BaseData(BaseDataError); } } - diff --git a/util/fetch/src/client.rs b/util/fetch/src/client.rs index 9bb55aad0e..cda802cfb0 100644 --- a/util/fetch/src/client.rs +++ b/util/fetch/src/client.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/fetch/src/lib.rs b/util/fetch/src/lib.rs index f42aacec5b..8e50fa5e6a 100644 --- a/util/fetch/src/lib.rs +++ b/util/fetch/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/hash/benches/keccak_256.rs b/util/hash/benches/keccak_256.rs index 8b398417d8..d59e534104 100644 --- a/util/hash/benches/keccak_256.rs +++ b/util/hash/benches/keccak_256.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + #![feature(test)] extern crate test; @@ -33,4 +49,4 @@ fn bench_keccak_256_with_large_input(b: &mut Bencher) { b.iter(|| { let _out = keccak(&data); }) -} \ No newline at end of file +} diff --git a/util/hash/src/lib.rs b/util/hash/src/lib.rs index b75e095a68..c54d7233cd 100644 --- a/util/hash/src/lib.rs +++ b/util/hash/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -32,7 +32,6 @@ pub const KECCAK_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x5 /// The KECCAK of the RLP encoding of empty list. pub const KECCAK_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47] ); - pub fn keccak>(s: T) -> H256 { let mut result = [0u8; 32]; write_keccak(s, &mut result); diff --git a/util/hashdb/src/lib.rs b/util/hashdb/src/lib.rs index b65f304e42..182e81c5dc 100644 --- a/util/hashdb/src/lib.rs +++ b/util/hashdb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/io/src/lib.rs b/util/io/src/lib.rs index cd635121ff..02dbf223be 100644 --- a/util/io/src/lib.rs +++ b/util/io/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/io/src/service_mio.rs b/util/io/src/service_mio.rs index 2ae3d55e0f..089d54cc45 100644 --- a/util/io/src/service_mio.rs +++ b/util/io/src/service_mio.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/io/src/service_non_mio.rs b/util/io/src/service_non_mio.rs index 22a795e4e8..315f84c4d1 100644 --- a/util/io/src/service_non_mio.rs +++ b/util/io/src/service_non_mio.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/io/src/worker.rs b/util/io/src/worker.rs index 89657810dc..da144afea4 100644 --- a/util/io/src/worker.rs +++ b/util/io/src/worker.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/journaldb/src/archivedb.rs b/util/journaldb/src/archivedb.rs index b58558a332..e2d8c80070 100644 --- a/util/journaldb/src/archivedb.rs +++ b/util/journaldb/src/archivedb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/journaldb/src/earlymergedb.rs b/util/journaldb/src/earlymergedb.rs index c26a67e0ad..25e078bdae 100644 --- a/util/journaldb/src/earlymergedb.rs +++ b/util/journaldb/src/earlymergedb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -394,7 +394,6 @@ impl JournalDB for EarlyMergeDB { .filter_map(|(k, (v, r))| if r > 0 { assert!(r == 1); Some((k, v)) } else { assert!(r >= -1); None }) .collect(); - // TODO: check all removes are in the db. // Process the new inserts. diff --git a/util/journaldb/src/lib.rs b/util/journaldb/src/lib.rs index c1fb23b6cd..7607271c8d 100644 --- a/util/journaldb/src/lib.rs +++ b/util/journaldb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/journaldb/src/overlaydb.rs b/util/journaldb/src/overlaydb.rs index 54d0bb12d7..46bf42c0ad 100644 --- a/util/journaldb/src/overlaydb.rs +++ b/util/journaldb/src/overlaydb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/journaldb/src/overlayrecentdb.rs b/util/journaldb/src/overlayrecentdb.rs index 2c9ce5cb1d..c7153b889d 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/journaldb/src/refcounteddb.rs b/util/journaldb/src/refcounteddb.rs index d182d5cf80..cc81bbfba4 100644 --- a/util/journaldb/src/refcounteddb.rs +++ b/util/journaldb/src/refcounteddb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/journaldb/src/traits.rs b/util/journaldb/src/traits.rs index aaf5b27970..e37ac8aabf 100644 --- a/util/journaldb/src/traits.rs +++ b/util/journaldb/src/traits.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/kvdb-memorydb/src/lib.rs b/util/kvdb-memorydb/src/lib.rs index 0530c613e3..45ed1c3e69 100644 --- a/util/kvdb-memorydb/src/lib.rs +++ b/util/kvdb-memorydb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/kvdb-rocksdb/src/lib.rs b/util/kvdb-rocksdb/src/lib.rs index 4f2220a11d..6052468298 100644 --- a/util/kvdb-rocksdb/src/lib.rs +++ b/util/kvdb-rocksdb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -388,7 +388,6 @@ impl Database { DBTransaction::new() } - fn to_overlay_column(col: Option) -> usize { col.map_or(0, |c| (c + 1) as usize) } diff --git a/util/kvdb/src/lib.rs b/util/kvdb/src/lib.rs index 9ed1038bff..78e7b2dc19 100644 --- a/util/kvdb/src/lib.rs +++ b/util/kvdb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/macros/src/lib.rs b/util/macros/src/lib.rs index 78bcd0397e..cc5f92ba15 100644 --- a/util/macros/src/lib.rs +++ b/util/macros/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/mem/src/lib.rs b/util/mem/src/lib.rs index a8b9e53f66..db3ad59239 100644 --- a/util/mem/src/lib.rs +++ b/util/mem/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -54,4 +54,3 @@ impl> DerefMut for Memzero { &mut self.mem } } - diff --git a/util/memory_cache/src/lib.rs b/util/memory_cache/src/lib.rs index af70b0cff3..ff996142b9 100644 --- a/util/memory_cache/src/lib.rs +++ b/util/memory_cache/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/memorydb/src/lib.rs b/util/memorydb/src/lib.rs index 12eb62e057..e297d1e6d1 100644 --- a/util/memorydb/src/lib.rs +++ b/util/memorydb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/migration-rocksdb/src/lib.rs b/util/migration-rocksdb/src/lib.rs index fbc9681b40..2e39a380ba 100644 --- a/util/migration-rocksdb/src/lib.rs +++ b/util/migration-rocksdb/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/migration-rocksdb/tests/tests.rs b/util/migration-rocksdb/tests/tests.rs index 85c48f12b6..c98ff9d71b 100644 --- a/util/migration-rocksdb/tests/tests.rs +++ b/util/migration-rocksdb/tests/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -119,7 +119,6 @@ impl Migration for AddsColumn { batch.insert(key.into_vec(), value.into_vec(), dest)?; } - if col == Some(1) { batch.insert(vec![1, 2, 3], vec![4, 5, 6], dest)?; } diff --git a/util/network-devp2p/src/connection.rs b/util/network-devp2p/src/connection.rs index 5dbf71fa01..37824ae5d7 100644 --- a/util/network-devp2p/src/connection.rs +++ b/util/network-devp2p/src/connection.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index af43546a5f..8e8a3d6cc6 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network-devp2p/src/handshake.rs b/util/network-devp2p/src/handshake.rs index ffe0276d97..18869de55f 100644 --- a/util/network-devp2p/src/handshake.rs +++ b/util/network-devp2p/src/handshake.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -515,4 +515,3 @@ mod test { check_ack(&h, 57); } } - diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 245492de80..6d28a838c2 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -1154,7 +1154,6 @@ fn key_save_load() { assert_eq!(key, r.unwrap()); } - #[test] fn host_client_url() { let mut config = NetworkConfiguration::new_local(); diff --git a/util/network-devp2p/src/ip_utils.rs b/util/network-devp2p/src/ip_utils.rs index 3d7d33a066..a68fc51f10 100644 --- a/util/network-devp2p/src/ip_utils.rs +++ b/util/network-devp2p/src/ip_utils.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -533,5 +533,3 @@ fn ipv6_properties() { check("::", true, false, true); check("::1", false, true, false); } - - diff --git a/util/network-devp2p/src/lib.rs b/util/network-devp2p/src/lib.rs index 12383fdbee..01fc1fe25f 100644 --- a/util/network-devp2p/src/lib.rs +++ b/util/network-devp2p/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network-devp2p/src/node_table.rs b/util/network-devp2p/src/node_table.rs index d5d0207ecd..087caefe18 100644 --- a/util/network-devp2p/src/node_table.rs +++ b/util/network-devp2p/src/node_table.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network-devp2p/src/service.rs b/util/network-devp2p/src/service.rs index f90c660671..d7182f4618 100644 --- a/util/network-devp2p/src/service.rs +++ b/util/network-devp2p/src/service.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network-devp2p/src/session.rs b/util/network-devp2p/src/session.rs index f830dcc0d7..a405ad469d 100644 --- a/util/network-devp2p/src/session.rs +++ b/util/network-devp2p/src/session.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -515,4 +515,3 @@ impl Session { Ok(()) } } - diff --git a/util/network-devp2p/tests/tests.rs b/util/network-devp2p/tests/tests.rs index 3c2333cd10..970aa3b8a5 100644 --- a/util/network-devp2p/tests/tests.rs +++ b/util/network-devp2p/tests/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -99,7 +99,6 @@ impl NetworkProtocolHandler for TestProtocol { } } - #[test] fn net_service() { let service = NetworkService::new(NetworkConfiguration::new_local(), None).expect("Error creating network service"); diff --git a/util/network/src/connection_filter.rs b/util/network/src/connection_filter.rs index 5afe5865b7..e146aee4c7 100644 --- a/util/network/src/connection_filter.rs +++ b/util/network/src/connection_filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network/src/error.rs b/util/network/src/error.rs index 50bd01e9ba..4233b9e058 100644 --- a/util/network/src/error.rs +++ b/util/network/src/error.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs index a04eb04880..9b7328bdbd 100644 --- a/util/network/src/lib.rs +++ b/util/network/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/panic_hook/src/lib.rs b/util/panic_hook/src/lib.rs index 1136e9e362..ef6220572a 100644 --- a/util/panic_hook/src/lib.rs +++ b/util/panic_hook/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -8,7 +8,7 @@ // 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 +// 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 diff --git a/util/path/src/lib.rs b/util/path/src/lib.rs index 761b511522..38608db660 100644 --- a/util/path/src/lib.rs +++ b/util/path/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -98,4 +98,3 @@ pub fn restrict_permissions_owner(_file_path: &Path, _write: bool, _executable: //TODO: implement me Ok(()) } - diff --git a/util/patricia_trie/src/fatdb.rs b/util/patricia_trie/src/fatdb.rs index d428ff8116..90cdef9021 100644 --- a/util/patricia_trie/src/fatdb.rs +++ b/util/patricia_trie/src/fatdb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/fatdbmut.rs b/util/patricia_trie/src/fatdbmut.rs index 4b7f2de063..9bf7b88036 100644 --- a/util/patricia_trie/src/fatdbmut.rs +++ b/util/patricia_trie/src/fatdbmut.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/lib.rs b/util/patricia_trie/src/lib.rs index d1563becff..8e0e44f032 100644 --- a/util/patricia_trie/src/lib.rs +++ b/util/patricia_trie/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/lookup.rs b/util/patricia_trie/src/lookup.rs index 2d63f7d00e..ae91689a31 100644 --- a/util/patricia_trie/src/lookup.rs +++ b/util/patricia_trie/src/lookup.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/nibbleslice.rs b/util/patricia_trie/src/nibbleslice.rs index c2dd6611e2..4153049810 100644 --- a/util/patricia_trie/src/nibbleslice.rs +++ b/util/patricia_trie/src/nibbleslice.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/nibblevec.rs b/util/patricia_trie/src/nibblevec.rs index fbe97496ae..4398dbc6f7 100644 --- a/util/patricia_trie/src/nibblevec.rs +++ b/util/patricia_trie/src/nibblevec.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/node.rs b/util/patricia_trie/src/node.rs index 0b99acded3..0ded1f66db 100644 --- a/util/patricia_trie/src/node.rs +++ b/util/patricia_trie/src/node.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/recorder.rs b/util/patricia_trie/src/recorder.rs index 35a515b704..6a0f9b45eb 100644 --- a/util/patricia_trie/src/recorder.rs +++ b/util/patricia_trie/src/recorder.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/sectriedb.rs b/util/patricia_trie/src/sectriedb.rs index a9176d022a..c8d5ec0ec8 100644 --- a/util/patricia_trie/src/sectriedb.rs +++ b/util/patricia_trie/src/sectriedb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/sectriedbmut.rs b/util/patricia_trie/src/sectriedbmut.rs index b0436b271f..335fb2f183 100644 --- a/util/patricia_trie/src/sectriedbmut.rs +++ b/util/patricia_trie/src/sectriedbmut.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index c18e4fce96..65ce3caba8 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/patricia_trie/src/triedbmut.rs b/util/patricia_trie/src/triedbmut.rs index b8d919deea..994045eb3a 100644 --- a/util/patricia_trie/src/triedbmut.rs +++ b/util/patricia_trie/src/triedbmut.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -893,7 +893,6 @@ impl<'a> TrieMut for TrieDBMut<'a> { self.lookup(NibbleSlice::new(key), &self.root_handle) } - fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result> { if value.is_empty() { return self.remove(key) } diff --git a/util/plain_hasher/benches/bench.rs b/util/plain_hasher/benches/bench.rs index e7e8570abb..cfaa95eaa6 100644 --- a/util/plain_hasher/benches/bench.rs +++ b/util/plain_hasher/benches/bench.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + #![feature(test)] extern crate test; diff --git a/util/plain_hasher/src/lib.rs b/util/plain_hasher/src/lib.rs index d08d4dd1ab..74e2225dc8 100644 --- a/util/plain_hasher/src/lib.rs +++ b/util/plain_hasher/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + #[macro_use] extern crate crunchy; extern crate ethereum_types; diff --git a/util/reactor/src/lib.rs b/util/reactor/src/lib.rs index 9c049b8f75..8fd37e7c88 100644 --- a/util/reactor/src/lib.rs +++ b/util/reactor/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . - //! Tokio Core Reactor wrapper. extern crate futures; @@ -122,7 +121,6 @@ impl Remote { } } - /// Spawn a future to this event loop pub fn spawn(&self, r: R) where R: IntoFuture + Send + 'static, diff --git a/util/rlp/src/rlpin.rs b/util/rlp/src/rlpin.rs index a55b4f7907..23fdc452e7 100644 --- a/util/rlp/src/rlpin.rs +++ b/util/rlp/src/rlpin.rs @@ -281,7 +281,6 @@ impl<'a, 'view> Rlp<'a> where 'a: 'view { Ok(result) } - /// consumes slice prefix of length `len` fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { match bytes.len() >= len { diff --git a/util/rlp/src/stream.rs b/util/rlp/src/stream.rs index 000b6e15bc..550ede0399 100644 --- a/util/rlp/src/stream.rs +++ b/util/rlp/src/stream.rs @@ -133,7 +133,6 @@ impl RlpStream { self } - /// Declare appending the list of unknown size, chainable. pub fn begin_unbounded_list(&mut self) -> &mut RlpStream { self.finished_list = false; @@ -206,7 +205,6 @@ impl RlpStream { base_size } - /// Returns current RLP size in bytes for the data pushed into the list. pub fn len<'a>(&'a self) -> usize { self.estimate_size(0) diff --git a/util/rlp_compress/src/lib.rs b/util/rlp_compress/src/lib.rs index b895e1ce1a..af5b09aac7 100644 --- a/util/rlp_compress/src/lib.rs +++ b/util/rlp_compress/src/lib.rs @@ -107,4 +107,3 @@ impl<'a> Compressor for Swapper<'a> { self.rlp_to_compressed.get(rlp).cloned() } } - diff --git a/util/rlp_compress/tests/compress.rs b/util/rlp_compress/tests/compress.rs index a01dbde358..9d23f8c670 100644 --- a/util/rlp_compress/tests/compress.rs +++ b/util/rlp_compress/tests/compress.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate rlp_compress; use rlp_compress::{compress, decompress, Swapper, snapshot_swapper, blocks_swapper, Compressor, Decompressor}; diff --git a/util/rlp_derive/src/de.rs b/util/rlp_derive/src/de.rs index dac4e34cdb..fe0ccfba6f 100644 --- a/util/rlp_derive/src/de.rs +++ b/util/rlp_derive/src/de.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use {syn, quote}; struct ParseQuotes { @@ -28,7 +44,6 @@ pub fn impl_decodable(ast: &syn::DeriveInput) -> quote::Tokens { _ => panic!("#[derive(RlpDecodable)] is only defined for structs."), }; - let stmts: Vec<_> = body.fields.iter().enumerate().map(decodable_field_map).collect(); let name = &ast.ident; @@ -132,4 +147,3 @@ fn decodable_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> quo _ => panic!("rlp_derive not supported"), } } - diff --git a/util/rlp_derive/src/en.rs b/util/rlp_derive/src/en.rs index 484ac015e5..607255a96c 100644 --- a/util/rlp_derive/src/en.rs +++ b/util/rlp_derive/src/en.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + use {syn, quote}; pub fn impl_encodable(ast: &syn::DeriveInput) -> quote::Tokens { @@ -104,4 +120,3 @@ fn encodable_field(index: usize, field: &syn::Field) -> quote::Tokens { _ => panic!("rlp_derive not supported"), } } - diff --git a/util/rlp_derive/src/lib.rs b/util/rlp_derive/src/lib.rs index 93f8d9619d..bc6bff1d5c 100644 --- a/util/rlp_derive/src/lib.rs +++ b/util/rlp_derive/src/lib.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate proc_macro; extern crate syn; #[macro_use] diff --git a/util/rlp_derive/tests/rlp.rs b/util/rlp_derive/tests/rlp.rs index ba51309146..7115b87c96 100644 --- a/util/rlp_derive/tests/rlp.rs +++ b/util/rlp_derive/tests/rlp.rs @@ -1,3 +1,19 @@ +// Copyright 2015-2018 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 . + extern crate rlp; #[macro_use] extern crate rlp_derive; @@ -41,4 +57,3 @@ fn test_encode_foo_wrapper() { let decoded = decode(&expected).expect("decode failure"); assert_eq!(foo, decoded); } - diff --git a/util/stats/src/lib.rs b/util/stats/src/lib.rs index 74fda92726..8d107f4e9c 100644 --- a/util/stats/src/lib.rs +++ b/util/stats/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -130,7 +130,6 @@ impl Histogram } } - #[cfg(test)] mod tests { use super::*; diff --git a/util/stop-guard/src/lib.rs b/util/stop-guard/src/lib.rs index f208138ab6..208b57c6d9 100644 --- a/util/stop-guard/src/lib.rs +++ b/util/stop-guard/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/trace-time/src/lib.rs b/util/trace-time/src/lib.rs index e9566e7f94..4c3b0b2743 100644 --- a/util/trace-time/src/lib.rs +++ b/util/trace-time/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/trie-standardmap/src/lib.rs b/util/trie-standardmap/src/lib.rs index d7ee08ac46..51c8593ea4 100644 --- a/util/trie-standardmap/src/lib.rs +++ b/util/trie-standardmap/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/triehash/src/lib.rs b/util/triehash/src/lib.rs index 7f20d3915e..c78ed0ca1b 100644 --- a/util/triehash/src/lib.rs +++ b/util/triehash/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -283,7 +283,6 @@ fn hash256aux, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, }; } - #[test] fn test_nibbles() { let v = vec![0x31, 0x23, 0x45]; @@ -296,7 +295,6 @@ fn test_nibbles() { assert_eq!(as_nibbles(&v), e); } - #[cfg(test)] mod tests { use super::{trie_root, shared_prefix_len, hex_prefix_encode}; diff --git a/util/unexpected/src/lib.rs b/util/unexpected/src/lib.rs index 4cf8448bd4..77d4035a64 100644 --- a/util/unexpected/src/lib.rs +++ b/util/unexpected/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/using_queue/src/lib.rs b/util/using_queue/src/lib.rs index 03862e9c8a..42eb1cbe38 100644 --- a/util/using_queue/src/lib.rs +++ b/util/using_queue/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/version/build.rs b/util/version/build.rs index 47c0e128f2..a367296a5f 100644 --- a/util/version/build.rs +++ b/util/version/build.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/util/version/src/lib.rs b/util/version/src/lib.rs index 6c56bfb7e6..77fc71c70f 100644 --- a/util/version/src/lib.rs +++ b/util/version/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/lib.rs b/whisper/src/lib.rs index 85ab55e0f4..190169b2c2 100644 --- a/whisper/src/lib.rs +++ b/whisper/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/message.rs b/whisper/src/message.rs index d0de9af4b5..95c2112551 100644 --- a/whisper/src/message.rs +++ b/whisper/src/message.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/net/mod.rs b/whisper/src/net/mod.rs index 1115b17d4f..6ec3b08a54 100644 --- a/whisper/src/net/mod.rs +++ b/whisper/src/net/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/net/tests.rs b/whisper/src/net/tests.rs index 51c9c00ce2..15aba5c3ee 100644 --- a/whisper/src/net/tests.rs +++ b/whisper/src/net/tests.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/crypto.rs b/whisper/src/rpc/crypto.rs index 667656d6bf..a796a0613c 100644 --- a/whisper/src/rpc/crypto.rs +++ b/whisper/src/rpc/crypto.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/filter.rs b/whisper/src/rpc/filter.rs index 8d125174ed..d1b9c4c1cc 100644 --- a/whisper/src/rpc/filter.rs +++ b/whisper/src/rpc/filter.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/key_store.rs b/whisper/src/rpc/key_store.rs index 1fb4e264ac..a63ef8652c 100644 --- a/whisper/src/rpc/key_store.rs +++ b/whisper/src/rpc/key_store.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/mod.rs b/whisper/src/rpc/mod.rs index 7daa3f4559..7406d6421d 100644 --- a/whisper/src/rpc/mod.rs +++ b/whisper/src/rpc/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/whisper/src/rpc/payload.rs b/whisper/src/rpc/payload.rs index 75d24bd7cf..5884cdee98 100644 --- a/whisper/src/rpc/payload.rs +++ b/whisper/src/rpc/payload.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -184,7 +184,6 @@ pub fn decode(payload: &[u8]) -> Result { } }; - if next_slice(1)?[0] != STANDARD_PAYLOAD_VERSION { return Err("unknown payload version."); } diff --git a/whisper/src/rpc/types.rs b/whisper/src/rpc/types.rs index 9598f48bf8..3d132c73cc 100644 --- a/whisper/src/rpc/types.rs +++ b/whisper/src/rpc/types.rs @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify diff --git a/windows/ptray/ptray.cpp b/windows/ptray/ptray.cpp index 8fc29880e9..8701daecb5 100644 --- a/windows/ptray/ptray.cpp +++ b/windows/ptray/ptray.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify @@ -358,4 +358,3 @@ void EnableAutostart(bool enable) { RegDeleteValue(hKey, L"Parity"); } } - -- GitLab From 8057e8df43e78328509c3a468592b8e798772f84 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 4 Jun 2018 10:26:30 +0100 Subject: [PATCH 210/263] Remove Result wrapper from AccountProvider in RPC impls (#8763) * Remove AccountProvider Result, it's always `Ok` * Remove unnecessary clones * Remove redundant `Ok` --- rpc/src/v1/impls/eth.rs | 11 +-- rpc/src/v1/impls/parity.rs | 23 ++---- rpc/src/v1/impls/parity_accounts.rs | 117 ++++++++++------------------ rpc/src/v1/impls/personal.rs | 17 ++-- rpc/src/v1/impls/secretstore.rs | 15 +--- rpc/src/v1/impls/signer.rs | 7 +- rpc/src/v1/impls/signing.rs | 9 +-- rpc/src/v1/impls/signing_unsafe.rs | 8 +- rpc/src/v1/tests/mocked/parity.rs | 4 +- rpc/src/v1/tests/mocked/personal.rs | 3 +- rpc/src/v1/tests/mocked/signer.rs | 3 +- rpc/src/v1/tests/mocked/signing.rs | 5 +- 12 files changed, 66 insertions(+), 156 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 38e36cf11c..8de5783aa3 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -170,12 +170,6 @@ impl EthClient`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn rich_block(&self, id: BlockNumberOrId, include_txs: bool) -> Result> { let client = &self.client; @@ -404,10 +398,9 @@ impl EthClient Result> { - let store = self.account_provider()?; - store + self.accounts .note_dapp_used(dapp.clone()) - .and_then(|_| store.dapp_addresses(dapp)) + .and_then(|_| self.accounts.dapp_addresses(dapp)) .map_err(|e| errors::account("Could not fetch accounts.", e)) } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index e3ad5a3b1b..5707104212 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -105,12 +105,6 @@ impl ParityClient where eip86_transition, } } - - /// Attempt to get the `Arc`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } } impl Parity for ParityClient where @@ -124,15 +118,14 @@ impl Parity for ParityClient where fn accounts_info(&self, dapp: Trailing) -> Result> { let dapp = dapp.unwrap_or_default(); - let store = self.account_provider()?; - let dapp_accounts = store + let dapp_accounts = self.accounts .note_dapp_used(dapp.clone().into()) - .and_then(|_| store.dapp_addresses(dapp.into())) + .and_then(|_| self.accounts.dapp_addresses(dapp.into())) .map_err(|e| errors::account("Could not fetch accounts.", e))? .into_iter().collect::>(); - let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; - let other = store.addresses_info(); + let info = self.accounts.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; + let other = self.accounts.addresses_info(); Ok(info .into_iter() @@ -144,8 +137,7 @@ impl Parity for ParityClient where } fn hardware_accounts_info(&self) -> Result> { - let store = self.account_provider()?; - let info = store.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; + let info = self.accounts.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; Ok(info .into_iter() .map(|(a, v)| (H160::from(a), HwAccountInfo { name: v.name, manufacturer: v.meta })) @@ -154,14 +146,13 @@ impl Parity for ParityClient where } fn locked_hardware_accounts_info(&self) -> Result> { - let store = self.account_provider()?; - Ok(store.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e))?) + self.accounts.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); - Ok(self.account_provider()? + Ok(self.accounts .dapp_default_address(dapp_id.into()) .map(Into::into) .ok() diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index eb069cf27f..d7e1fd2546 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -40,19 +40,12 @@ impl ParityAccountsClient { accounts: store.clone(), } } - - /// Attempt to get the `Arc`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } } impl ParityAccounts for ParityAccountsClient { fn all_accounts_info(&self) -> Result> { - let store = self.account_provider()?; - let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; - let other = store.addresses_info(); + let info = self.accounts.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; + let other = self.accounts.addresses_info(); let account_iter = info .into_iter() @@ -82,29 +75,23 @@ impl ParityAccounts for ParityAccountsClient { } fn new_account_from_phrase(&self, phrase: String, pass: String) -> Result { - let store = self.account_provider()?; - let brain = Brain::new(phrase).generate().unwrap(); - store.insert_account(brain.secret().clone(), &pass) + self.accounts.insert_account(brain.secret().clone(), &pass) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } fn new_account_from_wallet(&self, json: String, pass: String) -> Result { - let store = self.account_provider()?; - - store.import_presale(json.as_bytes(), &pass) - .or_else(|_| store.import_wallet(json.as_bytes(), &pass, true)) + self.accounts.import_presale(json.as_bytes(), &pass) + .or_else(|_| self.accounts.import_wallet(json.as_bytes(), &pass, true)) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } fn new_account_from_secret(&self, secret: RpcH256, pass: String) -> Result { - let store = self.account_provider()?; - let secret = Secret::from_unsafe_slice(&secret.0) .map_err(|e| errors::account("Could not create account.", e))?; - store.insert_account(secret, &pass) + self.accounts.insert_account(secret, &pass) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } @@ -112,14 +99,14 @@ impl ParityAccounts for ParityAccountsClient { fn test_password(&self, account: RpcH160, password: String) -> Result { let account: Address = account.into(); - self.account_provider()? + self.accounts .test_password(&account, &password) .map_err(|e| errors::account("Could not fetch account info.", e)) } fn change_password(&self, account: RpcH160, password: String, new_password: String) -> Result { let account: Address = account.into(); - self.account_provider()? + self.accounts .change_password(&account, password, new_password) .map(|_| true) .map_err(|e| errors::account("Could not fetch account info.", e)) @@ -127,181 +114,156 @@ impl ParityAccounts for ParityAccountsClient { fn kill_account(&self, account: RpcH160, password: String) -> Result { let account: Address = account.into(); - self.account_provider()? + self.accounts .kill_account(&account, &password) .map(|_| true) .map_err(|e| errors::account("Could not delete account.", e)) } fn remove_address(&self, addr: RpcH160) -> Result { - let store = self.account_provider()?; let addr: Address = addr.into(); - store.remove_address(addr); + self.accounts.remove_address(addr); Ok(true) } fn set_account_name(&self, addr: RpcH160, name: String) -> Result { - let store = self.account_provider()?; let addr: Address = addr.into(); - store.set_account_name(addr.clone(), name.clone()) - .unwrap_or_else(|_| store.set_address_name(addr, name)); + self.accounts.set_account_name(addr.clone(), name.clone()) + .unwrap_or_else(|_| self.accounts.set_address_name(addr, name)); Ok(true) } fn set_account_meta(&self, addr: RpcH160, meta: String) -> Result { - let store = self.account_provider()?; let addr: Address = addr.into(); - store.set_account_meta(addr.clone(), meta.clone()) - .unwrap_or_else(|_| store.set_address_meta(addr, meta)); + self.accounts.set_account_meta(addr.clone(), meta.clone()) + .unwrap_or_else(|_| self.accounts.set_address_meta(addr, meta)); Ok(true) } fn set_dapp_addresses(&self, dapp: DappId, addresses: Option>) -> Result { - let store = self.account_provider()?; - - store.set_dapp_addresses(dapp.into(), addresses.map(into_vec)) + self.accounts.set_dapp_addresses(dapp.into(), addresses.map(into_vec)) .map_err(|e| errors::account("Couldn't set dapp addresses.", e)) .map(|_| true) } fn dapp_addresses(&self, dapp: DappId) -> Result> { - let store = self.account_provider()?; - - store.dapp_addresses(dapp.into()) + self.accounts.dapp_addresses(dapp.into()) .map_err(|e| errors::account("Couldn't get dapp addresses.", e)) .map(into_vec) } fn set_dapp_default_address(&self, dapp: DappId, address: RpcH160) -> Result { - let store = self.account_provider()?; - - store.set_dapp_default_address(dapp.into(), address.into()) + self.accounts.set_dapp_default_address(dapp.into(), address.into()) .map_err(|e| errors::account("Couldn't set dapp default address.", e)) .map(|_| true) } fn dapp_default_address(&self, dapp: DappId) -> Result { - let store = self.account_provider()?; - - store.dapp_default_address(dapp.into()) + self.accounts.dapp_default_address(dapp.into()) .map_err(|e| errors::account("Couldn't get dapp default address.", e)) .map(Into::into) } fn set_new_dapps_addresses(&self, addresses: Option>) -> Result { - let store = self.account_provider()?; - - store + self.accounts .set_new_dapps_addresses(addresses.map(into_vec)) .map_err(|e| errors::account("Couldn't set dapps addresses.", e)) .map(|_| true) } fn new_dapps_addresses(&self) -> Result>> { - let store = self.account_provider()?; - - store.new_dapps_addresses() + self.accounts.new_dapps_addresses() .map_err(|e| errors::account("Couldn't get dapps addresses.", e)) .map(|accounts| accounts.map(into_vec)) } fn set_new_dapps_default_address(&self, address: RpcH160) -> Result { - let store = self.account_provider()?; - - store.set_new_dapps_default_address(address.into()) + self.accounts.set_new_dapps_default_address(address.into()) .map_err(|e| errors::account("Couldn't set new dapps default address.", e)) .map(|_| true) } fn new_dapps_default_address(&self) -> Result { - let store = self.account_provider()?; - - store.new_dapps_default_address() + self.accounts.new_dapps_default_address() .map_err(|e| errors::account("Couldn't get new dapps default address.", e)) .map(Into::into) } fn recent_dapps(&self) -> Result> { - let store = self.account_provider()?; - - store.recent_dapps() + self.accounts.recent_dapps() .map_err(|e| errors::account("Couldn't get recent dapps.", e)) .map(|map| map.into_iter().map(|(k, v)| (k.into(), v)).collect()) } fn import_geth_accounts(&self, addresses: Vec) -> Result> { - let store = self.account_provider()?; - - store + self.accounts .import_geth_accounts(into_vec(addresses), false) .map(into_vec) .map_err(|e| errors::account("Couldn't import Geth accounts", e)) } fn geth_accounts(&self) -> Result> { - let store = self.account_provider()?; - - Ok(into_vec(store.list_geth_accounts(false))) + Ok(into_vec(self.accounts.list_geth_accounts(false))) } fn create_vault(&self, name: String, password: String) -> Result { - self.account_provider()? + self.accounts .create_vault(&name, &password) .map_err(|e| errors::account("Could not create vault.", e)) .map(|_| true) } fn open_vault(&self, name: String, password: String) -> Result { - self.account_provider()? + self.accounts .open_vault(&name, &password) .map_err(|e| errors::account("Could not open vault.", e)) .map(|_| true) } fn close_vault(&self, name: String) -> Result { - self.account_provider()? + self.accounts .close_vault(&name) .map_err(|e| errors::account("Could not close vault.", e)) .map(|_| true) } fn list_vaults(&self) -> Result> { - self.account_provider()? + self.accounts .list_vaults() .map_err(|e| errors::account("Could not list vaults.", e)) } fn list_opened_vaults(&self) -> Result> { - self.account_provider()? + self.accounts .list_opened_vaults() .map_err(|e| errors::account("Could not list vaults.", e)) } fn change_vault_password(&self, name: String, new_password: String) -> Result { - self.account_provider()? + self.accounts .change_vault_password(&name, &new_password) .map_err(|e| errors::account("Could not change vault password.", e)) .map(|_| true) } fn change_vault(&self, address: RpcH160, new_vault: String) -> Result { - self.account_provider()? + self.accounts .change_vault(address.into(), &new_vault) .map_err(|e| errors::account("Could not change vault.", e)) .map(|_| true) } fn get_vault_meta(&self, name: String) -> Result { - self.account_provider()? + self.accounts .get_vault_meta(&name) .map_err(|e| errors::account("Could not get vault metadata.", e)) } fn set_vault_meta(&self, name: String, meta: String) -> Result { - self.account_provider()? + self.accounts .set_vault_meta(&name, &meta) .map_err(|e| errors::account("Could not update vault metadata.", e)) .map(|_| true) @@ -309,7 +271,7 @@ impl ParityAccounts for ParityAccountsClient { fn derive_key_index(&self, addr: RpcH160, password: String, derivation: DeriveHierarchical, save_as_account: bool) -> Result { let addr: Address = addr.into(); - self.account_provider()? + self.accounts .derive_account( &addr, Some(password), @@ -322,7 +284,7 @@ impl ParityAccounts for ParityAccountsClient { fn derive_key_hash(&self, addr: RpcH160, password: String, derivation: DeriveHash, save_as_account: bool) -> Result { let addr: Address = addr.into(); - self.account_provider()? + self.accounts .derive_account( &addr, Some(password), @@ -335,7 +297,7 @@ impl ParityAccounts for ParityAccountsClient { fn export_account(&self, addr: RpcH160, password: String) -> Result { let addr = addr.into(); - self.account_provider()? + self.accounts .export_account( &addr, password, @@ -345,7 +307,7 @@ impl ParityAccounts for ParityAccountsClient { } fn sign_message(&self, addr: RpcH160, password: String, message: RpcH256) -> Result { - self.account_provider()? + self.accounts .sign( addr.into(), Some(password), @@ -356,8 +318,7 @@ impl ParityAccounts for ParityAccountsClient { } fn hardware_pin_matrix_ack(&self, path: String, pin: String) -> Result { - let store = self.account_provider()?; - Ok(store.hardware_pin_matrix_ack(&path, &pin).map_err(|e| errors::account("Error communicating with hardware wallet.", e))?) + self.accounts.hardware_pin_matrix_ack(&path, &pin).map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 045496fc95..3a8d13c82e 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -55,16 +55,12 @@ impl PersonalClient { allow_perm_unlock, } } - - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } } impl PersonalClient { fn do_sign_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<(PendingTransaction, D)> { let dispatcher = self.dispatcher.clone(); - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default = match request.from.as_ref() { Some(account) => Ok(account.clone().into()), @@ -94,22 +90,19 @@ impl Personal for PersonalClient { type Metadata = Metadata; fn accounts(&self) -> Result> { - let store = self.account_provider()?; - let accounts = store.accounts().map_err(|e| errors::account("Could not fetch accounts.", e))?; + let accounts = self.accounts.accounts().map_err(|e| errors::account("Could not fetch accounts.", e))?; Ok(accounts.into_iter().map(Into::into).collect::>()) } fn new_account(&self, pass: String) -> Result { - let store = self.account_provider()?; - - store.new_account(&pass) + self.accounts.new_account(&pass) .map(Into::into) .map_err(|e| errors::account("Could not create account.", e)) } fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option) -> Result { let account: Address = account.into(); - let store = self.account_provider()?; + let store = self.accounts.clone(); let duration = match duration { None => None, Some(duration) => { @@ -141,7 +134,7 @@ impl Personal for PersonalClient { fn sign(&self, data: RpcBytes, account: RpcH160, password: String) -> BoxFuture { let dispatcher = self.dispatcher.clone(); - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let payload = RpcConfirmationPayload::EthSignMessage((account.clone(), data).into()); diff --git a/rpc/src/v1/impls/secretstore.rs b/rpc/src/v1/impls/secretstore.rs index 52404a58d0..771599eca3 100644 --- a/rpc/src/v1/impls/secretstore.rs +++ b/rpc/src/v1/impls/secretstore.rs @@ -43,16 +43,9 @@ impl SecretStoreClient { } } - /// Attempt to get the `Arc`, errors if provider was not - /// set. - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - /// Decrypt public key using account' private key fn decrypt_key(&self, address: H160, password: String, key: Bytes) -> Result> { - let store = self.account_provider()?; - store.decrypt(address.into(), Some(password), &DEFAULT_MAC, &key.0) + self.accounts.decrypt(address.into(), Some(password), &DEFAULT_MAC, &key.0) .map_err(|e| errors::account("Could not decrypt key.", e)) } @@ -65,8 +58,7 @@ impl SecretStoreClient { impl SecretStore for SecretStoreClient { fn generate_document_key(&self, address: H160, password: String, server_key_public: H512) -> Result { - let store = self.account_provider()?; - let account_public = store.account_public(address.into(), &password) + let account_public = self.accounts.account_public(address.into(), &password) .map_err(|e| errors::account("Could not read account public.", e))?; generate_document_key(account_public, server_key_public.into()) } @@ -96,8 +88,7 @@ impl SecretStore for SecretStoreClient { } fn sign_raw_hash(&self, address: H160, password: String, raw_hash: H256) -> Result { - let store = self.account_provider()?; - store + self.accounts .sign(address.into(), Some(password), raw_hash.into()) .map(|s| Bytes::new((*s).to_vec())) .map_err(|e| errors::account("Could not sign raw hash.", e)) diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index 14fd6a33a4..e679388cbf 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -77,17 +77,12 @@ impl SignerClient { } } - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn confirm_internal(&self, id: U256, modification: TransactionModification, f: F) -> BoxFuture> where F: FnOnce(D, Arc, ConfirmationPayload) -> T, T: IntoFuture, Error=Error>, T::Future: Send + 'static { let id = id.into(); - let accounts = try_bf!(self.account_provider()); let dispatcher = self.dispatcher.clone(); let signer = self.signer.clone(); @@ -110,7 +105,7 @@ impl SignerClient { request.condition = condition.clone().map(Into::into); } } - let fut = f(dispatcher, accounts, payload); + let fut = f(dispatcher, self.accounts.clone(), payload); Either::A(fut.into_future().then(move |result| { // Execute if let Ok(ref response) = result { diff --git a/rpc/src/v1/impls/signing.rs b/rpc/src/v1/impls/signing.rs index 6229a54c84..b22bbc80dd 100644 --- a/rpc/src/v1/impls/signing.rs +++ b/rpc/src/v1/impls/signing.rs @@ -108,12 +108,8 @@ impl SigningQueueClient { } } - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount, origin: Origin) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default_account = match default_account { DefaultAccount::Provided(acc) => acc, DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(), @@ -143,8 +139,7 @@ impl ParitySigning for SigningQueueClient { type Metadata = Metadata; fn compose_transaction(&self, meta: Metadata, transaction: RpcTransactionRequest) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); - let default_account = accounts.dapp_default_address(meta.dapp_id().into()).ok().unwrap_or_default(); + let default_account = self.accounts.dapp_default_address(meta.dapp_id().into()).ok().unwrap_or_default(); Box::new(self.dispatcher.fill_optional_fields(transaction.into(), default_account, true).map(Into::into)) } diff --git a/rpc/src/v1/impls/signing_unsafe.rs b/rpc/src/v1/impls/signing_unsafe.rs index f14d1e028d..6016cbbfc0 100644 --- a/rpc/src/v1/impls/signing_unsafe.rs +++ b/rpc/src/v1/impls/signing_unsafe.rs @@ -51,12 +51,8 @@ impl SigningUnsafeClient { } } - fn account_provider(&self) -> Result> { - Ok(self.accounts.clone()) - } - fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default = match account { DefaultAccount::Provided(acc) => acc, DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(), @@ -107,7 +103,7 @@ impl ParitySigning for SigningUnsafeClient { type Metadata = Metadata; fn compose_transaction(&self, meta: Metadata, transaction: RpcTransactionRequest) -> BoxFuture { - let accounts = try_bf!(self.account_provider()); + let accounts = self.accounts.clone(); let default_account = accounts.dapp_default_address(meta.dapp_id().into()).ok().unwrap_or_default(); Box::new(self.dispatcher.fill_optional_fields(transaction.into(), default_account, true).map(Into::into)) } diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index c9dd50a3c6..4bb653c4d2 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -81,8 +81,6 @@ impl Dependencies { } pub fn client(&self, signer: Option>) -> TestParityClient { - let opt_accounts = self.accounts.clone(); - ParityClient::new( self.client.clone(), self.miner.clone(), @@ -90,7 +88,7 @@ impl Dependencies { self.updater.clone(), self.network.clone(), self.health.clone(), - opt_accounts.clone(), + self.accounts.clone(), self.logger.clone(), self.settings.clone(), signer, diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 131a865da7..1e445c67a0 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -52,13 +52,12 @@ fn miner_service() -> Arc { fn setup() -> PersonalTester { let accounts = accounts_provider(); - let opt_accounts = accounts.clone(); let client = blockchain_client(); let miner = miner_service(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); let dispatcher = FullDispatcher::new(client, miner.clone(), reservations, 50); - let personal = PersonalClient::new(&opt_accounts, dispatcher, false); + let personal = PersonalClient::new(&accounts, dispatcher, false); let mut io = IoHandler::default(); io.extend_with(personal.to_delegate()); diff --git a/rpc/src/v1/tests/mocked/signer.rs b/rpc/src/v1/tests/mocked/signer.rs index 8bbb590c06..b935818422 100644 --- a/rpc/src/v1/tests/mocked/signer.rs +++ b/rpc/src/v1/tests/mocked/signer.rs @@ -58,7 +58,6 @@ fn miner_service() -> Arc { fn signer_tester() -> SignerTester { let signer = Arc::new(SignerService::new_test(false)); let accounts = accounts_provider(); - let opt_accounts = accounts.clone(); let client = blockchain_client(); let miner = miner_service(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); @@ -66,7 +65,7 @@ fn signer_tester() -> SignerTester { let dispatcher = FullDispatcher::new(client, miner.clone(), reservations, 50); let mut io = IoHandler::default(); - io.extend_with(SignerClient::new(&opt_accounts, dispatcher, &signer, event_loop.remote()).to_delegate()); + io.extend_with(SignerClient::new(&accounts, dispatcher, &signer, event_loop.remote()).to_delegate()); SignerTester { signer: signer, diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 2dc80f066c..ba9fa6d4b6 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -56,7 +56,6 @@ impl Default for SigningTester { let client = Arc::new(TestBlockChainClient::default()); let miner = Arc::new(TestMinerService::default()); let accounts = Arc::new(AccountProvider::transient_provider()); - let opt_accounts = accounts.clone(); let reservations = Arc::new(Mutex::new(nonce::Reservations::new())); let mut io = IoHandler::default(); @@ -64,9 +63,9 @@ impl Default for SigningTester { let remote = Remote::new_thread_per_future(); - let rpc = SigningQueueClient::new(&signer, dispatcher.clone(), remote.clone(), &opt_accounts); + let rpc = SigningQueueClient::new(&signer, dispatcher.clone(), remote.clone(), &accounts); io.extend_with(EthSigning::to_delegate(rpc)); - let rpc = SigningQueueClient::new(&signer, dispatcher, remote, &opt_accounts); + let rpc = SigningQueueClient::new(&signer, dispatcher, remote, &accounts); io.extend_with(ParitySigning::to_delegate(rpc)); SigningTester { -- GitLab From e2a90ce159c751fdc548610749388a3c3a3cd9ad Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 4 Jun 2018 21:58:44 +0800 Subject: [PATCH 211/263] Conditionally compile ethcore public test helpers (#8743) * Mark test helpers and test-only specs as cfg(test) * Use test-probe to conditionally compile test helpers * Remove test probe and directly use features tag --- ethcore/Cargo.toml | 2 ++ ethcore/private-tx/Cargo.toml | 3 +++ ethcore/src/client/mod.rs | 4 ++++ ethcore/src/lib.rs | 4 ++-- ethcore/src/spec/spec.rs | 25 +++++++++++++++++++------ ethcore/sync/Cargo.toml | 1 + 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 71c84a293f..2b6ab9ebc3 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -89,3 +89,5 @@ json-tests = ["ethcore-transaction/json-tests"] test-heavy = [] # Compile benches benches = [] +# Compile test helpers +test-helpers = [] diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index 8283ab314a..441c9882e2 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -35,3 +35,6 @@ serde_derive = "1.0" serde_json = "1.0" tiny-keccak = "1.4" url = "1" + +[dev-dependencies] +ethcore = { path = "..", features = ["test-helpers"] } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 6e12c03052..3691768dcf 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -20,16 +20,20 @@ mod ancient_import; mod client; mod config; mod error; +#[cfg(any(test, feature="test-helpers"))] mod evm_test_client; mod io_message; +#[cfg(any(test, feature="test-helpers"))] mod test_client; mod trace; pub use self::client::*; pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType}; pub use self::error::Error; +#[cfg(any(test, feature="test-helpers"))] pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; pub use self::io_message::ClientIoMessage; +#[cfg(any(test, feature="test-helpers"))] pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::chain_notify::{ChainNotify, ChainRoute, ChainRouteType, ChainMessageType}; pub use self::traits::{ diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 00113f7303..e89b0dfff9 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -157,8 +157,6 @@ pub mod snapshot; pub mod spec; pub mod state; pub mod state_db; -// Test helpers made public for usage outside ethcore -pub mod test_helpers; pub mod trace; pub mod verification; @@ -177,6 +175,8 @@ mod tests; #[cfg(test)] #[cfg(feature="json-tests")] mod json_tests; +#[cfg(any(test, feature="test-helpers"))] +pub mod test_helpers; #[cfg(test)] mod test_helpers_internal; diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index a8ab757549..784aa2a4e5 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -515,6 +515,7 @@ macro_rules! load_bundled { }; } +#[cfg(any(test, feature="test-helpers"))] macro_rules! load_machine_bundled { ($e:expr) => { Spec::load_machine( @@ -838,38 +839,44 @@ impl Spec { self.engine.genesis_epoch_data(&genesis, &call) } + /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring + /// work). + pub fn new_instant() -> Spec { + load_bundled!("instant_seal") + } + /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a /// NullEngine consensus. + #[cfg(any(test, feature="test-helpers"))] pub fn new_test() -> Spec { load_bundled!("null_morden") } /// Create the EthereumMachine corresponding to Spec::new_test. + #[cfg(any(test, feature="test-helpers"))] pub fn new_test_machine() -> EthereumMachine { load_machine_bundled!("null_morden") } /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus with applying reward on block close. + #[cfg(any(test, feature="test-helpers"))] pub fn new_test_with_reward() -> Spec { load_bundled!("null_morden_with_reward") } /// Create a new Spec which is a NullEngine consensus with a premine of address whose /// secret is keccak(''). + #[cfg(any(test, feature="test-helpers"))] pub fn new_null() -> Spec { load_bundled!("null") } /// Create a new Spec which constructs a contract at address 5 with storage at 0 equal to 1. + #[cfg(any(test, feature="test-helpers"))] pub fn new_test_constructor() -> Spec { load_bundled!("constructor") } - /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring - /// work). - pub fn new_instant() -> Spec { - load_bundled!("instant_seal") - } - /// Create a new Spec with AuthorityRound consensus which does internal sealing (not /// requiring work). /// Accounts with secrets keccak("0") and keccak("1") are the validators. + #[cfg(any(test, feature="test-helpers"))] pub fn new_test_round() -> Self { load_bundled!("authority_round") } @@ -877,6 +884,7 @@ impl Spec { /// Create a new Spec with AuthorityRound consensus which does internal sealing (not /// requiring work) with empty step messages enabled. /// Accounts with secrets keccak("0") and keccak("1") are the validators. + #[cfg(any(test, feature="test-helpers"))] pub fn new_test_round_empty_steps() -> Self { load_bundled!("authority_round_empty_steps") } @@ -884,6 +892,7 @@ impl Spec { /// Create a new Spec with AuthorityRound consensus (with empty steps) using a block reward /// contract. The contract source code can be found at: /// https://github.com/parity-contracts/block-reward/blob/daf7d44383b6cdb11cb6b953b018648e2b027cfb/contracts/ExampleBlockReward.sol + #[cfg(any(test, feature="test-helpers"))] pub fn new_test_round_block_reward_contract() -> Self { load_bundled!("authority_round_block_reward_contract") } @@ -891,6 +900,7 @@ impl Spec { /// Create a new Spec with Tendermint consensus which does internal sealing (not requiring /// work). /// Account keccak("0") and keccak("1") are a authorities. + #[cfg(any(test, feature="test-helpers"))] pub fn new_test_tendermint() -> Self { load_bundled!("tendermint") } @@ -903,6 +913,7 @@ impl Spec { /// "0xbfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1" and added /// back in using /// "0x4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1". + #[cfg(any(test, feature="test-helpers"))] pub fn new_validator_safe_contract() -> Self { load_bundled!("validator_safe_contract") } @@ -910,6 +921,7 @@ impl Spec { /// The same as the `safeContract`, but allows reporting and uses AuthorityRound. /// Account is marked with `reportBenign` it can be checked as disliked with "0xd8f2e0bf". /// Validator can be removed with `reportMalicious`. + #[cfg(any(test, feature="test-helpers"))] pub fn new_validator_contract() -> Self { load_bundled!("validator_contract") } @@ -918,6 +930,7 @@ impl Spec { /// height. /// Account with secrets keccak("0") is the validator for block 1 and with keccak("1") /// onwards. + #[cfg(any(test, feature="test-helpers"))] pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") } diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index cf163cc7bd..66ee566215 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -38,3 +38,4 @@ ethcore-io = { path = "../../util/io", features = ["mio"] } ethkey = { path = "../../ethkey" } kvdb-memorydb = { path = "../../util/kvdb-memorydb" } ethcore-private-tx = { path = "../private-tx" } +ethcore = { path = "..", features = ["test-helpers"] } -- GitLab From b3ea766bd5a77e1d3491db2b6f48c3ded2dd5fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 5 Jun 2018 08:58:09 +0100 Subject: [PATCH 212/263] rpc: fix address formatting in TransactionRequest Display (#8786) * rpc: fix address formatting in TransactionRequest Display * rpc: use unwrap_or_else when no to address provided --- rpc/src/v1/types/transaction_request.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index 7fed6f681a..4fa47b5acd 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -69,14 +69,20 @@ impl fmt::Display for TransactionRequest { f, "{} ETH from {} to 0x{:?}", Colour::White.bold().paint(format_ether(eth)), - Colour::White.bold().paint(format!("0x{:?}", self.from)), + Colour::White.bold().paint( + self.from.as_ref() + .map(|f| format!("0x{:?}", f)) + .unwrap_or_else(|| "?".to_string())), to ), None => write!( f, "{} ETH from {} for contract creation", Colour::White.bold().paint(format_ether(eth)), - Colour::White.bold().paint(format!("0x{:?}", self.from)), + Colour::White.bold().paint( + self.from.as_ref() + .map(|f| format!("0x{:?}", f)) + .unwrap_or_else(|| "?".to_string())), ), } } -- GitLab From 6ecc63002b5357ed16955b4f28f714cec62a9023 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 5 Jun 2018 17:28:35 +0800 Subject: [PATCH 213/263] Have space between feature cfg flag (#8791) --- dapps/js-glue/src/js.rs | 4 ++-- ethcore/evm/src/lib.rs | 2 +- ethcore/src/client/mod.rs | 8 ++++---- ethcore/src/lib.rs | 6 +++--- ethcore/src/spec/spec.rs | 26 +++++++++++++------------- parity/lib.rs | 2 +- parity/secretstore.rs | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/dapps/js-glue/src/js.rs b/dapps/js-glue/src/js.rs index f89fcefc76..906b238ec7 100644 --- a/dapps/js-glue/src/js.rs +++ b/dapps/js-glue/src/js.rs @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -#![cfg_attr(feature="use-precompiled-js", allow(dead_code))] -#![cfg_attr(feature="use-precompiled-js", allow(unused_imports))] +#![cfg_attr(feature = "use-precompiled-js", allow(dead_code))] +#![cfg_attr(feature = "use-precompiled-js", allow(unused_imports))] use std::fmt; use std::process::Command; diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index 1b5610cef5..6eca25f42f 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -43,7 +43,7 @@ mod instructions; #[cfg(test)] mod tests; -#[cfg(all(feature="benches", test))] +#[cfg(all(feature = "benches", test))] mod benches; pub use vm::{ diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 3691768dcf..8c5abf3f5d 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -20,20 +20,20 @@ mod ancient_import; mod client; mod config; mod error; -#[cfg(any(test, feature="test-helpers"))] +#[cfg(any(test, feature = "test-helpers"))] mod evm_test_client; mod io_message; -#[cfg(any(test, feature="test-helpers"))] +#[cfg(any(test, feature = "test-helpers"))] mod test_client; mod trace; pub use self::client::*; pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType}; pub use self::error::Error; -#[cfg(any(test, feature="test-helpers"))] +#[cfg(any(test, feature = "test-helpers"))] pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; pub use self::io_message::ClientIoMessage; -#[cfg(any(test, feature="test-helpers"))] +#[cfg(any(test, feature = "test-helpers"))] pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::chain_notify::{ChainNotify, ChainRoute, ChainRouteType, ChainMessageType}; pub use self::traits::{ diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index e89b0dfff9..51e75d4b40 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(feature="benches", feature(test))] +#![cfg_attr(feature = "benches", feature(test))] //! Ethcore library //! @@ -173,9 +173,9 @@ mod tx_filter; #[cfg(test)] mod tests; #[cfg(test)] -#[cfg(feature="json-tests")] +#[cfg(feature = "json-tests")] mod json_tests; -#[cfg(any(test, feature="test-helpers"))] +#[cfg(any(test, feature = "test-helpers"))] pub mod test_helpers; #[cfg(test)] mod test_helpers_internal; diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 784aa2a4e5..6f785fe7fb 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -515,7 +515,7 @@ macro_rules! load_bundled { }; } -#[cfg(any(test, feature="test-helpers"))] +#[cfg(any(test, feature = "test-helpers"))] macro_rules! load_machine_bundled { ($e:expr) => { Spec::load_machine( @@ -847,28 +847,28 @@ impl Spec { /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a /// NullEngine consensus. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test() -> Spec { load_bundled!("null_morden") } /// Create the EthereumMachine corresponding to Spec::new_test. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_machine() -> EthereumMachine { load_machine_bundled!("null_morden") } /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus with applying reward on block close. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_with_reward() -> Spec { load_bundled!("null_morden_with_reward") } /// Create a new Spec which is a NullEngine consensus with a premine of address whose /// secret is keccak(''). - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_null() -> Spec { load_bundled!("null") } /// Create a new Spec which constructs a contract at address 5 with storage at 0 equal to 1. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_constructor() -> Spec { load_bundled!("constructor") } @@ -876,7 +876,7 @@ impl Spec { /// Create a new Spec with AuthorityRound consensus which does internal sealing (not /// requiring work). /// Accounts with secrets keccak("0") and keccak("1") are the validators. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_round() -> Self { load_bundled!("authority_round") } @@ -884,7 +884,7 @@ impl Spec { /// Create a new Spec with AuthorityRound consensus which does internal sealing (not /// requiring work) with empty step messages enabled. /// Accounts with secrets keccak("0") and keccak("1") are the validators. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_round_empty_steps() -> Self { load_bundled!("authority_round_empty_steps") } @@ -892,7 +892,7 @@ impl Spec { /// Create a new Spec with AuthorityRound consensus (with empty steps) using a block reward /// contract. The contract source code can be found at: /// https://github.com/parity-contracts/block-reward/blob/daf7d44383b6cdb11cb6b953b018648e2b027cfb/contracts/ExampleBlockReward.sol - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_round_block_reward_contract() -> Self { load_bundled!("authority_round_block_reward_contract") } @@ -900,7 +900,7 @@ impl Spec { /// Create a new Spec with Tendermint consensus which does internal sealing (not requiring /// work). /// Account keccak("0") and keccak("1") are a authorities. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_test_tendermint() -> Self { load_bundled!("tendermint") } @@ -913,7 +913,7 @@ impl Spec { /// "0xbfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1" and added /// back in using /// "0x4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1". - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_validator_safe_contract() -> Self { load_bundled!("validator_safe_contract") } @@ -921,7 +921,7 @@ impl Spec { /// The same as the `safeContract`, but allows reporting and uses AuthorityRound. /// Account is marked with `reportBenign` it can be checked as disliked with "0xd8f2e0bf". /// Validator can be removed with `reportMalicious`. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_validator_contract() -> Self { load_bundled!("validator_contract") } @@ -930,7 +930,7 @@ impl Spec { /// height. /// Account with secrets keccak("0") is the validator for block 1 and with keccak("1") /// onwards. - #[cfg(any(test, feature="test-helpers"))] + #[cfg(any(test, feature = "test-helpers"))] pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") } diff --git a/parity/lib.rs b/parity/lib.rs index 6ef332da65..c768722552 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -76,7 +76,7 @@ extern crate registrar; #[macro_use] extern crate log as rlog; -#[cfg(feature="secretstore")] +#[cfg(feature = "secretstore")] extern crate ethcore_secretstore; #[cfg(feature = "dapps")] diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 3b4a4e468c..0723a1d078 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -111,7 +111,7 @@ mod server { } } -#[cfg(feature="secretstore")] +#[cfg(feature = "secretstore")] mod server { use std::sync::Arc; use ethcore_secretstore; -- GitLab From 5d6a0d4dae8b804ea9af07f6ade0320448c4d2e6 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 5 Jun 2018 20:40:50 +0800 Subject: [PATCH 214/263] Fix evmbin compilation (#8795) * Fix evmbin compilation * Move features declaration to dependencies --- evmbin/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmbin/Cargo.toml b/evmbin/Cargo.toml index c3ef5847d4..51865091a9 100644 --- a/evmbin/Cargo.toml +++ b/evmbin/Cargo.toml @@ -10,7 +10,7 @@ path = "./src/main.rs" [dependencies] docopt = "0.8" -ethcore = { path = "../ethcore" } +ethcore = { path = "../ethcore", features = ["test-helpers"] } ethjson = { path = "../json" } ethcore-bytes = { path = "../util/bytes" } ethcore-transaction = { path = "../ethcore/transaction" } -- GitLab From 123b6ae62ef266131f24da9b184e68b16955fb06 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 6 Jun 2018 01:49:11 +0800 Subject: [PATCH 215/263] Disallow unsigned transactions in case EIP-86 is disabled (#8802) * Disallow unsigned transactions in case EIP-86 is disabled * Add tests for verification * Add disallow unsigned transactions test in machine --- ethcore/src/ethereum/mod.rs | 3 +++ ethcore/src/machine.rs | 19 +++++++++++++++++++ ethcore/src/verification/verification.rs | 19 +++++++++++++++++++ ethcore/transaction/src/transaction.rs | 4 ++++ 4 files changed, 45 insertions(+) diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 6456440759..db07cbbd49 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -101,6 +101,9 @@ pub fn new_morden<'a, T: Into>>(params: T) -> Spec { /// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead. pub fn new_frontier_test() -> Spec { load(None, include_bytes!("../../res/ethereum/frontier_test.json")) } +/// Create a new Ropsten chain spec. +pub fn new_ropsten_test() -> Spec { load(None, include_bytes!("../../res/ethereum/ropsten.json")) } + /// Create a new Foundation Homestead-era chain spec as though it never changed from Frontier. pub fn new_homestead_test() -> Spec { load(None, include_bytes!("../../res/ethereum/homestead_test.json")) } diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index d54dd2e292..dbf66aa121 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -485,6 +485,25 @@ mod tests { } } + #[test] + fn should_disallow_unsigned_transactions() { + let rlp = "ea80843b9aca0083015f90948921ebb5f79e9e3920abe571004d0b1d5119c154865af3107a400080038080".into(); + let transaction: UnverifiedTransaction = ::rlp::decode(&::rustc_hex::FromHex::from_hex(rlp).unwrap()).unwrap(); + let spec = ::ethereum::new_ropsten_test(); + let ethparams = get_default_ethash_extensions(); + + let machine = EthereumMachine::with_ethash_extensions( + spec.params().clone(), + Default::default(), + ethparams, + ); + let mut header = ::header::Header::new(); + header.set_number(15); + + let res = machine.verify_transaction_basic(&transaction, &header); + assert_eq!(res, Err(transaction::Error::InvalidSignature("Crypto error (Invalid EC signature)".into()))); + } + #[test] fn ethash_gas_limit_is_multiple_of_determinant() { use ethereum_types::U256; diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 3b9104f0e1..1275b5c5c3 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -576,7 +576,17 @@ mod tests { nonce: U256::from(2) }.sign(keypair.secret(), None); + let tr3 = Transaction { + action: Action::Call(0x0.into()), + value: U256::from(0), + data: Bytes::new(), + gas: U256::from(30_000), + gas_price: U256::from(0), + nonce: U256::zero(), + }.null_sign(0); + let good_transactions = [ tr1.clone(), tr2.clone() ]; + let eip86_transactions = [ tr3.clone() ]; let diff_inc = U256::from(0x40); @@ -612,6 +622,7 @@ mod tests { uncles_rlp.append_list(&good_uncles); let good_uncles_hash = keccak(uncles_rlp.as_raw()); let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| ::rlp::encode::(t))); + let eip86_transactions_root = ordered_trie_root(eip86_transactions.iter().map(|t| ::rlp::encode::(t))); let mut parent = good.clone(); parent.set_number(9); @@ -632,6 +643,14 @@ mod tests { check_ok(basic_test(&create_test_block(&good), engine)); + let mut bad_header = good.clone(); + bad_header.set_transactions_root(eip86_transactions_root.clone()); + bad_header.set_uncles_hash(good_uncles_hash.clone()); + match basic_test(&create_test_block_with_data(&bad_header, &eip86_transactions, &good_uncles), engine) { + Err(Error(ErrorKind::Transaction(ref e), _)) if e == &::ethkey::Error::InvalidSignature.into() => (), + e => panic!("Block verification failed.\nExpected: Transaction Error (Invalid Signature)\nGot: {:?}", e), + } + let mut header = good.clone(); header.set_transactions_root(good_transactions_root.clone()); header.set_uncles_hash(good_uncles_hash.clone()); diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index dd1e8ca2cc..27b8b346cf 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -409,6 +409,10 @@ impl UnverifiedTransaction { if check_low_s && !(allow_empty_signature && self.is_unsigned()) { self.check_low_s()?; } + // Disallow unsigned transactions in case EIP-86 is disabled. + if !allow_empty_signature && self.is_unsigned() { + return Err(ethkey::Error::InvalidSignature.into()); + } // EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. if allow_empty_signature && self.is_unsigned() && !(self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero()) { return Err(ethkey::Error::InvalidSignature.into()) -- GitLab From 6771539a90ccd5900e72728517fa1e904a6e2664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 5 Jun 2018 19:49:46 +0200 Subject: [PATCH 216/263] Fix ancient blocks queue deadlock (#8751) * Revert "Fix not downloading old blocks (#8642)" This reverts commit d1934363e7c2c953f17cd451bea8476f46f52b82. * Make sure only one thread actually imports old blocks. * Add some trace timers. * Bring back pending hashes set. * Separate locks so that queue can happen while we are importing. * Address grumbles. --- ethcore/src/client/client.rs | 115 +++++++++++++++++++++-------------- miner/src/pool/queue.rs | 2 +- 2 files changed, 71 insertions(+), 46 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 9e2cfeff40..f3a3dda103 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -17,7 +17,7 @@ use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque}; use std::fmt; use std::str::FromStr; -use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; +use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Arc, Weak}; use std::time::{Instant, Duration}; @@ -90,6 +90,8 @@ use_contract!(registry, "Registry", "res/contracts/registrar.json"); const MAX_TX_QUEUE_SIZE: usize = 4096; const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096; +// Max number of blocks imported at once. +const MAX_ANCIENT_BLOCKS_TO_IMPORT: usize = 4; const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2; const MIN_HISTORY_SIZE: u64 = 8; @@ -210,8 +212,12 @@ pub struct Client { queue_transactions: IoChannelQueue, /// Ancient blocks import queue queue_ancient_blocks: IoChannelQueue, - /// Hashes of pending ancient block wainting to be included - pending_ancient_blocks: RwLock>, + /// Queued ancient blocks, make sure they are imported in order. + queued_ancient_blocks: Arc, + VecDeque<(Header, Bytes, Bytes)> + )>>, + ancient_blocks_import_lock: Arc>, /// Consensus messages import queue queue_consensus_message: IoChannelQueue, @@ -434,7 +440,6 @@ impl Importer { let hash = header.hash(); let _import_lock = self.import_lock.lock(); - trace!(target: "client", "Trying to import old block #{}", header.number()); { trace_time!("import_old_block"); // verify the block, passing the chain for updating the epoch verifier. @@ -763,7 +768,8 @@ impl Client { notify: RwLock::new(Vec::new()), queue_transactions: IoChannelQueue::new(MAX_TX_QUEUE_SIZE), queue_ancient_blocks: IoChannelQueue::new(MAX_ANCIENT_BLOCKS_QUEUE_SIZE), - pending_ancient_blocks: RwLock::new(HashSet::new()), + queued_ancient_blocks: Default::default(), + ancient_blocks_import_lock: Default::default(), queue_consensus_message: IoChannelQueue::new(usize::max_value()), last_hashes: RwLock::new(VecDeque::new()), factories: factories, @@ -2008,8 +2014,9 @@ impl BlockChainClient for Client { impl IoClient for Client { fn queue_transactions(&self, transactions: Vec, peer_id: usize) { + trace_time!("queue_transactions"); let len = transactions.len(); - self.queue_transactions.queue(&mut self.io_channel.lock(), move |client| { + self.queue_transactions.queue(&mut self.io_channel.lock(), len, move |client| { trace_time!("import_queued_transactions"); let txs: Vec = transactions @@ -2028,6 +2035,7 @@ impl IoClient for Client { } fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result { + trace_time!("queue_ancient_block"); let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?; let hash = header.hash(); @@ -2036,31 +2044,51 @@ impl IoClient for Client { if self.chain.read().is_known(&hash) { bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain)); } - - let parent_hash = *header.parent_hash(); - let parent_pending = self.pending_ancient_blocks.read().contains(&parent_hash); - let status = self.block_status(BlockId::Hash(parent_hash)); - if !parent_pending && (status == BlockStatus::Unknown || status == BlockStatus::Pending) { - bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(parent_hash))); + let parent_hash = header.parent_hash(); + // NOTE To prevent race condition with import, make sure to check queued blocks first + // (and attempt to acquire lock) + let is_parent_pending = self.queued_ancient_blocks.read().0.contains(parent_hash); + if !is_parent_pending { + let status = self.block_status(BlockId::Hash(*parent_hash)); + if status == BlockStatus::Unknown || status == BlockStatus::Pending { + bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*parent_hash))); + } } } - self.pending_ancient_blocks.write().insert(hash); - - trace!(target: "client", "Queuing old block #{}", header.number()); - match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), move |client| { - let result = client.importer.import_old_block( - &header, - &block_bytes, - &receipts_bytes, - &**client.db.read(), - &*client.chain.read() - ); - - client.pending_ancient_blocks.write().remove(&hash); - result.map(|_| ()).unwrap_or_else(|e| { - error!(target: "client", "Error importing ancient block: {}", e); - }); + // we queue blocks here and trigger an IO message. + { + let mut queued = self.queued_ancient_blocks.write(); + queued.0.insert(hash); + queued.1.push_back((header, block_bytes, receipts_bytes)); + } + + let queued = self.queued_ancient_blocks.clone(); + let lock = self.ancient_blocks_import_lock.clone(); + match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), 1, move |client| { + trace_time!("import_ancient_block"); + // Make sure to hold the lock here to prevent importing out of order. + // We use separate lock, cause we don't want to block queueing. + let _lock = lock.lock(); + for _i in 0..MAX_ANCIENT_BLOCKS_TO_IMPORT { + let first = queued.write().1.pop_front(); + if let Some((header, block_bytes, receipts_bytes)) = first { + let hash = header.hash(); + client.importer.import_old_block( + &header, + &block_bytes, + &receipts_bytes, + &**client.db.read(), + &*client.chain.read() + ).ok().map_or((), |e| { + error!(target: "client", "Error importing ancient block: {}", e); + }); + // remove from pending + queued.write().0.remove(&hash); + } else { + break; + } + } }) { Ok(_) => Ok(hash), Err(e) => bail!(BlockImportErrorKind::Other(format!("{}", e))), @@ -2068,7 +2096,7 @@ impl IoClient for Client { } fn queue_consensus_message(&self, message: Bytes) { - match self.queue_consensus_message.queue(&mut self.io_channel.lock(), move |client| { + match self.queue_consensus_message.queue(&mut self.io_channel.lock(), 1, move |client| { if let Err(e) = client.engine().handle_message(&message) { debug!(target: "poa", "Invalid message received: {}", e); } @@ -2480,38 +2508,35 @@ impl fmt::Display for QueueError { /// Queue some items to be processed by IO client. struct IoChannelQueue { - queue: Arc>>>, + currently_queued: Arc, limit: usize, } impl IoChannelQueue { pub fn new(limit: usize) -> Self { IoChannelQueue { - queue: Default::default(), + currently_queued: Default::default(), limit, } } - pub fn queue(&self, channel: &mut IoChannel, fun: F) -> Result<(), QueueError> - where F: Fn(&Client) + Send + Sync + 'static + pub fn queue(&self, channel: &mut IoChannel, count: usize, fun: F) -> Result<(), QueueError> where + F: Fn(&Client) + Send + Sync + 'static, { - { - let mut queue = self.queue.lock(); - let queue_size = queue.len(); - ensure!(queue_size < self.limit, QueueError::Full(self.limit)); + let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed); + ensure!(queue_size < self.limit, QueueError::Full(self.limit)); - queue.push_back(Box::new(fun)); - } - - let queue = self.queue.clone(); + let currently_queued = self.currently_queued.clone(); let result = channel.send(ClientIoMessage::execute(move |client| { - while let Some(fun) = queue.lock().pop_front() { - fun(client); - } + currently_queued.fetch_sub(count, AtomicOrdering::SeqCst); + fun(client); })); match result { - Ok(_) => Ok(()), + Ok(_) => { + self.currently_queued.fetch_add(count, AtomicOrdering::SeqCst); + Ok(()) + }, Err(e) => Err(QueueError::Channel(e)), } } diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index bd5a98edc7..4ebdf9e3f1 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -174,7 +174,7 @@ impl TransactionQueue { transactions: Vec, ) -> Vec> { // Run verification - let _timer = ::trace_time::PerfTimer::new("queue::verifyAndImport"); + let _timer = ::trace_time::PerfTimer::new("pool::verify_and_import"); let options = self.options.read().clone(); let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone()); -- GitLab From bd4498cffcf34cf8ef3b002dd6d268d9cae307a5 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 6 Jun 2018 10:01:15 +0200 Subject: [PATCH 217/263] docs: add changelogs for 1.10.6 and 1.11.3 (#8810) * docs: add changelog for 1.10.6 * docs: add changelog for 1.11.3 * docs: markdownify the changelogs --- CHANGELOG.md | 138 ++++++++++++++++++++++++++++++----------- docs/CHANGELOG-1.10.md | 104 +++++++++++++++++++++---------- 2 files changed, 174 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee66149ed0..25e2a28a57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,71 @@ +## Parity [v1.11.3](https://github.com/paritytech/parity/releases/tag/v1.11.3) (2018-06-06) + +Parity 1.11.3 is a security-relevant release. Please upgrade your nodes as soon as possible to [v1.10.6](https://github.com/paritytech/parity/releases/tag/v1.10.6) or [v1.11.3](https://github.com/paritytech/parity/releases/tag/v1.11.3). + +The full list of included changes: + +- Parity-version: bump beta to 1.11.3 ([#8806](https://github.com/paritytech/parity/pull/8806)) + - Parity-version: bump beta to 1.11.3 + - Disallow unsigned transactions in case EIP-86 is disabled ([#8802](https://github.com/paritytech/parity/pull/8802)) + - Fix ancient blocks queue deadlock ([#8751](https://github.com/paritytech/parity/pull/8751)) +- Update shell32-sys to fix windows build ([#8792](https://github.com/paritytech/parity/pull/8792)) +- Backports ([#8785](https://github.com/paritytech/parity/pull/8785)) + - Fix light sync with initial validator-set contract ([#8528](https://github.com/paritytech/parity/pull/8528)) + - Fix #8468 + - Use U256::max_value() instead + - Also change initial transaction gas + - Resumable warp-sync / Seed downloaded snapshots ([#8544](https://github.com/paritytech/parity/pull/8544)) + - Start dividing sync chain : first supplier method + - WIP - updated chain sync supplier + - Finish refactoring the Chain Sync Supplier + - Create Chain Sync Requester + - Add Propagator for Chain Sync + - Add the Chain Sync Handler + - Move tests from mod -> handler + - Move tests to propagator + - Refactor SyncRequester arguments + - Refactoring peer fork header handler + - Fix wrong highest block number in snapshot sync + - Small refactor... + - Resume warp-sync downloaded chunks + - Refactoring the previous chunks import + - Address PR grumbles + - Fix not seeding current snapshot + - Update SnapshotService readiness check + - Early abort importing previous chunks + - Update Gitlab CI config + - SyncState back to Waiting when Manifest peers disconnect + - Revert GitLab CI changes + - Refactor resuming snapshots + - Revert "Refactor resuming snapshots" + - Update informant log + - Refactor resuming snapshots + - Update informant message : show chunks done + - Don't open Browser post-install on Mac ([#8641](https://github.com/paritytech/parity/pull/8641)) + - Fix not downloading old blocks ([#8642](https://github.com/paritytech/parity/pull/8642)) + - Fix PoW blockchains sealing notifications in chain_new_blocks ([#8656](https://github.com/paritytech/parity/pull/8656)) + - Shutdown the Snapshot Service early ([#8658](https://github.com/paritytech/parity/pull/8658)) + - Shutdown the Snapshot Service when shutting down the runner + - Rename `service` to `client_service` + - Fix tests + - Fix cli signer ([#8682](https://github.com/paritytech/parity/pull/8682)) + - Update ethereum-types so `{:#x}` applies 0x prefix + - Set the request index to that of the current request ([#8683](https://github.com/paritytech/parity/pull/8683)) + - Set the request index to that of the current request + - Network-devp2p: handle UselessPeer disconnect ([#8686](https://github.com/paritytech/parity/pull/8686)) + - Fix local transactions policy. ([#8691](https://github.com/paritytech/parity/pull/8691)) + - CI: Fixes for Android Pipeline ([#8745](https://github.com/paritytech/parity/pull/8745)) + - Ci: Remove check for shared libraries in gitlab script + - Ci: allow android arm build to fail + - Custom Error Messages on ENFILE and EMFILE IO Errors ([#8744](https://github.com/paritytech/parity/pull/8744)) + - Custom Error Messages on ENFILE and EMFILE IO Errors + - Use assert-matches for more readable tests + - Fix Wording and consistency + - Ethcore-sync: fix connection to peers behind chain fork block ([#8710](https://github.com/paritytech/parity/pull/8710)) +- Parity-version: bump beta to 1.11.2 ([#8750](https://github.com/paritytech/parity/pull/8750)) + - Parity-version: bump beta to 1.11.2 + - Parity-version: unset critical flag + ## Parity [v1.11.1](https://github.com/paritytech/parity/releases/tag/v1.11.1) (2018-05-15) This is the Parity 1.11.1-beta release! Hurray! @@ -156,47 +224,47 @@ The full list of included changes: - Backports ([#8558](https://github.com/paritytech/parity/pull/8558)) - Fetching logs by hash in blockchain database ([#8463](https://github.com/paritytech/parity/pull/8463)) - - Fetch logs by hash in blockchain database - - Fix tests - - Add unit test for branch block logs fetching - - Add docs that blocks must already be sorted - - Handle branch block cases properly - - typo: empty -> is_empty - - Remove return_empty_if_none by using a closure - - Use BTreeSet to avoid sorting again - - Move is_canon to BlockChain - - typo: pass value by reference - - Use loop and wrap inside blocks to simplify the code - - typo: missed a comment + - Fetch logs by hash in blockchain database + - Fix tests + - Add unit test for branch block logs fetching + - Add docs that blocks must already be sorted + - Handle branch block cases properly + - typo: empty -> is_empty + - Remove return_empty_if_none by using a closure + - Use BTreeSet to avoid sorting again + - Move is_canon to BlockChain + - typo: pass value by reference + - Use loop and wrap inside blocks to simplify the code + - typo: missed a comment - Pass on storage keys tracing to handle the case when it is not modified ([#8491](https://github.com/paritytech/parity/pull/8491)) - - Pass on storage keys even if it is not modified - - typo: account and storage query - - Fix tests - - Use state query directly because of suicided accounts - - Fix a RefCell borrow issue - - Add tests for unmodified storage trace - - Address grumbles - - typo: remove unwanted empty line - - ensure_cached compiles with the original signature + - Pass on storage keys even if it is not modified + - typo: account and storage query + - Fix tests + - Use state query directly because of suicided accounts + - Fix a RefCell borrow issue + - Add tests for unmodified storage trace + - Address grumbles + - typo: remove unwanted empty line + - ensure_cached compiles with the original signature - Update wasmi and pwasm-utils ([#8493](https://github.com/paritytech/parity/pull/8493)) - - Update wasmi to 0.2 - - Update pwasm-utils to 0.1.5 + - Update wasmi to 0.2 + - Update pwasm-utils to 0.1.5 - Show imported messages for light client ([#8517](https://github.com/paritytech/parity/pull/8517)) - Enable WebAssembly and Byzantium for Ellaism ([#8520](https://github.com/paritytech/parity/pull/8520)) - - Enable WebAssembly and Byzantium for Ellaism - - Fix indentation - - Remove empty lines + - Enable WebAssembly and Byzantium for Ellaism + - Fix indentation + - Remove empty lines - Don't panic in import_block if invalid rlp ([#8522](https://github.com/paritytech/parity/pull/8522)) - - Don't panic in import_block if invalid rlp - - Remove redundant type annotation - - Replace RLP header view usage with safe decoding + - Don't panic in import_block if invalid rlp + - Remove redundant type annotation + - Replace RLP header view usage with safe decoding - Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity/pull/8541)) - - network-devp2p: sort nodes in node table using last contact data - - network-devp2p: rename node contact types in node table json output - - network-devp2p: fix node table tests - - network-devp2p: note node failure when failed to establish connection - - network-devp2p: handle UselessPeer error - - network-devp2p: note failure when marking node as useless + - network-devp2p: sort nodes in node table using last contact data + - network-devp2p: rename node contact types in node table json output + - network-devp2p: fix node table tests + - network-devp2p: note node failure when failed to establish connection + - network-devp2p: handle UselessPeer error + - network-devp2p: note failure when marking node as useless - Betalize 1.11 :) ([#8475](https://github.com/paritytech/parity/pull/8475)) - Betalize 1.11 :) - Update Gitlab scripts diff --git a/docs/CHANGELOG-1.10.md b/docs/CHANGELOG-1.10.md index a8c7ad20a7..1c15e456ea 100644 --- a/docs/CHANGELOG-1.10.md +++ b/docs/CHANGELOG-1.10.md @@ -1,3 +1,41 @@ +## Parity [v1.10.6](https://github.com/paritytech/parity/releases/tag/v1.10.6) (2018-06-05) + +Parity 1.10.6 is a security-relevant release. Please upgrade your nodes as soon as possible. + +If you can not upgrade to 1.10+ yet, please use the following branches and build your own binaries from source: + +- git checkout [old-stable-1.9](https://github.com/paritytech/parity/tree/old-stable-1.9) # `v1.9.8` (EOL) +- git checkout [old-stable-1.8](https://github.com/paritytech/parity/tree/old-stable-1.8) # `v1.8.12` (EOL) +- git checkout [old-stable-1.7](https://github.com/paritytech/parity/tree/old-stable-1.7) # `v1.7.14` (EOL) + +The full list of included changes: + +- Parity-version: bump stable to 1.10.6 ([#8805](https://github.com/paritytech/parity/pull/8805)) + - Parity-version: bump stable to 1.10.6 + - Disallow unsigned transactions in case EIP-86 is disabled ([#8802](https://github.com/paritytech/parity/pull/8802)) +- Update shell32-sys to fix windows build ([#8793](https://github.com/paritytech/parity/pull/8793)) +- Backports ([#8782](https://github.com/paritytech/parity/pull/8782)) + - Fix light sync with initial validator-set contract ([#8528](https://github.com/paritytech/parity/pull/8528)) + - Fix #8468 + - Use U256::max_value() instead + - Fix again + - Also change initial transaction gas + - Don't open Browser post-install on Mac ([#8641](https://github.com/paritytech/parity/pull/8641)) + - Prefix uint fmt with `0x` with alternate flag + - Set the request index to that of the current request ([#8683](https://github.com/paritytech/parity/pull/8683)) + - Set the request index to that of the current request + - Node table sorting according to last contact data ([#8541](https://github.com/paritytech/parity/pull/8541)) + - Network-devp2p: sort nodes in node table using last contact data + - Network-devp2p: rename node contact types in node table json output + - Network-devp2p: fix node table tests + - Network-devp2p: note node failure when failed to establish connection + - Network-devp2p: handle UselessPeer error + - Network-devp2p: note failure when marking node as useless + - Network-devp2p: handle UselessPeer disconnect ([#8686](https://github.com/paritytech/parity/pull/8686)) +- Parity: bump stable version to 1.10.5 ([#8749](https://github.com/paritytech/parity/pull/8749)) + - Parity: bump stable version to 1.10.5 + - Fix failing doc tests running on non-code + ## Parity [v1.10.4](https://github.com/paritytech/parity/releases/tag/v1.10.4) (2018-05-15) Parity 1.10.4 is a bug-fix release to improve performance and stability. @@ -187,61 +225,61 @@ The full list of included changes: - Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136)) - Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035)) - updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059)) - - updater: apply exponential backoff after download failure - - updater: reset backoff on new release + - updater: apply exponential backoff after download failure + - updater: reset backoff on new release - Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067)) - - Enable code size limit on kovan - - Fix formatting. + - Enable code size limit on kovan + - Fix formatting. - Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060)) - - Limit ingress connections - - Optimized handshakes logging + - Limit ingress connections + - Optimized handshakes logging - WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970)) - - update wasmi, parity-wasm, wasm-utils to latest version - - Update to new wasmi & error handling - - also utilize new stack limiter - - fix typo - - replace dependency url - - Cargo.lock update + - update wasmi, parity-wasm, wasm-utils to latest version + - Update to new wasmi & error handling + - also utilize new stack limiter + - fix typo + - replace dependency url + - Cargo.lock update - add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084)) - revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066)) - Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)" - Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))" - - fixed broken logs - - bring back old lock order - - remove migration v13 - - revert CURRENT_VERSION to 12 in migration.rs + - fixed broken logs + - bring back old lock order + - remove migration v13 + - revert CURRENT_VERSION to 12 in migration.rs - more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104)) - Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113)) - - Use `subtle::slices_equal` for constant time comparison. - - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 - - Test specifically for InvalidPassword error. + - Use `subtle::slices_equal` for constant time comparison. + - Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5 + - Test specifically for InvalidPassword error. - fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098)) - network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061)) - - network: init discovery using healthy nodes - - network: fix style grumble - - network: fix typo + - network: init discovery using healthy nodes + - network: fix style grumble + - network: fix typo - Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137)) - - ethcore: postpone Kovan hard fork - - util: update version fork metadata + - ethcore: postpone Kovan hard fork + - util: update version fork metadata - Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105)) - dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160)) - Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135)) - Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053)) - CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968)) - - Fix cache - - Only clean locked cargo cache on windows + - Fix cache + - Only clean locked cargo cache on windows - fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026)) - fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031)) - fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032)) - fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052)) - Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841)) - - Add test chain spec for musicoin byzantium testnet - - Add MCIP-6 Byzyantium transition to Musicoin spec - - Update mcip6_byz.json - - ethcore: update musicoin byzantium block number - - ethcore: update musicoin bootnodes - - Update musicoin.json - - More bootnodes. + - Add test chain spec for musicoin byzantium testnet + - Add MCIP-6 Byzyantium transition to Musicoin spec + - Update mcip6_byz.json + - ethcore: update musicoin byzantium block number + - ethcore: update musicoin bootnodes + - Update musicoin.json + - More bootnodes. - Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022)) - Make 1.10 beta - Fix gitlab builds -- GitLab From 114d4433a93e30c92aa76452dc158e64596dd0e0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 6 Jun 2018 09:02:25 +0100 Subject: [PATCH 218/263] Remove windows tray and installer (#8778) * Remove windows tray and installer * Remove make_exe (installer) target * Change windows $ARC to amd64 for consistency * Fix windows build - revert to winapi 0.2.8 * Remove publishing of windows installer bins --- .gitlab-ci.yml | 2 +- Cargo.lock | 8 +- nsis/installer.nsi | 191 ------------------- nsis/logo.ico | Bin 102596 -> 0 bytes scripts/gitlab-build.sh | 18 -- windows/ptray/ptray.cpp | 360 ------------------------------------ windows/ptray/ptray.ico | Bin 102596 -> 0 bytes windows/ptray/ptray.rc | Bin 4364 -> 0 bytes windows/ptray/ptray.vcxproj | 155 ---------------- windows/ptray/resource.h | Bin 1788 -> 0 bytes windows/ptray/targetver.h | 8 - 11 files changed, 5 insertions(+), 737 deletions(-) delete mode 100644 nsis/installer.nsi delete mode 100644 nsis/logo.ico delete mode 100644 windows/ptray/ptray.cpp delete mode 100644 windows/ptray/ptray.ico delete mode 100644 windows/ptray/ptray.rc delete mode 100644 windows/ptray/ptray.vcxproj delete mode 100644 windows/ptray/resource.h delete mode 100644 windows/ptray/targetver.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c615be99ce..6be6b45838 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -173,7 +173,7 @@ windows: - stable - triggers script: - - sh scripts/gitlab-build.sh x86_64-pc-windows-msvc x86_64-pc-windows-msvc installer "" "" windows + - sh scripts/gitlab-build.sh x86_64-pc-windows-msvc x86_64-pc-windows-msvc amd64 "" "" windows tags: - rust-windows artifacts: diff --git a/Cargo.lock b/Cargo.lock index 680b9606ec..a9d9ab7d10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,7 +22,7 @@ version = "1.2.1" source = "git+https://github.com/paritytech/app-dirs-rs#0b37f9481ce29e9d5174ad185bca695b206368eb" dependencies = [ "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2995,10 +2995,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "shell32-sys" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4032,7 +4032,7 @@ dependencies = [ "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" "checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" -"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d" +"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c" "checksum siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "833011ca526bd88f16778d32c699d325a9ad302fa06381cd66f7be63351d3f6d" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum skeptic 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24ebf8a06f5f8bae61ae5bbc7af7aac4ef6907ae975130faba1199e5fe82256a" diff --git a/nsis/installer.nsi b/nsis/installer.nsi deleted file mode 100644 index c1f4033312..0000000000 --- a/nsis/installer.nsi +++ /dev/null @@ -1,191 +0,0 @@ -!include WinMessages.nsh - -!define WND_CLASS "Parity" -!define WND_TITLE "Parity" -!define WAIT_MS 5000 -!define SYNC_TERM 0x00100001 - -!define APPNAME "Parity" -!define COMPANYNAME "Parity Technologies" -!define DESCRIPTION "Fast, light, robust Ethereum implementation" -!define VERSIONMAJOR 1 -!define VERSIONMINOR 12 -!define VERSIONBUILD 0 -!define ARGS "" -!define FIRST_START_ARGS "--mode=passive ui" - -!addplugindir .\ - -!define HELPURL "https://paritytech.github.io/wiki/" # "Support Information" link -!define UPDATEURL "https://github.com/paritytech/parity/releases" # "Product Updates" link -!define ABOUTURL "https://github.com/paritytech/parity" # "Publisher" link -!define INSTALLSIZE 26120 - -!define termMsg "Installer cannot stop running ${WND_TITLE}.$\nDo you want to terminate process?" -!define stopMsg "Stopping ${WND_TITLE} Application" - - -RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on) - -InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}" - -LicenseData "..\LICENSE" -Name "${COMPANYNAME} ${APPNAME}" -Icon "logo.ico" -outFile "installer.exe" - -!include LogicLib.nsh - -page license -page directory -page instfiles - -!macro VerifyUserIsAdmin -UserInfo::GetAccountType -pop $0 -${If} $0 != "admin" ;Require admin rights on NT4+ - messageBox mb_iconstop "Administrator rights required!" - setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED - quit -${EndIf} -!macroend - -!macro TerminateApp - Push $0 ; window handle - Push $1 - Push $2 ; process handle - DetailPrint "$(stopMsg)" - FindWindow $0 '${WND_CLASS}' '' - IntCmp $0 0 done - System::Call 'user32.dll::GetWindowThreadProcessId(i r0, *i .r1) i .r2' - System::Call 'kernel32.dll::OpenProcess(i ${SYNC_TERM}, i 0, i r1) i .r2' - SendMessage $0 ${WM_CLOSE} 0 0 /TIMEOUT=${TO_MS} - System::Call 'kernel32.dll::WaitForSingleObject(i r2, i ${WAIT_MS}) i .r1' - IntCmp $1 0 close - MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "$(termMsg)" /SD IDYES IDYES terminate IDNO close - System::Call 'kernel32.dll::CloseHandle(i r2) i .r1' - Quit - terminate: - System::Call 'kernel32.dll::TerminateProcess(i r2, i 0) i .r1' - close: - System::Call 'kernel32.dll::CloseHandle(i r2) i .r1' - done: - Pop $2 - Pop $1 - Pop $0 -!macroend - -function .onInit - setShellVarContext all - !insertmacro VerifyUserIsAdmin -functionEnd - -section "install" - # Files for the install directory - to build the installer, these should be in the same directory as the install script (this file) - setOutPath $INSTDIR - - # Close parity if running - !insertmacro TerminateApp - - # Files added here should be removed by the uninstaller (see section "uninstall") - file /oname=parity.exe ..\target\x86_64-pc-windows-msvc\release\parity.exe - file /oname=parity-evm.exe ..\target\x86_64-pc-windows-msvc\release\parity-evm.exe - file /oname=ethstore.exe ..\target\x86_64-pc-windows-msvc\release\ethstore.exe - file /oname=ethkey.exe ..\target\x86_64-pc-windows-msvc\release\ethkey.exe - file /oname=ptray.exe ..\windows\ptray\x64\Release\ptray.exe - - file "logo.ico" - # Add any other files for the install directory (license files, app data, etc) here - - # Uninstaller - See function un.onInit and section "uninstall" for configuration - writeUninstaller "$INSTDIR\uninstall.exe" - - # Start Menu - createDirectory "$SMPROGRAMS\${COMPANYNAME}" - delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" - createShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME} Ethereum.lnk" "$INSTDIR\ptray.exe" "ui" "$INSTDIR\logo.ico" - createShortCut "$DESKTOP\${APPNAME} Ethereum.lnk" "$INSTDIR\ptray.exe" "ui" "$INSTDIR\logo.ico" - - # Firewall remove rules if exists - SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity outgoing peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity web queries (TCP:80)" - SimpleFC::AdvRemoveRule "Parity UDP discovery (UDP:30303)" - - # Firewall exception rules - SimpleFC::AdvAddRule "Parity incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" 30303 "" "" "" - SimpleFC::AdvAddRule "Parity outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" "" 30303 "" "" - SimpleFC::AdvAddRule "Parity UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" "" 30303 "" "" - - # Registry information for add/remove programs - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayName" "${APPNAME} - ${DESCRIPTION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "${COMPANYNAME}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "HelpLink" "$\"${HELPURL}$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLUpdateInfo" "$\"${UPDATEURL}$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR} - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR} - # There is no option for modifying or repairing the install - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1 - # Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${INSTALLSIZE} - - WriteRegStr HKEY_CURRENT_USER "Software\Microsoft\Windows\CurrentVersion\Run" ${APPNAME} "$INSTDIR\ptray.exe ${ARGS}" - DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}" - ExecShell "" "$INSTDIR\ptray.exe" "${FIRST_START_ARGS}" -sectionEnd - -# Uninstaller - -function un.onInit - SetShellVarContext all - - #Verify the uninstaller - last chance to back out - MessageBox MB_OKCANCEL "Permanently remove ${APPNAME}?" IDOK next - Abort - - next: - !insertmacro VerifyUserIsAdmin -functionEnd - -section "uninstall" - !insertmacro TerminateApp - # Remove Start Menu launcher - delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" - delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME} Ethereum.lnk" - delete "$DESKTOP\${APPNAME} Ethereum.lnk" - - # Try to remove the Start Menu folder - this will only happen if it is empty - rmDir "$SMPROGRAMS\${COMPANYNAME}" - - # Remove files - delete $INSTDIR\parity.exe - delete $INSTDIR\parity-evm.exe - delete $INSTDIR\ethstore.exe - delete $INSTDIR\ethkey.exe - delete $INSTDIR\ptray.exe - delete $INSTDIR\logo.ico - - # Always delete uninstaller as the last action - delete $INSTDIR\uninstall.exe - - # Try to remove the install directory - this will only happen if it is empty - rmDir $INSTDIR - - # Firewall exception rules - SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity outgoing peers (TCP:30303)" - SimpleFC::AdvRemoveRule "Parity web queries (TCP:80)" - SimpleFC::AdvRemoveRule "Parity UDP discovery (UDP:30303)" - - # Remove uninstaller information from the registry - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" - DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}" - DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}" -sectionEnd diff --git a/nsis/logo.ico b/nsis/logo.ico deleted file mode 100644 index cda99eef8b3668827befd6a13ff8268c096ceae4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102596 zcmeFYbz79}*ET#ff~0gSARrQgbV?{gh_rNwfOK~ZDj*>sAdQ5iluGviB1lW8lyrA9 z&vANr{qCpk=L5XktAEJmIdh!rSh=r#EnqM-@E7`n24jMiM5Dndz|Wyi9zP<$qrn3| z62KMY)L}48@FOM+7aRN&K+pLK20jdzd!Xr=x-sn$r?q%mwQIvq#&HMFteJFUI{!-w zRcJDmjb;|M&)uy7Me2Zf#*nzz5#Sd4E5zG;ow!_sK zzRB~e!Kvex%~}H+%-p^7o6QNx5F{Hiug6&Gc3B|sQU8~a6Z3ha+hDB6yx3^6*=w>n z)4`2bRx-mzQDgfG(VY+{Uau$eCBK`*0xy0IKCPZygkJP0_lI%bX@&j%dO&)Lj%gCy zf{K^gv-DJe+LQ7G+zlS17Xf`X^Mz{eml?7#;<2LB^;+psM9q+Q4=X>eC%$LJ>AH=1 zFy>n{7Z6<gNW+kQ|PNkKXvu4|hU z&d2K2MFmnO8^ug!3^-pJt(4x*2+f{4yY5NhS$isQE%CbsWaE(WeDhr72DJ zI7P(w-wlcOFoC<$c-Eh;Pi2I%z_ETnpVEoPa=$&evyE;myOiw@AJ@ec#}R*M!L)<9 zW7jVill>CPBXL7v7kT3-fh3Ky@Rzq^@HB2D>0>jn@soL?Co%xZ3RIkd^m^*k9rw?h zZ2ax;%JGvG6!Y55dr3U2PYZ=EbF!84Ly(t99>-x)yGPiaMY|1C>U6;&cEg0+mEm&b|* z{-=D!8K_IHCdnu!4lqy$UTXP!-1@PEQ*GMhJi@KuzZ(YxpZyTc~;Qm z!R*}_%_orhw~8=QVRQrs*TL&1YD*D?ft-jR;Nt2JplDLc!yQXdUT6}NoaBMmR8n~o zQxQxN+=nh^mjD!_Xu-;-f`Vmufb-%g(%*TBo80H+f^Ojg9qulO@fd>;BmNpVe85`L zQGyrGQviC(51tP6+2CA|2-A;2pC1VD!L7!vPUv1hkI80)Oy+MOG^@b(7UliN3KMna zg6QAT%ODGkKv8#TY=fSM-i|&EuEp})^7f7gFnAPnM{P)Hm+iNaBFIeX5Tq^(T*;Dz zmr$6<^N(QU;MJrXn5p<11ai>P&Yaj=Xu)Wzn7y~)4@6+maoQxGDU-ejEJNSqdUh-6 z0n(H26&hTT8~}xZTntCtBrTK*^wywVQQp*UX7q4$@K%Zin6$c{>n)f3nQ^2Zbg*7X z)Q?mWM^;`baKBD5@NK+lK64sWv-CD}bn&32IRgRJt5+~MRyP_VTV|MAII{aw)7vIc zC474Wu+jFRb5ntb74*AeN3so`lu`(XvlQ4R%Pd78ehTA8{|TTwWNCpnI#Sn~6oC!0 zTXwKe)R^4_K;iMpz(96}kNDmOT>I?&=iveC6Cwk`yO6C(p>vC^ap(v&(VK9S<$(DZ z(a4d9(i)H{1%R{@$+%;T`B;LGBgQ>;fIUY_!K9Rx{@Bi1$sJ=2VJD08j^&ysAv-n$ z9=%*lyj)#B8q14own|H_!>`6Jlw$Ov>^ka&Brt6$f#8>Sgl3Er0(&+)%Cv+pU@^f8fk=L@+utMrWpQcRx^Wa zg#jD~S9*3k3B!ixdm#pE1u1a!3W|VRWm`@5D@-vgi~Z(&QCL%+bdRh zX97V-{iu=bQiDzmDJaAop}4|$o;QTEP6NRAE!rah)R6niWc)O~0H zXppaQ90LjP1_S@`i|h?sjC$#%eiJy>cQl0N)7of}m2JTc9}wjrmFUHHk3Z1CFa+r= zP8NDsq)K24LPZ9$71jdRtjQl+aY+clvRfR*lPr%Qr%~s&!xfiZDhtjQ>?ME|*sY@* zJX~610F9DwEg==Gn*iLFj}Vq!X@db-f(EjL;@eSB!5IjmhrXZSB8CJHF+Q{{83VD4 zRDOt)_VWOBkAsXiqQ9w%v`{2S8!4e2Ku|ioaj8TO3<(9M8jEf44*w?4q$X)jgs8M9gV7cmz9;(4{FXD z#cZh>Sq~w7wm=z<20Ji+@e{gs8w^!5;7!d9ye~-4w<;)?3248&^htKPjT+F3#tbE2 zQYVgG=sr~ET);-Wbi|l#Z*#g3o3+Szv;vZ>MVUp9*-3xql=EN@>Ts}@+px|NB}?>W z?NcGPGFyfBV4!RkyEnUQ^hgJTawc%bid#-}>1b0?z!|aJjtxD&Jerwt+OJNz>ccs# zaamH=G9qD58nQTmZP{GeG8epe#E^bajkYs0FT8a<0_`jWsNluX&k#m6BfXYyY`3pA z(i=9yer_~|;G`=l%|4tRV-H&jA{@{gd&NP91H)@ULk4_vs>gO@`>X}Ys~t|kH6PaX z$Yr&SvdnR=h4quJ*L$sMR3^^qNU{EhK{(bNmI;bIO!68~(r2I~;80j(?Yo4?GGG{W z-ag6w>pt73j~*I0Hj@gWV8;HtSj^njOi@3wUw$RuvE8?1ga?8YiXOUf!h^&#dEc+g z!tvIkH?euPtZ$A7hq1*cmd()@=b5X3PFcPJlVWt`Hw$Br7;>b2F{K}5pOPSi zBbhU>*|7)Cd1PY1Nr__iO=-ck-r$&bZhi?RhE%TKsp*`4tC3akbjr#U%(h8mJfV?S zyOToV!y7aY1BbZ5`hCY{Dv%E{0SuyPKwX{3ktghQ52~_#nz1{cF32z0!;|I^vd1A* zU6?~0ncxAy@ls&{#uT}r1>minEGXOMx}QzZ5)8dLKJwJ1%7;@tH*5lCRX5UFEkLPn zN#Ji#%KxOyd{xf!?@R4q#O=GckrGHf=&cjtB2Kp!b8>u7nnQF)Dags4zNtOBw-Uj> zGEkwk)e1*Hp&H{1%NmuzdBO3o0E3VK(}DVdi;w{KlO+8_4+Scw+?LZq*Mw%wT&&mE z$30_JoKuwth!U|bM8dLgz}K(+`}Hp9>&$`oq(dOJbIl7cjifl3K9$7)UfNmPXfs-p z>eefAAa%hzQL*2`Qh>#U9vPmslHC7buLrniIT5||9Ze^?glLgXDf&S|xHZ-@bMGP#=$uy0NVmR(Ynv^mWq}gLDRI`sCag49MWp`H+$Gul$0y22~jQp zv+QqV=)nn7SX4M0v`{FwH8J``><#cqUjB|PvI(D{+#P)uwKz1Wn&-0I>!rZB%M7hH;6Ds>8}>q%h9BvtZo4gC+C+kh5@VNZyI?!(?Jc+&E5T7RHog?k;1=sT$K zdE)Xk9jIrW`5jFs#O(2TA8jN73HCs@lmhDm0^t8EKpZ51U!YjvbI1#11Rb^v9!66A z7%MEvD&RQhZyqtQ;re7_Gk!WMwtO=!n}Uz_M1xG8D2VWD`9?EY7zPYW4Hp9h(J_WS zw&ML`_9d-J(6Bz_jjzw+&47Wjj?+~t1J~H3kc?q?0RIP9WhYGBm`lgPYpRSNj3SH z5Tw5Q=>bFP%_aaVA0-jg0OW+WEf+dc^CO zGbv>cvj`&Gll@nZdN@Fj9&BZzm3GiA*th5dhy=8>lv4z`)+ZjPi8^(@$a9{$#@65H zcMg()Ch`N8KcoE5?*0c?3I7W5CnJ+1Z~}|}gu>2`c18^&z3&UCE03%*W7Lw6=CEej zlAg_?a8fo|66OYj{LhH~2aSDy(?&s6zGHvR&YY83=W{A@c`ZR(uxZMu~dP&2CCEUn0Y6wp`CMC>q+!7M*N1GVVE5CHP{gzE24c#|w$9qqhK7fB z4o8hG4JT_{EFUx8fAcX)Bsl9x9;87yYSGK2s=o^3Z{5Fj@W*@*s5zoJSm&`##}=ENesDi&60PwXIr8tNZ~igdO_$-B-ewsEb=peD zIhlvX?jlev#HZx$uJvEk(#|Z(N|oBEv1Ay450HAj>?Ss`f73Me_k>JrSWgd10_pGy zGdf#vD=9BMw>~@W_?HjQ`h@%Dgwq&Fh|70f%b&&iRlxGuMdElH(Dp==60{k29uD=h#qUr+M9eMCZjKFVC>YR-ko8`8j}0 zeq3rWF8W``bB63r;z;{BAp9~XMicfcMLcO>p7evy(YV~9&&AbooR0R_&QFEEg_Bqo zr_!XG*u!Y_=XoGpxhaDay~hEPP&IZ+09?-upW?2`H!RA}#~%Wehb~HM*FHrs@CP@& zZJb(?3KWj4xvZR|a-7-~yr$kY&PX+RF|Ky!>830=!@)F zA3+Ta3lm;Td`2Z~#gta(`a`z11?Y8K%}BkIUsZ|#SxxKko9EJxHdap|z~r{0;tG>` zBf#A+twJBc=7mepJNK_B;p%87YlWp&`Naz*V%xwWPAO6}fGa+vbx2(>U;S*-jLuzm zpbps_;KegkQ`5%Ru07=I5ZxC!@6mH()$?wLW!3u!m;cRIjgZ5n6Gn8e8{dLsF-1PJ zXYjbu8bY|3;?Ve`wo$*zKGknagl?iqYIEY$+>})HajJsX3l2vAojIbb{f47oDdF5T z)z4+&G-UE>za*6={sFJI(jiBPf_+DqY-NQ@&81b%WR_PaQr=bp(X(t6kX@AZ(x}0E zQCL@0IbAaCEO~-;qPBW1`OAexf}tMM`)rGQj;>_#qrVqZCSP$7gNVFk{HHErZNcho z6l46q)qCw%n-8&<(D4WVfhRh~&j>(ewN8|Px9{4kkxASTjVLdl0^p=(3IZpFvv4GH4C`tDD2s`-rA;69 zL(>h|jO}X{g)MhX2qh1qDQcQ?h%e8-w6pVYxva}rPv)YDJyg3dLOIj@H`Hs+ zh^gCm70r`TZZ3NStObbr)9 zsdgE!Zzpf(CqZjl{Qv~Aq7`4#O=Nk_<-@;G+|dT5FmBL9)a6`R0H%4VH>pdW`4QjI zr$Q_1PXB4&V&futH#>T<&3X-n0rJMSa7zBIU|L~^v7MZW+LQg8I6f6wLucX`2XC{i zwg!A}{Ke^aH=%=X@#S4^r^EsZn~A}H=jNTRt|Y$aiX#>DqOP;AZ{Rr2|6m&|(8v?d z=Ja)FJiVPG8|HPIlR!GWUAEmA7nks}%(4$8&p25R3>-PNxXafSNq-%|nHNw!j%M}) z3hI+W&pXMi?-Y8@UY*|$J`1A-wRL`O>_5Sc@t~kfzLWW1=-}fBAcQ_Zl;lKrj8lSf z5qF2<(8%kQyi-xp^Ri-;bePd`Ht;$JhiMSGPKVQ1*Auf&N=+T@+rMhZEGF#=ic28} zs56`0VGpzKsO@J^294emVmO4BjX886OBR04{Bs89l21q44ppiKO4H>sWE%aeopV+Au9?mMw*+ngQkJ&2P0%F0QkPe5Q5~og$rO*;;3}Y zkfMNqpwsXSsyF`~bCQsQ(a52M_d!N=dEDhyc>u#ePV43I^dqB1&+@+DOu#o+Hnh+;5fmMSRzv{YEy*jekI^gMnpZcue$ zY$5WapO57Qy#8Q59O}iFQXFo7+VoihxZ~jYVW^PHWYSf7fYiFx#)% zrydQ5`8N3;>oNl#OXz+d*}a!St}_1ysJ|_!?YnEpePkyWjY16i3tL_+l`AWoHXDP@uu~SY%T(Qfv;hiks!Klqb+w zUhQBNb%pUazg+bHlen4!i}l5U%sW$MeQMh3Ex$cxdTIs3Ze2N#nSwri{BGUGS1$#f z6Uoz)XPru2o)XNuf56p6(YlV_3s%L>t}&l< zzrES(n$!?I9k5jNoDDJ_jcpb=`2Z0B^cj9#u1Hx`sX0g~jnu@p4&G4kn`S7R>{|lR0CTmxwk_K@IoY!U4xs`D$-)61&{WX`I+QD>YfGS!_NG~(|bmu@r zRZZKV1&7f$+Rd)ceN%WopPAZqDamznLV#!$Zw5S&mVZGFAWUMu|7fFMK~X`j$M!GK zMRBwlVO6rZsALSy10o|1x0-r|67Z&r6QjlfDzb+3sOrl|xkG?ksVffMY-`6YL>|Wz z0z7Sg@I1j~JSX8cNHlt`i~b$mPB{KE4c%+s}C zV3UickCFbGFzdh(mJvTh;z>4k(~%I~8Op{GkP6X2|AD|~rR|Vkx^4}yLS_N9qK2M9 z3m|S&^8KS`P#^X>6@i>V2V^_?Oy?L%*_d>&d{#ruR0`48EL_EWWH*?C07(!~mORc_-^29UMt+UhZ$ z>+|`~B28zRASH?h+;$N|#OVMPk_y5;V8jF3JtoHcyts;ki+ib!(nvwGY4n$m2Ix=~ zIlV9yNsavu$st0}Z`2ToJ!Xb)O}jR3weS|uaWT&Gv?ltqoBaM2A~q3#Sj%@5fjwz7#HV8bx?|m4VUBvDruW@4-7ntFPVM|wq}UZElo8`~Et3Ag zrKUr{=d7&tye|ORCAHN+3Eb&mZI}}@xf~897?HU2GC^Hvh`m+J*}eXoEFAh8O&2k1 zpYCkc9UF(P1yuBu<`)z`Yd9S319>b_$blgtf~M{Lv+qzL_IoRkUs5~=5`PTnw&Oh5 zU^=e}Gh4tK!|7M*o$LJ~UEb*&h}|e{b=G0E#_aiS&ak;ngQo*`x>75ACYz0uJCr~D%@0PK8 z%Kn*6shXZacVTILG61$xo2pJPI6z&8(ru!s+a17dT&#ca0YIog6r@&XBGjMci=pLLrY{gNFv5H%BAsl{7St)|Z-A_VFP?&nYj>nUNc-ak930 zwthcR!pHp|(Sbp@aTvYd=u=*k*gd&1#qTeEC`)_c!Ct}rF%T_NHvcn3-C`{>fzeI{ z36bOuOpBb{_ugW7k&T$^3K9|f*c=IG`}rR@yNk^#8@$umRm$>d#sPK7!R@kstKfeM z37Bo&X63~y5(7Oi=0JiCMub)sM3~hwhmCN4!8I#y5(K6prSR&k3N++2#<& z+;hCfw@Sqw*G-gWKLUMI0e$O)Ap$VOp!us*Zo!vOo9{+F9VE<&Vr=K_cXXaQVFky< z?c`w)I%D+V9RZfa=vkM`l7Y4*!s^{Jhdqb9kBYg*u6S~8B>UUnDE|9MX z&BjibD;)2@r54~Olo|J2i7WgFVR4)l((n~xu#y9TVa4!puZ6?W8^er4rHrq_Lrw;N zz6OWOxXH5uy-H`DZC1{F0QGr9*JGNFO)12-M7!R9>aA^4Dt~o8Y_{26R#=H%fo+YNVgHg1PFDFyH7$f^Is7ErJO$Hw9eDOo2+eg z0FOiW_^*JglnZE7O_!W35P5PdVj?SR%lP)i3WjpFXSbbm!q1fwL*tg_D10vhKAYUE?1Gqz>EW%HwB zM&JN1tL!3xalQSBD3lF}&fdN+Ah>(XS!zDi@$MhO4m6Ta)Q!G3o^K|ExUM?RG@!C- zKZO+-`zQUw&92622>T}CIhp(D__kQ$w`6%3yMlq>A8!fQ_>6v?vvV%_1hWX0j3 zEyxcL@Pp#~Br6=GxPKdjqPWYW87ZRGfw@c^#_Uh^ErsMcu3mU20!giCIjl?6FvWRW zD8|t}X51*1blGWpn@z^6i{3q{k=dJPCK^ zl;O?37e61xCB*N2TTlhrVzH_z=Tl|yu#T}r`;UP+!0*gmn6^@TEW8C_ZoRfPcBa$R z2@E|tH1@4xG~)TUAWH9wtT=o8K)b*MSsb-Vuog7FqL6z!BMvh4YPr?VTP4-L_Y;hK z@BLvG8+A&J;{!beNY{h)Jqs$P%eymv@88}5io)81us6s7f2NMK@+6l;QmJLVA}N0m zk>Old+lc&gH}ZcQ2oR+;An{hu)vh<_sSO<4JznBJiv|`ItVYXVt-#n3PQrk(7PJBA z@(LiBDfjhaFqivfegkT7&BD2$&JlnfYJTtg2@$o4SojnG3k)c7s%fh=Gamoqgbe%t z4$Bz5z}tK{=#u23Z}g;aV0xr!9R{aW5U3ttj(oONzrZ*&I?T7QPOUrYu{99%!1DTh z$H&Or{D!hF7UwT+PD|sKUpBt}qDuJ&h3Io#5ikN*03quBD|Ah-R69<6p36kZ#D9g! zdKyexl(L|3=32Qtp2;h!er@@|UsUbVzHa-myc>C8Nv$>1RCOouQ;+b*0WwTP?eZb5 zo!n+WHi&|=E$cP_D)<8YkJ1-?4ptt(y}&r4${5hW);WSK`$-MLASZzZk(Fgz0`a%4 zx8PhRb1gvzS5-|;<2eD(erCz*j+O$Dsi~>;<($FiH^7GH_Ul=I=KW9K!Ry#B9VvQ7 z1zzWEI=}*W3R1&jDtVFs$=@d6E(3)mV+@I4Nkoqa2L{$q0+$1Oz}AE2$%j;}t~mkeJ1)GCywKX_so&u+ zK!fVERk&l=o&XM2ND{&hWG7<1wq_(`;9mE@-~s}dr^_EyHBliF$JzB?Um9_iLcA|D zT+lGquhZ101XPG^ZIY51{H|X48%}P664c>=Y<@HmA|?APim9|ci;wo6kvy2kLd~)Wzz=r z$bf&?S-@c|nyqJn@x*%_T~=UI)1?UNq(X9s8dk`G9hB{48z3`$M+bg5ekvPj; zUy<=z;Y(Lhk5zzpgSMei1*4R_bniR=gsPWT4!Dh;UO-#liS-gpdPX<2+xtlr@TUqt zhlWE6)>k1rdrCa4pJps){5UvxK3evDfDjtgN`MM-vAnFVNUc zN*zw^f8#POn=F~o7E>84K+S<>w9!QptTDw8K>VfKPk95k#hDk@ombIK0wV^o$+dd! zSBIthzy@4^R!;f;b^!zvse@sv8{q%X5}K;r-u1`cU{g2J>jcOx5%dpgB+wuRqffjQ zIMt#$5nuXY6mY7!8Z@R3amoYUBz~~}`tBN$YR1>1h(0Nl`1-`r=A_F70xi|G^T*w? zZa%1#f=XuxLATu?NoCyTo^O=>*>G^0+GTSDv(Z|&cTc!WwC|P{ zWsG)mE`veSWyWFPO=`;W^_DTbPoP zu2UO1l!tQtPg#fGYuOuO@&#P^a#OqA(=l?A&nhH`RxzHd2-F=N0=c>D(ExZU21*IW zKpcdD-EBjVN{8Hm#32w_Tk)*a6zoChjvlWLh9m>rI%6907qzP#?zL;SA z0Zf%MXPN`tK{%%x6bm~trHOg;0@76PR@6HYjP8fLL3FU}QDX$HOi1*QySO9j5^&6W zZE-wbOE&v6G1xx%l43j-4UME1gXjWKpxdHjNWBksS`t`tRZX$c%hFsA4GcNJG= z*Lr>UU045S61yUPU@{dl^g=<)zskf;pw@2y73c3{jNx{%{WjWqCqC@WANn;q4UlMp=GTii6Mw-5ki<1 zzjza|s`(OdG3h@6z8NblHT(VMU3ZF@(E1sUk?o)N4qI^#6=TZca$|#cB?G63r0I_&NnsNIyjA?9NJoaTm~LuImo*|7BnwPx#*h zxtv!(X2nn}qy@4LfVo9saO5u12oM$4X^odh`rN|XzV_8yqA~SSMP*yHV1{4TQ#lEh zUmI)N`Q$G;{PQg&khjduUDJ$zzx%&V6&{O>LmDSPhWUgLX2yf@yy4L;epqxiYT?)J zF^HeG@)v`^l0yYIz^Lm^dzvHq=H$7nE@^4~1zt{DTmA0YdgvMvaQ)^s*_Fl?yg#W3 zERhLl4MSP-?Ge@$wdiX-$P1rhdlEcl12D0;i;Xcr`MDR?fAt%~6%|D_BYHIi@uXl7 zvve`HT;oQfprLUCgaSR~hX8-z;9$JnTO*6@(w`2%oO;S3+UI*vWG<#l<-()NzMLi; zNW6Xf)1{3`V<}b`zK)@8ZLEBSt@8foQ zC%4TF0SE<-#coL?nXnkI&kb=`|8!GH`jmnH*Kh-jzWbO{J2WU~T0*BqV+5{v;SAmo zY`V{LEm6RR0vfe0ISGLrZ_-MTZ(}w44}H4YKQ`8(rE`@AfEq;Y{QQW+y7+vfZpI(F z91z|KVgg2z^OL0)>Vag;>-pDhHP6QjiYp&$`eaigDJ?DrMi<*{s$B?2pVrtS1# zev$)PSIFL|I=3&UOZqz@Qd`ub@!2SMUhq2wcYtN0qF`i|Z@N)|RnWGrFr(iI2_TZd z9-Ud%nc?|S&ez=JUkyIXAg6<&Y&cXkbDb7Q>G!Ixu-7%fQkS;ALmDWOrGPW|qGQ|! zID-bgd(n*G>cfSUM9Q9t0QO@k-(JNL$G0UKW1(Qjfdv&yIr@R_zvXGQd~mfi9G zXdY2b?Oc=vha6aIG9gd4zy*~#(PGh5!(!BLfp(?((w$~)ElK3rL%>$ox|{YVSvr4v z_efpyH_k2#Sf$VftA(Bpd%ufpKC)+_=0aQm_^Sg5AurumMqalD-0+ zei#6A+GGLRI{qtLR!`*7rezqnO=t+wTbQpsr6Rio*%%FNE(@$aH~~ z{2zcPubP6fi?3spqHS?2V%ayp#4>PS&53B-a0dE{bG!UhSfcpcO`vJg53I3p`a03= zM~Q7gn<~`CY?HNMLxcDcgIoD}-!*7!2(&NtdiRK{xU*l5;@aZX(~G`wZU?bdLodt( zV(V03H#Af;?)}~z4x@#kzNRKn6k`wa!K;7PMRSnn+fAyvPN7hi0L~BCT4%5}OgilF zc@BF>;J)XHflSRn>iDhvmTkU>_T)fvdC!!4)EtVpMRDp!hk^8U?pek@KNWT zJ0Q??psp1x*A~tY+@bSk#8?ONCf}LDwW`9+)d}A18 z+9$#BFG2))@x&Wjc6}Y%DIy&P{K$arT5-5h1AA!^7%JTnzeJd$OtlMvy*4=k@)iH7 zbO#0^JEyWX8AN+*zJFnHRc>xcB!S=*6Vy5V*ZS_?y^?}Y#ZCa(feSAjO}@x4v|NfX z*Wn}--B*qj-ctw*GZ0d3DaHrjg}}sx>0C&mf(C3d^{b14NG<5m|I_YN2kr+GSRQSR z>yCoeH|JD-PhN1Q);B4uJOiK)p}>XSQ&Hd53%Z=BBqlz%apz#u*e0z(+GV3Mxk^+`5T4LhM`>B%a{4Cx<{w4bb4L- z8kXgj+KVv6W{%U3KlH8pepvo+BW=dt!oR%MBrYW-ylr<^;c5NrRcrZxfB-7x+pe2O znHUoyQa`jQTOaj5y24cpW`PmFes>za{+x*=y-I=ZeZrPK)Y;o9V_-|CUGfwyMdc#7 zM0<0BSO4xx|Cd+b%S}x>lx5E>=D;pY);{?iO=QFl?{ymSM9IDOm7UDi{$08ld$!Qt zPnvfkPS!Y;2?%lu$*HI7y>5s`<_%-rl#7^P_r*?P^B`#nrhw%nP$J}D2SFS%ikZg8 zTd&kg+b_?Lt8QdtaH2HTI;B~SWs3aZ^j-p(} z+*CQaxh>WdpWW~$hr?7-1cF%kNZz16j9xTr2W=2SW zjAB{{5kreP?`(pEPvTzjWO<-TMTY&8=x;r7H^n&d_vhz#Hic{p!;>qln{7$@zi6=G zl)L!5*U{6CIv|Tyta1yV^&MN2AE7;aYWzeyupft{zCX4dJky~|PVEpc&i!D63#y}Xv` zwZg_tJRR7$Gv&?se)J4i8vH-TtaiK-2j8LOF)-;oUY}vKj+AAcQ6v@82nP3;;Z6GN zGs>OoyDnI4TKSY%v-HEC`-{=;?o*nKf6Y+_3{}1w26kC!iMF|U)#UDF@Y^?`VP<-U zo<2U$9zLZi=El8=(ib2rftf9G%Y1{pXaQ^XHtcMk@FuIl!-v>r%iYb%T7_y)o-m0T zSJ@jQOgW6*?>mCw>Ke!H(Z(-=*ycBnh#13qy*)imre0se zWuQbSA|it9McJDk62IVhHRY9iVR?D}pvP(F@bGzTDPidqBeeSKm1vcK z0a6-`ej$Xscovx0*osri)O`H>Bx06?+NB0<<+ZriufHC*&K$=2*i@>WN>2YOBI5eb zQ#|rJOm}agW8e^F4P!Cu84}AFm7T+0N^>IAUxAS5qUvvzy2%>DH52ThQ-rJ^dunbO zj^ghh9i>dw4wpnEQ(lasqL}mxPUx)d|Yi#$ZBR_JE*JruS-q3}az`RIrh&Fn$4XAKM|(TFW^aYH?;-g6hd?BlZ? zP`*t>lnFlR5XCES>Q!1V0@v6!E)1_0Hn)5p+IxO>Ce!1zGP%v~y<>W?{>zVd?GSin zZC%|nTLs?ls@a9)x`vIe*Xn~?$D6LqI*-?;X;U970rM$1VP!aCeSWfa>-R9QpJ;XF z&NNC7vLD&R7eBGPxA_^Q{O^jcudapy2Qxhw`{L;G(d8)xps%nPGruo(B_!=(U=zw! zCu>s{F-Usi#x^62k2Xv@tLz7{Uk<;leeeLN1RFA-Vul!O4ZS0w4)@gZK&WqEPU(*g zTc*W4G8QU?PudxkPakhL;KZ6d?9n?genG)wRFB+9)IG7^)LR-30{Q|0NDuTiZYx-1 zRDt)!Wr>MX<6^BPPn}iHYG?&@x(rf!dB995?~1E(A-<51Pz1rX=GX8)abH4#m#(Yb zW%&AnAEY;5ZWv%q?|P8P#NCyWV(cO%C2lgg>FoTiXXY zm-el4VL0FOPLuiHaH<=0;OvJWW^nRGX6J+Ol~4UI&t-d@@_*~Y=Pf#+m{8zwBtcHX zR?x~YKVl$aN+}U`&IwF%KOU!vUwd5K{C0g*-qO&(U}rJKz=ksVp6CJgXTvSh-%XGZ+r%($coZ>pc3vK{C?8&mpuKsg zko6F*MIlztjMpO|d31Vu)M8h>>0JFOxb7XTPl(a={xTgNoN|p|i8_x~bKd!%vXzD8 z?J9|gS*M$>6}SGxrD7&?hGhcjTSAy(B_X>wjOlf~g?_*UdiXe4biMymmxqT(`5Hl+ z&c}xj7IU4Y#g;wRe#3WY2uDi|Z=|_7IW^DnG<^g0Q8WKZGumdVv9mMZbv=5*jhVhU zhnY+a<(CN2KsT1n95QNZ>NjcpI5yhF7J7#Dr%Nfkx|on({oZ3hyaM_~Q8(b~ehum} zL=fk|m6cydE;t=@kmUM;-&D&GN+Kqfu5$nCd9*=omX-C{=@L8F_f;@~NoYhi$UFgH zpg|kHv0?ku%h=f1QIG4)cVrZ8GcHh@@-;CVF`+1o{R@Z=XMu-v?WmO?2^phT_4R-i zHhKxrLq}KFjkJJ|dIBrgy?rl!un}72U56A<$iyTdpyfK!)rB9M_qZ*;v?&)#a=oc& zdD;tW?+cYr17G2oT6hXW=|@C_`e7R3dBAgh!*ZJ$hTGu?BvLvwg+%6!l{>8G$;n+= zMJnL82BuJ1HVT)DVh95FTOZ;2sjH)-bDdEHT_aCLw#Io8N+_(;k6(g>{(HwX_X5YT z7HI-rTu8}dWa9369jt*zo?6Q*Ws`I1S3u@?1SRns&JX6wx_LpKLxoeoST(p{LJx56 zzZM=EEYEvW{&Z(ysYm(ryGk;W^o4wE)l57n4!;){O;=+u@9I@Yd%0x}ukQTFo2Ku7 zOzmzvL)dK963eD4XDJ~eanEUwC4xaL9=PklXcB+FwXi{>ZxRQpEh7*&{7nWZ{@E;@ zI8P{%^x)+Ij{?jRlw+k)RX4wxZn%s2kCk8h`A$tC;7rr?*W@H^=3w5lu{U#13aspV z=TE*o1E)>Zduh0i3=fmbh7h%uQ}bJa48N5o*1xMqcdzjA{>lK{$qeZdazj=rZ zNf6X`pC44>D|#-N;s9{sp4}a=kJ3J}31l3d{INf6dVRC}h?&4FJt;Vo+^z~7ul^QjO zUcY^#)^}_e#6$YDeS1`j5c7c9b3MbjL+ZL)Jlmi=L_xlbwFm6l1Jy576tHVJC!!Gc5&)|={35<9yybKuVsJP>5byDr zAH8iE>Mz*2qdx*(I@3cdl(FbZC*>Z&F|+wGDubV9c6*!0iT}BRs_G+Gb234@sg5{@ zp?s3p3Y^IT4&30$iH{q}pB(Bew_K=QjQ2QCzR#$Eu0N7khHeWRfeph0@5TFxo?*U< z1wfY^pXvwkz&7*mM|P8mdp*fQA;d4_KR$d50kxW%nx}M(QLo#ScJ>yPetP|{z`Slc z(oVm!#Y~Wyi%Z4z7YHv68QI<8d^M1fK5DS3zSJ08li@zznr`i-mjd+`Rl;L1WRTRiTUi}0apgDjRrN&iPQ|i&9cGB;o)I4g0vaX z-)Am}uuNMR8!9J>l0R<%0OHoYdnBTf?LV0xCGHtYZs0ZiRM6q%Qv`}p)+B43K~~mU zjeWieDW+*Z63X6Cfl1(MZSmTF7aRL3!~3uw{O(JQ4M~={#seS>b_4no=X$JJbiC~z zme;(s-ivpDRV^QsklYPhLh|bO4agUZrR*|?gCZWMi((mlY_2FAy*iXC1nzaTF{xDQ zL~^V2HjKN|@MS-mH2fP+uMzFqH)@k5m(~gWO@W4-@eKHCk=rRZJnH)gfh9A*{y?mibsTu7M&ie6IkA{ zq2MdvSG|IP!fg$j=A^E+o6gQ`9QCdQs&2i$AnJleysyK|1jQ-~4I~`?5AIXoL2wc;&n9YCap9VO!YT+ zma8l53EvK^8&s6+ayT3wIBxZ=B;A8=QNP^w8c3UmYoiGu{V9B@jQBALr?kjyCA7w6hPSv_8{mE3V53fI3Iap=aDM^KT#q3FV zzq7$R9ZClwKU%4agBzF2X~d^iXt>S^Peesw(do1ZeV8@qjiLv#GBRN6BSmc+iBx~O zA)TV9B&H-JCuaT9)z$r$LQgMt&$mJ9o2v8Can)YTZCSbZjMr(;93+ccr%Tatx~LoN zQT&TiXD82Au48NNm)-_}>zRB+_KpI-nA?00MB81%7{mz{zFaA{XBr{%BftMa*muWc z-M;-__TCwhEqj&<*}D=+nVFSPLRpE(4v|u+Y$b(|k?fJo%xu}Rl98S9JI+hp_xuviT?G81? z%GE^8wZ9XSG-i7!WPn-&JR9nC{m%}7g&5#22b*V6pLi^+bgOi&OyO*%87pDVlhWX( zNx-kQ{LdA<1ZC!CXYamhe`&cEOtT~;nLJt(u9PFJuie@f2=kOHci+RV`Hw)d^ z$z@pCWZgMrX1;$92Z+RU#1gkYN?;U$^?$OCmk#EsHz?1(J`)KKOZLVhJ}{5IclPJ& zk6a$u_b63U@=Et90A%y4(^f{xxMroE0y5?$9xh0nSkFpB;sn${_9G7J&#UWm3;AbE z8Bk+fo2P*a$hqH-HNXJZ?0!-3=~f}kB9`Hfm3hn$;e^S^t;~LDi1L1CZxStxJKdQf z1h2pLFCn8Mw-5m5;YJ2B8D~I6p}xMjSNgMXa*~ps05jVyj4ePhDcNPnMQU27m3iO6 z4bra~?vD39Fs|^elfvTx&Gz;-?GbMOJ$__9)R+h3qDg0RG4~>fNEQ5*6zoAzz(5HhH^EGcz;LsG9) zqd9J9S>{ZJ@mcg>#_H${KjG%vf2ogh=q#4TPb0WH;Bf+B*uMoGTbJRvIjWMnV5%aQ z>xxH}gYnyR*W@q@-gVs7>SUO8attu6MemrSHz|wN{Z257!LPtBjv2N)B)G1BAH5jQ zd1_uioU(5{RZ$LKQYheGaq;s-{i&y?$57mXt<Q&ZLf-7I%1_%u18tK8292;-gLyD; zKRQAHUHXDpWad?99I58&dYGXJ%P!#55Q0AR?C`CK$y!a>n=4vaV0W;xQv5>qDS-2* zHzbM5R{|_6!_08*X$1EZ5DSppfAGMvW!lkV=T?g6PfAvce8W>k+V;@+{Pv`gJy0tz zvhS0D-Xz4&UtW0Vvcyqd!Y5Cjfbb@yuUcSy7YDBlU}o|l(w#}y+&N^$Sv_6JL!3%ysL^J2Jo4d_fbRF#vpvR-gFZKd-+B8O zbxSE8G^&xgj_MeroO_XxoHFLwR%-rgszaelct|w)55Wmg?ZhdXfM)f}&^dX~C%J{E zC`L+KePer5+FDKReAULX#rlNy7U43dVFvtWFHrR|DWw>EV|e>Uc6M!36GQCk@-o58 zj-=*GUWh-eY%h{&dEmhjsu)#94-XDd>-dSs<*z!RiPw$RL~t^lT)R<2nX-9Q#8@%Q zxHZ8N4>6?+D@2n$lX*#aK3zh@<%cj!IXJpevwis$RtHAw9`Nm=ajA<3KrF*Ma)enV zdu^t1ucMtywm##*s;c49QEt=>|E!Z442WtX?jWGgsGj3P$qJ7H+lRX{s?sN!QaaQE zNa?rp3KJqWX-1;HVVINV_ueTcTzWUvHFFsnrS3hz*ewgP&}^WQlwH5X^ojR#s*xV5 zVii;bjD% zOJ||}C4mD$&)>3EH7PuajNUv;T72hkpIdQe;Ul!*VGiL0?+_8v+}*Zb-EhW(ic28n zw26;ci$gy(mbKiotP%%AS^rQ7>78@`$=w1$7iE8^oO?`-jM)D%yZc%ar8Ma!*7gvlf*!JYS5 zOK|KR5rCTV-1=Q#_IORaMIJHWF<`rCSB(6%$*O}R&9SnH%7okE2aruDuAVCsm6;hC z@f8aquK?L3O3Zu!F*c}c7A@2BfR?q^DOrz}^Zc%nDxfcaZHl`K=szn%bh5yRZ6+c|l)U~CUV;p?$|pQYEx1F=OvFIgv|%R21d#YX zxoiFcgX2|i#G|!R%}NRpJ-*+e_M9F#90JDB;Mc6zuQf)5s%UG6PkN5mKZIjB`Q>E< zUavsa_t+wf1I&?&laZ6(2Gc?%D$WnXf9S6PBlA?9;Mg4>;3jEs*#`!R%ChyLIG6s%3) zj|(0=NC!%z#d7^wP{lx$LH*cX!}}00mS@SB-Uidko>m;6(Grk`CpQ#Ec*5DFaan7) zB_wp6^j;;nA=21nTt0(kvYE`m9T0^)w+J< z^;y5BgqoUo&k^+R*w5%2YFR%|Ndd3G!^5gAN?^^S(FRpvBzfzlIl-ey*(|T{qh_E{ z0x5KLZZJscW!1J<*@5xCJO`==YKj&X38)5Xe;_D7h2ec4Dg~OW)Brt(VoX$tSO|gF z(j7J=?C9t)#;&fcd<5Y}+<8qr^^D|^OA8aN$sp{cbOfZO2?a*%Q$nWBgD8a5TPjqv z)>n_Z1?q}}RKWbJDqDvV{L->6L1XTt7ZMjc%m5fI=|^d4=}@lm()Yd~`9%$4fso4y zm-vE`@Gv!Yctg?s`-v@GMmJpGQfbFY)kW<*zv%`N-df2*Ae`x8+g?3YW8pQYAJ!?J zqr4|A?&K!b^*NjX`vL&@ofju)vuuWyp@D8~ZYFfhw3gJoM9u$bzC#eGKY#Qa6?jbl zQp{y`{Q_=(srPO;`yLnh=Oii6u+E$SX`+&gkB+Oy=GFV zH}uV}S+?`4nsD1fou;eN@qs%1<0D0@5hEib`QF3i2P>_UK+HgAh{wn@`edqZP73;+ zz>kb(W%Zlu%s6jsiry! z+=)3bK5LiNYlT`BVp(4voE(mi;)-Bb2<#BH_?d67wQl|CSrsk)oj?i}WH4R3ejRC1 zk3@}>)5!LA&$?b&U*Izo!Hr9iqmNw`Gy%S(EMYZffHZ7q>+P4C6xSEWk+<-r`V@r1+9p{fR)NcYw)`A1?VfdN0h9)!B};y69B zDpsb!4+61|gPyfWrF`XbRHxH7KOV^H-oLC_d<=nnor zBsj1zS|h7Ke!J1HT`VG#cKVgL=a{BeEW>f6w*6Dzrz)znIDkGHWDu$8=mYM~91$O9 zk-UOAae-%7gCph~Gxx-C#+%RSSBs&5x2Nt6Z*OsMUw0WhVFo4C{iGb^Aj`Q5^J>T8 z>*(m9c3_Zsjv%vDJW~|BAQH1oFshS3e?9|6p?h&uM{E7vvr-DUKTsRcnMVRsXMBG7 zFIf_){#aR(9~Ee`&}LBj?k5{yo@@N@KF#$))&n2>*e^w{65}R$R|(*+!GZ(5K=2@h zqmNJx3Y$}!l&*EC-Fn$*LZ!1R-Aj zZ#C|@>5A6xEC4QO1i)!@+h%!eq$#ngoOjC$GIDD=TwGk9tLku8&N7oK5c6+;h~6{+ z(r$JMy+5TZhgmu^j6$VztT_)J)N?MistzGGNRzM_VsvzJa#B>8Slw0VpkCLX43IeQ z2N#g68hM}$y0W5@k811 zpXzybEz>S*P=$$dx&7~XkA+rVN-H_A>L}=p;V5Yy7geks6g4ZrfRed>ed5WY*H14( zisq`W$4$A0u!|Nyr_SG0VeUfxJDVO_a7m{-GLc|i`zMDY%pqZS1|Qo9%EIRS)@pEg zn6igQ;bif{sHuU?OAfY8^HEoE7$s=M_3a2Dq+mgB?AoDUr-R$p~M>Q zd~rjK3p}jgrpIFDYzMh3C2Zy`0F*@Xq=gFT4V}$TN9_99k*hvkjzBS_^tO{D6aqUF zg38Lu;5l;2$+6z_UMIjST~q!p=r5JL4Iikk1;@wv9LAH^jU-7n-;+f@W0N8K`uWJ% zhx=vB>)z2y?u#hhl23jw4LdVdD^uG?EBuI(ascc@c*56-jyC~jZ_yijbM8H^sPf$$ z@2%>nxsIYEQn3vGUvcjrO4YxjN4pNk_KaP%j}JzscE75}7Dfw4aqi6tpHdu-*nCVl zs73q@u;is8?NEW|6s_K^az=BGbF4Vv0Hb0=#U|^c`|^^RX>nh^2y|Zv|6IIu(Q>=^ zhGF(53lOzW#(5U`#FO2x9-ya&gg(PEHW2y{o`4v$N`n(1E*@;rz4n=3iz4QT;u*SZ*%9)PoF5xt0;@# z8o|>4|5O6+J$*`=W>nrOViLXhSELE61kURi2=RW=R^Idth(3J2P-~Xh$#@GDVe~n# zVp4_NNJchYzpw4}t@DqH+SA&D{Qb=jcmAPp!7agqBGy(NsUBXsRC|15A0+ogL&7$-AuM%S!+uAvTw6~^Ee+*WT$ z{!1A9?ptSJ0kJ5EAc2?&(sdx&L^B*VDev#HdZi9!%?ZOd);2Z}ggeb92Y>iE=%@f7 zvK_ZQh0XKH^F0^RLXjb5b9i{GDfWffOAI_}km&twF7vdtw}-|Yby?&=o}Q99rK`nJ zwtN<@?^Bh;m&bRa{ud)x=4-UqtN0 z2H|LsnQXu>yFJD2O~HKF2ZAu6k3_I9`7f#sa2{mDy(rTYYPEK;nGJMX(650he)+;W z${VIpyS6YtKaX0G+d?G)P#y&Pu!>{wUriHA{szS~Y6gGf=l?DFU80mW8o^0Dm^B>D z2Su8;>SR76Kk=95b$D|BV2z8PU#)p8*`)SQDm)TK{-a3EFk~K*azsT%kzEDSVgeuu zR6S8c@Y4?3`g!YO{kwl;9|Tmat$9bjezaPyf2hU2o1gQ!@+liVJ{V`>B~PFDqK zahvPc8$&`q1}@J)oN$+i1K^H?gxSNvH;NGTe4F#ZJY#ZZhU`#HA{^DpilEj3^INxd zGhf0X6*Vu!*UtF(K4&6&(Q9KR;OWFE0OwE@svrnqA@L;JtM71%XU^A8mUlu_s{$$Z z1K?UW_wb>_ganx3@UzjAPVD45@ihM8mXJoO*mvI6CGW46 zd+8#l=wV7BgLJr-pI@7@0GDQ!f!|wANeQQPFe?(6&+{csmEp^nk)7MeFp!xn=)KLh zeM|zf0p!NvH4qd~y<}=?Dgo-fR=hMFs6Ak|Ot|q0kjTWDwKFV4ArCr?HZlw@oK zrBN6zj7a-*(!V-GN4*2h(Ibzb_hWmn4m!#%bMj2iGP3UTirAz4OA?L}(EEre=zsME zK#xOY333n%Vid@L0^mMLX6}D%qy1&@TlJBklh2|T9S&V32h{y5(IIAD`T+#K4`PPF z{r%@!Z-C(rriuLQF$YX`@B7h9(RbBlZ*3Yn=R?DfmbyW^8|Y|-1`LI~05Fx__75C9 z>O|ct$fBVqUPVM@d4OrYAx=(fz0=z&`34{G9e$<))pgf2Xd%OP~p-Yvf*jS#^feu&3Dut2D zRJ(TVEw*j}q(>nhcOaw*tenq--}uB;M7QE#ik@P=*P8l9vHh0|s28~OQiq0>{_aVZ zBL~J=U8z7!1Ox<@Co8ymBa1TPNSWxXY$F@}bNT2aQU2Sc7e@{-f>oW76J$r(ix-v`{ zAQZZFv1UuRBa)k@@*31Q{47%_KRNs+X3fz@laUi zsZ_JD_G3~v#k1=wyRw61lE?Bi2x5VtGjZ|?l0pL8qW*|YHwMK-yeC)@KmqYUUwDV` z$LI+BhQCcK_Kkjuw7>Fw3kE`e2ZWV@X%}J{LyDn+kX^22$2HtQ%5Wg{u7$Wh>fL54tWq_~83k;U35CIHw!JX0UJt6S+Ko0d$ zH&MtE*TE=JY`Kg$32v`j0($!uaX6{ug_NfxjWJoal%R?3+=eh!%H2T-K+-~ArNc^( zVOioJnMHl4vv!8S+~f@r&}h{zofV`95_20u2^GK6EdRlqQ^^0fL;tUW3ke#}A}fNg z)gQTz9yM_u_}_f;J2x@#(+= za?_JELz}4V$iO{#pwC~ts1PLnrwH)^o)Ad6D7&FX#>gcmrsF&?clSs_`^>_xR37Ra zp>>V9h4V{GAI4tkA(HMLD~$&|3yLUYc!{Vg8|NL@*47Z^gAfBISvvw)&w=ql`#uH; ziNf|xkPwMEDVI0_O-XtX_Q)7}X)F-Iq5!hH= zo#ukWI5jnu^aCXDX!+~Bf#fWt4@1~I4Y3`BBIwx>hmfYi!a}Rbc}qa*geVO;8OWp5D%>yMg_QlLIN+O9+xIh zNbcW%oJ9sh-Aq=lhsmYjUPF+qYua%&e9c7j%vC{8IS)zRlTUCVqlyHd->L;ken&Om zmm-x*Ey!a3GXi-fJHa+51zj~@qLA7{Z39AI^FREWED}1@B))Z*vii3A^XbHaZ4LtZ zNK_q@oHcoWzsqdvQ66_H=PMds>X(U6d(mm`__!oSlY!88cskE}UC z_IB5Nb8)E#<;Y6CTMOlbAbspy%s{lW<|i;XRkDiG$3|(75OqeO1nW46sxKkU4UotUGJ;SuCdpv{!dv%}y2b5-rbZV_bImVA|#X#r})vSLvZFJZ{ zh!8%ZSq|nn@Ms|!^Z!+nu_hA}80uUyGsDBTNgnW8LJYnipfIEnx%}Qhqt%5&EGvUK zl`3TL#wYaD=r?n3iSe7u-zgxr_)yUKHhySL1bda$f%7#hvs&w4=Zf(-+d}?Um$Rkh z*+9G!H_e!Y9^zN$|K`gid!jJB6;;%&Kjs%kGc$+KaF-=TY)Z%gCxPjb|Hx_1!7Q!# z^irdNkn3bO4sV5TuZ!J@{xE8;gBzmHG?yqaPM$cjgo+AZ1U3KRwf^+K-0_Cu0Y}1l zz72H}Y*c5L!7q#itQizT1~lRc%`lUsJJ1p)R(WS8nK%`wVAv!Ijk#CAtHeae4PmpM zu;v4lE~%A?c&&BF%J>ajK#}OBC1+I)b<6gTceU2x?kNT5CK>(siX0c@-V2+DuRA$` zwnh`1dG7rI5IjnLE;&KUMw7&X=oG!rnvmn35C+VMGp^jGQ2n;~YE?qV$oAIHU73}I z))(GMn^$ERQclb=D!^D0$3FeLk2E@7pGASaKcXszT->db8Sjv|fzqLGZD<||8$&ru z{c29(kxcVNexnxh+Sr}~t6UyE;+2^h9}f^nOkA`33=%B1r{wOdan4IZnl+OoHN@sp z4YQN*dTEr86Ep4^z|T7So$CbwD<-)8*mvBqW%soqP8c46$(c{s^iLxLj?(fpBEx?R z+5o=bjxfNFSdX@PUqp%`@H89=U0wI>&G(a@5XVN=_OGzy|D6Yd&-RCy4ZR$)9*Tc( z63G1zCdh-70)sft*ay8N56HF_&T-5tXrucY{+<-Vq6;riPwF?iqku~%VOP4~o#}QS8;LzKxiHVK8%izVv$h(9H41%!*>E`(# zKOPhqwF0W)IKoFHw)bif26N;gi)@MP#iIq9Cr<{PrOsOBTfxSpv5L69BrtP$Ra#xN zxB*A@xZm)oTM51KcThED=Lkrg%+9~VszOhpfsK9rdO%L9sGy*{y1JQ(-$aGlLRsnm3k+dHrZ0 zhhtU$&h87TZ-;S`KBHy(rJsb&OPWkDNhlgjGZ`_h^dK9%X@N6o%xWqxFe{szP zUh^F=?nY)>lP~`4`0;;dc^X{vMyB*$mS2`Ea9w_i^>zp;*utQSq@GIjMZXZFZ4<_& zVq~4}3+w=_NNk@OUj4{Idqn6dns|Z-(N*#@dhwr{u2HM($(tdXp)YEKTy{+U>7u6F z`~$cx)t~td+$K4^-gCL5h{}E*4wy3AHCW4MoDrd~Pf;Fr!?@N1p-;f`NlLc8L)Qy4 zURs3QY;t>cLLUYN5yA5Zt;6ZzYX;J0EULhs3ZtUrvwM-n*Ov9)GLHx81Ioo)$50Y zT&`Dz-{!o9Xz9AXZ{TR_yTMCu_YL%bw~%E^my{9tZ;N|z-@xqFIAin@;a{|tbF_vN zMEV~2GdD-pNKndSpnwyb^5Corw1fuTgIrMBaXCn8N5cPFOZePyxMKf3XvQHf{yRDP z>2-%znIQooVdVvymN#BE;Z(>1uZ7&N=c28f(e@S@DQVWNFEWiG;Y#Z2fs>vPV**G2 zHVmcIv!<7Dlz!BjmT4Wc+YCHq+2g{*5iw@;lT}n-34ME;C-pct@J4 zf2C6kQi=CYhsAY-1cOGBBJ86Nf$Zx4H27bhY5H`+w{1Jl(W#)YaHJto<>FTLGz#5* zp0+CCOaCf;=GAGn5o@&v&PPc+?5DhR*1%|{4&&V{K2M~#9m^mB&WcS-*6k0ULU;l2 z!1S)=m#2py@&OZU5N6K3+TM#ZYbNrKS&d6;r!Fi{cUX!)YlS>NQSQw{&>6w}QH3;e zZT$rk)7`{Y*_E_V5ru91G_`U-l1V@Q!7P!jyy=i}YORrXn?0OVg$Se8&Y(DTvzKG% z>u)t@{Q!vj<+q6qG|Fpg(3sY#{#Abzvq-jhG|QMa;_-JhxuMMa9|&PLjg@cMl9=o{ zMy9pMGK07IKeNfmuHGl9nIEw^+rMxS{{hKg#2Y#UOc)#Hi#4(Xf-nxRihaI| zAR?31E$t@HxIcV2VORa{oY*6K7c`nQDaGc^CRZOd*E_2M;hZy>W~L}=$~PQd>5!kj zrKYC@4a^3TuRd8f7e)xIHEM>6TxOzgWs}03BZ!gu8MgS9Nx5Zw=gwU$X|S?OEiNO#JwdAxELU=@CF!5M0{a?sL#u z508~WQAil9%dHNXgq%iJbYpj^J&Rr`z#D3=44coXk-yHsFVOo${*1|yf5go)AN?IZ zYVAtGRXns~*TQmla-~%R2{}#&Vo|&cSiD-h{&!sePydl?0K&;rH?90})ju@N=>acs ztOP4$r{8Y=RQQkFvA*O#a}|&MJF1Hdq&$C8{Df?0bSrlD`eq&i#vqiFO?i-PuEoO)whiv|?5kJ&8)vmS9CU?`f z-FA3lg3l=@={+bfFf4fMsH2a-VB&d@1<35WA}5-&VDiwA0LSFk<{g0@*Ya#D+o7-tFgwkhrC0@z||Mew#wW(?CR-B`)8w^B4DF(~A zJZcV-m!J0q9WPykTJpbOIm*Sw@-TBYq_h5aLOkRv$b%3CuUut0e1LV}5J)lBp=vNc zne&&Q5jJI4job|Ec+Fz}=HJ(fxg_(c>d!c3)oxc(GIcR_RJy#5iJSb3x5IbcGqO$+x&ugCL7?cV7KLY5{lDhC~ z>iiP@=@-1=JULbTnvsT3wzFc9K@p6jfDz576LX>7yRGCX;K0oRcM#(JsRL|@WH4(Q z&X{?-rEPDL)m1V5|3l0|(Qn{t5PHQ99nSR<aLooO@R{fri4$TNPcMF63;4B*iJ}8XJ zOt!(`68e4gPM@}b_dGKZtF_J`Vp0i{kR=<-`>*OtHpeT}q^H_|g&GI4N|}-uv3?p{ zERaQzpnQ>pLg!Gvl42#n{h7EgZ`s`ucv1sfH^ovqM@Na0{3QDEuvuv1pHIK z;6Ega6&BOGnzi26c&BiD)-pMS z@a4Lk=j?7R~b8yRQ`FD1uNVd#S+7H1H+f|r$9r|ns&?_}{Clto>M+Qi=%JiDUbM4b|G9U0ur8m2>p8w& z;{4w5SwV4vgrGieb-MesV=&F5T(j_J@}+hq^sMb;08hr@LY>pfO{joOG{>LUMt;s! zR+vu!7u*n@U(fNlcTZ7f#Bm!Jc0`mfxvW5n0XAC5c+cNPZ@EmL5u}4A+MQ(I%uF#! z*$7zI@Nn6#S~HY>N(U)Sv4<(DG{T~0=f4A?uxOc@AF9A>HG;7d7^A2tAfdYe@A<<5 z9q4F~IRZKlielhiOXwBb>^CP^^{ew-7XpZVyXonRvTGi7UzU8-eKU;ta#(kk50_(8 zKytR$IDtWIQo5Y0|X^&#cbT;HDeXn1_B>B`rFz1BP1n^!v@ zxXg|6H5LsnziD_Z=GSGj(3e?8JN0vAhDbZp@7=q1jZL2`%+Crf8jHBj^=ZsDOZr7d z*y0_=teJFUhT<*pd^{Deoj!0yUkEhV}I?Ngb8HAW;P;!_lBmOHn&yk-vDTjZ0bo=tlMKjhvoz1K3)vit3ggOQ~bMRUqo zcWiodU!k8sAcibCDa)?C>i>>rX23fDP<%{b-J4KkB zJ@&2Nxf1+k!H>#)UzIOT($C+A@RcOQ-A z@QvQWEa=reuV2vh_wWG@KareFljFQsH!mq7f@+DEyTh(J?{X){wE@{;%?G6}y04vW zZKOm9srD+{&sf#u&r)aL-hc3Xhx~`I@gAHUTyfX_OP}*aDcPimADHQ!$uKN%v|Q8n z0ND;w=lE^}>>97>zx4NKU7lkD_w%QS%z5!exmBDj6?1Pq7R;s`Jw~(a`-gi0EM1v? zUDu>Q$cx-gW|K=e!mQi+G6~-N?Y8Tc$N7YW$g(9Q42vCUbhW!-PF=?Dww<>7Xdp!} zar}uWI#Jyud|W@j)UW=l-+C!R>-;q$*p78F2%N@mx7G@pdwvW)Vw72iyXg0Q?imba z=Ea)NcibmW;a`^IH%-Y!&ka^zwOp6ICGX^`Ihc3z2uuQ=d96A@!L=}~5`CBVTVK&* z&B3ILWW-6qy)M(W-?UgY?`q{;>7X^gI-r&D$+x2Rd--=Zi9_MH`X(z)Fy@|p z;OVEy-jZi@{q&v}U{Bh?N384IV@t2vhw_ZUd^q_QB_!g*_uVNU;@Bf*)=%>N+x7Lu zi;kSkAGTIlB1_G8wuhEvqJ#{ztuKW;O|00%JKuy5cVwwbO}IE2!jEdL_Z{^hmkF<$HF?K#8Clg=H{I8W)~a&&V;O~BTp#^N zF)3}94d?d3{rkS+Cj2+F3zYDP6Aybx4>O8oaR`!{r=L@cqI;uXBGc#_V5}_#Z(GRf ze71XqGMYVji^j%>C_I*CyPDw<=~2I?U!CnC%V`aUvFJKuC|heM<0%J^(Y-n=#0I80 zp;^${ntPowtZjh32!uE}m#QF8jUFxvW*Cb!#UIsq&MxInohuswnI!Zw#||CH+xa=y zgYl_YGkD?{LK9 z!O{NKUy7H+!66`U?Cn5%JKaG%-1(lhg)`SHVdn(I_aCQ=oGTEAs(R9X0hUm2ECp(3zSPffpBs>4a`D)7 zpXZ1yg$0ptgHz4?nmVh^O)ouGhDyg7%*A}zjwk0}jpm6HDr1mBgV0jz{2OZ!-AEYh z;5}+I*{KowEhuC;ye~t)AKOaM$2w30t$utwNlZmi4ar`fnNWJ6KWAIrj6$z|5S8|QMSU)u9QWN#m&E+WyNX^6kmj-yt{BnHh&Sn$-kF9#{ z?^o>zp%>KmAFxr3h?9#QYLdS;=I@us>?!NapBFRVG<(z{&oKC%sP)><^P8|>x36$* z3YnLz;QwqZ3O{#g zhtFeWnxLdr(S8OA^f25cm9;~}zCF~zVh+CN2f2N z5HE!j`-r=qgi-Je@%fK;Up%ENh0R-V)W|04u2uR4k_QHkrjGkNY&ns^g#~yQyu|K0 zg_~R*R{wA+mrS6{ZbOlR)j(P38FJ=5UXAx_SnOKxE2lGa^2}cGZuDqx-YMOc{h|kl(-a=)waGPrhj^2aj`PJTrrIK;8VC~MP5H4 z?-YEk5^}QWM)2yyDvR)WEV=-lHM2`E^IWnobzL>o z;+6GS(tMk*8Ob&OOrE0j0dK{pPoGfNSgO^Xyb+hmCZ$mRntm_&be2P5nGclEFcyq! z&o_}%ua{S&;Sx3w~ zW17CD(wRNF+69nyYFU&eBxlwX;VXuKUw1m!>H9k#j}i5$44GKFYUIA!UFd5s^qDSq@yGyso<*$%I5a=hlxde4>OG=t8us* zPNOwd3gzr^YEx%~K2}%XrhG`@#gj?K zf#q%oj$RKVBB25qU}4K`kY>sx-;N;kY{DZt?PJH3qDA(Y9CqMsJ7UvnlUL4Ta6J?xh-M17c{Ic83cKDcSB~Te`1-fixX>6GQ+4Yc2MO z_hUX2I7a42ZsNls-78ZRCs++oi~-iZ{#>pqScta_iD%D4*k!71|2%Vs6@s9dV)`cs zZ&G!hVuAkfW1^Xch9O++$Q6!ylCC#;M9=~OklH#+qC%5q&_=WczmE8C{MVxa90Ek2 z?ri&`s%i7@vfp@D=Gf>0NIKttX%yiWSx0K#5;oYW^I#V$XvGBE9!$|IYPz-3xEDan z8?(rPtWlUsg>agMwx;;;D1Ly~EAOG_AVeD{cVc`n-XMzYiIq61_}y|s%npLrdkR5ze@bNIKPZXl_tsZnWO*clkRfBf-PQ%lKby01>} ze-bOLK2jAV&T=xOq-lF;O3yzCWRY2m0TCFkw{UJjZUkz}4bwq$iS&-hTZu(fB)s|V0JHNs=W9a@s%-lB>HaPrDP z0m*P;B78+wbqKwRMaw=<8M{4zd;oFzK{URK2+*P4=BBu9{RKPe;dq@GAMFNCd3m$9 z`KJ<{337`f|#nuBRN4&af& zShX3D7ie;hr%%(WDwT)Z_uW~7L|Y(7h)s8J)7*JmTif8LN7yfSrE`X8b)*~7L3G1) zc52^iujOg_M`EE$OG#=lS{;=R;Zj+Mym_pAA4lv4%)~&K85$Zk?WKe17wYa4ciI5E z;g>s5ZIOEK3Z@#P>Ak?8kX7cj{kYJAeJ9K_1YQwEO(NhG^os6Ku~%L>U^&S4Hbxv2 z_9N265W%IHn(4?SO8XSJI^b;%A3HKGE*t`qR%%y-;ftvMfy6#ZmzSl{b92KV5H&JS z(c0@M!@5DWPjR+(u*)Q$Lo1ha|9-W%Xs1>VE}jJRXavs7nr{8sy{|3tH^vF4IZukwEnHKlh;0pg0MIQ$GN8?#2@^8&9*x`@*TaAavJ)`Avv)ll4bXjx&+G>5 zAV4gpfArm)4?nT0v?Yw(HO{ZrtTijVd_*VjIY~_}Blj1UrStTXu>VMo5~$GGM{fP3 zC{|DFj+sa6pWxs2nwE?#1@XRR?^5ciY+&X4MiG)_3ELG!p5@zH=9B(LvI2E=#Ps%S z9t{j!TSXKs%G7F-w!Nx|r*h2_a7{GVz*&HA+_n3hj+4W2s;}^r$Aypz3s`J%w+5<~ zFEmz0nJp9YkAn#a|I}U9b}vu3-Lkl3mVWg&Y8{id#3EK9)ZkE;1vqrQ60JDn2uU@G zFw>UG><9tas@A}OE)>Y{s$#}ruzHab3tOQDi5m<58@7fNH^sqv8+(&?mDco;_k{t& zrW)wtH$H`-yBb}Vfh}0H3X3ynX=!;bgQkIQ-|OXa*drDgKDx&Q8jJWg#m|pF#Q@=X zTY5_|t^2}vkAU^Ve;9a2)V9?_h!aG=XaLpcDL>!2L@Tw)B@ehUcUcZwTs4$Bt*5tt z=0p_#ZD8KyED|x}p!#@>5j*dTIQq`vL?;UHZTdG$od2rj&hSDngNc!G)njI4b@0xT zio*KXa;KWDOyn!b`YFF0pKoYZpqnaknS+sLd~g#`VOCbgh0ngwsfOe$nhYd}pk~43 zorGhLw@w1k+q|2dlJM+UJqZ<)WDCjn&q`+3D?yB|fH32$62tLBe6qWc^7$jWQh>Wd zl22vF{SV0o0SiDK{X0}+xy-7__*-0UZkt1RP~M<6?ZS+qK8I4ywj*A1a)v7Qspj!b zvT}zG(bEiHr@t91_ooQ;7qeceYpVa)dnk=Y+FRc2`LV%5{J(?9GPJ&QFt`j$)hT-)e6Ze;4@>s*dky_nzLm%*ft*SQTk)Pf1Er^D0&PwFA-f&Cqw*GQO#~LE0$+2*Kdm;=6@A@l0`Ak= z)`%L{R*gy!mugyKzDwd#?H<31H4U>N7dp((d4fL7n!{@!ug!z}92(l)c66=91hH@v zZakn14+-P($QCqBkyOrw`*5L-q&e;`oXyh!6D)S9U?*)z6UlXEkvHZ=yhcA$j3vaS zh~cBVAzk6UCjqcx^X9nyZD=mBScwW|Tj5}QgaIhaAs5uK|LB~){3BliDG)z^s95w7 zH^c&ToKy3mm1P+c*wwA?BG*4Pjf z1DxC zbI^fe)c>Jkm_;no3!;{d06mO%vQx3~w7r{aVY99XnLadm#gvC{KX+qFKazQrR827# zylv^l(bI3ap=^~J0yHSyuyh|RM>>5$yMQBMi81ZGMubw0Q-RmaqYD`@fcx<-d&HCN z?a$XLCz@l4GCTf4e2P_0{HB4RHnA^wD>nZK`9#7e?@0`1Af%URr(kIxj?y08BFfko z?_cV~TU|9|I_%J|Dp{OnP{sy)0hU)Hf^q{AM+{=;{JX~`YMbtZuKfPmMKF_Pyw?(c zX$QXrqIk=T4UY(3cIkfk)f%X)@=JCI0L>B|##l(vznJiU7!Do#fm*_f)qZqCauPv! zN30M^sDuI+F07j3ZXoG;O^|a|5vm|%p(FtF=3?(aXrWtd#i zVi^yOXw7;;+wc?mQQ zHuMT%>}>KztQG9>CRdNM9Q44pG`!gMFJZVk$B);SnWt-}nwQDrKdS{@AGK&0sa1Bj z;fKAAyhi5fh7$OMpDJD^^MjWCJpk5sRuQ$O(W6!L)y-57QnUh#ii%K~c^vN@7&l7) zjIPvu7#Ao2yfnTxs(rG=%;73MZ!e;2`)<2{zz@4e69~V;CbfF#UNkj}%m9xiV&A$j z7>}o!8g%F+hhAy6<$>523T9okVS@Fenn3v9nVAwNY1+>yBZ}z9$@0x)&OD2`eCHl% zd1yX~dWAB=xXDmGy%>byUu$ZkCXX9 zVN&ZQQ-x(^d1(f8tm|pIIfRYAJ^<{_2$gy)lQulAzGr?3CXhXnBYRy|z~e8b*Uk&DLTJU8DL1m z0?xvl(|Lkg3A4IG&%bhVi;?WD`E3$mc^PE_vH%WDJLUgoRgeHfMZ@bL3{RVD4T_~49< z)soDR6E01+_o3!tpzRJ~@#i-=b69&aC+T|SjST%Is`;Qxx-!zk|HcYRuiBhn(>n|l zlf*vK`{uIpe<&sT8PV`wvRcHi^b|kQ931-M#@VeZY2SP17iXCa2&HBziV;3=_62De z!@)ePDWLyKsZa41NLprkck^)q7i&L#s_x7zQ%|)4B^gBd3hx!+PQDl-fKo0~tAikQ zW7&v;#gL+nd$^r;cS8GUt&RfC)X`h>IE}spXVY5Og;4r0i$ovZnx38>4UIe_EVDUa;zG@W>Q<{(3oCYU0hVQI7Qtt^KEdpj|c!s5Y_YD?_>b^4jvL(q=_u1JEJv; z6Yd{sYIa%FQnv(gv>c0>nX~Z&v90Z+?jjoJGP=QzvT>2kLr}by@j2e9EwPa+7|b5L z`50()+v6z9DuP?u^ZtS6V6Lqm@!?4HmLel>N542h|I_Lr$VY$M=C@)?&P=tnI2x0) z9qD6H6 zPoL(QDJd=%7ZRsV{uq|xnz}MXMFe-?4mM3Nbkvr%!%pqRFSk4t;&O|?mi5@>H|I)WQ`~NQm%V}etmAbz2s*;XS@$MK%k(ph#Z3qxcKng#&9@&i ze8qbj9tm^4)=xi`&9$VChrXWTmzwl=ri+`)^9>Y^!EgN}X+6F$d8XNkrZ@x36h7*# z#Te&}=)iJ(D1%M2efRU;1ei)}|7ez|8jSDlRO@#rgDsCvpd@o`wOCeBr;{kXI{gB9 ze((hic$ppd9ZZ+NAB-HpRaGJ;O1R z^S~BTbVWlKY`o%5eNQw(g4D;<8sbG)Pk4grxK4~hB`ge+=ESu8NYDrqfk?OH5MTHW zXu+U5S}e9w$oxpN5?nCt^@cu1AYenR@BA=r!u05&~`8~wY>|j&rW`rwfICX!HN-SL}+OWb3bcE{o znR5c=XpK{xtw|3Xa)-~DGwE&gK>F^i?9+SL;`vsIy(wA-T<{nZz57TnQ9YbQ766rX zL-DGoQL^gUdCY9=6$4z0QAYmwADR)fZDEUu)nLS7(?WnR3`JBT#y}p7QAB8)t=LW7jX2|zc^(6}#>wiCJR<#ptURB2l-qh95m(Nvk{pJ3oSnM)Dch~wGfq_{NS&dl}D=rH2}@Wv=+pDa+Ur5YNzV> zdCXYkStvK!ALE@PyxE}pnE{2Ym__tti~%*=_4S9v$S3w11gI5q`NLj5+j3vnY!W;& zH#aw1OolgvZ{?CSqm{dF3!U&=3SLxlAzI2ItuOMf7Wrozq*ffTu@M2w z4VAZcot)*;-I8CM?=FltgvKn_rsP0fJaZ(EcTU%q1f$Hc<8qc7%V^3D?GgEjYZzue zcnABjuG?gyG~BXKZk|uM@-nmHLejB8g#ZcHr2Cc6=MCFEr^fxQ*(XtUlq>-zaTf#c-%JH=bKcweW0&VvUZ%NaC-Txw%p}X;iZNM z%$d=sTk^d0=mfj*D&8eamukKyv&6Palr4gaH&AGXVPG4MRLHUy^8;A<9{R&10X!M; z`NEm>ME5ixuu96jR6B9TW=xtP;AOgzfjqJ5#QL~$VRp{m*1Lyh=NVe;aEsh*T)*Bi}6Ts)W5n{Nx#zAU9L0GAS&l{S|wR#z@(%nGE`uXA8z;Jf%Bl$CQ8 zB|84FZ|A=8AD`8R-zzCd?BmoWS;?WjXzsf$eL4Wdy1(Ag2Ix*DVW>1T8zROZxb+zSdC8AO1 zuZnu068Y>5z%wl(ffAKo#(eXN!0JzcR=U}SWI38j6PX)(9zwp&Pj67cSX&#AbEUGOdpsK^aw9+Z;siTkAfoT z+*xpX)p#E`{Y3EB+u8&kqWp&GeZuhEl?tA}+!tV}bw$-#r=v#^|CtuI$M%U+@;NBR zfl*ozJqT?%*5kPDB~ix69~OY%t_p93N_sB=W{HhiCHF@;d!q{M=)lS9yes+*d6|vv zdmrr-Q{*a&vn1C^d49zEB}2||7SftRk==FAmE~C!3e|*C6a>?*Ya9C z@DO(%wX)AG{OjCS0;0KhJMY!_f?L#VH2QoY(d=$H7PO5zNyA9jnD*){;Bvh~~bXkqly^0Aj(2kH4MJjg(1?QtP#q6*ANFpuQ&kg|-|j=gREtFw$HXXiZ|j}Ita*lI3g3zs z|LV>FMwY(01Nb0TnI5W9fCNbdVCTunF)p?c1>cFW>oURNp4P0J+;7+L|Kz<(7i(qA z7#qwlV?#S61!iHMw!XqvE6zDTPQj?vZ8x^!_A1W>56M`+yK);=ku6*r$z$-v*J;JUw~O#$)h( z^%|lh(+EY}U8bQE`O)>qe**1)BwfTCKjd1lynhgRf%aWpUFcb(Wj&*}wPW~^|LHL5 zw&$;4_p?YK_zyz*;aw?yd-XOV z>PO}>N+v7;vbHpsZOJj?j!sDg|E+5UR)G)z zIi4u|!>MYonJos}`{gHINa!fNpbllwZ@nT^05l#MJoe%(Q}adNDdXIa%V?i)hUaG@heG-mr>Hu+xUIuHwR*G}~_}aELku2u{&h6Uwn%s&_9^>E7%77GWpN)iOx9pCUEgKmLsr$`C}&>uo)5$B}2DHX?BB zt`x{mPJ5oSM=Q<=Y&-*DQMdoA`g%?|$3=*t1QE)!-4U5Ni>%=#I16SHzVBaSoO@!; z9-TrJ#-6!M2=2&wr|)@gM$8w(rpMe;(zZi(n9Wt0df4=I-cgAR+YpeYk|pGp7CO_r zpRZZ1IHR5T?RAL)WCW*ApSE#(XffXykWfJOTnZEYW0FfhXEyoUiu zhGzgv{4KG46ViyiX@S@+;pab_7Bk;(E zyX&xrKoOaWN6KT#VoW_Tk53$m{&i5IlpcXVtyd+vy z#G;5Ml@K}6!D4qkr#6I_S|+HY!9x&QU2kRqwJPCvFi29O4t@tBP`hsgQlSa4^uR^< z>XPZ2==h^wYtAq7Q?B_(7eXX7@n#PFzU3lH`R%>{zAaKX36J|6V+Yb3*Rx?+s)3D; z?7DT_2-_8ed%&E%z9~x&AQARiA2Kn{+UiGXJo!RlP^gk* z1{gFW=$u*~b>F3-k_p6UDFf`-xYo~d3D`%7O4p|F8GO42d=SGGibiJ6RxBe1<@ zW}8z1#W27w{?J)fswu;Jv3OItUT)1Z3tcLSOGe6iPJWMeN`@;6P$CyvbcIAG$MT&# zrZ%9%0FVqPFp%7Hs07V@+qq(&o>hjd@7>Fnq;>VonO9Z=7epJ*PcDzysyNMzE)J1F z>va*YTfjGLRzZJdg8u5B+sF#=CpfpF^`m{S$RyVrJT5(o-j{;d>u~0i;NQvvEd%<8 zdFBU_NdfHWQn8(PwK_aBY&@_NUCdVto?m`v!K*cv?^TJW z?$f@va;P`|$m~JLcn~ z9g~`kzQO0;Lv!l{2!uccczFRT=7mkm7!&UCHXunaC9r^6Un38*b{Qdh1C=p>8SWD2t^Q4c|LDFH!TX4$li+KHm z_KXGK@Bs9X=qf$U+UUuec9K#iug}lO{#ru&DjA6Sg_&Ih!b4^1BnhqhFpY;r?$k#% z=oL`gT&4=yfx(i=i=|pAKP*Ld(qsdR6c=sUmgorZ7razj6TbVB;%%oeS~3LZM|-r? z0EEkIxIm?^pms+8sSvOLwMqhx)0Q;TOuZqB_m_sXbLNxSglLJgP8$ysR9v)fYKp{B z0(sr&8U)p>I(`JsbdGD|ArmBe(4AOQh>nPeS`xFMX<^W-ns|1-mOM@bqsGUVjrn;3 zaGq+%A^TT(GQ=-!7t8%Nm7aReNS?SmImP{33t;v{^lL$T&@g;8XD2t2UT>{}HAHxR z_FWywuh}=9LTAz8#BImO3Q8A(VWFH_F>c^rZlf|9wgqU0>%g<;F@PGzEBVhP#qjVo}??cqIdl~3}1*O!Dhq1SNO(lR|Q=Cff0D+l-<2`ZQnf+Q}Or!u-j zB$Qw7BA76j$>uen7~gkwEu~HXVr*dy)-|hF|7hZ3Av%sl4B#;?6cLE#GC#L}(vg>KuXLAg;NB8$iX%pMYkv#EuKrUC?b@ zUCmKa7et!_l5hS!?($$Y7dkLFt+$?+X$2T0$(+H6U^7pB8}HwfTEJwk0DEqIO= zgUKpB5fd^Va}D#6Y%ECGy3Z6(8s7g=t}6uxFwCur8dW{SgW8=rC!!i|rwUITbr}C9 zGdq9B>B!9o*b!Z-$vvTs{GzPcN|SYOuw8G<$dqfZrb6X$vMMpj13mY#J_h_sU`*sl zX4|V30qwGWcRfESdSe)BbP$ouul+l^;2jH6-MaY{4V_utlsqkFoEVs{*`8h%>SY8NcHnL^`pXJJy!YZ5@3EWMMJ+ zlag0fYZw__vGKrBvb+;HXn9pi$7%OKEwl?{4Q*cVHq9%Lc{HRigBJc_dD}N_ z;eYHs!t&}_65M*?&tR;8xP31%6naV6fL|FPyGJU{&PTm z{FfZe7HL6!x(d1t6TH?k%#llh(nbvUC(r^t*e&)&Ad0|VnznmxPxQhl2Cy9(QRE6N z<5vwDnnE?R2jY)UecboH?@o|bZb#bb^f+n!^`1M+Y{w_M@&>zboi3sI%VZ%hkVEMXGYuTkd?k*^^G(KK z8Hupa$nM{M<@eO7#|jlR@)|Dy(j~M1lCa@koCPPugN|_fRVly>3%0P4;7xTPXeh^! zEX-1@Tc0n?5WhMoqkCAUCcvg*pVBtEGPf@N2F-2TysPc3JSr~142{e~{TGewoGmT} zl1xmDmLGcbs8z=Q8XB>eygXFZZ?CpUBTQ&%{qerH3&e?T&CqtmJ-#zd%Ju^i8oS=38`7aq#S34bU%+l?yI)Co$0yZrYk-l8tfQZC_ZerW( zt1C>%*$! z_`6#<;Ve~{gBw;(NMNgDwj5cXw`5sc zc4as-1Xe;|(_j9qAsrg>ut!2?Yf~#P-U`AZGB1nt1dOQ;|WN#pI+AS5S+a<>VHe;N7>zAasS- zHEVhbQ`f3rJQYbc{|nvd>-b;x74jI~{2RZ>UD7XUn8uJ$?MwExk#7mWPvP$2Ks%lb z(a_<3Ly($f%V_br@P#q_fPkzqCD;91C6$wj{W%3v@mE*vuTfj@+rw?%xx| zWYTr#84hcWX=XCYF8E1X0jBX{M`?({qZPfnx~&_)Ny)fLDB7{c$==Wl#W&%k2osskYo|$(v zExdQnGPvCUdyg(3HsurpfA_oK)SvwuitvB1>93)T2c_ihU?t8{V}TL|Dio3R=ZIWG zIc+GOng;s+mN6mQ1?@u?V%lm(N-?Kd|FsCcxWVwE6BdQ?kGKm>c2dGi58ro#H9_&v za|Kdl_pUY*S+RBw%>AI-NTC`*U=geW_1$7qAMgQHRbyG2L>eqVkw^!HFD4mC;=FL+ zjjlcUVoOncLRl}1{DIuiB!$WJlzsPd@uldf^~FX4J3M+s^2F-XQqDJju{}7Cu>F;J zoiRNtd}wj_w2FJaRqxs)EZ!qK%wgEE1hYg?1fD@iTDB`Oh`ef|EBX@@Xp0S`+0-ci zmr=HqaFX@^9zn-md9ByG!B4s;`0Rf^M4^5-#m`I>Khed0)^Tr7QR`l zVZ*RQN{an-(8rw~73bIfh5-zglgjKr^`92FxPL+8`!vzy{W)idGkWys;K*)s(WktR zao9+=1JjcuZNUCVW)chaSNZ`623?|qE&xnSX$&)PBTTjF-> zA~FHRoNG2Bwhwge((T8j?UxANA2*S(Q~FbrGE(OvZ?6Hgti)6p}1L|6II}tw{mZS%CqH8DrXybn zg|KGgOo|2vv5g!~B~?lpJ|rW93`JKI7sW~7P^mGDbcT~>PWds-74d)b5~{~Jw=eA^ zIDgect3lrYRgVhP-t>qnFsh-}GOYz1wh1g8!rQWpjvYTt8qRvgbc%jlfm15#F0(sJqJ?L zGq1)Je>`8eDa~c#z2w|kaT|Npit1142m2o5R8>mbmc_EP_Nm;_TQS!(RYc;ruN%&oB64As9(h-x2B5kK;nhv?NMGs0J{qZeC_}J##pYEAm%o~04?J+Rv z12;X#KdtWl`TbMPd@nEe78yPau`=O|0;trYY5?IK8p$Q(4To3+7>bAN3I5N@LD-zJ4$hR!TFn`S7R{ zU4_ushgA?6!V+aHh--jjK%;c>CwPsixCX|~GjADVA1_NmZyrW@8KU6-3a4a+`)JSE zyI)$%E!M{2*=p@|(IlI1voCOx%|@Eo3b`Zbx5n4CBU@o$B$y|Xo6Cnf2Lr{K&#T^- zdB;}=N3F~K^y#K$L;v71Blo_Fnwr_xHDQ&_gI%du1=rt{wKcgr#Y9gO;}TeR5S`u- zV3!~JxhT3W>7 zpUoDA0B3?Q(%3^OvT_Lnyi+cYFwU7@78t4m#V9eE^jJa)guOe|K!(5T!(1vBZE~WA82|6{&Pqp99*)16ie9SOQigX!QuAITz zMyrpDT{wcm$S(R~qv#$*cpB@tpwS}l=?ZxQm(1Gl0W42#RZc$|| z%6Cj&-XSynN4gr4ZuD7$lzU;Y^X=I=F+e#!i(gLA;&V0O>^%5RolwuLfz5VUPuWz!xLk;8|# z*wH8KQB8V`GlRiz#_&8_>yb1=gUl2P*Z{9vQWqnVW)_*jGYztRILS{fcP(d5l48D` z@aCw~1`bN%fk|fH3jqqpzbbW5#Q>T!&Nb&>MujfZzZHt_LkuDKcMbUo&|_ff%w++$gCJAFnmRb`iFPTZHKJlf@ngkFew^H3mPvcfH4WA|})Zk^AjE zMaMLr#kLwEt1g3qelpne?vwubfaQm#%@4{%n1jxpyPPpHI9ML(Y`x}41;dADQ4k@$ z6~<|;@``)osEpTQFfl-{JQ=a+)DJeJyr9gzccrQJ03pxRadogZkUT4>%)L`h24m`z z;$E@#ybZv;Z2`jyGfZj~+uz?GqN#tYBVBJX39OI;C?$7Crt?gAOw0MMFE_}1w9Ua` zWvK5BIadORMyjs+)d`ZfGj=oOhw_OHGcs{+nrACdas$`zY@I8}#XHXz+U@PHCw~64 zbhi*;n!7+79|$56p;4T6L9M@oZD}qHeH}aU-xqB-6uFBp3#%mU z-ejbb$HX2;kAhsKDr3*K9pTfGyTjwv;yUm2yee3oB*l+Bq&&Impq8NS9P&g2Cq$SJ z9PR(O1B&(MH{>c4ztv|-9&_J3!m{on=S@mfwePcbuNQ!wbQU5F^}VKHd5~wW+#?hK zL~!wD)A6wDfZUann-YNRkV8vgr#c&}G^3|c8&^Nv8I4nNuLH^(3`%@#s6H??F1js2 zxy}lwP5DYgfSPI}aWhiqbmU1Rku1KA=>f@GzdN?$G!Iw7$ z7>XX%xNBc+S=rI87B-pVL>ua&VR=&`{l3JW{_ZaU#O50t3mYV!K7zWtoHl@`+1?wmGj?4MITuy_h=(fKy{(SdhQF1} zY{9D0Uyz+eL2J(G-nCDo)&-{V@L16TqIPP?rjy^v>PLQ{#fY{DZN3*m?H@2UZlc6$ zP*_x$;8#Vq$OQHHf&&Oq=61(%63$DcO9nbj6#C^PxPjSoc=kq*utK2 zX70>IOxf2S&VTRiL%(LREHkX^K}C#yD)*a>JV@*jHQOQXj$FlSkfxo=%Dc=}ne%DN z-Fapx$yJl)a{5b>LGh9P*Os<+{0Mq4USYMDe_4mcu&}ImJX#95(+ofx-bM1$ZnN;3 zS<`gWkFMUtwHf_VU(3GleVS%7LkocPA32OL zhq)c;Ieb#^Bcn#r3yi%vn>YF}Q5cjzMBafphq|g&cQ6kwCW>6&7OOby4k5|Ld5XzD zz+Ys!=6LIdKWZ5~b^;wR+^G3h_kiTmla@ULodY)oC|EV{^I58QWV^M+Gt&qsSxlqPx2;GdND*8s^%*?kI_33~he^4tGLU2Gp^}mkl-S1F zk?X_9{TIa9tL-N(pyB+S{X-nu<3%HVDtAlbu%;a%-jeU*0>! zCsC+ByVYxwE56R3DrY6t9@)+$XFtEV1nUVT6v(Y;p;Emw^NqgD^e~79Xyk-hU}Sb^ zr{bF4D49b{b@rHRXe2owtE{EHzV2JOx9C!;Ne=cWU|BqYTP8mmDB+~a9G>KjlMy5v zVE4eFH?Y^oXUu9qgp|-9(Ahd~Ld=7pr<8wFB&pAExR^JE5z}d^G&`Zi|5tB`Vo@ae z3@*uL<7sJU?qW*wWf^5oM@huLLq?hEB>riJPwUzv{&6L;JVfBBTkM4{_<^u{435ei zXYh$A)Ubr}S>m_1NvsThi;~(-YM}TNStCj(Y9v_NdgrX>46vN7cTDuMJU5f(os@yF zA&gW!zKA+Xy#2~b7Fg4vc0?N?Kjz#jW2|k91M7cuz())BcT&QazKoT^cv(h;(^2s1 zYSUSOv>taq(H@5%k_x1#5>L1NtGZE5=OI(q1h>WX{l^zEfl1rr5#!Od`IS4UOt3G6 z9(k%3##tY~Jz*}htF)-9cC3@Y`8E2pA-FxMgk-MC5Rry{Cw>XA_xt zLv#A=t10!Ohw}gA5ucdQ@AKu7OXC?4U;Oyea>!6!vD76&>tmcnckPF;uQQ9 z_o(@=M)&Zfa4enDEQ&zbJO=NZZr{$-T2ysuge^HV^r6-d=HwR8Q<1QWA#-BQc%oA* zqICDSwwD7!xE|lh;G;S>aiyl(1tY5dCPRPu`k?gIZVcZ4_>zysdfj}n#ZV{1NMg3} zDlz>&G4tt3G-Ndct2JkdP7W!e1gNy>?9Sr037>jmfj(6B0z7 zHl1I%`Ela6fk6%FNbO&tj}BF$3YWpu+>{?Ep4V(tE@WZ9Pj8-O>?6m;MN<_RW$??! zu$OH4g6XHej{jcWkh?MtM8J2$pJ5Q`{p63&3o>lE_7*r;);Fb_bJ&KUf>{6+Ss9W4 z*_Er@YEUCE*+v1BtU*GlA>OHU{4$f<5oP9$j;+~TpJs+m(CWtW!`>p7IwtQO#puhv z`)=nn+o8!}IOwYf^$h`&(~JzRpap$;F0?B6zjS$vcjv#474^g4c$AZ%fk%M{vXttm z0Uulj?I7{^o4ob|kw#vwpSiIhd&tWvB#|D{z_ zV8@B?s^f2;V7no=_zp;$tW$PIa*=0O6Sk<_VZG((ZBy-WbgoJWFc`rnPZsy-++URr zF;H&zm{_H9Sah5Ar5mS5hK4E|dS9(M(ZhM-q~6XW+#ZWkpyePSUTy#KQNdCkH&6)B*;ff{K_26PeqS=QJHc#0(VC{4W zp*GzJEVr8K5br7yUz}xyj4?}W8yJW&A+_967%Vc^Gj!#_h-xm^V(4ML%_Oo7CEZVT zriU+HbMP^yg={|j$lQx6FM3OLWD)iQ$d`B@*Sd;PDf!rjfL!7#u$@=Kvb^{tSb?!8 zUgA%AeZv&oQ~`s{SRVKHO&J%|#Z~O}IKa>;*8Js%;)K6>>FMQr%%O^N@@0Q_Y8a!$ zuGy!Wq+soghZyuf`$f`U0TQ^LZ%^biFe9GF`e}99#p)2tf>x*qpmOzV31t^{#qS#p z+{O3!D2Cq#Or%=vtAXn%t-mgPV7l1r(SkwV*ggjD*-sW`3)V4|El=9P>Hn5!C_!ws z797Fg(TNisAJ8_P4@GD_G9-;YrWN)l;?d%S~ z#=Hs}FE3nEl!p5?wYMn+HJa-TO3+nYu*kjfFW!1G)Es3E{-m589n*H z`!LEb2C$|5h($m5ZNqe4)hM1{eP^t_T6fFP&nOCQW9aT<5^cN^8}!BXVK_o#YZg zj*9)k?JY~$L+Qzma5{N+I-8LD1J+hzwsz%{ju-{FsILSu2dxw*~Fr|5LT+w@%mY^uJ5n>e?*hKjjQR)%M zE*-gJ+3wrXze?>8)Tn8f%@~#)hpEY?nW6oy54zBkit-PSB_2KSk9sYssrHY04QbM)6Mos{0)K{W5{MI;HHh-% z;OG%?k5{(OEba!8ZWV()03NKWbGuP4&*71*aNweW8JCDkg7d_p2O2X{XnMK>;wl3d zTl5)x7=5z(f!zDU>LX!guN-5tUQn1Ty7{-*EYrCmE4t?s2qvti5VLr*e*QAuGM49W zg-N(0+eu$Pb;{VAcV;D(`PeHasVPSf4oDU+S{%g=>?%=@;aiFXa=ZdI=PvoD#IdO zu?E{pG&xKAr{MOuS(+0L&bJx@iu9)F2i8+4UrBZ~?rBNqlkplQ{tnS!6#KEMV&t~n@;*m5L z92cH9FL7fcWl;(iKbqXNPl}xRoe9MD_QfB+xihZ&Wc4n-vn(v+AH$nwbV zz&rTz3d@T#^HGFMHML8^+yc&(Tl&UwWlt*F*G%Q9QU)FXWdTh9&a!IgVV^RL(M;C7)j>f*>S@Oqw-!mL<0an~C zcWgj}!K}t8v*$|ympKCI;MJ5ZbRFg2y)Q-$F7lStiV|Tq`s}9Q?$-a~lg33Dt3kg* zhgsqePj;?u&E;IUaIR06^XDEtagV?-Mc+0%gA9{3Uk9xtL)AaG)!xmqf1Ajnn$FmG zsNq7(p65hYQlX+knqYB{XC@mgb6Q@;T5i1-(;Z5R!ERHb}|Dek|4}}P#kjH&($S~BmJ>VbplAqGbdgI8fxfJhNl*G{j&Z@mt zE$a@voXPV{+5KP(zH5H_shtP6OPx*MEop0OYXyy&R0-9^{7+1feJHu zizmL`C-=%FQ3^evYya}dqR0(kp)y@+8v@d)NKE@_zk!$1ze)vnT@jFUEraX^ZL>7! zy_>4&m!;id@qIKG1c4GH?Y)7E7UP0qPEAx^-h}#Kwgz(e%`~J2AIZRE6!aWxdrx`1 z5j44>fdRPvxE5BPVPr00_z{=52O3Qa>8MNFO{=O=t6DXkkI^QIol2{`6<3PjRl`^T zDcG|jSMA2&#*Xs*v0r{zO3~BLs%ozuJ)Ax_h`f;(3ey?KbxfA`QjfG|}Sb3wU=bfNQj7w_BspH>N zvbdcF%IL(WW(#{VC$uCQ=fB6iAtrAJyY3#=9v`18u*`k!Wf}#9{StHa`-ll6uE6@k zuNzpt=2D$Y;O}~|TJOY2-({+^i-q*H`Lw(9wXDs2v?BIZXJ=*L#e59-@^5xq3En29 z`Gs`F((o=R6HZZ_s;EO~MyW8QmiPW!yh`#Yi{sSqem^hlrN zx`G`$PL|}D-19wbZJ6q^G*Xq-q(D!cI;Wn+_p(F-dV(i6NI=EDU`tU^$bv6stk#Vs zWua9^ta5OS_Lny~+(_8Y&h;;Jhdw?F8RV9*f;Z5>;Gi>t3!1asRMy>}^gb^R5(lO> zPfLlO@{-aqcRfXfnMdSFO!lwJpBjgZOYE28l&IU!X??iDI9=^#sYkC)WVre013&gp@JbmC6*zQWAz8-AE-hg63MZ(&C;ZUO)Z`0BuxCC=WgzJn|bQEldn#WeKqK_ ztuOkWEM`2#J)$_?lr0Gkz9r=l&-hnY&Kq@Z7vGBNPA7{meH(y9KOfdT3}pjnVq-_1 z=M+HLY?YC3v2i{WE&EcMr6h-59sE{=Qai-ZKJBGES5V8PzhA(Y>A$i zdAnDWyLo(@DRm`E?FZ^Z#L_U3uSfIWCwoj_Y}z1m+lMRdmt_WIlyKc9ZxLcN+Hd9Y z3K>cJCYVI!MTg^h+>oP(rU#?7z!%{34KDsEGyATUuFlwy0(9?BQX@$UxfID1JKM<)IL|YNsk<0$ z(;3O;XkP`DfNfdsF4WTu2F*Vz9LTrhMu%g)=Nf5y(<5b!K*E*#Yevj}!2P=a#N?u> z`!<;*g|Z8u_fFLhZ{K;ZA%Hs7wO`x=M=7pTcK)hc+I@%wmotq{BU##>Ib+o|J{Nf$ zlMrb7i4hKY?r7tqikxP9z9|v3O$bjlS%cvuFATUs7Zmz(qi_n-K)WVWM>2xDh)bBl zTNc4%vwnPQtx0rzcWZ-oJmcjRl6g7qROqKJ>6`z7z(8vpEQi#PG()UDp1P z_w1`(54{%Kv@*0;rw{=U-Z~FI(T__a5dVww`jy{MRn7kKEznG&V|sJ%&Lt$reMr$G z7JGQMj{&k+ax#3L>fSBx@x&<8A~y)lZt&CR%$FnPjK8K=V)6F+w2|_7{z+~IQP$g~ zIWB(@pG6-Yu8@@Mf6-9=ud3N-J(fsb8yMqiec1ObCVQ7)IxW+qsYo$d^Kq2F$8{45 z=%>FybnJIujdK|Hqd|?-BX^DQJ%xSb-IdzeMb$3#yB#JHCPOmhbSA7NEN{gTor}AjD0GM-H4*j3ls#QC3OOeyD*23N64SWuB zYZj*Qc(vrsR#*Opn1L-H3|ZYyRB;k4$xp92A$@E1bD+tKZ{H|#ay2VH;qzNzaMO}h z17Jw()!yG!8W*lVG6x?oV0f2}ugLtZ=M_3>{mJc~hmY-f2eEFT*2LW09Eu}G^K$|$ zj*k1Mmnoj;pfH$y$~{gzZRwNiq?4p5u`^|KIG;wi+4vL#CS>u5O+D#Udf40%9?tnL zdhofWGSRUuo)P$pVLFu0d!BFm3n{Uxr5N5vNB!0Q8*LABOp z3#RJsc1WqEUtuRSd16X~*M$o%IqJe?37x(bwm2RqZ{GNU{1{aE0&5A)2p!n!)k`UvDZ` zVfq7tMyshJ*T@9|AMv1R^iNfEQKantwd&^ulA0g({Vze&W9m}BzXdJ_*9RL)PXB0i z1XxV04}Pm1koBH2E%u!5l@KSEpO$xnXzT7=&ZH+x?OS;N-TD37uUbt<-_z!3ys}Jh zR@#hwx`Sl%!c*rilMz+%A8&y>5dt{n2k5aC*h3*W+S+rWypjb zyDkn;chE$~ZpEe=(%(UbrG&z$r$bqM3R)U0z=~6;4kpz#=nRK^E3(UC^}Zlbg=>z;30LR5SU7ilY=#?wP@+khp5l8#(rHA&vSZ|-&F7vvZNYRZ zo1B&_m|pT=a*m%!$GyxSI;A1!+hZ)I#bUe-^&1gv* z`)$d?9hhXN%&_b|xm=ku_kG{-3P@zzDff{# z84Fa?)$S>DR;i+yY}V()AS_$X@~cJLwpW7J$Z_c11sTB{9*gx+FYlTv{Cw6;L1%(x z1C~c@mb{8_LPG?x)9~j;tf0#!IDC|hXNYdpT+kI)Ge&{K50@#i39L1)YY2eI^xquT zqX-F@#nr{-@%!<$w(3Y#v=xg6k<`JMH9EIp@4b{rq+p z9B!fRRQu-Nlwoo%Xipwc&XD=5f<<;n10>s-qtLlgFr6&Q8^?RG4u&RAXpKtFxkjI< ziMS>fslAye05=YpWIi#HZ2Qe_Bwrhjx$ou^+mz6t@a+)_!A&OyC`>UOZ&E|{mAb~+ zpur*(5jp^4S+6bn`R^5ywr`bSM!i>j?&Zd|2g+De@gc3Ai5crHovHf-s%4Dsm17$Q ztd{&{?xYS34e3`^c5lC0cJL1JjnKbfgmN1cWL$iFF#8NLRd8F|E4bkZ8v-NbJ>;&E zz_@P7e6VW=Ah(3EGnt+6&fvR*YRWIOd0hEerrdG?d8JlO;1@U$yKH3 zkND!Uo!Bp!WCpjfXkf2%qvURYYHc2)*a0nOa>oJIk}VN5g@Gl!rg1rl!XUY+E8=+! zsS@7CnK;AeF#Eb14*Di!v0-_-(XVY#CZT8z$|@xoK5jfMtLgTspj%0g_*d}&F$Vd7 zwrdB+1;fTjG?!RSr%JE;(dn{?fq!~C%O_s2XWCI~=*eEVt5?^qtDzC8$66FRVRoXN z+zl89lWl-vf!T@zip8I7x^2doTt{R$+T&&=r?$fR0D^oHo$jw$1DF>CuPt?1mwH_& zb?+Vy$;s~wPz3z{nGAvKpP8(WbYDC2XNC7C*=TS>7W_kVDmO!d5AgWiK3~)hZajmK^Nfe`Sg4%KKdK8s=Ux&3gd>IwLN_~}VJ@8UA_;7~jyCGIK zUvKotwIy{zO2^`P2vLq{1odZ zslZ!I(aX+(xUJgbz|;cj98>~=c}R(|4=hd}nIr&d0A?Zbo=M$r)!#y8*|~RX&b{Tw zf!cWWl8h4P*C2A>{m{UuhZ;=l7$>{DK#i_V`Y$ zp969Z0-1^xSzBAm@FTWEErHB;dv9jsxV-D&h|7L_`8eN?++9q-Qs_D_j_Ic=w<%DGmIwCps= z$LE`I%9Uq04;wY48Ey~vnhC+;xJ3dFPfP3rcWUflRQ=T-R{uGq*xggi?{?obw-l0U z43s=hk`iLiFw39Am1iruVJRF*w$;VM=XbcbbvOF;RZ(8vjbdV=W`K<#*XEMmK&d?A zl?ou`e_$WKG9KB$@NXgMlSR9CqT_%Zz{EkO!SfqcG(v0(R+;$oJh{>pC|t1IO+MMB zhoNJpv-~@2TvQjmNO#zSc?{)`$N-!}?Yyh+jBCr`?e{X{^bt@7w z>-=Tjy*}#(sx83ucK<~Vv3HD2$fY-B8fN6EB^A%=7_BistBAmAew1B_%0Q-z)x-?I z;en^s_?|q1VE}v=sAUP4r@-$7&P?w`GK?N5peW2^Ja62JO^&$>|^PET~)6J3oWaB=oevZ8sJZe!&9- zh4m+=2C1r7-Q@*G+8ChAf%sLMtV>mam=V$s!gId3vDxpLRr!@?ijz(4taERkEghNj z-0`;-;HJkdZ^=d%y5Sw8<_Kz8dsr+Y>&2NX8l6VYT~4?}TAl(8g>%*L|JSnh1c)d=~pazf{=3wV$G1htB> z+TiMqMsjiBcYr&BorC+Ri~1i>%r2OD82J3=w4_e8B}$R4BUG8%KQkN^hGp8(n{Y-K-1F$?g-Znt)~8#&q!5@uq*&%v%!nRH`{Y~C)TX|SZlLKH zWgwlrB_8TqihyPb;})my`>evMOrupnGLi!8F#rrS3y<&Q(T^5CbN3_D6LQo}rn8b5 zs!N>`Lc6xo{QSM}aJ;HQ@-SIhoLlUxNh-!FoCM>$4b_;wSmQP+i|k87;ZaI#!crMX zV6;qABHt%S zNnSggDfRasGpncp=f=3hNZ=}1fH)kl`1##ZOUXO_c*Vr%7e82$K;?Nc->l7ye}g+4 zXicm_H7Drm(5L4lj}mYFU>sb$8?2E z7Fq41&8wHQ`yOoWAh92)9F4j*{LiFJg#*ZjR<^lYU0iZ)Jixb+zW`hvs;ls=vpG~c zutsO}w#{Lv1qWWOJ{8>&Jmz(Y!Q<5w-?3Q(O`GVQIJ^)2IM3xDf!g45IyY*`%~aEb z$l--s`Y0u}{?yG?z&SU2vgOrQ75|Hr0%Tl~k$nxXWz5z(AMq4y3I2z&7;ItbyUV#=y}U%`0y*wL)ElDJMe zqHsYN=EP$0=F%9=_H4byK}P9MZwEc-*wWKAvpSBhY~~}I9Yu+A#s_uUeR=pRAPe({ z@UFBd;`U5Fc95B=`>Q`3PjikuGa-cSI~G2vef-J-bH_(!_MwQURVbak`n?bI$Nmyw zUV@fI{`>(ny^xVsJ<5`9X*Wk70P(pu$Lo$a`G>TL{omqk+@WG>!KA!@ic?9 z{>SK6Gt>5^|7yJD(s-Wn0(UAa6yTg5i9JZ%gXzI&LJ##DfqBeLeH8sTfhkfr$B<*k4}GfnN)y}}h?1cNI26(9d4kn72@miENJO0LU)6i;Y_XI7%wBIT#o)|ooaDq(G* zjW_PSPCa^6>SZruvA)SQ9JmP1nepn5zhv*Uxy62Z>@YXp)66Y7oZmT=j_&)%q_*7P(rp_bUp;T14bkd&T z*4V^i$QDVrL%mqE_O|SW;#5_lBelcD)(*o6D6F<^-%mVeG%EexOQ zkgr00hk_`%tAvkzZqWQrQR>Ba9Xilg!RuSa0J}|3PtSpyGCXML^jEs(kXf>N!N`q9 z*n?JG$ih9p)i?&O=kn)|BE~`1;sdgLDC?KhiUx>s>*U@QMK zaf6IR?f)R7%H~-e?Iq)9@tXSk+khQn0tqH%0qAruT)&7_L5X&H42L%KOtc(;3d!bM z)+x)Ey#oWCTWd`)7K+XAyxih?eJaY$W`%}y4YLMDH&K+{*)Y&q^u(6SxgY!bLZNfH zK0fX}`Qu00nSfbB+a>OiymO0>g*0kvq2B{*&1SMk02M+*O4>V;sIZovi1rUIMhg4# zCSUYSv+i#IhpKcu)^hGL5S-kk?Q6WA@1w1_hqGPB@A0OVA#qpOe4a^6Tv9vk%gAbl zIRx5V+lp>5DOjZW2PVU=7Q#cdW|%+09AE2?l}=DmuRlBsU2%S2BVd_r9io)|X7X-y zpw~tnm4rfnp#UhOG2Ms^ z=HTG{Jp+ezait_(1jhp&_~>T6!Tu>fbmMv`f`5ZuL$_?cL^V|3DO<42AmsvqaA*T^ zvd6EiI{5}1*MPeZ?%h&3xdnNZmGE^EATwo#=@m9yGz%cwOxbNSzn0EU0DHX4cQGjc z7Wh0KqW9jS6?I~7T;1pPqe6s}qbMakzAWwheaTbynxwivIh5sU(vu)(*G z?mhH6jV0vS8K${{j}ay(uN7gp8oR>YzCRK>wZQmr*Tng)KMPsON(5Cu>zBfl?5dQR zRsHDKq2+frg<$UwqXecEmsf17=BiUpn5{VYsduNZbM-h@FD?1^CWMz-+y=V58QAYOqUH7BT>3z?6 zfB(FHbb5Q9=li|yYkbCa#bcmt8HNV1E1LoI3s+&chIdP^^PNSg;=_cc$VZVtBZj z#Z0_5Va21RGsxd_%xl7IDj@ayHGA}3>Apv*mkI%`XpOZl84inUF03s`TZsy>IKJxt>_xTw9Ba zoKx@l3@y7-_;01ovt+{$+k0XBSu?8Wc3(4eg)hLQ2mD4qz4B?^t3nfKC&zA! z@T)}lt?2?+U5?sLp#%7K*n!lAqLyU-71@88Sddo_RVlxVwgm>i!atSlu98ZaCLw)d z6Sj=*h6um6IGC%O`@;p+MDz)m#gP=SG29C zxCsk3>?M3Q3;LS2oH&~>XYF3%os33wsZuDwrGNWbv4Wgq0C2&~lWq$vQp(g?Q3JSj zYnT08f&3Yvu(m4On!NK7&#J*iG z@~IrtA>389!ylFNDq?dRDD(*%lC9YL)BEUNTb4lqyk;imohHmLcLIwMHvGNR0B zWi~q{1L9p~mF)PcBEhV`?8k;bd>!V7+*v$z?#Ii)I=ZPrtYtgY)1>30HY}im@fLq6 zKwbUbnq(QG``5dN=!ml|KmL=d%O;$%5FACY9Rx72mucwm!J~DX(IDGsS{4H8MukC* z){8S75>PY`U2{J>#|wa~zqTgH8Ki&trz!6ataL^>9xG4b|5J1Y`e5)jyS4m{Q~k4$ z+nu5EPfGAmEVGi=g!R_!_07XSRV|mbaJX@Vf_urX5;2PzbID?>-?-lJx&O8>>0Jj6 zG=k7}?f5S!vy3!bI!&4|fkb3jN6W5~0vJ^g?0DZaP6DeDm^W}yxBvqZj01vESg@^( z(rOcIxoH!(rl?t|aTDl)GCW*4)GFXW2YTNWJ4ctRL_}m{iRjfJWime<(O!ZRAaz)o z=VVP(@MT*D^tJ{q|9LcO@h_b@uxFFcArq!j5C5_5)#W*A4; zg=2U2uwOh#FkTOx3Czkpn12>@GHCch#bGkQ^O5%pd1NTKuR&46!zoK6<|7Lb6qZ#~ z`goTV@E4Fw1hEdh;o+ zxBKhlKlRMYeYT_@Zw#&l?F?{!#nXE&e>B4~Ru3oq=Q|USu0{`iE@gUh_Wm_vPFVo~ z0hG%tZoPTi6+ZWCEU3lCXDogPe%mJiY#q-dE(9SXpa&BT5!%=VDnLkrIRU*Wuzv0@ zkTQjG0tV5jad>s*Y7_Vs!t%{eU54>n{dTCmF}X`RkfiJd!m{f1&IAGi5IBz`ZkI5@ zt3B}nl|~06XnVzi;LO&=) zAzmtnqn%XXK0r>-md+#@Vyx@^?noBd+(Ca#)lqg#)u{xG6rNse#?dEd`w6kVfX09v z304o}1s1uBk7)D3$M{J>Sia?1P9Fs49=ITpGz#`bQrfBn!C;JL z#&>tYLh$JoXqljdl>-wDsEQ3_UYrtaIM87J47?>zuKEBJ4jXH%K3UbCfN+HMhKF8K z71)(AAb;t~&>>9c%z-WUD7Z;H_~<6N^qM5CJ1(DklBoc?Ah<#ZqvcQ0?3Z(ZvK<~7 zw6(J6P5l_zav85Lw`1RG%zG9qx>7I8j&DMO3hv?~B+&5t} z&-GW=pE_;{K7e{bgB8^akO~3VfcAKo%FK2`yOx8pNI{L@2J`l5zzl?n!<<{n;6BE% zJ$Z5)1~8z{gqbc+0P~(2{->=Ous19eFWZ)oD4F>#5s`ODcVoJ3kMy9A`w=N>@xZpT z=T;O~kGaSGo8_-0==YqZz>K-#3%kwq=MY=~t)UO)&5rSEzx^Y$Qe}WJz)2#%VtX97 z625jma2TLYhB61LR@f-tl}I8udzdLj2|mpv3E8$ePp3Ytl)B&$UEvMPV*H(Z!EFHi z{+8zeFpKu7KoJ2M9sNEKk_uSO{|^pHh9Q^t-^;0wUDq;QTg@f7ceNZYiqi1e(oDLC{G=!R0m5F6ymw-6;r$8Ge91OHI-tGTvVy# z`sdlNU;?;PXm11c0?ZKrVIG>!2pXEye=DW_GUB=;!t=>bcZ0vCju@TWOK7HA?Wxq%R1ivRrs*Epjp~X_ z*5JoQN$5{Wt%ONZ%iViNPaX9PV339W0jwc=(#xN882O7U|8m*^eiqd_-3;9jToNSh z+{`v2L!xy7hl}!PkcH>H3z{I`gO>slxi=Ggy zdIYaXetFYY(Voe}7=75TxyPBcas1exq5Hty0|)nPX~4cTKb2LHQLk4d_-zvm>c!G< z-p@6lHeh%_XzM4Q>K*XQJH<-<1Zo4l)OYwD7ZsD~YAXyTcTyj#4#@;O+{kjGI>6M1 z@qNjTqmTPUBK2)N-Nm=~H%PwS;;o+HkD@8?ypJP)k?!F0ClcwmV;;XE#1STN6{^Yl zGO$!ozEon(dV$8GVWYRrin20uNP;zD;`GROjV`fmN2Lus!q8heR?UghChI?^b>*gq zeFk=5qX^9WKU$xzuC8u5+2*NE^K8H6bcq(ncSX|N4CY>Di6HuDi?sa~um>`qnM>7a zDWJuEmNuf8_(wF1o#&+`I1E!9B_nwQf?IXz9O6F%AjGZ2tYWzQnzF^ykdc^fpPo}A zgNQhuQ0O_eBWEuiJ8)D>)?tf-B96h?B#BdvLy_BRA!fXLZq78Aq9T5vH;a z7z$h8A5MMGeUOAxCvzC)E2aiB)o{sP;&}M1Z;XAWVhX$t+2m4%JKwLwu7SpTaNZ_C zF5z`UHANkW7H-UGCtD3I+axIGeTF}hWXWJ2uL~*n7xxptb*r5Ztt(G@bR{Lzy6?!h z@0Vz3o;C(D6HK;0cY(E?g%l5f?zF!SM zW@l>0|14Sd&`+{NKy**kMK-#cjrc2&x*a6F&|qjdtx-;@I=pC`{W_+=%9qweW#5rg zl0hGT+?*D^^EQi_kb>KzTuY;Jc~)XEB}>nx+!#&0LvI0AKUGXDqs?8hYcTVE$lE9G z>xj>EnB<;Ul-`6ydhmtwGOHeAT=A`8vPfM758GRlq(El*k~gk*(5&V~kms(QqPX(< z(QFUdBhAe5p7!iBgy4PRXdJH#_H)GBhsJDC)6i_a`o5iJtJ$9O@Bw@`jV@3JE9a%Y zk(}vE7t=3X>MOa@M1hny zN!HS)mv5uj!tn;_CPY>F&sy}F*S&|oa?DbiGzMLw1g}QiwYZlpxkToex4!mxLV0|} zB*kx{A5n<}elyeL03K;!qVb2j<;vs1Vw|K4=?mU6UR?dfhUuptXeggo?sxC)4&U!*&$l~JUgEv!ggI>Fea}E<`uDMer10z9sa&8 zmrms!_oFyJol8YC@CmfZ1S5*1@UQvwX^hncvxVrE(v*B_PA7$~>@4VO&~Jbs;>y!d zwrtenKOS1NeOfjz{LPz_;eMVNOHw*qy`lpL)LSr3%zL}=^Ytu=s9ZUrmC?R$FDx`5 z2TpF^918(iTj^{#P1yw$NEZnoyRu?XE>28qzOignzlb&k7^W|bE1IlP^=)bE=xlHB zs|S!J#>dmaCUo^l@Ai=PM6)Z(pqEftG;9dt`PQ03S+M@|f^I{Y`BTz_$Vh0iW9OQ(F>Xt zNwSA5>FMcVKw)rqx-NYd^BHE^#-h0=aLX}ER~F_{g3n;$<-N{e@Q<==L#kb|6_=1` z;fq8^_%MY?=StowI8~51&&YO9qNII`_iJ@@yu6`j5PO-KZ_|O?21raJ* zY`SE2@$_=Cmyik4dw+u22^B9X>S3ZaMH5kx-cO&-1FkF}VBiHv63G=-fsr1ogQ^Z}bs2MX&(^)czU89{A^sJnS zzB^Wfo>XUws;*=S9o(gN`3lV=i+8eA_|a)%9FPlO_AZ@e1sIQ?DO`HIVJ!LpF>GyV z=A$Gh_wF_rOO|Cqw+Ws7!Wp*f<(0Y#R`V*Ags$#n7S^Pb$*^LN3qG3LaWfkmj9_hX z9Z0wiKU79OQLpObpWwGBgK&W&$jjt`Lo_@1_4#{MF2U5}W}aaDV*_O5XNju0Fm0n4 zW{jveA+_tOu5GVe_ZdPJ$1xK09Z?9nq*RuDSrd1;Vk$9!VLrE4sW8dmiuCv1oKt{c z*f&Mz?cSTIM)E5xmE~rzUOsjWy(MbSj!(zFT`l^p1?VXEEp>-LV7R53*s_^eAF655 z4ZISVdpxvgjSFk&r^lHtyr67^io#zd*fwJ`I-8H;G$$(zMSfdbRi#!v zT>jz|M+jK+>lb07jGBlcqft+mUx(YO^hdKF@{IM9XI-wJ#u%_>cjD^l!bK|ES)LAL zlDnl7OO|+s#~clGxn`2I{Jr}rgvynVeG-dIidiLEsh|o=MhB(RKs2uM*0+{eE2(8Q z2xT&H#>#vGk?LHs=vDTjSZ$qpclsT?U+WQvHoFCJ^r(8WOxUzrv~(In5+FFpd^k>+ zN^2%>!5UQkrYD z|6;0{IW?U!&#esmSi~0%;jMn#84`kVbn0@joAudYx%v};@g>-B^6`Zk_X(oy-VwJTsZ zU`!^M7mC?VxuJq{`@sorbxVAzvI4S1CnnVfI#v7Pe!1kWZM(2XS0)(q4cV@|6 zdlx4zt8cD4D?P)_d-=RM<`u_=%ZKak zMAZI}Z?rRetYfUr&~b+U%W&Eif0LvL$MI82Dn4*@V39)(sC?5K{l_U&RLHX$ANCrQ zV~SEGZr;>ft_zk7W|vQ}y7P~^<9wuJP1l|19J6a17veV87TNe7odb6Qmtp3+4CWU` z$}?Yc2)wGx3JdJusOYyole>4u?I2mY!sVuLP)P)pepwlCh+|g;g({!GC78_A0{7m0 zzq7%0cl`Sc2ZcK9pF%`d_h@Uo|6VGhBa=Pt3aW7V#)OUx98()d^U@$)>Ue`mJS1-pfGaO%v|zGhDZ(6R1!8)ukc!`byXc5 zZHyd%BI-x63*H;e5#i5P^D`EWLza1mjFeYC0#Q{}eSE?oi0<`5eb}cA`qjcQz@z`kajuN)Ywnw$&0=-oi|DTZN7f}hlJmc2#%d5<+;vZX$5q=;SXFe$nf)-5@tr>~5!-H0bh zMoxXZ8b_$Z70=W8a^%+&)MaoB52Vy4+iS{fc+$>YC?m7g=cSW%e41062^duqe)P&ZN@t@yX zxs4u;wLb^Zammb2wb5{tJ~ZI8OwYD0TcvbLBV&fJltlFYuNwM9F> zYJdNOl01Cj3xkTJP>O_bUxp1k-}JxP^XU@$U62}Gp6v;lK$5p^ow53?{)KC~O>=!A z9NA~2n8P}^qrRfI7pE!+i`9*~+zmu;%RlAY)b%`r(dy%>!f_^Yw1C_O8|pxC_#nio zK$L*-QD_vG>?1Eko{8(DwJeaSY698DD2`OQctr#jo@d8D2!OjKGWcAq^wlr7=HOcv|O&1XA8qU9~qlNK8<31 zwo99@m{()tVi&7>bL`pGaiN}sEEyerSur`k{X;C2l0<^h_M? z>JXhjR-XFR+ejJ0l!uvS1zi^N^|FeV_p^D=9KyFyos`3mlLvui3l@dKt=dm`=61+V zp4A;#1sU#l;ET@akYMd7ZL~n)bwZ45lN&u}U}NBi0^Nr{y=7!&5)}4kbv}fgHrtaG z%&O0tu3LYO|CZhKJJ4Km_cE*K89?q3DnwkusA_ExTMcO=0O%ZzVxpp#wYpe%AAQ$? z>#^~puyoASbUSRh1A@^xhxMh{#{-4GvbP_tlv=u6SGIa|%ce!6pik?_d&_Svs8QrH z?p2$KZ~m7WhZxs6;QD_2eG3Pj1wPW0g!z4beGxg0ZS9n;QzN?dlG} z&*sBrsw-OqZWH(u^Hc2!_j6vWQ_{C-!_=#*AQ7uX@rIt>bGGL*eZfb}igEbEwj}+o zrxU0`3}M=w-}nLjYySF0Xpx4`Kc9xT6w{kq{t_nVKmH!pVlOFq2vl|F0q{fxwo5;F zR&Hv-_E4~phU(cEH1|P29WnuP@H|Ur-+%L} z$Y91*2D|~ckFsdTrCe(ml)}(tl$1=u)cMluhqz|u=$b%FbS$*I=9#MFoe-0Sne=Qv z;~IaaLG#-~r6gD5n89H)F zj;I+br@1cQjE4jLpE`u!_GGK$ae4*7%h!uIeB?;n!z|-Nr};b}m9JAN&*gRIvMg5q zaH6Xx>&wNrgo;J|ehJ-D`*R<`m$d!5*k2VGxcsBTt;XHJ3wFlVV1lsk;lxgO zQpeIm?d*Qcy3I2?%J)RVlWN1O^HA2TIc+T#4G@2Ck2?bUm08cq4_+}H#Ef@wKiXc4 zYuO|-DfH~tiPdXk&prSO zB3TBH->#WFE4=3^R6QzAOELiFbQbM&-;);f?wN>%KwYtyK+P852RnXtVP)xqiWGd8v!_BhbVcTER*xzm=^YhO3Z4e>$0H^L6PyD4YKWWolEMEc@HZ> zFov?CCVq9#Qio`!LAHZRMEpIm2`%B?&Qot0-#TQzSXG5aQq|8H2NjWWhW#0y4dlFc zxpP^}bl6}6VuLK@8o{|~MC-S^OdGjrdk^RPWiQI}TgOny9sJ#Vt4;JlF$hs2FZnvf_7(;NFp-9Q4bM^wg z_{P3WFtW@I4SvZVNDj?lcD?idY@=K*^cN2N`!}_qOn(BopjK~rq4xMirLIXjoNs?5 zUdli6;_@BcpV872#r(C$Lmf(8F6&z=VZ4RC~JScqyQKn+Bl*P z2-?MZM7BZFSvt*uS{6vgrFGxf-UwJ-1hA%=Z|BDRaMzhfDmF_pf-%Ixej;zrz1=#l zyh$V9k&t4kcD|_<4vLv50O-*M(L{FiYkWskM?etLav%_1EMYaC|IFg|omHTv-W@K2e zRaSxYLyVPr5{>&2&C9`E>y@&xYY#%XD#t$&FM1rOmw~G#oZneX8tL?rT@`Fg`SSt> zZAl3bcG5&<1@-1Bs~IrsUVE4^3nghp!%^}ZTPxhNk3eISVzd0C{dvL0@_8(lM7oK( z>vlt(&IVEUyCR%Zqw*vCVw!msNhW+m_q)+=eApBBnSGn>UJO@wlZ8xxD6nxiaj3wT z_?lrxESnzuuX!V!C|4X;0`s*~&SS@q9kV$?IJdW{4_%KzvyqC!72c<6q3*lGlby;;O z;3M7~>v?F*z?RkwHFNIDjQFp{O!>-Vm;nP~zm%5ED@I?59zKu0t-dCZbP!$8^XJ_F zR%LzMP$`k@#j0I9ylku28{>%@I;aC+gJsR6>z;o}1$$nTx>!M?xemueaHv>csPF@| z>+MJDZS*sMHShfNYq1}>;B98Z=g;&&YCw$&M(YHpMpw>#dnYQ9h=%pK_Dn~8xhK8$ z>j|MwoLl`#2J@k`-6kNm{rSrvEk41$d#SwIk!*6A_Eoc&RqOvyBc7n8e@=svdS8ctHq73u8}~5iGei zn;fLVvP)2-L=2_U(BFRRj2<(nzeYZNUDe;Rja`GGN<$0Q^egch%=b}V`#T3*OqON5 zA5TQ10qBdyiOmd0{zqOi37|4QD&-TgqClFaaA(h_I80_=;Bet6rg(=C*XIyZ(gcT(gibpOn-6o_DRhxdOmlll37bc^Vw%=V@42gC(P zjev2e1l_7NsCX3u&nDcElq{RIOj{2%2^gR5NOb4w7aOY_ZIn9NL`c&p<#;{?vpS$r ztPlBAWcf4DF!shrfRpLq3%&B#7y?h({=Ph7ilg7%Ex(u`$h%$#xSaSuA#bR#C*i+d zf_-!qw@!~(+QnE!P5x?6+!jgc97a>@*A}?>jUkiJ0cC}(`;UI=L9Y+O`cp^AYV&5l zN=!r9BML?QqZZ6u(ZS-QLXOk~P*V~+g%=xerrWe$h+PBFvV7>#9f->4X@HiU?SlI8 zn?a0s6p~lv0xA&#k^G<$s-j4!d$N`{ewclo4HJ9}l)~R##%Nt|EBp-v)d41)`f!3d zb}dWcbD35qT2Bofkh+KDTUOJy$+KT12{9Be>x;aYjmx zx2NZqanre}hxL%v*zGgT&#MF}LUI@^J+k&z>@hWUjAWd!0%-*=ryS40s8x;OevW(uYqI%Xd+1ybrRL!8s6$*H@lRhf=d+CvG3KfklN-D3jK&`XMT z$Kr4rF+%8~%3i6LR$)QMy+!}KVL}OQAd!UjMWj#-Qzk50Np}lORuu13YW8{PRIHwE z_E+eiY7GTY(-#~1iA!!1ydWex7=trsdVF64ZrYv)9z>7Me>)gGJhIlgFeb6+^C0CV zun4lV3Mg$p{?V`9@gi6&!ud^78MUC8p7p zD6?}=DtNcGqR<}?wKlJRgK{nr1vBN^y?JO7z?A|MKt0C0KYe21wVWygd^Xl9>IS@u zb-T=Ai1+~tq<}Y;0N+t`)d8hC0Ad*BSRxOMRG3Y_hn_U5#Lbf}RBvm!2cWz!GYq3c zJ5jIjoZWSCpuiESLgV3~SAp%3GWy%GI`yCO!u;v(2v2B54Z*mW7tf{D)^sE3>jhN` zc#R{2z~nQ%TlHEGd|cm`)mjaLN}wid0#KlAjYj1~CLBY6CN`G8%Y-<^-6FeQQGSP8 z0gl6DJsYo3{Hq5TiU`xeb1NU1ggwrp{tf7#U>=8k@aTaOekXDOQtu^ByK2-BfGG$# zrel$vr2*$=Ne|jAjBC%m`eONQy%0VK^()~54yW_VYru&TgXI^Y_|UGcHV`F&N#ZXk zuLOds8AkC(*%U&(4ypJw-;zIN%K_inFuWRE{p}|nVTeswN;(BoKdJvTq!N_pe zK7*l@5hs0Y>t@mU5&9q3{5v*FM@Vs@Gk#WYI0W^h|G26_$Dz>HtJSZ~RT9zFKnQcg zOt<8k-s={F@^_+M8fgkz5G|9|9&s?cKLvSmeL9cDc+7w^4&;@4vJB5}r(tYXo%GPr zl-Wm!yMP-+bafIm!GPDoBG)K()x<|k`SbJl?KT1Jc6;`}Y0)pz@cBK3MzEgD6P#`E z&HodNfkG>s$6}v*d&RodwEs96rvc=@*xqP35LD-h;}7cXd^zu5g;QL*!Zw!#oi5RO zH9#Kev9%||UlqfwP4>o#+901_1++OVm~wahVzT)DRu`kZp0ee)lDARUJf1&C6(9Gb znUk`9JU0h&q4vuKQ0p=;l?#yi_tvXa13t*0pq8N6iQcTO0xxA_aA}MuF`VFCN)@7} z>xaWt>CM+5iu2i9yxOU9!#@oZ0ZPv3YCy1-SgcodI-J-iB`Nu$p<4JFh?fL>+(}gJ z6WGyyDn0>9m?*&a_+@mh$$heN#bR2J>-*4~=JYqgc;A@Y&%Cph$ON;SNN| zqbvfPa4LQG6_*B)auZZZ+fw1mfh82?BdRYa1;@n2K8(1eoXZY0(}b$^mtTjnHprnO ze$^U+{{8!HMT#f^dZYGqIE5He3iMww>^s7(@4J+xP`?2q(qD+5EN?k~6BGu2!f;X^ z&SvCvIC=v<^#0;_gF|_H8TYN9CKthv8V`zes?bR_hmr={VS%XhDRfw`0cJ**92)Qn zC`W(_004*6{HfC1N1)3LU?~XE=F9;-NtvG2C++l@n%8U}OYK z{hQ0t*Zso6l57fvTyS4_c*h!TJaTobK1M`B#${M+@EKXHcG2zWZ5WGx_*YRi4e{*U z>hS-H`VC3)0HXwBqdv?~C^g7hRPgHD0@TGh^MIbArN`}aeKaGIVgMvoEhFl%TuWyn z(&=J-(foMm8zb50Czw8dFof2Xj4!9pPUE7an|8;sKJ<`*bZ&?G_A+)I}E3lj?};b;^QWvSwX| zVf=Qo*ouVTcIn-K^Y&;>KrO0BT=4d@R90vwSgEHepzT?3U!TGS3HU4AKZ76%qchbW z^VlTFv!OE$=`d+^_@=$ekq56cvX~b}>uU$8o_=dtazIZY(%}i;CK(XU6(8`=;Evi# zco@Q7fJG3;{8M`*4104A0u!P2Jil6e8BK%wq}s(S`}Hq zgB??>_)%_UEt%d8R$(atc-xdBJu7tH4q6A1$M1jPJ-qz;sad` zh}F6FYpeoU?jV_iYxO~yz^Actq&*R3R*+M z0W3*W!eaO6M+Jn&9})Z#i_q1Da;FEEG_#$2v-DdF;ARCk_1Gn);(wD&U@?L~l|+&& zmQ!@e1fq(ZCKWoLO*dD~AW@l*zP0FNM&$^|S^%4&rmL>pIdmZfbMg`{cSFGub$lv{ zcR-+A28sn%FS0kv#^1&X>MU(-p-1>p$N(RLsyHx8 zuv7+j6&i)M*e`afmKvl(!WM-!e5-sEvi9?_E%q>}4AD#}cdnsVkl89^BebD#DvAtV z!KK4*4rGIdLL{CZ)~SxW@BGas-2zHx%bzj(-&zM=1ys@OB5KfJjRK7FA8()ivw)JJxn`Rx;0zI~kgK-I@{@Fd_g^y{}zxloFr z?Zsnk~!&jHNh1@W&KKRqo8KG9FN14KPXE)OhFKE z6|C^uneX2H6FUO!89oQSko@;#%<+A%@tkKgPc)SRX6_oYwXxj1;LWwuxDxpnjWc#l z@`O@{;|@QR>)^D1h^5x0iwXf4dGM?Ihms_p`Ej5ugDt3c?kB%P(F+t#?{5Xy07HG_ zW~<|x96~~jxo)W%LR1%aebFr>9eoX-2U8_Qv40t3o=jbK?Zl6z`T3ddoz)-xMxB92 zQ&W#$ygx}5caRVkHkPZWr$U?nphdrn2spA|$_138P=sPsse5xL8kBh*d}!JjB;^I; zyw3~1f};O3kQ2$T?D^CRznTz}7HZ|3-$q+@Ezo@WL`r_!Op(K(M$%cLjuVe}d!plNDs( zB)Y~#zS0ddyat~gl!eJWUo7mwC|_hu&Y$Zbgd`nYZv`O?Qd0{T`hCzqeS*eFSCLau zi+$*4qf@6qyC!3s!3;VDdr%S9Br8gWvH03pOrYjk@#7h0A9v_C5oUwbH{V{LMDmYEs`{l7$ zFvRB6728AL-4q#neDhC68+-8LDh(xCo?%88!%_{;9zUu)E3xp)tfe_5yZUtC8{WZGM9UxDepOXBe#O`hSSD%4bH;wB z@3F+<5*d5($l~49*I_$}puAFVDf9dn!e7`m-=$b9`kKd1B#^;^YtHwaH%Tr)wuRM5 zZhZzLFiG}qh)HkEWq4F+V>RE%7)3xb`4o6TiRqHFxk<9@Wk_h+9ygl@Giy^+mWOQ%m4DG2mc!$`a`WN1$MVicD{!n_# zTf@s(7W)L#b6~N(xdwg$i;cx4x(moG!aNJ?mg(xV95;-H>vRr^k#;~5y^(K<6I5Ca z;y*a=Njv8Ngp&wh0O=?GylUN5itTiAkWff#yF^#vcoR{Ref@vyb#cI7poNhbHwtAYJ$IF);Ji$c6l#HVAlg`6WQsr<~c0MCbKy_%Py(R!vm#T#zO@ZnX zxz3N|KBncP?)??;tbj2Hdz1&SstN(?+{Sza+qp;8rNei9iA7|GTz`2yCFWm{@3b zJrENU1C{T~mlcMY3p%w~F~%SDW>*GAGJ1HNr0k}t|5iPr%EHv)DPO6UBDzi-`#4WR zp?TC65fwAR>2G*#Sg}L}B{A{S`k}%0&JehudU81$dj+xp;n>%`HW3MEK$=4HSrqQH zAJ2ilOkz=*e~TTuWmr--iC#Y@LNr1>jS0f$HYaY2Jh3nzd(qA^nXF%Mw3v@UM7=M~ zeo&`rRDDt(tquAO`B))T_vPvOI4@F$WZ9(qIjsHGluHrzEvN;7?rCwtp~Q8b_(qP^ z%|-j6$&xp9Clo##pHC*BdXaj{=23OWDCX>j9o}jUTv(66$NwAhfRx-1wCa#qF33z% zL4746QpFW0Gt-+xoLF6ll|1#pNce&dQFZxbI#-u|;Rxk44)kM6ocW7K5SFng4&d6t z)lG}x0s)xE3A~}neUMC(OH4E{9~kY{HM8mUr&pAPtW32F z&Vo=>7)qW$LzOGh>6wv!_qs70HZnh&shLZ}C->HI!A+%Jg)Y6hVV&<*TK+vAG8Qna3)o*}vxV>O}!+gsnd z^GJa&aJ)h5+N5`UVJ>o39PccP2(B0=M*-MXY7UNoZ};L@E!Gcx?=MKSDg0AdzgMtN zffS3@BomPId^RpWqdQzRREnjUty8Y;f98GWD#*DJQS`4kML;Xp8zSL$@wdm`ZuuOX zzl}b*cW(v84{1d4?Xg1P)Va?2BKF2-?(VI-Qg2~^iPqf-a8M-$1NfgvtFxGo8x4Gh z72jo1Pu=0`xw)Zz70)VP#z0So9%j{(bRkipjf4p6N%V2Xcn6Blp4#?gPy4bNmu? z&l3R;R6#=8H23cjEU3ecsJoNrd*624NpcasllquFfydR@S(*|5GQ$Kk26#DH>^dY{ zT3a|8gP4_1yZ4kYUdkW*Rqtr0Dnj6IIG4`8!zx0Eg(nT!;pNsdOGjFGowd2yB&bZ(yfAz&aqhvGbt-+u1ANl2@Tr06A{z$8*Y5{nKM!je-wC zQdFY%L72cQRiUl3TVYPusnePotpIm}wh zFOD}(Zla#JE8-cY1Nm#zE6<|G?2A!a? zBr5S?#*F#mIXlxFb}sfWDIm@=Ll5rcLzqzjD-i!p{Q%eBT8X((dC9vaKZ7~#0$g$Z zd+%8uR!G8mfUP`b-z{t4BK?AA&#l@kiQj#w32tbN|_oPmgQY29(Y&wZxmz{Hloh-+PCC3aJm{GZS7kw6^9}&a={N8U&pVLn4U` zkkN-A+WsS+u~L;?dsS7?v!e*V>MQ!lSj>FYbqtkoLoTIb8NlAlGxGK6h^(6F3;m;{ zL*XIzX3$&?KcM;0Qo$sd`LYcy=qv!?(2)$Sc%k14y)gg)#p9MuGh;!3bl}gwT7Bid z<9r?-Wgr1JzCWspN_K#F_Ng5j1fdfcM__meMPv}Hq4}+TfX4*%jz6$GAU9K9v@f(@ zJ1Jnk2gYQ)YJdJ5NfGKb{sm73?2+0z9P{Moc(j2UwB-J9Q`9A8cNm( z-T?2;WzyfqrwVdZK#>=qxVy{sz&`*hw1P_eb%*E)n88Mr*v$xzRP(h3ZF`C%pt#tD zP5}(T;(>5RFw7tXdkar*&J8aQ^Nsc3QP<^}es6Gz^z+;Kk1G~!ae@-WEt=pLxGje) z7QyVEz~2D_$9QjFP-T63BmV^Ag?@<&?%VTqepGJdqa-0gNEfJzqM9e)7LL+PQJ-s5Q_QYgbHLZpwkSvyHY{Sb0Iw<}H&o-_gteXRzP z<)79LjY69X`E9&TJkoJ%vOSIqU}q>_2cZGcJb&TB@FQONt@c!UZY0{SDa0~mm2^QD4Fr#CnM(d1v&q9{Y(wSk_ni{B+1r2QFYutmDgU8 z;77~R_)N^Tb@u6zliYf*&~uc!g!d4XZ)xZQYkh?7p%2Uum%cgSmt(P}SF#7jDzZ0< ziHT``Rp2SwrE zcc{V>*t5GlxxJ)*4ns@n4(kUB9qWWK4~QF-Jp95y+EGX z$UaRm@A1}huRCizN(tuLAPJe`r;pseO$Cmpt?cFfXE@2Aqip3PJ9SDtMW6sYMUg;( zSc2oKF4gQ$k-h}*%pgQ{tPH+Pr0RWWH<+fo-(e=ZV z(mpB$9v-iDLKCYDric3;8J#)`Sd9#PUa9uuPs?_hjUDXPQ}n$mK1e+R-8SW|uqs;0 zMi~Q`fcAhesPfjxgaUP6fg>~k9FCxJFAISh{!TOMS+9iK!?24M`>lOTW_AU;QfFZg!x`S&r*5$G zdNc)Xo+l1F=F;q3iGG;f_x@Y0n{$-^sfCNv`f>|VLZIH>>`Dc#@ohLG04kepEk`fSF#G58m}L}eLtzC3=|0jd<}_mZue!QNuKGD`!kk#G-X@jYk0 zbNlEaJUbqC@$S8Hh)DP(BeWnvs`j2BC)?g?q@Y(h6I$B9kWy%%mR9_Ep_atD&ln8G z?2QuB)YIF&sdyGjXZ9b7cVNr~<^d59Fkb}4h5tspf;zA5s={6IS%QU#)%@Ui?m(2$ zlRKEf!Rtyi9Py(gDN6N+z-X24Qz>O$Hqc^01l6@na<&8*cIE^_C|AN(GIg?75?VY3 z5kjXrE)wt}`=lC8FySEu!f#8PC$V@=?3PU5YpM=`1k^PoQG#O;*p1z#eSlt98M6T5~&j% z`_lG8s|GgI-3JIGu3hRiw88ZxvDnDJ!$%kdWa!1*ze6CDB>@*7RLm~j#ZubD!h2ZA z203|M=LF%Uk>|KLIOh-2y5iq>@cJXskEMn3iAaX}2Pt>(O!5I+f4;4f%nb&yyZ7#a z-;hD}P-0)hLnf6KRNT*gFfqLnzN-ATJj>IJ`1eRzf0kSOHrE#aP)%qR3Zug zf%&$N%8ICO{!?I-yruCG#JzGeoC^8#&roOdr0lV?JrOiw@EHk*X7-sw*1@OR_Ji^d zd5~bnaE{%|$MH3+Eh|TFy~XRd0eHSVsLZawAdzHoe5~~9Q$%8;J;R{WgMtLx>&>gU z6CNVJ90sGaR;j{?sBgsJa=4U2kUHX%zvqN4As(@_92R*J?EYVpHtl)O=ew59t~8tU z7W>v9m9imoq`X5>;}>(ReKYW4{R7bHo7nS7w| z5!5IlK@BZmZDY~xkQDjE3&trA&=vaoDnq*`_MEiRAblPy>5;-eTIRS<1v7e;We+%^ z^b!wldfF4+hI&6XCWb}3<=l8(#4THe-0`&*?V7=bY@1~sp3?jCK#~+%gS7eswn?Wd zeb$_6L5m3Ol>x_616GTllXrHhBFzb@L#H@j0Kc(@j)O-mu9fo^JiiJMdkFX7s2x{B zodmTdQjQTOdV}cfA-0(X2MJjHB7ZfrSIk#gK*5mgWC+5MOdAVE&QMh10CELZ<6YAT z=!lVqAPK=-uCJS`N}X=_?Q^a=JhO)a`w7|qTHh{=NR)$gNVopYRoL|S>&Sx>QR5!U z#DB_g%taUN|CZr^o*6%Cis&|3wvi=~`WfKdFt=PNvsaWcP}9pmM+@+}2AJs1(LUVi zzx}uT>)444g75De_I|=i>@L}@ZUMeY-q?R=bM6{?e&9s_$0ur^!5*h-vp2C+3T8(E z?d^(B6)eOyCFwFmdDABv)1w4t4SGcw$jX%W=2smP=V;u1RGzX19yMO|KQ zuRSpP5{sFU*0?6Ze7_jy8z5?hxLy|~@D$t`1`(I;yxT(<e>A_azdjyzc`JDPUVKXen`yJLOdsIJ~7KgQ#@0 zYj-S$H<(@Zu|(B_$bN)EE9Gci^?aW6QPv)710#bHsuj`I|3#ldbZDn=QUZp?gNXB( z%_`}R4?CvJiDX~Weyx;1BH{G^Hqk=G3OFN@F+d;jhTV+XV!}QN%9DGa8JT@T!PYwc ztJ8x3#L7!`HNnakhAM%(zrl|D3dmIOqvBMZCvsK}W2ivYwt1=DncP{a-~biH4cO-c zh_)_x_Ih(|0GRz-eT8VPKL;1=s3doRRQ4Au`~!yQzZsD<9Qb@ozi@3jMLn|zU<$C0 z6H%AJZF-gIG+YFisca{M(iBGpg@?2vRKflstz}_lehCEEzfrzD(*cl>&~IhcKW3rR zcmZp3vJ7U0oD^ZVZG$lPvVx*-V?(N&TrC))opZRWB=N}9Ewbz%7FM^Kswod+?xDE} znP8Aj@&NzFFZJvOsL){AJ9wgj1BYR=poD(OX*3Yf;r0%7cVMmo^b~Riba${+as9}d z8(8JH6h2iK4m+j=D!w#QIDR|T#Kk{^Vo>?sT^nNZV8onPJm2){-_lsyrE`Bs-v2O^ zQ#Tj}!fyjLE>!La-;G_%U78x2U$ahn4vi$Z34`p8>^MPxtR)DJs#WRjJ;OMm*bgfG z=U9Upeg!E=tyjTUxT9*fa!N# zp2uL3%GjrZ!+DTgJBkYeomEvnoBuW3-_;?`JaMiTmb}>0=d_`~&1B+am zLGg8l)-Ps9_splgESD^aNG=dyn5xImP2glJibzCpsW^qF4VBuMY}(1!AK{+4jlS(d z?WM>Ot#7Zq5=kDCP02q@&NL5WBnOv%`FT>+lEa;U^l z&Zon#`U1{L>?O5Qc>TbIz*#-&=?w#3$PN>m;KiQpP^^AWw>_3y6!S64rJi$zvDuKF zS#MODYtz^3Qtq4Xbk-sTGdE@imi(j_ct?1vX2<1ihv$nfze{_aQn-F`q#Jg`o0SY+ z4YRDF|DOA*&7ZlXyeP1k9HVgBNL=dJEIF@7%%mebaYMN;lOAi?^PfU(~7_U34QeYk?`P#9= zTJ7H1McpO;izhG&3O%^ec<15g)c72Tbd=Dx;c4XCl9XM%GMmrVp2?B)d3}mUDv*#( zr*81cV#CBZnMs{NXZhCx+dG|2#es@O!S0sjDXFQxf;-=&mF$Py>Oz9oK6*7UBo)u4 z-6dRKO6jwrN=V?qy@K25PWY~5qK8dEp%E|IrKRcWxv>r~u;+Xad6+$%Rtq99CtnqHT`S+8VhiuRP{+d(9}Aw=?~Fao$R1T;L%xZABkdQG2OC(ng=2(qUD-BK^*B zv$A5BFsp`c#;jg*n;Q={1$H(qKGZN+PgT>x6H~7wk55R9o;ZyjCLDIt=Dnn*t&t{L zLnUsf8dD0EzqYk?rY>>zj8cW4V+!DMPM&XbVmeQN(Kf()oru%(jF6h%?p~af_Rp$2 zy*3-O^7ScM{kCo1r^O=$9ME|?!6;X})VZY|{85%MF-fgxYo+m8uBG+pkb6S%$DsjL zUB^s~>5gQc`BA@9mcwcaS;pb+majAJk7E>ZyNy)uUR=X>W?dqz*2Ivy!Dm^(($OD% zD^0gmE3@tu)>{{XzcuXg=%JTuv#I_WKX1G;%wL{L^bZPL*tYwj%SR@9)ScqdN!`dR zZRl=+|B2<@yVpfND=jZ#9VNtQ)8Iy69vvVTX=&LQ z^^=ZgWS9UUT&+Rj592)6ckiFc$jYCutZq^NnxU`6vd)(xdnm^2DveYAwk>nPs)kNu zMEJZt@C|f{@oGDGN2;#ziq~`vxb!*KMXKKYAdjI_Y>9Y|I3#Y$%cdEvrKtZ;n zBD;u3c*P$LW1SYh8}(-2PaJ{6i2SP)+S6-TwT#BRas`T?wGM{%JyGYY|09`$3$k4-en4>))+NH|qI3 z=HDtkl0D+{7{aaaBB}jsvbGw|TkTA07Q)G+5F^U?opM6gzbd?!3J;k#bSEU|UYtqi zS%`P>_qVQ67^PYH5*_&q_UrUABmsO|K2BO3MI$MWqPLWp5?5w|NB*z9 zFMot`5Br|6Obtuj44YAr*==s)>*#Buoj%zNC-v80?|q(J)Ktl$#8l+XSQkHO3~#)jdZAl zcFnrzQFn4{IggvV9iJ|&m+OoZCBVzcsp^)V_q2SK&*i>ufOC0n58Ydtu82d_cj7*I zHW1bk)r0=o792435^{pY_!E{?7A9xfQT#h#;o26Dvyr)vvkWo5;$HtkFE9Nm^@)zq;&Jy74tTBB8W z(avf<$hY^-c2(7!f(8YRlX3+ASuwJ02_-EbbxJ21eR7M0KG92trs4d6oi?yCb=2Qd z7Q!@F+H?ODZU6l;lanC+cyQW%qtCO;zBMQo!iMIoJExy`83+VSl{rgx5Qq+TtlXRu z`ZYBydW<$nKan%KApO0oeP^dCS_h``hhiT+K4=UvZ0x)5-s{7LPfSviX9E%Y4H!Qa zE9^%pS1wq1H{WV*X7j2OW2>Btj}ioC+PO6*_xRcyx||$ff5mnooHz69pXiLho-Kac zXU^{ATR`X)6rP4oT z#JW8m#~>+k&P6R>buUF3_#>+Kwc^! zoxQ$4>~g_5a?6%o;GO){=aUes!?za~FZ36?Bg#qi!*p||ubh^&Mm@tV$l=h*TrlQ( z*Sm18vY*MerKAP_KsZoQq}BIZ=k3B)iEkex8|n9-ravlplLnXpA`OACwN5->k2AN% z&1>I##~>%F-kvrTWDXt0n0XeWPMI@!JOaR6i%MsQ>de(#)!i#+k6F#H{3wxfx+CE8 z{j(~PIRMync6H9t))t*r2b~j5o=K^a2Py)_)bC?e%g{85M@OG6Atc&!q={<&g>8PQ z8r7&=ku;gN!Wt8EUuv%8dh5f^PhI}SeNXpHfW z7xn;MKx z^NSyzm`HXAR4vw49S01NSM|#V>}k4?Z^ZJB&*Ueix_T_`mQd(}Q2$3a4d@-X-b8=YSTC?fl;Z%SnNxF8v_Hck`IM)3h+@*WibJ4xEn(7OkW8_H{IkGU<+$JqJ2Wp7H;I55P3 zS3JGlCOmj`hPP$PHynNUb#Zu*dD7CK-7#<$500;7tiJx&kuoJlP zJ)!MLlCmI*GfVs#4|up|KtP|mLPLY_;-}J_Q9ku?J)_1(IP=OFah5~O^+Uy~s@kh< zj=+WMd^1(5ho)Jz>J*zufH$-C>_L{`D&c=5r1@O;7~e^bY=txL%9h@7G3I$f{`?m; zm5ru!s&y7Nzv>-@v}z0G#GygI9YSfo4p!yL$&SJPEfP9uM>$q&?S;sZ?e^G1=gYR4 zCxZEGGvnW0=ZT^FlODJEV+G>sB!iLw-7fuGDD=Npy=khM@OJkD13*mk@wrPCD=k_G z*7=m`?xb49L}O0bn6*SI=H7$EX0fdn-OF;n zV{rYg2BX^b@3(VCOZwfkT)s`7@orW{lJ$k=w3-?r`}gVYrPA5i0wFI)RRANNEB{{7 z8l+B8;5H9^ktx6YkLo@Bmq2oq`$Y6msnpC~Nltkj7g7cd{p|9dfHElHQ%>|)IlPQA zQ?Q>G#9WfK%%6 zR;>cKdaCzStIg#XcMw5%w8UnPzncyj5+jd{}DF z(&SA(Gh6#+2wG6+!LglB)2=Dh@rfEVCM#{|@8_s3qQ4(n)8|z~W~3wb=J=>TIDJMM z{EWJ@f@4Y;-_G}$*hS)md~#&9Q%lEFJdfiIr;mGw9+`8%d57HI%!0_L4+HmSGbFC{ zC8WHzxt{y-nA^>)_t7E;N@rH*%NVt($a^Md7BdPVZnG-k zPzJESJor?n&QlzH=xZ~I_`J`zwc=ps$9?{D!_m&Y#h2@-Pt#kbW3^(*$+8H>bO`uq z2|>jVO7IO-=FTfYYdc$gCYUiYAAb^*)l8$wM+RR@7}>PKtcqW_*r89fMA|DxlML>S zDf1^zz{yE_ajFoKVMmFIjLYRSS3g=J=KaJpy@m1kn0N1sk_$iIE!>@4C%^uiL#;P( zUYn9gx$uRZ^i)1_RB1xxHHW!8M7mvx0qH~PKRC283k|kA32&QH55-;1m8_o5D}}QK zlb2E^m=l#9Miy3(yH|)(=cSnEDz?C9*c@DHQM_^lzaQP z7}3_TwKhnt#k0WYo^FUvSFA|&ox6^2VOi|JLx7uFBX{mh6}Ju`bxL!Cc18$4Uc~bfvcL=EQy z5xn;42ZlE?^Vz;$75e7bPD+TCxba1^zj7E=k;6TeGktjC=oN{@{s4DCqKiHEmJ?*G z-Pe9@REW)~bswvkhfmuxR&uV{=k%R(dj33nqGaXAh8jOd=?%(9UQlWj^5l7P3SfeP z@`fJE(XHqTuQ_&Er9}1Evb9gW>LCjk|3%exu@V{q;~L_@!wE$f+jsG8jT-cB)iDOR zkRCWk*r*e@wU_1pPP-~7q3MIv=`Npi*j`0tUi?}REWH`ChM%KQw}wiE2wU5foE10n?Scvl%gJ1Gf+-?e?ff zilxlG3Fl|i83GEr?=}->*`5t267^%5QBtJdZU&5`s8XJGIj`dHTK4<8yk(!iWgp0V zlJdZ}N0x6Q(owt)Y(*mNkPH9+0^L_zG{pDK80J|eQKSy-=vIx)oXUO4*q-~AKaxH4 z#y?llsBLwgj`Xt`S6iw|DN;YbOP7i+cPYahgAr1J zdI;|O?{x%$*nSVQ5SMw;Rk`XJgn^FzJ}BJjOnFhUx>*!mnO5?WA~%B+ki|H%lo(+w!XpIUx2aYMN;@GEpj|G7#jNmU)b+g;(nQwx35cKARX)ljU6~3=38C+j6w=p{j z8^`9Qo^LTpQ%_h&sdk+G>D7u zSa!0wvBh2_yUS;FUn%J`0%fCY-HHXS^8C!{&pu7JX#N1FEtNrXEM0%C+tz)L@i7uQ zC4?(M5?WKG=a4F@{k4d&Fy3rH$nf{54b@fP=LD|VVa!nJ z;hAmu-tj1M(LLXR;MBPeVr_-0ayEmNS2Mn2&g(Vo$bdAK#A(VB08eLAt6u(oy3$wx z0rT5Q5hQ7B*5}PSp={PPq~%+Dm1>t=B9zpxdIz!vWO2r=sDNW;NsLd~;(%#30^InO z=bqxeERyW6wu%}MziF>`pR+h^ISVgAIcxVmw^Tf-&A@V``~303b_3HHg$soq1`$-g zue!f`Q!`uaQKw^pRjcH0&lMi}t-4z`yO;N0v*`L*@X6-#2$Y^# z4T>~3Gky~;k>3$2{M5$dEPDmJu|9%?8Y%*YUw?@MFkI90@DAhL6Gb2Eu#N&RK=-s8 zj1qHl3iVKEr5S&anC7ibDR55UUB&C{2`58~+2WJT5x6)~ZOj-epT3|P@=qu_O>4?d zGcR8ssjt4hK~G8I+uyexp|R+FL7=+60umz~5-4ol2Z4g-K?K&)-ypD7tnhk5$+bL( zPSu0?BUZMfP>W}^OzKt1N6JO;&K=&2-~2Xc6w_av?n#;l0jN5L1kFghWM|)3-#35g zK6G%a!3f{Y-sEV9-TDZY>h!-e{D6sjbaPM3rX7W!L4?pJ;>SI6=J& zW|!c*l|hgYE);*XY6K|phliqv4?lkXD8^b8GsZBMpFAhv5RmAxUf+wY0GNlLJ&v1=*CjNhAEPJ9N9OWMU~PZL z*dOdDJ@GmWssw#S-#MXZN@soP9AIw0*>ItPl))E{y3bvnPi#O-0$K0?pZb1)0nB>1E~xg!O0n3r?R^`awod%o6Bfx>*~z7-$qW5cE=)DSnqfoy$6p<;N;F5H3E!z+94jEt;KCWbg|;6<}K@oM0M0vNiCZ#TiF zuPQ9)vHW!npLo09QEi_93I#UP z-N^+R9Tao~k{EaPu>U6!RvYdZbAC7N6PWX|=l{K#iUqa)b5x(u!SqW2r@sB@<}i6P zDn-8BfOUuK--fRI-Lh*U;(vg3Ig}M6o$oRPlVLQy4X|f8FZuFsxBRr>Q-9EnNT#msSf~_dis+Wc>~)F5zUx2iLxTMl>>U{JkDv_hR58ag&RV z4aW@RCfw{-@PI??fL^d`(G1#FGyeWmT6PJP!>5m?y_~n$&FC)FnkE!2jUw<8hVJjIucKUzVp$&z&1}#{aZC#{-prH!M`n0az?z zYei$AtzZIU)c+o114z5E+F`^+U<~eBoqfsM1q1>aBX?od%(aIMfN6Bt+!O&!NNBLR zks3M#nNm#C(A;}7+1hM4s7!|Vvsy70N)Bw@>FSIYetRxXC*|WRtp4Hw0KpR2ZfML9 zjHNlAhrX7NB$f&P4sR(N%G5?J$>#?hx(+|l9sCC`WJiOv4^?Sj*@3ZS-ZA=7 z-q}HE0_Qn34_AIXd^G(N3dJ`*k>Y2o& zGV-8gu*GFP!;zWt#mOnB%_$twt5Q~8*c$j4&L_SNqD@lrBUZypg7|h=WN_!{V|5kO zjI;Pha(&XV&}KF7zcwcCU@ze+c*VEj+y81iLOJM-3BBQgq4Cvt_Qei+(5j(+<@^Xx zaH48OGH|`e+4$$8ZHZg+ZAg0=J1`$!U!Bx`iddDcA@52m90vLbad4Zzcz13E$x7hc zx6^v`Mi=i9aBaEv&|Gx6`wf;)`>$y)jLW3KM@5v^WpQc8=xOqiu^zK30vu53Zt+E} z7OBUspi9v95aKx7{|lss&4fvo7Wsqdm6hpeY`7}B`oYM|x}zAJ!KO#fgfm*BhWwPs z-e@)62Y7{piE<`?E>@QBho-pHDnpu;!{f)ySsyr%>ePNh$1Zm?25+`tHoh|)i7T_) zQB)NCzAyiWrqR_;K3a3|=m+30(;4<1(0n@7H?0Rx^$ixlUxMk@>szGsJ}j@CjVevj0Xv%IH~N z@(!QVuz!V&od`K0S5`m%64ve4w7F1J#`xAgUe_I(x3EB?3W_y!D|G8^_LuM*H`lSz zPtye8S28x?jT}Qj8BT_(mOv5beYVVCAf_L|0)A>j#nx0uW?iUb(Q~Q1p14Zy-wVr6 zA=tT=Ydy-D4#1&A3rjUQFtoBA)s{WZVC?O_fKW#X5&D6vp6SU2{o5^ z>o3R1z-2?1CxL8w3X)==n#l;>T?BGuZ8_}`trTWe((*+a)|?a1m-V;;?Qkqr-p+XL zGwkZH!1kec3Ov0@2)^jci!iIIWga#ZR<4gpNU{|~5oc{!OW8LTC&`_z+8A-(Kv7uO z?L+AE3*ww&>ty9(MaT%hB3*y^?+1vLD8W<{`CJ|{`7Rq%(E|xy*=^lG#mHSP6vbyr zs|{0n0O8o;)Q?^MG4!vFMrbY+?ywwd6*`vX3405W{x0R%Tnc>~iAdi=PPr8aBX;gs zl4(1HJk~i}%TmQI_ZROj>ZLMPJ)@^v^>pbcNGIV|EcH^8G^1ybPl!oWfNLGgG!xnr zL?0CR^679!l`k;HAFGAJR&crUM6-!*5MTDuaPB~`nBA%|b&MB9i0TzwV$F9zh`)3{ z1{2HvkPr3_o%O(kQfdzKxpG9a2(lqG78HgKJ2ReuT8e~$=Ve@KVjq7#m@7O-jgis# z!u$wK3rKEU%VV)ceWb0@tifnnQ%&a%1aQH8%Uge-;)@Qd$@TE$TO$unF#ThO?U^M& zrbRcX=F+7%crSB3+}=YTf?y)|xRMf9qp!`XT)GVxapo0a`)GM^FBVs`j^^H_G2uu~ zjs)(UT(t8K)EDa~Rv&|FS3$Be4C|?{j>KcgnASe5$|w#NGelqlg~FxV)y3`!t4C2T zG_dFql^57^S%O6nv%`-E(G5thKv&8kDRg`i*Exb4=QEB`L_@@v_m0mM7V|-f7zu?L zM?Sx%eZ;oP8IdVd+FQ9f2Ds9W61T$=I>jy^Za5*dI!pzTHMNXE9(KOy2)sA!<3bS_ z+gMA;QyjwKaqNcVBJ6xW}>^x{xY(Nc)oOF^|n z^QCR$d{b59-UKq66dDu18tpTyf|~{gsnlZD7Pbb#AY}saa}$SXD3=iYXaWn>MES#n z7K}RoEyQ=Ixc9Uxw7n#KkOT1_xOlM_C8V-!Nv8bylV$Ju_B=BGU(P5)&hP9bEjmeC zN{?(2sKdq)znbF>6Ul>G6|gVD%)`7gyb(z%MN#!6>XpqF z6uNS68mliV?l%)bmyAW6(_Q zG(1!}Og3Kht6hv9ETQ=Zu;G$x!*ZPEqh2dwf)jhghCQmp!r0F~HYASjL19&WUxe)l zBW45uCzP)XJZ&gDo+cg`r{Ds}^Gp$jBQdS=4dRWIuQTrSKyo;<2?n}!A5go3+V>^* z?fG8F#nFk&_QyhYAu^zL|mbT;BLE|QgBtGJjwVTFdo7Uaom-$RE8 zk)f6dvjR_4!rE!Yr89Re-UCHhcw4$UUHpxz9yw_#dRT;cIZOk2ZUCM$O0}Y$rIpc^ z;Sc0@es|AjGnF=ci&_tYH_G19eV4MOTNzx2_`xq0uCj)z+>p(RWe>%^jm6?=4%nJd zEYx5(VhylNUZDvj%geaV~Iz)E4G-*pxBrTLOhZQ36;nbejS}+5k;N zZx9(<_n=@Yzu&eq;B;7lgK)K>sg^cD`=ZwiS8*>!3aB^Pl7*_oM3Kr+6<49gM+_w7Qag8SXp%yF$*k z9V90a;T8+wWDG}q61tau^#(bmO4u(9=+mnAUMEvR!9=JtIRvkZ^e-EBKzuSFtI;-X zMIS;W90jIFdG`sUe&f7v=oq`9f<-!{#Y3#_9Kgx)R)l=*BGjwhJpwag8OGh}8Pkx*w-STLym>e__P=pfd<^6{aqBnOy| zVuwio>%!W7G-l888AVrdLNjeQ?JzcK-FfzYFhM~RNKE1tV_8vJ?j}=q#wWRPh214Q zoT!rW(}J6cl?aK;IR;*S^oQ7pt=G84juUsJptU))xwTQN8@HH4#Gv?G=9xlGu}|?V z@WLIE(U^5kZ38d+^wxP}q7jTi7F^^aE#jrh(Tx}r8JyUM(5i&AZl?T9UdAOXfxQ~k zxL|I>Vw<2Xm#>)rGgCLw;*20lg`D<@*`3)c#AX74*$`-@WPRM;eV@YJeP@{TR{s1> zT-Kjt)|H267H0Wp?Ar{;lnZZRsH7JHgciPTktKmPjQmy+Lj__CEtRGlx|{HDC|!Ji zJeKMYL}N#cc9Zo<$4R?MTp5;a2E_S;QhwpX57wR%1Xn-Yl!L5=m^QJ}2lYz2MTfUw0(~9H{I|f>sBJmiu9f5G z3h`CBf(H}e9A1nAyMygiSKbYv>C!$#45Jx}^-8R%C^41gz##4Or_MHEz%K7ImFO|} zbW=_d$d9sMn^@J;FG3w?f77mG$F}D1t^RRQV(;C^I&FFoJ)PDY6&!?F3Z<}tJgkwM z1;EEOu}-vQY>nPDKID@QNm(G*8XL7di=CdTDje_P^L(U2P}qeKaL`)dOhEhbJctp@ z0Y%QJUJLp;GJb7QN=j*YX%|VEKu(DUUI@2yS4;TE30^ZKQxcG7yN&-96&o=V#ChV( z0)uV6ynB%m2w)WvPLYo$nV%(lzS@f&{U+ z>Dv`DAlZZ?qnCY*VJ4#wuaC{UVYRjjGS4WVXd+e0_?HCF#@)t7t<(rD4~FRMJ8=R~ zY8>*w**i1U`lRrh;O}fjvbe3ute+F63@(<8xAw-1yLO9?=XZCxqW3Um2D3k8PM4G( zBQ3|R_FtmCs|nUk9JW}srrD8r_ofa%SnR=atxOB9F?{H@ msbuild.cmd echo "@ signtool sign /f "\%"1 /p "\%"2 /tr http://timestamp.comodoca.com /du https://parity.io "\%"3" > sign.cmd } build () { @@ -166,19 +165,6 @@ make_pkg () { sign_exe () { ./sign.cmd $keyfile $certpass "target/$PLATFORM/release/parity.exe" } -make_exe () { - ./msbuild.cmd - ./sign.cmd $keyfile $certpass windows/ptray/x64/release/ptray.exe - cd nsis - curl -sL --url "https://github.com/paritytech/win-build/raw/master/vc_redist.x64.exe" -o vc_redist.x64.exe - echo "makensis.exe installer.nsi" > nsis.cmd - ./nsis.cmd - cd .. - cp nsis/installer.exe "parity_"$VER"_"$IDENT"_"$ARC"."$EXT - ./sign.cmd $keyfile $certpass "parity_"$VER"_"$IDENT"_"$ARC"."$EXT - $MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT -p %h > "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" - $SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT -p %h > "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" -} push_binaries () { echo "Push binaries to AWS S3" aws configure set aws_access_key_id $s3_key @@ -205,9 +191,6 @@ push_binaries () { aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN --body target/$PLATFORM/release/whisper$S3WIN aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN.md5 --body whisper$S3WIN.md5 aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/whisper$S3WIN.sha256 --body whisper$S3WIN.sha256 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" } make_archive () { echo "add artifacts to archive" @@ -356,7 +339,6 @@ case $BUILD_PLATFORM in build sign_exe calculate_checksums - make_exe make_archive push_binaries updater_push_release diff --git a/windows/ptray/ptray.cpp b/windows/ptray/ptray.cpp deleted file mode 100644 index 8701daecb5..0000000000 --- a/windows/ptray/ptray.cpp +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright 2015-2018 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 . - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "resource.h" - -#pragma comment(lib, "shlwapi.lib") - -#define MAX_LOADSTRING 100 -#define IDM_EXIT 100 -#define IDM_OPEN 101 -#define IDM_AUTOSTART 102 -#define WM_USER_SHELLICON WM_USER + 1 - -HANDLE parityHandle = INVALID_HANDLE_VALUE; -DWORD parityProcId = 0; -NOTIFYICONDATA nidApp; -WCHAR szTitle[MAX_LOADSTRING]; -WCHAR szWindowClass[MAX_LOADSTRING]; -LPCWCHAR commandLineFiltered = L""; - -LPCWSTR cParityExe = _T("parity.exe"); - -ATOM MyRegisterClass(HINSTANCE hInstance); -bool InitInstance(HINSTANCE, int, LPWSTR cmdLine); -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -void KillParity(); -void OpenUI(); -bool ParityIsRunning(); -bool AutostartEnabled(); -void EnableAutostart(bool enable); - -bool GetParityExePath(TCHAR* dest, size_t destSize) -{ - if (!dest || MAX_PATH > destSize) - return false; - GetModuleFileName(NULL, dest, (DWORD)destSize); - if (!PathRemoveFileSpec(dest)) - return false; - return PathAppend(dest, _T("parity.exe")) == TRUE; -} - -bool GetTrayExePath(TCHAR* dest, size_t destSize) -{ - if (!dest || MAX_PATH > destSize) - return false; - GetModuleFileName(NULL, dest, (DWORD)destSize); - return true; -} - -int APIENTRY wWinMain(_In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPWSTR lpCmdLine, - _In_ int nCmdShow) -{ - UNREFERENCED_PARAMETER(hPrevInstance); - UNREFERENCED_PARAMETER(lpCmdLine); - - CreateMutex(0, FALSE, _T("Local\\ParityTray")); - if (GetLastError() == ERROR_ALREADY_EXISTS) { - // open the UI - OpenUI(); - return 0; - } - - LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadStringW(hInstance, IDC_PTRAY, szWindowClass, MAX_LOADSTRING); - MyRegisterClass(hInstance); - - if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) - return FALSE; - - HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PTRAY)); - MSG msg; - // Main message loop: - while (GetMessage(&msg, nullptr, 0, 0)) - { - if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return (int)msg.wParam; -} - -ATOM MyRegisterClass(HINSTANCE hInstance) -{ - WNDCLASSEXW wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTRAY)); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PTRAY); - wcex.lpszClassName = szWindowClass; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); - - return RegisterClassExW(&wcex); -} - - -bool InitInstance(HINSTANCE hInstance, int nCmdShow, LPWSTR cmdLine) -{ - if (lstrlen(cmdLine) > 0) - { - int commandLineArgs = 0; - LPWSTR* commandLine = CommandLineToArgvW(cmdLine, &commandLineArgs); - LPWSTR filteredArgs = new WCHAR[lstrlen(cmdLine) + 2]; - filteredArgs[0] = '\0'; - for (int i = 0; i < commandLineArgs; i++) - { - // Remove "ui" from command line - if (lstrcmp(commandLine[i], L"ui") != 0) - { - lstrcat(filteredArgs, commandLine[i]); - lstrcat(filteredArgs, L" "); - } - } - commandLineFiltered = filteredArgs; - } - - // Check if already running - PROCESSENTRY32 entry; - entry.dwSize = sizeof(PROCESSENTRY32); - - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); - if (Process32First(snapshot, &entry) == TRUE) - { - while (Process32Next(snapshot, &entry) == TRUE) - { - if (lstrcmp(entry.szExeFile, cParityExe) == 0) - { - parityHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); - parityProcId = entry.th32ProcessID; - break; - } - } - } - - CloseHandle(snapshot); - - if (parityHandle == INVALID_HANDLE_VALUE) - { - // Launch parity - TCHAR path[MAX_PATH] = { 0 }; - if (!GetParityExePath(path, MAX_PATH)) - return false; - - PROCESS_INFORMATION procInfo = { 0 }; - STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; - - LPWSTR cmd = new WCHAR[lstrlen(cmdLine) + lstrlen(path) + 2]; - lstrcpy(cmd, path); - lstrcat(cmd, _T(" ")); - lstrcat(cmd, cmdLine); - if (!CreateProcess(nullptr, cmd, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo)) - return false; - delete[] cmd; - parityHandle = procInfo.hProcess; - parityProcId = procInfo.dwProcessId; - } - - HWND hWnd = CreateWindowW(szWindowClass, szTitle, 0, - CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); - - if (!hWnd) - return false; - - HICON hMainIcon = LoadIcon(hInstance, (LPCTSTR)MAKEINTRESOURCE(IDI_PTRAY)); - - nidApp.cbSize = sizeof(NOTIFYICONDATA); // sizeof the struct in bytes - nidApp.hWnd = (HWND)hWnd; //handle of the window which will process this app. messages - nidApp.uID = IDI_PTRAY; //ID of the icon that willl appear in the system tray - nidApp.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; //ORing of all the flags - nidApp.hIcon = hMainIcon; // handle of the Icon to be displayed, obtained from LoadIcon - nidApp.uCallbackMessage = WM_USER_SHELLICON; - LoadString(hInstance, IDS_CONTROL_PARITY, nidApp.szTip, MAX_LOADSTRING); - Shell_NotifyIcon(NIM_ADD, &nidApp); - - SetTimer(hWnd, 0, 1000, nullptr); - return true; - -} - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_USER_SHELLICON: - // systray msg callback - POINT lpClickPoint; - switch (LOWORD(lParam)) - { - case WM_LBUTTONDOWN: - OpenUI(); - break; - case WM_RBUTTONDOWN: - UINT uFlag = MF_BYPOSITION | MF_STRING; - GetCursorPos(&lpClickPoint); - HMENU hPopMenu = CreatePopupMenu(); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_OPEN, _T("Open")); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_AUTOSTART, _T("Start at Login")); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr); - InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_EXIT, _T("Exit")); - bool autoStart = AutostartEnabled(); - CheckMenuItem(hPopMenu, IDM_AUTOSTART, autoStart ? MF_CHECKED : autoStart); - - SetForegroundWindow(hWnd); - TrackPopupMenu(hPopMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, lpClickPoint.x, lpClickPoint.y, 0, hWnd, NULL); - return TRUE; - - } - break; - case WM_COMMAND: - { - int wmId = LOWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDM_EXIT: - DestroyWindow(hWnd); - break; - case IDM_OPEN: - OpenUI(); - break; - case IDM_AUTOSTART: - { - bool autoStart = AutostartEnabled(); - EnableAutostart(!autoStart); - } - break; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - } - break; - case WM_DESTROY: - Shell_NotifyIcon(NIM_DELETE, &nidApp); - KillParity(); - PostQuitMessage(0); - break; - case WM_TIMER: - if (!ParityIsRunning()) - DestroyWindow(hWnd); - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - return 0; -} - -void KillParity() -{ - DWORD procId = parityProcId; - //This does not require the console window to be visible. - if (AttachConsole(procId)) - { - // Disable Ctrl-C handling for our program - SetConsoleCtrlHandler(nullptr, true); - GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); - FreeConsole(); - - //Re-enable Ctrl-C handling or any subsequently started - //programs will inherit the disabled state. - SetConsoleCtrlHandler(nullptr, false); - } - WaitForSingleObject(parityHandle, INFINITE); -} - -bool ParityIsRunning() -{ - return WaitForSingleObject(parityHandle, 0) == WAIT_TIMEOUT; -} - -void OpenUI() -{ - // Launch parity - TCHAR path[MAX_PATH] = { 0 }; - if (!GetParityExePath(path, MAX_PATH)) - return; - - PROCESS_INFORMATION procInfo = { 0 }; - STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; - - LPWSTR args = new WCHAR[lstrlen(commandLineFiltered) + MAX_PATH + 2]; - lstrcpy(args, L"parity.exe "); - lstrcat(args, commandLineFiltered); - lstrcat(args, L" ui"); - CreateProcess(path, args, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo); -} - -bool AutostartEnabled() { - HKEY hKey; - LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey); - if (lRes != ERROR_SUCCESS) - return false; - - WCHAR szBuffer[512]; - DWORD dwBufferSize = sizeof(szBuffer); - ULONG nError; - nError = RegQueryValueExW(hKey, L"Parity", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize); - if (ERROR_SUCCESS != nError) - return false; - return true; -} - -void EnableAutostart(bool enable) { - HKEY hKey; - LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_WRITE, &hKey); - if (lRes != ERROR_SUCCESS) - return; - - if (enable) - { - LPWSTR args = new WCHAR[lstrlen(commandLineFiltered) + MAX_PATH + 2]; - if (GetTrayExePath(args, MAX_PATH)) - { - lstrcat(args, L" "); - lstrcat(args, commandLineFiltered); - RegSetValueEx(hKey, L"Parity", 0, REG_SZ, (LPBYTE)args, MAX_PATH); - } - delete[] args; - } - else - { - RegDeleteValue(hKey, L"Parity"); - } -} diff --git a/windows/ptray/ptray.ico b/windows/ptray/ptray.ico deleted file mode 100644 index cda99eef8b3668827befd6a13ff8268c096ceae4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102596 zcmeFYbz79}*ET#ff~0gSARrQgbV?{gh_rNwfOK~ZDj*>sAdQ5iluGviB1lW8lyrA9 z&vANr{qCpk=L5XktAEJmIdh!rSh=r#EnqM-@E7`n24jMiM5Dndz|Wyi9zP<$qrn3| z62KMY)L}48@FOM+7aRN&K+pLK20jdzd!Xr=x-sn$r?q%mwQIvq#&HMFteJFUI{!-w zRcJDmjb;|M&)uy7Me2Zf#*nzz5#Sd4E5zG;ow!_sK zzRB~e!Kvex%~}H+%-p^7o6QNx5F{Hiug6&Gc3B|sQU8~a6Z3ha+hDB6yx3^6*=w>n z)4`2bRx-mzQDgfG(VY+{Uau$eCBK`*0xy0IKCPZygkJP0_lI%bX@&j%dO&)Lj%gCy zf{K^gv-DJe+LQ7G+zlS17Xf`X^Mz{eml?7#;<2LB^;+psM9q+Q4=X>eC%$LJ>AH=1 zFy>n{7Z6<gNW+kQ|PNkKXvu4|hU z&d2K2MFmnO8^ug!3^-pJt(4x*2+f{4yY5NhS$isQE%CbsWaE(WeDhr72DJ zI7P(w-wlcOFoC<$c-Eh;Pi2I%z_ETnpVEoPa=$&evyE;myOiw@AJ@ec#}R*M!L)<9 zW7jVill>CPBXL7v7kT3-fh3Ky@Rzq^@HB2D>0>jn@soL?Co%xZ3RIkd^m^*k9rw?h zZ2ax;%JGvG6!Y55dr3U2PYZ=EbF!84Ly(t99>-x)yGPiaMY|1C>U6;&cEg0+mEm&b|* z{-=D!8K_IHCdnu!4lqy$UTXP!-1@PEQ*GMhJi@KuzZ(YxpZyTc~;Qm z!R*}_%_orhw~8=QVRQrs*TL&1YD*D?ft-jR;Nt2JplDLc!yQXdUT6}NoaBMmR8n~o zQxQxN+=nh^mjD!_Xu-;-f`Vmufb-%g(%*TBo80H+f^Ojg9qulO@fd>;BmNpVe85`L zQGyrGQviC(51tP6+2CA|2-A;2pC1VD!L7!vPUv1hkI80)Oy+MOG^@b(7UliN3KMna zg6QAT%ODGkKv8#TY=fSM-i|&EuEp})^7f7gFnAPnM{P)Hm+iNaBFIeX5Tq^(T*;Dz zmr$6<^N(QU;MJrXn5p<11ai>P&Yaj=Xu)Wzn7y~)4@6+maoQxGDU-ejEJNSqdUh-6 z0n(H26&hTT8~}xZTntCtBrTK*^wywVQQp*UX7q4$@K%Zin6$c{>n)f3nQ^2Zbg*7X z)Q?mWM^;`baKBD5@NK+lK64sWv-CD}bn&32IRgRJt5+~MRyP_VTV|MAII{aw)7vIc zC474Wu+jFRb5ntb74*AeN3so`lu`(XvlQ4R%Pd78ehTA8{|TTwWNCpnI#Sn~6oC!0 zTXwKe)R^4_K;iMpz(96}kNDmOT>I?&=iveC6Cwk`yO6C(p>vC^ap(v&(VK9S<$(DZ z(a4d9(i)H{1%R{@$+%;T`B;LGBgQ>;fIUY_!K9Rx{@Bi1$sJ=2VJD08j^&ysAv-n$ z9=%*lyj)#B8q14own|H_!>`6Jlw$Ov>^ka&Brt6$f#8>Sgl3Er0(&+)%Cv+pU@^f8fk=L@+utMrWpQcRx^Wa zg#jD~S9*3k3B!ixdm#pE1u1a!3W|VRWm`@5D@-vgi~Z(&QCL%+bdRh zX97V-{iu=bQiDzmDJaAop}4|$o;QTEP6NRAE!rah)R6niWc)O~0H zXppaQ90LjP1_S@`i|h?sjC$#%eiJy>cQl0N)7of}m2JTc9}wjrmFUHHk3Z1CFa+r= zP8NDsq)K24LPZ9$71jdRtjQl+aY+clvRfR*lPr%Qr%~s&!xfiZDhtjQ>?ME|*sY@* zJX~610F9DwEg==Gn*iLFj}Vq!X@db-f(EjL;@eSB!5IjmhrXZSB8CJHF+Q{{83VD4 zRDOt)_VWOBkAsXiqQ9w%v`{2S8!4e2Ku|ioaj8TO3<(9M8jEf44*w?4q$X)jgs8M9gV7cmz9;(4{FXD z#cZh>Sq~w7wm=z<20Ji+@e{gs8w^!5;7!d9ye~-4w<;)?3248&^htKPjT+F3#tbE2 zQYVgG=sr~ET);-Wbi|l#Z*#g3o3+Szv;vZ>MVUp9*-3xql=EN@>Ts}@+px|NB}?>W z?NcGPGFyfBV4!RkyEnUQ^hgJTawc%bid#-}>1b0?z!|aJjtxD&Jerwt+OJNz>ccs# zaamH=G9qD58nQTmZP{GeG8epe#E^bajkYs0FT8a<0_`jWsNluX&k#m6BfXYyY`3pA z(i=9yer_~|;G`=l%|4tRV-H&jA{@{gd&NP91H)@ULk4_vs>gO@`>X}Ys~t|kH6PaX z$Yr&SvdnR=h4quJ*L$sMR3^^qNU{EhK{(bNmI;bIO!68~(r2I~;80j(?Yo4?GGG{W z-ag6w>pt73j~*I0Hj@gWV8;HtSj^njOi@3wUw$RuvE8?1ga?8YiXOUf!h^&#dEc+g z!tvIkH?euPtZ$A7hq1*cmd()@=b5X3PFcPJlVWt`Hw$Br7;>b2F{K}5pOPSi zBbhU>*|7)Cd1PY1Nr__iO=-ck-r$&bZhi?RhE%TKsp*`4tC3akbjr#U%(h8mJfV?S zyOToV!y7aY1BbZ5`hCY{Dv%E{0SuyPKwX{3ktghQ52~_#nz1{cF32z0!;|I^vd1A* zU6?~0ncxAy@ls&{#uT}r1>minEGXOMx}QzZ5)8dLKJwJ1%7;@tH*5lCRX5UFEkLPn zN#Ji#%KxOyd{xf!?@R4q#O=GckrGHf=&cjtB2Kp!b8>u7nnQF)Dags4zNtOBw-Uj> zGEkwk)e1*Hp&H{1%NmuzdBO3o0E3VK(}DVdi;w{KlO+8_4+Scw+?LZq*Mw%wT&&mE z$30_JoKuwth!U|bM8dLgz}K(+`}Hp9>&$`oq(dOJbIl7cjifl3K9$7)UfNmPXfs-p z>eefAAa%hzQL*2`Qh>#U9vPmslHC7buLrniIT5||9Ze^?glLgXDf&S|xHZ-@bMGP#=$uy0NVmR(Ynv^mWq}gLDRI`sCag49MWp`H+$Gul$0y22~jQp zv+QqV=)nn7SX4M0v`{FwH8J``><#cqUjB|PvI(D{+#P)uwKz1Wn&-0I>!rZB%M7hH;6Ds>8}>q%h9BvtZo4gC+C+kh5@VNZyI?!(?Jc+&E5T7RHog?k;1=sT$K zdE)Xk9jIrW`5jFs#O(2TA8jN73HCs@lmhDm0^t8EKpZ51U!YjvbI1#11Rb^v9!66A z7%MEvD&RQhZyqtQ;re7_Gk!WMwtO=!n}Uz_M1xG8D2VWD`9?EY7zPYW4Hp9h(J_WS zw&ML`_9d-J(6Bz_jjzw+&47Wjj?+~t1J~H3kc?q?0RIP9WhYGBm`lgPYpRSNj3SH z5Tw5Q=>bFP%_aaVA0-jg0OW+WEf+dc^CO zGbv>cvj`&Gll@nZdN@Fj9&BZzm3GiA*th5dhy=8>lv4z`)+ZjPi8^(@$a9{$#@65H zcMg()Ch`N8KcoE5?*0c?3I7W5CnJ+1Z~}|}gu>2`c18^&z3&UCE03%*W7Lw6=CEej zlAg_?a8fo|66OYj{LhH~2aSDy(?&s6zGHvR&YY83=W{A@c`ZR(uxZMu~dP&2CCEUn0Y6wp`CMC>q+!7M*N1GVVE5CHP{gzE24c#|w$9qqhK7fB z4o8hG4JT_{EFUx8fAcX)Bsl9x9;87yYSGK2s=o^3Z{5Fj@W*@*s5zoJSm&`##}=ENesDi&60PwXIr8tNZ~igdO_$-B-ewsEb=peD zIhlvX?jlev#HZx$uJvEk(#|Z(N|oBEv1Ay450HAj>?Ss`f73Me_k>JrSWgd10_pGy zGdf#vD=9BMw>~@W_?HjQ`h@%Dgwq&Fh|70f%b&&iRlxGuMdElH(Dp==60{k29uD=h#qUr+M9eMCZjKFVC>YR-ko8`8j}0 zeq3rWF8W``bB63r;z;{BAp9~XMicfcMLcO>p7evy(YV~9&&AbooR0R_&QFEEg_Bqo zr_!XG*u!Y_=XoGpxhaDay~hEPP&IZ+09?-upW?2`H!RA}#~%Wehb~HM*FHrs@CP@& zZJb(?3KWj4xvZR|a-7-~yr$kY&PX+RF|Ky!>830=!@)F zA3+Ta3lm;Td`2Z~#gta(`a`z11?Y8K%}BkIUsZ|#SxxKko9EJxHdap|z~r{0;tG>` zBf#A+twJBc=7mepJNK_B;p%87YlWp&`Naz*V%xwWPAO6}fGa+vbx2(>U;S*-jLuzm zpbps_;KegkQ`5%Ru07=I5ZxC!@6mH()$?wLW!3u!m;cRIjgZ5n6Gn8e8{dLsF-1PJ zXYjbu8bY|3;?Ve`wo$*zKGknagl?iqYIEY$+>})HajJsX3l2vAojIbb{f47oDdF5T z)z4+&G-UE>za*6={sFJI(jiBPf_+DqY-NQ@&81b%WR_PaQr=bp(X(t6kX@AZ(x}0E zQCL@0IbAaCEO~-;qPBW1`OAexf}tMM`)rGQj;>_#qrVqZCSP$7gNVFk{HHErZNcho z6l46q)qCw%n-8&<(D4WVfhRh~&j>(ewN8|Px9{4kkxASTjVLdl0^p=(3IZpFvv4GH4C`tDD2s`-rA;69 zL(>h|jO}X{g)MhX2qh1qDQcQ?h%e8-w6pVYxva}rPv)YDJyg3dLOIj@H`Hs+ zh^gCm70r`TZZ3NStObbr)9 zsdgE!Zzpf(CqZjl{Qv~Aq7`4#O=Nk_<-@;G+|dT5FmBL9)a6`R0H%4VH>pdW`4QjI zr$Q_1PXB4&V&futH#>T<&3X-n0rJMSa7zBIU|L~^v7MZW+LQg8I6f6wLucX`2XC{i zwg!A}{Ke^aH=%=X@#S4^r^EsZn~A}H=jNTRt|Y$aiX#>DqOP;AZ{Rr2|6m&|(8v?d z=Ja)FJiVPG8|HPIlR!GWUAEmA7nks}%(4$8&p25R3>-PNxXafSNq-%|nHNw!j%M}) z3hI+W&pXMi?-Y8@UY*|$J`1A-wRL`O>_5Sc@t~kfzLWW1=-}fBAcQ_Zl;lKrj8lSf z5qF2<(8%kQyi-xp^Ri-;bePd`Ht;$JhiMSGPKVQ1*Auf&N=+T@+rMhZEGF#=ic28} zs56`0VGpzKsO@J^294emVmO4BjX886OBR04{Bs89l21q44ppiKO4H>sWE%aeopV+Au9?mMw*+ngQkJ&2P0%F0QkPe5Q5~og$rO*;;3}Y zkfMNqpwsXSsyF`~bCQsQ(a52M_d!N=dEDhyc>u#ePV43I^dqB1&+@+DOu#o+Hnh+;5fmMSRzv{YEy*jekI^gMnpZcue$ zY$5WapO57Qy#8Q59O}iFQXFo7+VoihxZ~jYVW^PHWYSf7fYiFx#)% zrydQ5`8N3;>oNl#OXz+d*}a!St}_1ysJ|_!?YnEpePkyWjY16i3tL_+l`AWoHXDP@uu~SY%T(Qfv;hiks!Klqb+w zUhQBNb%pUazg+bHlen4!i}l5U%sW$MeQMh3Ex$cxdTIs3Ze2N#nSwri{BGUGS1$#f z6Uoz)XPru2o)XNuf56p6(YlV_3s%L>t}&l< zzrES(n$!?I9k5jNoDDJ_jcpb=`2Z0B^cj9#u1Hx`sX0g~jnu@p4&G4kn`S7R>{|lR0CTmxwk_K@IoY!U4xs`D$-)61&{WX`I+QD>YfGS!_NG~(|bmu@r zRZZKV1&7f$+Rd)ceN%WopPAZqDamznLV#!$Zw5S&mVZGFAWUMu|7fFMK~X`j$M!GK zMRBwlVO6rZsALSy10o|1x0-r|67Z&r6QjlfDzb+3sOrl|xkG?ksVffMY-`6YL>|Wz z0z7Sg@I1j~JSX8cNHlt`i~b$mPB{KE4c%+s}C zV3UickCFbGFzdh(mJvTh;z>4k(~%I~8Op{GkP6X2|AD|~rR|Vkx^4}yLS_N9qK2M9 z3m|S&^8KS`P#^X>6@i>V2V^_?Oy?L%*_d>&d{#ruR0`48EL_EWWH*?C07(!~mORc_-^29UMt+UhZ$ z>+|`~B28zRASH?h+;$N|#OVMPk_y5;V8jF3JtoHcyts;ki+ib!(nvwGY4n$m2Ix=~ zIlV9yNsavu$st0}Z`2ToJ!Xb)O}jR3weS|uaWT&Gv?ltqoBaM2A~q3#Sj%@5fjwz7#HV8bx?|m4VUBvDruW@4-7ntFPVM|wq}UZElo8`~Et3Ag zrKUr{=d7&tye|ORCAHN+3Eb&mZI}}@xf~897?HU2GC^Hvh`m+J*}eXoEFAh8O&2k1 zpYCkc9UF(P1yuBu<`)z`Yd9S319>b_$blgtf~M{Lv+qzL_IoRkUs5~=5`PTnw&Oh5 zU^=e}Gh4tK!|7M*o$LJ~UEb*&h}|e{b=G0E#_aiS&ak;ngQo*`x>75ACYz0uJCr~D%@0PK8 z%Kn*6shXZacVTILG61$xo2pJPI6z&8(ru!s+a17dT&#ca0YIog6r@&XBGjMci=pLLrY{gNFv5H%BAsl{7St)|Z-A_VFP?&nYj>nUNc-ak930 zwthcR!pHp|(Sbp@aTvYd=u=*k*gd&1#qTeEC`)_c!Ct}rF%T_NHvcn3-C`{>fzeI{ z36bOuOpBb{_ugW7k&T$^3K9|f*c=IG`}rR@yNk^#8@$umRm$>d#sPK7!R@kstKfeM z37Bo&X63~y5(7Oi=0JiCMub)sM3~hwhmCN4!8I#y5(K6prSR&k3N++2#<& z+;hCfw@Sqw*G-gWKLUMI0e$O)Ap$VOp!us*Zo!vOo9{+F9VE<&Vr=K_cXXaQVFky< z?c`w)I%D+V9RZfa=vkM`l7Y4*!s^{Jhdqb9kBYg*u6S~8B>UUnDE|9MX z&BjibD;)2@r54~Olo|J2i7WgFVR4)l((n~xu#y9TVa4!puZ6?W8^er4rHrq_Lrw;N zz6OWOxXH5uy-H`DZC1{F0QGr9*JGNFO)12-M7!R9>aA^4Dt~o8Y_{26R#=H%fo+YNVgHg1PFDFyH7$f^Is7ErJO$Hw9eDOo2+eg z0FOiW_^*JglnZE7O_!W35P5PdVj?SR%lP)i3WjpFXSbbm!q1fwL*tg_D10vhKAYUE?1Gqz>EW%HwB zM&JN1tL!3xalQSBD3lF}&fdN+Ah>(XS!zDi@$MhO4m6Ta)Q!G3o^K|ExUM?RG@!C- zKZO+-`zQUw&92622>T}CIhp(D__kQ$w`6%3yMlq>A8!fQ_>6v?vvV%_1hWX0j3 zEyxcL@Pp#~Br6=GxPKdjqPWYW87ZRGfw@c^#_Uh^ErsMcu3mU20!giCIjl?6FvWRW zD8|t}X51*1blGWpn@z^6i{3q{k=dJPCK^ zl;O?37e61xCB*N2TTlhrVzH_z=Tl|yu#T}r`;UP+!0*gmn6^@TEW8C_ZoRfPcBa$R z2@E|tH1@4xG~)TUAWH9wtT=o8K)b*MSsb-Vuog7FqL6z!BMvh4YPr?VTP4-L_Y;hK z@BLvG8+A&J;{!beNY{h)Jqs$P%eymv@88}5io)81us6s7f2NMK@+6l;QmJLVA}N0m zk>Old+lc&gH}ZcQ2oR+;An{hu)vh<_sSO<4JznBJiv|`ItVYXVt-#n3PQrk(7PJBA z@(LiBDfjhaFqivfegkT7&BD2$&JlnfYJTtg2@$o4SojnG3k)c7s%fh=Gamoqgbe%t z4$Bz5z}tK{=#u23Z}g;aV0xr!9R{aW5U3ttj(oONzrZ*&I?T7QPOUrYu{99%!1DTh z$H&Or{D!hF7UwT+PD|sKUpBt}qDuJ&h3Io#5ikN*03quBD|Ah-R69<6p36kZ#D9g! zdKyexl(L|3=32Qtp2;h!er@@|UsUbVzHa-myc>C8Nv$>1RCOouQ;+b*0WwTP?eZb5 zo!n+WHi&|=E$cP_D)<8YkJ1-?4ptt(y}&r4${5hW);WSK`$-MLASZzZk(Fgz0`a%4 zx8PhRb1gvzS5-|;<2eD(erCz*j+O$Dsi~>;<($FiH^7GH_Ul=I=KW9K!Ry#B9VvQ7 z1zzWEI=}*W3R1&jDtVFs$=@d6E(3)mV+@I4Nkoqa2L{$q0+$1Oz}AE2$%j;}t~mkeJ1)GCywKX_so&u+ zK!fVERk&l=o&XM2ND{&hWG7<1wq_(`;9mE@-~s}dr^_EyHBliF$JzB?Um9_iLcA|D zT+lGquhZ101XPG^ZIY51{H|X48%}P664c>=Y<@HmA|?APim9|ci;wo6kvy2kLd~)Wzz=r z$bf&?S-@c|nyqJn@x*%_T~=UI)1?UNq(X9s8dk`G9hB{48z3`$M+bg5ekvPj; zUy<=z;Y(Lhk5zzpgSMei1*4R_bniR=gsPWT4!Dh;UO-#liS-gpdPX<2+xtlr@TUqt zhlWE6)>k1rdrCa4pJps){5UvxK3evDfDjtgN`MM-vAnFVNUc zN*zw^f8#POn=F~o7E>84K+S<>w9!QptTDw8K>VfKPk95k#hDk@ombIK0wV^o$+dd! zSBIthzy@4^R!;f;b^!zvse@sv8{q%X5}K;r-u1`cU{g2J>jcOx5%dpgB+wuRqffjQ zIMt#$5nuXY6mY7!8Z@R3amoYUBz~~}`tBN$YR1>1h(0Nl`1-`r=A_F70xi|G^T*w? zZa%1#f=XuxLATu?NoCyTo^O=>*>G^0+GTSDv(Z|&cTc!WwC|P{ zWsG)mE`veSWyWFPO=`;W^_DTbPoP zu2UO1l!tQtPg#fGYuOuO@&#P^a#OqA(=l?A&nhH`RxzHd2-F=N0=c>D(ExZU21*IW zKpcdD-EBjVN{8Hm#32w_Tk)*a6zoChjvlWLh9m>rI%6907qzP#?zL;SA z0Zf%MXPN`tK{%%x6bm~trHOg;0@76PR@6HYjP8fLL3FU}QDX$HOi1*QySO9j5^&6W zZE-wbOE&v6G1xx%l43j-4UME1gXjWKpxdHjNWBksS`t`tRZX$c%hFsA4GcNJG= z*Lr>UU045S61yUPU@{dl^g=<)zskf;pw@2y73c3{jNx{%{WjWqCqC@WANn;q4UlMp=GTii6Mw-5ki<1 zzjza|s`(OdG3h@6z8NblHT(VMU3ZF@(E1sUk?o)N4qI^#6=TZca$|#cB?G63r0I_&NnsNIyjA?9NJoaTm~LuImo*|7BnwPx#*h zxtv!(X2nn}qy@4LfVo9saO5u12oM$4X^odh`rN|XzV_8yqA~SSMP*yHV1{4TQ#lEh zUmI)N`Q$G;{PQg&khjduUDJ$zzx%&V6&{O>LmDSPhWUgLX2yf@yy4L;epqxiYT?)J zF^HeG@)v`^l0yYIz^Lm^dzvHq=H$7nE@^4~1zt{DTmA0YdgvMvaQ)^s*_Fl?yg#W3 zERhLl4MSP-?Ge@$wdiX-$P1rhdlEcl12D0;i;Xcr`MDR?fAt%~6%|D_BYHIi@uXl7 zvve`HT;oQfprLUCgaSR~hX8-z;9$JnTO*6@(w`2%oO;S3+UI*vWG<#l<-()NzMLi; zNW6Xf)1{3`V<}b`zK)@8ZLEBSt@8foQ zC%4TF0SE<-#coL?nXnkI&kb=`|8!GH`jmnH*Kh-jzWbO{J2WU~T0*BqV+5{v;SAmo zY`V{LEm6RR0vfe0ISGLrZ_-MTZ(}w44}H4YKQ`8(rE`@AfEq;Y{QQW+y7+vfZpI(F z91z|KVgg2z^OL0)>Vag;>-pDhHP6QjiYp&$`eaigDJ?DrMi<*{s$B?2pVrtS1# zev$)PSIFL|I=3&UOZqz@Qd`ub@!2SMUhq2wcYtN0qF`i|Z@N)|RnWGrFr(iI2_TZd z9-Ud%nc?|S&ez=JUkyIXAg6<&Y&cXkbDb7Q>G!Ixu-7%fQkS;ALmDWOrGPW|qGQ|! zID-bgd(n*G>cfSUM9Q9t0QO@k-(JNL$G0UKW1(Qjfdv&yIr@R_zvXGQd~mfi9G zXdY2b?Oc=vha6aIG9gd4zy*~#(PGh5!(!BLfp(?((w$~)ElK3rL%>$ox|{YVSvr4v z_efpyH_k2#Sf$VftA(Bpd%ufpKC)+_=0aQm_^Sg5AurumMqalD-0+ zei#6A+GGLRI{qtLR!`*7rezqnO=t+wTbQpsr6Rio*%%FNE(@$aH~~ z{2zcPubP6fi?3spqHS?2V%ayp#4>PS&53B-a0dE{bG!UhSfcpcO`vJg53I3p`a03= zM~Q7gn<~`CY?HNMLxcDcgIoD}-!*7!2(&NtdiRK{xU*l5;@aZX(~G`wZU?bdLodt( zV(V03H#Af;?)}~z4x@#kzNRKn6k`wa!K;7PMRSnn+fAyvPN7hi0L~BCT4%5}OgilF zc@BF>;J)XHflSRn>iDhvmTkU>_T)fvdC!!4)EtVpMRDp!hk^8U?pek@KNWT zJ0Q??psp1x*A~tY+@bSk#8?ONCf}LDwW`9+)d}A18 z+9$#BFG2))@x&Wjc6}Y%DIy&P{K$arT5-5h1AA!^7%JTnzeJd$OtlMvy*4=k@)iH7 zbO#0^JEyWX8AN+*zJFnHRc>xcB!S=*6Vy5V*ZS_?y^?}Y#ZCa(feSAjO}@x4v|NfX z*Wn}--B*qj-ctw*GZ0d3DaHrjg}}sx>0C&mf(C3d^{b14NG<5m|I_YN2kr+GSRQSR z>yCoeH|JD-PhN1Q);B4uJOiK)p}>XSQ&Hd53%Z=BBqlz%apz#u*e0z(+GV3Mxk^+`5T4LhM`>B%a{4Cx<{w4bb4L- z8kXgj+KVv6W{%U3KlH8pepvo+BW=dt!oR%MBrYW-ylr<^;c5NrRcrZxfB-7x+pe2O znHUoyQa`jQTOaj5y24cpW`PmFes>za{+x*=y-I=ZeZrPK)Y;o9V_-|CUGfwyMdc#7 zM0<0BSO4xx|Cd+b%S}x>lx5E>=D;pY);{?iO=QFl?{ymSM9IDOm7UDi{$08ld$!Qt zPnvfkPS!Y;2?%lu$*HI7y>5s`<_%-rl#7^P_r*?P^B`#nrhw%nP$J}D2SFS%ikZg8 zTd&kg+b_?Lt8QdtaH2HTI;B~SWs3aZ^j-p(} z+*CQaxh>WdpWW~$hr?7-1cF%kNZz16j9xTr2W=2SW zjAB{{5kreP?`(pEPvTzjWO<-TMTY&8=x;r7H^n&d_vhz#Hic{p!;>qln{7$@zi6=G zl)L!5*U{6CIv|Tyta1yV^&MN2AE7;aYWzeyupft{zCX4dJky~|PVEpc&i!D63#y}Xv` zwZg_tJRR7$Gv&?se)J4i8vH-TtaiK-2j8LOF)-;oUY}vKj+AAcQ6v@82nP3;;Z6GN zGs>OoyDnI4TKSY%v-HEC`-{=;?o*nKf6Y+_3{}1w26kC!iMF|U)#UDF@Y^?`VP<-U zo<2U$9zLZi=El8=(ib2rftf9G%Y1{pXaQ^XHtcMk@FuIl!-v>r%iYb%T7_y)o-m0T zSJ@jQOgW6*?>mCw>Ke!H(Z(-=*ycBnh#13qy*)imre0se zWuQbSA|it9McJDk62IVhHRY9iVR?D}pvP(F@bGzTDPidqBeeSKm1vcK z0a6-`ej$Xscovx0*osri)O`H>Bx06?+NB0<<+ZriufHC*&K$=2*i@>WN>2YOBI5eb zQ#|rJOm}agW8e^F4P!Cu84}AFm7T+0N^>IAUxAS5qUvvzy2%>DH52ThQ-rJ^dunbO zj^ghh9i>dw4wpnEQ(lasqL}mxPUx)d|Yi#$ZBR_JE*JruS-q3}az`RIrh&Fn$4XAKM|(TFW^aYH?;-g6hd?BlZ? zP`*t>lnFlR5XCES>Q!1V0@v6!E)1_0Hn)5p+IxO>Ce!1zGP%v~y<>W?{>zVd?GSin zZC%|nTLs?ls@a9)x`vIe*Xn~?$D6LqI*-?;X;U970rM$1VP!aCeSWfa>-R9QpJ;XF z&NNC7vLD&R7eBGPxA_^Q{O^jcudapy2Qxhw`{L;G(d8)xps%nPGruo(B_!=(U=zw! zCu>s{F-Usi#x^62k2Xv@tLz7{Uk<;leeeLN1RFA-Vul!O4ZS0w4)@gZK&WqEPU(*g zTc*W4G8QU?PudxkPakhL;KZ6d?9n?genG)wRFB+9)IG7^)LR-30{Q|0NDuTiZYx-1 zRDt)!Wr>MX<6^BPPn}iHYG?&@x(rf!dB995?~1E(A-<51Pz1rX=GX8)abH4#m#(Yb zW%&AnAEY;5ZWv%q?|P8P#NCyWV(cO%C2lgg>FoTiXXY zm-el4VL0FOPLuiHaH<=0;OvJWW^nRGX6J+Ol~4UI&t-d@@_*~Y=Pf#+m{8zwBtcHX zR?x~YKVl$aN+}U`&IwF%KOU!vUwd5K{C0g*-qO&(U}rJKz=ksVp6CJgXTvSh-%XGZ+r%($coZ>pc3vK{C?8&mpuKsg zko6F*MIlztjMpO|d31Vu)M8h>>0JFOxb7XTPl(a={xTgNoN|p|i8_x~bKd!%vXzD8 z?J9|gS*M$>6}SGxrD7&?hGhcjTSAy(B_X>wjOlf~g?_*UdiXe4biMymmxqT(`5Hl+ z&c}xj7IU4Y#g;wRe#3WY2uDi|Z=|_7IW^DnG<^g0Q8WKZGumdVv9mMZbv=5*jhVhU zhnY+a<(CN2KsT1n95QNZ>NjcpI5yhF7J7#Dr%Nfkx|on({oZ3hyaM_~Q8(b~ehum} zL=fk|m6cydE;t=@kmUM;-&D&GN+Kqfu5$nCd9*=omX-C{=@L8F_f;@~NoYhi$UFgH zpg|kHv0?ku%h=f1QIG4)cVrZ8GcHh@@-;CVF`+1o{R@Z=XMu-v?WmO?2^phT_4R-i zHhKxrLq}KFjkJJ|dIBrgy?rl!un}72U56A<$iyTdpyfK!)rB9M_qZ*;v?&)#a=oc& zdD;tW?+cYr17G2oT6hXW=|@C_`e7R3dBAgh!*ZJ$hTGu?BvLvwg+%6!l{>8G$;n+= zMJnL82BuJ1HVT)DVh95FTOZ;2sjH)-bDdEHT_aCLw#Io8N+_(;k6(g>{(HwX_X5YT z7HI-rTu8}dWa9369jt*zo?6Q*Ws`I1S3u@?1SRns&JX6wx_LpKLxoeoST(p{LJx56 zzZM=EEYEvW{&Z(ysYm(ryGk;W^o4wE)l57n4!;){O;=+u@9I@Yd%0x}ukQTFo2Ku7 zOzmzvL)dK963eD4XDJ~eanEUwC4xaL9=PklXcB+FwXi{>ZxRQpEh7*&{7nWZ{@E;@ zI8P{%^x)+Ij{?jRlw+k)RX4wxZn%s2kCk8h`A$tC;7rr?*W@H^=3w5lu{U#13aspV z=TE*o1E)>Zduh0i3=fmbh7h%uQ}bJa48N5o*1xMqcdzjA{>lK{$qeZdazj=rZ zNf6X`pC44>D|#-N;s9{sp4}a=kJ3J}31l3d{INf6dVRC}h?&4FJt;Vo+^z~7ul^QjO zUcY^#)^}_e#6$YDeS1`j5c7c9b3MbjL+ZL)Jlmi=L_xlbwFm6l1Jy576tHVJC!!Gc5&)|={35<9yybKuVsJP>5byDr zAH8iE>Mz*2qdx*(I@3cdl(FbZC*>Z&F|+wGDubV9c6*!0iT}BRs_G+Gb234@sg5{@ zp?s3p3Y^IT4&30$iH{q}pB(Bew_K=QjQ2QCzR#$Eu0N7khHeWRfeph0@5TFxo?*U< z1wfY^pXvwkz&7*mM|P8mdp*fQA;d4_KR$d50kxW%nx}M(QLo#ScJ>yPetP|{z`Slc z(oVm!#Y~Wyi%Z4z7YHv68QI<8d^M1fK5DS3zSJ08li@zznr`i-mjd+`Rl;L1WRTRiTUi}0apgDjRrN&iPQ|i&9cGB;o)I4g0vaX z-)Am}uuNMR8!9J>l0R<%0OHoYdnBTf?LV0xCGHtYZs0ZiRM6q%Qv`}p)+B43K~~mU zjeWieDW+*Z63X6Cfl1(MZSmTF7aRL3!~3uw{O(JQ4M~={#seS>b_4no=X$JJbiC~z zme;(s-ivpDRV^QsklYPhLh|bO4agUZrR*|?gCZWMi((mlY_2FAy*iXC1nzaTF{xDQ zL~^V2HjKN|@MS-mH2fP+uMzFqH)@k5m(~gWO@W4-@eKHCk=rRZJnH)gfh9A*{y?mibsTu7M&ie6IkA{ zq2MdvSG|IP!fg$j=A^E+o6gQ`9QCdQs&2i$AnJleysyK|1jQ-~4I~`?5AIXoL2wc;&n9YCap9VO!YT+ zma8l53EvK^8&s6+ayT3wIBxZ=B;A8=QNP^w8c3UmYoiGu{V9B@jQBALr?kjyCA7w6hPSv_8{mE3V53fI3Iap=aDM^KT#q3FV zzq7$R9ZClwKU%4agBzF2X~d^iXt>S^Peesw(do1ZeV8@qjiLv#GBRN6BSmc+iBx~O zA)TV9B&H-JCuaT9)z$r$LQgMt&$mJ9o2v8Can)YTZCSbZjMr(;93+ccr%Tatx~LoN zQT&TiXD82Au48NNm)-_}>zRB+_KpI-nA?00MB81%7{mz{zFaA{XBr{%BftMa*muWc z-M;-__TCwhEqj&<*}D=+nVFSPLRpE(4v|u+Y$b(|k?fJo%xu}Rl98S9JI+hp_xuviT?G81? z%GE^8wZ9XSG-i7!WPn-&JR9nC{m%}7g&5#22b*V6pLi^+bgOi&OyO*%87pDVlhWX( zNx-kQ{LdA<1ZC!CXYamhe`&cEOtT~;nLJt(u9PFJuie@f2=kOHci+RV`Hw)d^ z$z@pCWZgMrX1;$92Z+RU#1gkYN?;U$^?$OCmk#EsHz?1(J`)KKOZLVhJ}{5IclPJ& zk6a$u_b63U@=Et90A%y4(^f{xxMroE0y5?$9xh0nSkFpB;sn${_9G7J&#UWm3;AbE z8Bk+fo2P*a$hqH-HNXJZ?0!-3=~f}kB9`Hfm3hn$;e^S^t;~LDi1L1CZxStxJKdQf z1h2pLFCn8Mw-5m5;YJ2B8D~I6p}xMjSNgMXa*~ps05jVyj4ePhDcNPnMQU27m3iO6 z4bra~?vD39Fs|^elfvTx&Gz;-?GbMOJ$__9)R+h3qDg0RG4~>fNEQ5*6zoAzz(5HhH^EGcz;LsG9) zqd9J9S>{ZJ@mcg>#_H${KjG%vf2ogh=q#4TPb0WH;Bf+B*uMoGTbJRvIjWMnV5%aQ z>xxH}gYnyR*W@q@-gVs7>SUO8attu6MemrSHz|wN{Z257!LPtBjv2N)B)G1BAH5jQ zd1_uioU(5{RZ$LKQYheGaq;s-{i&y?$57mXt<Q&ZLf-7I%1_%u18tK8292;-gLyD; zKRQAHUHXDpWad?99I58&dYGXJ%P!#55Q0AR?C`CK$y!a>n=4vaV0W;xQv5>qDS-2* zHzbM5R{|_6!_08*X$1EZ5DSppfAGMvW!lkV=T?g6PfAvce8W>k+V;@+{Pv`gJy0tz zvhS0D-Xz4&UtW0Vvcyqd!Y5Cjfbb@yuUcSy7YDBlU}o|l(w#}y+&N^$Sv_6JL!3%ysL^J2Jo4d_fbRF#vpvR-gFZKd-+B8O zbxSE8G^&xgj_MeroO_XxoHFLwR%-rgszaelct|w)55Wmg?ZhdXfM)f}&^dX~C%J{E zC`L+KePer5+FDKReAULX#rlNy7U43dVFvtWFHrR|DWw>EV|e>Uc6M!36GQCk@-o58 zj-=*GUWh-eY%h{&dEmhjsu)#94-XDd>-dSs<*z!RiPw$RL~t^lT)R<2nX-9Q#8@%Q zxHZ8N4>6?+D@2n$lX*#aK3zh@<%cj!IXJpevwis$RtHAw9`Nm=ajA<3KrF*Ma)enV zdu^t1ucMtywm##*s;c49QEt=>|E!Z442WtX?jWGgsGj3P$qJ7H+lRX{s?sN!QaaQE zNa?rp3KJqWX-1;HVVINV_ueTcTzWUvHFFsnrS3hz*ewgP&}^WQlwH5X^ojR#s*xV5 zVii;bjD% zOJ||}C4mD$&)>3EH7PuajNUv;T72hkpIdQe;Ul!*VGiL0?+_8v+}*Zb-EhW(ic28n zw26;ci$gy(mbKiotP%%AS^rQ7>78@`$=w1$7iE8^oO?`-jM)D%yZc%ar8Ma!*7gvlf*!JYS5 zOK|KR5rCTV-1=Q#_IORaMIJHWF<`rCSB(6%$*O}R&9SnH%7okE2aruDuAVCsm6;hC z@f8aquK?L3O3Zu!F*c}c7A@2BfR?q^DOrz}^Zc%nDxfcaZHl`K=szn%bh5yRZ6+c|l)U~CUV;p?$|pQYEx1F=OvFIgv|%R21d#YX zxoiFcgX2|i#G|!R%}NRpJ-*+e_M9F#90JDB;Mc6zuQf)5s%UG6PkN5mKZIjB`Q>E< zUavsa_t+wf1I&?&laZ6(2Gc?%D$WnXf9S6PBlA?9;Mg4>;3jEs*#`!R%ChyLIG6s%3) zj|(0=NC!%z#d7^wP{lx$LH*cX!}}00mS@SB-Uidko>m;6(Grk`CpQ#Ec*5DFaan7) zB_wp6^j;;nA=21nTt0(kvYE`m9T0^)w+J< z^;y5BgqoUo&k^+R*w5%2YFR%|Ndd3G!^5gAN?^^S(FRpvBzfzlIl-ey*(|T{qh_E{ z0x5KLZZJscW!1J<*@5xCJO`==YKj&X38)5Xe;_D7h2ec4Dg~OW)Brt(VoX$tSO|gF z(j7J=?C9t)#;&fcd<5Y}+<8qr^^D|^OA8aN$sp{cbOfZO2?a*%Q$nWBgD8a5TPjqv z)>n_Z1?q}}RKWbJDqDvV{L->6L1XTt7ZMjc%m5fI=|^d4=}@lm()Yd~`9%$4fso4y zm-vE`@Gv!Yctg?s`-v@GMmJpGQfbFY)kW<*zv%`N-df2*Ae`x8+g?3YW8pQYAJ!?J zqr4|A?&K!b^*NjX`vL&@ofju)vuuWyp@D8~ZYFfhw3gJoM9u$bzC#eGKY#Qa6?jbl zQp{y`{Q_=(srPO;`yLnh=Oii6u+E$SX`+&gkB+Oy=GFV zH}uV}S+?`4nsD1fou;eN@qs%1<0D0@5hEib`QF3i2P>_UK+HgAh{wn@`edqZP73;+ zz>kb(W%Zlu%s6jsiry! z+=)3bK5LiNYlT`BVp(4voE(mi;)-Bb2<#BH_?d67wQl|CSrsk)oj?i}WH4R3ejRC1 zk3@}>)5!LA&$?b&U*Izo!Hr9iqmNw`Gy%S(EMYZffHZ7q>+P4C6xSEWk+<-r`V@r1+9p{fR)NcYw)`A1?VfdN0h9)!B};y69B zDpsb!4+61|gPyfWrF`XbRHxH7KOV^H-oLC_d<=nnor zBsj1zS|h7Ke!J1HT`VG#cKVgL=a{BeEW>f6w*6Dzrz)znIDkGHWDu$8=mYM~91$O9 zk-UOAae-%7gCph~Gxx-C#+%RSSBs&5x2Nt6Z*OsMUw0WhVFo4C{iGb^Aj`Q5^J>T8 z>*(m9c3_Zsjv%vDJW~|BAQH1oFshS3e?9|6p?h&uM{E7vvr-DUKTsRcnMVRsXMBG7 zFIf_){#aR(9~Ee`&}LBj?k5{yo@@N@KF#$))&n2>*e^w{65}R$R|(*+!GZ(5K=2@h zqmNJx3Y$}!l&*EC-Fn$*LZ!1R-Aj zZ#C|@>5A6xEC4QO1i)!@+h%!eq$#ngoOjC$GIDD=TwGk9tLku8&N7oK5c6+;h~6{+ z(r$JMy+5TZhgmu^j6$VztT_)J)N?MistzGGNRzM_VsvzJa#B>8Slw0VpkCLX43IeQ z2N#g68hM}$y0W5@k811 zpXzybEz>S*P=$$dx&7~XkA+rVN-H_A>L}=p;V5Yy7geks6g4ZrfRed>ed5WY*H14( zisq`W$4$A0u!|Nyr_SG0VeUfxJDVO_a7m{-GLc|i`zMDY%pqZS1|Qo9%EIRS)@pEg zn6igQ;bif{sHuU?OAfY8^HEoE7$s=M_3a2Dq+mgB?AoDUr-R$p~M>Q zd~rjK3p}jgrpIFDYzMh3C2Zy`0F*@Xq=gFT4V}$TN9_99k*hvkjzBS_^tO{D6aqUF zg38Lu;5l;2$+6z_UMIjST~q!p=r5JL4Iikk1;@wv9LAH^jU-7n-;+f@W0N8K`uWJ% zhx=vB>)z2y?u#hhl23jw4LdVdD^uG?EBuI(ascc@c*56-jyC~jZ_yijbM8H^sPf$$ z@2%>nxsIYEQn3vGUvcjrO4YxjN4pNk_KaP%j}JzscE75}7Dfw4aqi6tpHdu-*nCVl zs73q@u;is8?NEW|6s_K^az=BGbF4Vv0Hb0=#U|^c`|^^RX>nh^2y|Zv|6IIu(Q>=^ zhGF(53lOzW#(5U`#FO2x9-ya&gg(PEHW2y{o`4v$N`n(1E*@;rz4n=3iz4QT;u*SZ*%9)PoF5xt0;@# z8o|>4|5O6+J$*`=W>nrOViLXhSELE61kURi2=RW=R^Idth(3J2P-~Xh$#@GDVe~n# zVp4_NNJchYzpw4}t@DqH+SA&D{Qb=jcmAPp!7agqBGy(NsUBXsRC|15A0+ogL&7$-AuM%S!+uAvTw6~^Ee+*WT$ z{!1A9?ptSJ0kJ5EAc2?&(sdx&L^B*VDev#HdZi9!%?ZOd);2Z}ggeb92Y>iE=%@f7 zvK_ZQh0XKH^F0^RLXjb5b9i{GDfWffOAI_}km&twF7vdtw}-|Yby?&=o}Q99rK`nJ zwtN<@?^Bh;m&bRa{ud)x=4-UqtN0 z2H|LsnQXu>yFJD2O~HKF2ZAu6k3_I9`7f#sa2{mDy(rTYYPEK;nGJMX(650he)+;W z${VIpyS6YtKaX0G+d?G)P#y&Pu!>{wUriHA{szS~Y6gGf=l?DFU80mW8o^0Dm^B>D z2Su8;>SR76Kk=95b$D|BV2z8PU#)p8*`)SQDm)TK{-a3EFk~K*azsT%kzEDSVgeuu zR6S8c@Y4?3`g!YO{kwl;9|Tmat$9bjezaPyf2hU2o1gQ!@+liVJ{V`>B~PFDqK zahvPc8$&`q1}@J)oN$+i1K^H?gxSNvH;NGTe4F#ZJY#ZZhU`#HA{^DpilEj3^INxd zGhf0X6*Vu!*UtF(K4&6&(Q9KR;OWFE0OwE@svrnqA@L;JtM71%XU^A8mUlu_s{$$Z z1K?UW_wb>_ganx3@UzjAPVD45@ihM8mXJoO*mvI6CGW46 zd+8#l=wV7BgLJr-pI@7@0GDQ!f!|wANeQQPFe?(6&+{csmEp^nk)7MeFp!xn=)KLh zeM|zf0p!NvH4qd~y<}=?Dgo-fR=hMFs6Ak|Ot|q0kjTWDwKFV4ArCr?HZlw@oK zrBN6zj7a-*(!V-GN4*2h(Ibzb_hWmn4m!#%bMj2iGP3UTirAz4OA?L}(EEre=zsME zK#xOY333n%Vid@L0^mMLX6}D%qy1&@TlJBklh2|T9S&V32h{y5(IIAD`T+#K4`PPF z{r%@!Z-C(rriuLQF$YX`@B7h9(RbBlZ*3Yn=R?DfmbyW^8|Y|-1`LI~05Fx__75C9 z>O|ct$fBVqUPVM@d4OrYAx=(fz0=z&`34{G9e$<))pgf2Xd%OP~p-Yvf*jS#^feu&3Dut2D zRJ(TVEw*j}q(>nhcOaw*tenq--}uB;M7QE#ik@P=*P8l9vHh0|s28~OQiq0>{_aVZ zBL~J=U8z7!1Ox<@Co8ymBa1TPNSWxXY$F@}bNT2aQU2Sc7e@{-f>oW76J$r(ix-v`{ zAQZZFv1UuRBa)k@@*31Q{47%_KRNs+X3fz@laUi zsZ_JD_G3~v#k1=wyRw61lE?Bi2x5VtGjZ|?l0pL8qW*|YHwMK-yeC)@KmqYUUwDV` z$LI+BhQCcK_Kkjuw7>Fw3kE`e2ZWV@X%}J{LyDn+kX^22$2HtQ%5Wg{u7$Wh>fL54tWq_~83k;U35CIHw!JX0UJt6S+Ko0d$ zH&MtE*TE=JY`Kg$32v`j0($!uaX6{ug_NfxjWJoal%R?3+=eh!%H2T-K+-~ArNc^( zVOioJnMHl4vv!8S+~f@r&}h{zofV`95_20u2^GK6EdRlqQ^^0fL;tUW3ke#}A}fNg z)gQTz9yM_u_}_f;J2x@#(+= za?_JELz}4V$iO{#pwC~ts1PLnrwH)^o)Ad6D7&FX#>gcmrsF&?clSs_`^>_xR37Ra zp>>V9h4V{GAI4tkA(HMLD~$&|3yLUYc!{Vg8|NL@*47Z^gAfBISvvw)&w=ql`#uH; ziNf|xkPwMEDVI0_O-XtX_Q)7}X)F-Iq5!hH= zo#ukWI5jnu^aCXDX!+~Bf#fWt4@1~I4Y3`BBIwx>hmfYi!a}Rbc}qa*geVO;8OWp5D%>yMg_QlLIN+O9+xIh zNbcW%oJ9sh-Aq=lhsmYjUPF+qYua%&e9c7j%vC{8IS)zRlTUCVqlyHd->L;ken&Om zmm-x*Ey!a3GXi-fJHa+51zj~@qLA7{Z39AI^FREWED}1@B))Z*vii3A^XbHaZ4LtZ zNK_q@oHcoWzsqdvQ66_H=PMds>X(U6d(mm`__!oSlY!88cskE}UC z_IB5Nb8)E#<;Y6CTMOlbAbspy%s{lW<|i;XRkDiG$3|(75OqeO1nW46sxKkU4UotUGJ;SuCdpv{!dv%}y2b5-rbZV_bImVA|#X#r})vSLvZFJZ{ zh!8%ZSq|nn@Ms|!^Z!+nu_hA}80uUyGsDBTNgnW8LJYnipfIEnx%}Qhqt%5&EGvUK zl`3TL#wYaD=r?n3iSe7u-zgxr_)yUKHhySL1bda$f%7#hvs&w4=Zf(-+d}?Um$Rkh z*+9G!H_e!Y9^zN$|K`gid!jJB6;;%&Kjs%kGc$+KaF-=TY)Z%gCxPjb|Hx_1!7Q!# z^irdNkn3bO4sV5TuZ!J@{xE8;gBzmHG?yqaPM$cjgo+AZ1U3KRwf^+K-0_Cu0Y}1l zz72H}Y*c5L!7q#itQizT1~lRc%`lUsJJ1p)R(WS8nK%`wVAv!Ijk#CAtHeae4PmpM zu;v4lE~%A?c&&BF%J>ajK#}OBC1+I)b<6gTceU2x?kNT5CK>(siX0c@-V2+DuRA$` zwnh`1dG7rI5IjnLE;&KUMw7&X=oG!rnvmn35C+VMGp^jGQ2n;~YE?qV$oAIHU73}I z))(GMn^$ERQclb=D!^D0$3FeLk2E@7pGASaKcXszT->db8Sjv|fzqLGZD<||8$&ru z{c29(kxcVNexnxh+Sr}~t6UyE;+2^h9}f^nOkA`33=%B1r{wOdan4IZnl+OoHN@sp z4YQN*dTEr86Ep4^z|T7So$CbwD<-)8*mvBqW%soqP8c46$(c{s^iLxLj?(fpBEx?R z+5o=bjxfNFSdX@PUqp%`@H89=U0wI>&G(a@5XVN=_OGzy|D6Yd&-RCy4ZR$)9*Tc( z63G1zCdh-70)sft*ay8N56HF_&T-5tXrucY{+<-Vq6;riPwF?iqku~%VOP4~o#}QS8;LzKxiHVK8%izVv$h(9H41%!*>E`(# zKOPhqwF0W)IKoFHw)bif26N;gi)@MP#iIq9Cr<{PrOsOBTfxSpv5L69BrtP$Ra#xN zxB*A@xZm)oTM51KcThED=Lkrg%+9~VszOhpfsK9rdO%L9sGy*{y1JQ(-$aGlLRsnm3k+dHrZ0 zhhtU$&h87TZ-;S`KBHy(rJsb&OPWkDNhlgjGZ`_h^dK9%X@N6o%xWqxFe{szP zUh^F=?nY)>lP~`4`0;;dc^X{vMyB*$mS2`Ea9w_i^>zp;*utQSq@GIjMZXZFZ4<_& zVq~4}3+w=_NNk@OUj4{Idqn6dns|Z-(N*#@dhwr{u2HM($(tdXp)YEKTy{+U>7u6F z`~$cx)t~td+$K4^-gCL5h{}E*4wy3AHCW4MoDrd~Pf;Fr!?@N1p-;f`NlLc8L)Qy4 zURs3QY;t>cLLUYN5yA5Zt;6ZzYX;J0EULhs3ZtUrvwM-n*Ov9)GLHx81Ioo)$50Y zT&`Dz-{!o9Xz9AXZ{TR_yTMCu_YL%bw~%E^my{9tZ;N|z-@xqFIAin@;a{|tbF_vN zMEV~2GdD-pNKndSpnwyb^5Corw1fuTgIrMBaXCn8N5cPFOZePyxMKf3XvQHf{yRDP z>2-%znIQooVdVvymN#BE;Z(>1uZ7&N=c28f(e@S@DQVWNFEWiG;Y#Z2fs>vPV**G2 zHVmcIv!<7Dlz!BjmT4Wc+YCHq+2g{*5iw@;lT}n-34ME;C-pct@J4 zf2C6kQi=CYhsAY-1cOGBBJ86Nf$Zx4H27bhY5H`+w{1Jl(W#)YaHJto<>FTLGz#5* zp0+CCOaCf;=GAGn5o@&v&PPc+?5DhR*1%|{4&&V{K2M~#9m^mB&WcS-*6k0ULU;l2 z!1S)=m#2py@&OZU5N6K3+TM#ZYbNrKS&d6;r!Fi{cUX!)YlS>NQSQw{&>6w}QH3;e zZT$rk)7`{Y*_E_V5ru91G_`U-l1V@Q!7P!jyy=i}YORrXn?0OVg$Se8&Y(DTvzKG% z>u)t@{Q!vj<+q6qG|Fpg(3sY#{#Abzvq-jhG|QMa;_-JhxuMMa9|&PLjg@cMl9=o{ zMy9pMGK07IKeNfmuHGl9nIEw^+rMxS{{hKg#2Y#UOc)#Hi#4(Xf-nxRihaI| zAR?31E$t@HxIcV2VORa{oY*6K7c`nQDaGc^CRZOd*E_2M;hZy>W~L}=$~PQd>5!kj zrKYC@4a^3TuRd8f7e)xIHEM>6TxOzgWs}03BZ!gu8MgS9Nx5Zw=gwU$X|S?OEiNO#JwdAxELU=@CF!5M0{a?sL#u z508~WQAil9%dHNXgq%iJbYpj^J&Rr`z#D3=44coXk-yHsFVOo${*1|yf5go)AN?IZ zYVAtGRXns~*TQmla-~%R2{}#&Vo|&cSiD-h{&!sePydl?0K&;rH?90})ju@N=>acs ztOP4$r{8Y=RQQkFvA*O#a}|&MJF1Hdq&$C8{Df?0bSrlD`eq&i#vqiFO?i-PuEoO)whiv|?5kJ&8)vmS9CU?`f z-FA3lg3l=@={+bfFf4fMsH2a-VB&d@1<35WA}5-&VDiwA0LSFk<{g0@*Ya#D+o7-tFgwkhrC0@z||Mew#wW(?CR-B`)8w^B4DF(~A zJZcV-m!J0q9WPykTJpbOIm*Sw@-TBYq_h5aLOkRv$b%3CuUut0e1LV}5J)lBp=vNc zne&&Q5jJI4job|Ec+Fz}=HJ(fxg_(c>d!c3)oxc(GIcR_RJy#5iJSb3x5IbcGqO$+x&ugCL7?cV7KLY5{lDhC~ z>iiP@=@-1=JULbTnvsT3wzFc9K@p6jfDz576LX>7yRGCX;K0oRcM#(JsRL|@WH4(Q z&X{?-rEPDL)m1V5|3l0|(Qn{t5PHQ99nSR<aLooO@R{fri4$TNPcMF63;4B*iJ}8XJ zOt!(`68e4gPM@}b_dGKZtF_J`Vp0i{kR=<-`>*OtHpeT}q^H_|g&GI4N|}-uv3?p{ zERaQzpnQ>pLg!Gvl42#n{h7EgZ`s`ucv1sfH^ovqM@Na0{3QDEuvuv1pHIK z;6Ega6&BOGnzi26c&BiD)-pMS z@a4Lk=j?7R~b8yRQ`FD1uNVd#S+7H1H+f|r$9r|ns&?_}{Clto>M+Qi=%JiDUbM4b|G9U0ur8m2>p8w& z;{4w5SwV4vgrGieb-MesV=&F5T(j_J@}+hq^sMb;08hr@LY>pfO{joOG{>LUMt;s! zR+vu!7u*n@U(fNlcTZ7f#Bm!Jc0`mfxvW5n0XAC5c+cNPZ@EmL5u}4A+MQ(I%uF#! z*$7zI@Nn6#S~HY>N(U)Sv4<(DG{T~0=f4A?uxOc@AF9A>HG;7d7^A2tAfdYe@A<<5 z9q4F~IRZKlielhiOXwBb>^CP^^{ew-7XpZVyXonRvTGi7UzU8-eKU;ta#(kk50_(8 zKytR$IDtWIQo5Y0|X^&#cbT;HDeXn1_B>B`rFz1BP1n^!v@ zxXg|6H5LsnziD_Z=GSGj(3e?8JN0vAhDbZp@7=q1jZL2`%+Crf8jHBj^=ZsDOZr7d z*y0_=teJFUhT<*pd^{Deoj!0yUkEhV}I?Ngb8HAW;P;!_lBmOHn&yk-vDTjZ0bo=tlMKjhvoz1K3)vit3ggOQ~bMRUqo zcWiodU!k8sAcibCDa)?C>i>>rX23fDP<%{b-J4KkB zJ@&2Nxf1+k!H>#)UzIOT($C+A@RcOQ-A z@QvQWEa=reuV2vh_wWG@KareFljFQsH!mq7f@+DEyTh(J?{X){wE@{;%?G6}y04vW zZKOm9srD+{&sf#u&r)aL-hc3Xhx~`I@gAHUTyfX_OP}*aDcPimADHQ!$uKN%v|Q8n z0ND;w=lE^}>>97>zx4NKU7lkD_w%QS%z5!exmBDj6?1Pq7R;s`Jw~(a`-gi0EM1v? zUDu>Q$cx-gW|K=e!mQi+G6~-N?Y8Tc$N7YW$g(9Q42vCUbhW!-PF=?Dww<>7Xdp!} zar}uWI#Jyud|W@j)UW=l-+C!R>-;q$*p78F2%N@mx7G@pdwvW)Vw72iyXg0Q?imba z=Ea)NcibmW;a`^IH%-Y!&ka^zwOp6ICGX^`Ihc3z2uuQ=d96A@!L=}~5`CBVTVK&* z&B3ILWW-6qy)M(W-?UgY?`q{;>7X^gI-r&D$+x2Rd--=Zi9_MH`X(z)Fy@|p z;OVEy-jZi@{q&v}U{Bh?N384IV@t2vhw_ZUd^q_QB_!g*_uVNU;@Bf*)=%>N+x7Lu zi;kSkAGTIlB1_G8wuhEvqJ#{ztuKW;O|00%JKuy5cVwwbO}IE2!jEdL_Z{^hmkF<$HF?K#8Clg=H{I8W)~a&&V;O~BTp#^N zF)3}94d?d3{rkS+Cj2+F3zYDP6Aybx4>O8oaR`!{r=L@cqI;uXBGc#_V5}_#Z(GRf ze71XqGMYVji^j%>C_I*CyPDw<=~2I?U!CnC%V`aUvFJKuC|heM<0%J^(Y-n=#0I80 zp;^${ntPowtZjh32!uE}m#QF8jUFxvW*Cb!#UIsq&MxInohuswnI!Zw#||CH+xa=y zgYl_YGkD?{LK9 z!O{NKUy7H+!66`U?Cn5%JKaG%-1(lhg)`SHVdn(I_aCQ=oGTEAs(R9X0hUm2ECp(3zSPffpBs>4a`D)7 zpXZ1yg$0ptgHz4?nmVh^O)ouGhDyg7%*A}zjwk0}jpm6HDr1mBgV0jz{2OZ!-AEYh z;5}+I*{KowEhuC;ye~t)AKOaM$2w30t$utwNlZmi4ar`fnNWJ6KWAIrj6$z|5S8|QMSU)u9QWN#m&E+WyNX^6kmj-yt{BnHh&Sn$-kF9#{ z?^o>zp%>KmAFxr3h?9#QYLdS;=I@us>?!NapBFRVG<(z{&oKC%sP)><^P8|>x36$* z3YnLz;QwqZ3O{#g zhtFeWnxLdr(S8OA^f25cm9;~}zCF~zVh+CN2f2N z5HE!j`-r=qgi-Je@%fK;Up%ENh0R-V)W|04u2uR4k_QHkrjGkNY&ns^g#~yQyu|K0 zg_~R*R{wA+mrS6{ZbOlR)j(P38FJ=5UXAx_SnOKxE2lGa^2}cGZuDqx-YMOc{h|kl(-a=)waGPrhj^2aj`PJTrrIK;8VC~MP5H4 z?-YEk5^}QWM)2yyDvR)WEV=-lHM2`E^IWnobzL>o z;+6GS(tMk*8Ob&OOrE0j0dK{pPoGfNSgO^Xyb+hmCZ$mRntm_&be2P5nGclEFcyq! z&o_}%ua{S&;Sx3w~ zW17CD(wRNF+69nyYFU&eBxlwX;VXuKUw1m!>H9k#j}i5$44GKFYUIA!UFd5s^qDSq@yGyso<*$%I5a=hlxde4>OG=t8us* zPNOwd3gzr^YEx%~K2}%XrhG`@#gj?K zf#q%oj$RKVBB25qU}4K`kY>sx-;N;kY{DZt?PJH3qDA(Y9CqMsJ7UvnlUL4Ta6J?xh-M17c{Ic83cKDcSB~Te`1-fixX>6GQ+4Yc2MO z_hUX2I7a42ZsNls-78ZRCs++oi~-iZ{#>pqScta_iD%D4*k!71|2%Vs6@s9dV)`cs zZ&G!hVuAkfW1^Xch9O++$Q6!ylCC#;M9=~OklH#+qC%5q&_=WczmE8C{MVxa90Ek2 z?ri&`s%i7@vfp@D=Gf>0NIKttX%yiWSx0K#5;oYW^I#V$XvGBE9!$|IYPz-3xEDan z8?(rPtWlUsg>agMwx;;;D1Ly~EAOG_AVeD{cVc`n-XMzYiIq61_}y|s%npLrdkR5ze@bNIKPZXl_tsZnWO*clkRfBf-PQ%lKby01>} ze-bOLK2jAV&T=xOq-lF;O3yzCWRY2m0TCFkw{UJjZUkz}4bwq$iS&-hTZu(fB)s|V0JHNs=W9a@s%-lB>HaPrDP z0m*P;B78+wbqKwRMaw=<8M{4zd;oFzK{URK2+*P4=BBu9{RKPe;dq@GAMFNCd3m$9 z`KJ<{337`f|#nuBRN4&af& zShX3D7ie;hr%%(WDwT)Z_uW~7L|Y(7h)s8J)7*JmTif8LN7yfSrE`X8b)*~7L3G1) zc52^iujOg_M`EE$OG#=lS{;=R;Zj+Mym_pAA4lv4%)~&K85$Zk?WKe17wYa4ciI5E z;g>s5ZIOEK3Z@#P>Ak?8kX7cj{kYJAeJ9K_1YQwEO(NhG^os6Ku~%L>U^&S4Hbxv2 z_9N265W%IHn(4?SO8XSJI^b;%A3HKGE*t`qR%%y-;ftvMfy6#ZmzSl{b92KV5H&JS z(c0@M!@5DWPjR+(u*)Q$Lo1ha|9-W%Xs1>VE}jJRXavs7nr{8sy{|3tH^vF4IZukwEnHKlh;0pg0MIQ$GN8?#2@^8&9*x`@*TaAavJ)`Avv)ll4bXjx&+G>5 zAV4gpfArm)4?nT0v?Yw(HO{ZrtTijVd_*VjIY~_}Blj1UrStTXu>VMo5~$GGM{fP3 zC{|DFj+sa6pWxs2nwE?#1@XRR?^5ciY+&X4MiG)_3ELG!p5@zH=9B(LvI2E=#Ps%S z9t{j!TSXKs%G7F-w!Nx|r*h2_a7{GVz*&HA+_n3hj+4W2s;}^r$Aypz3s`J%w+5<~ zFEmz0nJp9YkAn#a|I}U9b}vu3-Lkl3mVWg&Y8{id#3EK9)ZkE;1vqrQ60JDn2uU@G zFw>UG><9tas@A}OE)>Y{s$#}ruzHab3tOQDi5m<58@7fNH^sqv8+(&?mDco;_k{t& zrW)wtH$H`-yBb}Vfh}0H3X3ynX=!;bgQkIQ-|OXa*drDgKDx&Q8jJWg#m|pF#Q@=X zTY5_|t^2}vkAU^Ve;9a2)V9?_h!aG=XaLpcDL>!2L@Tw)B@ehUcUcZwTs4$Bt*5tt z=0p_#ZD8KyED|x}p!#@>5j*dTIQq`vL?;UHZTdG$od2rj&hSDngNc!G)njI4b@0xT zio*KXa;KWDOyn!b`YFF0pKoYZpqnaknS+sLd~g#`VOCbgh0ngwsfOe$nhYd}pk~43 zorGhLw@w1k+q|2dlJM+UJqZ<)WDCjn&q`+3D?yB|fH32$62tLBe6qWc^7$jWQh>Wd zl22vF{SV0o0SiDK{X0}+xy-7__*-0UZkt1RP~M<6?ZS+qK8I4ywj*A1a)v7Qspj!b zvT}zG(bEiHr@t91_ooQ;7qeceYpVa)dnk=Y+FRc2`LV%5{J(?9GPJ&QFt`j$)hT-)e6Ze;4@>s*dky_nzLm%*ft*SQTk)Pf1Er^D0&PwFA-f&Cqw*GQO#~LE0$+2*Kdm;=6@A@l0`Ak= z)`%L{R*gy!mugyKzDwd#?H<31H4U>N7dp((d4fL7n!{@!ug!z}92(l)c66=91hH@v zZakn14+-P($QCqBkyOrw`*5L-q&e;`oXyh!6D)S9U?*)z6UlXEkvHZ=yhcA$j3vaS zh~cBVAzk6UCjqcx^X9nyZD=mBScwW|Tj5}QgaIhaAs5uK|LB~){3BliDG)z^s95w7 zH^c&ToKy3mm1P+c*wwA?BG*4Pjf z1DxC zbI^fe)c>Jkm_;no3!;{d06mO%vQx3~w7r{aVY99XnLadm#gvC{KX+qFKazQrR827# zylv^l(bI3ap=^~J0yHSyuyh|RM>>5$yMQBMi81ZGMubw0Q-RmaqYD`@fcx<-d&HCN z?a$XLCz@l4GCTf4e2P_0{HB4RHnA^wD>nZK`9#7e?@0`1Af%URr(kIxj?y08BFfko z?_cV~TU|9|I_%J|Dp{OnP{sy)0hU)Hf^q{AM+{=;{JX~`YMbtZuKfPmMKF_Pyw?(c zX$QXrqIk=T4UY(3cIkfk)f%X)@=JCI0L>B|##l(vznJiU7!Do#fm*_f)qZqCauPv! zN30M^sDuI+F07j3ZXoG;O^|a|5vm|%p(FtF=3?(aXrWtd#i zVi^yOXw7;;+wc?mQQ zHuMT%>}>KztQG9>CRdNM9Q44pG`!gMFJZVk$B);SnWt-}nwQDrKdS{@AGK&0sa1Bj z;fKAAyhi5fh7$OMpDJD^^MjWCJpk5sRuQ$O(W6!L)y-57QnUh#ii%K~c^vN@7&l7) zjIPvu7#Ao2yfnTxs(rG=%;73MZ!e;2`)<2{zz@4e69~V;CbfF#UNkj}%m9xiV&A$j z7>}o!8g%F+hhAy6<$>523T9okVS@Fenn3v9nVAwNY1+>yBZ}z9$@0x)&OD2`eCHl% zd1yX~dWAB=xXDmGy%>byUu$ZkCXX9 zVN&ZQQ-x(^d1(f8tm|pIIfRYAJ^<{_2$gy)lQulAzGr?3CXhXnBYRy|z~e8b*Uk&DLTJU8DL1m z0?xvl(|Lkg3A4IG&%bhVi;?WD`E3$mc^PE_vH%WDJLUgoRgeHfMZ@bL3{RVD4T_~49< z)soDR6E01+_o3!tpzRJ~@#i-=b69&aC+T|SjST%Is`;Qxx-!zk|HcYRuiBhn(>n|l zlf*vK`{uIpe<&sT8PV`wvRcHi^b|kQ931-M#@VeZY2SP17iXCa2&HBziV;3=_62De z!@)ePDWLyKsZa41NLprkck^)q7i&L#s_x7zQ%|)4B^gBd3hx!+PQDl-fKo0~tAikQ zW7&v;#gL+nd$^r;cS8GUt&RfC)X`h>IE}spXVY5Og;4r0i$ovZnx38>4UIe_EVDUa;zG@W>Q<{(3oCYU0hVQI7Qtt^KEdpj|c!s5Y_YD?_>b^4jvL(q=_u1JEJv; z6Yd{sYIa%FQnv(gv>c0>nX~Z&v90Z+?jjoJGP=QzvT>2kLr}by@j2e9EwPa+7|b5L z`50()+v6z9DuP?u^ZtS6V6Lqm@!?4HmLel>N542h|I_Lr$VY$M=C@)?&P=tnI2x0) z9qD6H6 zPoL(QDJd=%7ZRsV{uq|xnz}MXMFe-?4mM3Nbkvr%!%pqRFSk4t;&O|?mi5@>H|I)WQ`~NQm%V}etmAbz2s*;XS@$MK%k(ph#Z3qxcKng#&9@&i ze8qbj9tm^4)=xi`&9$VChrXWTmzwl=ri+`)^9>Y^!EgN}X+6F$d8XNkrZ@x36h7*# z#Te&}=)iJ(D1%M2efRU;1ei)}|7ez|8jSDlRO@#rgDsCvpd@o`wOCeBr;{kXI{gB9 ze((hic$ppd9ZZ+NAB-HpRaGJ;O1R z^S~BTbVWlKY`o%5eNQw(g4D;<8sbG)Pk4grxK4~hB`ge+=ESu8NYDrqfk?OH5MTHW zXu+U5S}e9w$oxpN5?nCt^@cu1AYenR@BA=r!u05&~`8~wY>|j&rW`rwfICX!HN-SL}+OWb3bcE{o znR5c=XpK{xtw|3Xa)-~DGwE&gK>F^i?9+SL;`vsIy(wA-T<{nZz57TnQ9YbQ766rX zL-DGoQL^gUdCY9=6$4z0QAYmwADR)fZDEUu)nLS7(?WnR3`JBT#y}p7QAB8)t=LW7jX2|zc^(6}#>wiCJR<#ptURB2l-qh95m(Nvk{pJ3oSnM)Dch~wGfq_{NS&dl}D=rH2}@Wv=+pDa+Ur5YNzV> zdCXYkStvK!ALE@PyxE}pnE{2Ym__tti~%*=_4S9v$S3w11gI5q`NLj5+j3vnY!W;& zH#aw1OolgvZ{?CSqm{dF3!U&=3SLxlAzI2ItuOMf7Wrozq*ffTu@M2w z4VAZcot)*;-I8CM?=FltgvKn_rsP0fJaZ(EcTU%q1f$Hc<8qc7%V^3D?GgEjYZzue zcnABjuG?gyG~BXKZk|uM@-nmHLejB8g#ZcHr2Cc6=MCFEr^fxQ*(XtUlq>-zaTf#c-%JH=bKcweW0&VvUZ%NaC-Txw%p}X;iZNM z%$d=sTk^d0=mfj*D&8eamukKyv&6Palr4gaH&AGXVPG4MRLHUy^8;A<9{R&10X!M; z`NEm>ME5ixuu96jR6B9TW=xtP;AOgzfjqJ5#QL~$VRp{m*1Lyh=NVe;aEsh*T)*Bi}6Ts)W5n{Nx#zAU9L0GAS&l{S|wR#z@(%nGE`uXA8z;Jf%Bl$CQ8 zB|84FZ|A=8AD`8R-zzCd?BmoWS;?WjXzsf$eL4Wdy1(Ag2Ix*DVW>1T8zROZxb+zSdC8AO1 zuZnu068Y>5z%wl(ffAKo#(eXN!0JzcR=U}SWI38j6PX)(9zwp&Pj67cSX&#AbEUGOdpsK^aw9+Z;siTkAfoT z+*xpX)p#E`{Y3EB+u8&kqWp&GeZuhEl?tA}+!tV}bw$-#r=v#^|CtuI$M%U+@;NBR zfl*ozJqT?%*5kPDB~ix69~OY%t_p93N_sB=W{HhiCHF@;d!q{M=)lS9yes+*d6|vv zdmrr-Q{*a&vn1C^d49zEB}2||7SftRk==FAmE~C!3e|*C6a>?*Ya9C z@DO(%wX)AG{OjCS0;0KhJMY!_f?L#VH2QoY(d=$H7PO5zNyA9jnD*){;Bvh~~bXkqly^0Aj(2kH4MJjg(1?QtP#q6*ANFpuQ&kg|-|j=gREtFw$HXXiZ|j}Ita*lI3g3zs z|LV>FMwY(01Nb0TnI5W9fCNbdVCTunF)p?c1>cFW>oURNp4P0J+;7+L|Kz<(7i(qA z7#qwlV?#S61!iHMw!XqvE6zDTPQj?vZ8x^!_A1W>56M`+yK);=ku6*r$z$-v*J;JUw~O#$)h( z^%|lh(+EY}U8bQE`O)>qe**1)BwfTCKjd1lynhgRf%aWpUFcb(Wj&*}wPW~^|LHL5 zw&$;4_p?YK_zyz*;aw?yd-XOV z>PO}>N+v7;vbHpsZOJj?j!sDg|E+5UR)G)z zIi4u|!>MYonJos}`{gHINa!fNpbllwZ@nT^05l#MJoe%(Q}adNDdXIa%V?i)hUaG@heG-mr>Hu+xUIuHwR*G}~_}aELku2u{&h6Uwn%s&_9^>E7%77GWpN)iOx9pCUEgKmLsr$`C}&>uo)5$B}2DHX?BB zt`x{mPJ5oSM=Q<=Y&-*DQMdoA`g%?|$3=*t1QE)!-4U5Ni>%=#I16SHzVBaSoO@!; z9-TrJ#-6!M2=2&wr|)@gM$8w(rpMe;(zZi(n9Wt0df4=I-cgAR+YpeYk|pGp7CO_r zpRZZ1IHR5T?RAL)WCW*ApSE#(XffXykWfJOTnZEYW0FfhXEyoUiu zhGzgv{4KG46ViyiX@S@+;pab_7Bk;(E zyX&xrKoOaWN6KT#VoW_Tk53$m{&i5IlpcXVtyd+vy z#G;5Ml@K}6!D4qkr#6I_S|+HY!9x&QU2kRqwJPCvFi29O4t@tBP`hsgQlSa4^uR^< z>XPZ2==h^wYtAq7Q?B_(7eXX7@n#PFzU3lH`R%>{zAaKX36J|6V+Yb3*Rx?+s)3D; z?7DT_2-_8ed%&E%z9~x&AQARiA2Kn{+UiGXJo!RlP^gk* z1{gFW=$u*~b>F3-k_p6UDFf`-xYo~d3D`%7O4p|F8GO42d=SGGibiJ6RxBe1<@ zW}8z1#W27w{?J)fswu;Jv3OItUT)1Z3tcLSOGe6iPJWMeN`@;6P$CyvbcIAG$MT&# zrZ%9%0FVqPFp%7Hs07V@+qq(&o>hjd@7>Fnq;>VonO9Z=7epJ*PcDzysyNMzE)J1F z>va*YTfjGLRzZJdg8u5B+sF#=CpfpF^`m{S$RyVrJT5(o-j{;d>u~0i;NQvvEd%<8 zdFBU_NdfHWQn8(PwK_aBY&@_NUCdVto?m`v!K*cv?^TJW z?$f@va;P`|$m~JLcn~ z9g~`kzQO0;Lv!l{2!uccczFRT=7mkm7!&UCHXunaC9r^6Un38*b{Qdh1C=p>8SWD2t^Q4c|LDFH!TX4$li+KHm z_KXGK@Bs9X=qf$U+UUuec9K#iug}lO{#ru&DjA6Sg_&Ih!b4^1BnhqhFpY;r?$k#% z=oL`gT&4=yfx(i=i=|pAKP*Ld(qsdR6c=sUmgorZ7razj6TbVB;%%oeS~3LZM|-r? z0EEkIxIm?^pms+8sSvOLwMqhx)0Q;TOuZqB_m_sXbLNxSglLJgP8$ysR9v)fYKp{B z0(sr&8U)p>I(`JsbdGD|ArmBe(4AOQh>nPeS`xFMX<^W-ns|1-mOM@bqsGUVjrn;3 zaGq+%A^TT(GQ=-!7t8%Nm7aReNS?SmImP{33t;v{^lL$T&@g;8XD2t2UT>{}HAHxR z_FWywuh}=9LTAz8#BImO3Q8A(VWFH_F>c^rZlf|9wgqU0>%g<;F@PGzEBVhP#qjVo}??cqIdl~3}1*O!Dhq1SNO(lR|Q=Cff0D+l-<2`ZQnf+Q}Or!u-j zB$Qw7BA76j$>uen7~gkwEu~HXVr*dy)-|hF|7hZ3Av%sl4B#;?6cLE#GC#L}(vg>KuXLAg;NB8$iX%pMYkv#EuKrUC?b@ zUCmKa7et!_l5hS!?($$Y7dkLFt+$?+X$2T0$(+H6U^7pB8}HwfTEJwk0DEqIO= zgUKpB5fd^Va}D#6Y%ECGy3Z6(8s7g=t}6uxFwCur8dW{SgW8=rC!!i|rwUITbr}C9 zGdq9B>B!9o*b!Z-$vvTs{GzPcN|SYOuw8G<$dqfZrb6X$vMMpj13mY#J_h_sU`*sl zX4|V30qwGWcRfESdSe)BbP$ouul+l^;2jH6-MaY{4V_utlsqkFoEVs{*`8h%>SY8NcHnL^`pXJJy!YZ5@3EWMMJ+ zlag0fYZw__vGKrBvb+;HXn9pi$7%OKEwl?{4Q*cVHq9%Lc{HRigBJc_dD}N_ z;eYHs!t&}_65M*?&tR;8xP31%6naV6fL|FPyGJU{&PTm z{FfZe7HL6!x(d1t6TH?k%#llh(nbvUC(r^t*e&)&Ad0|VnznmxPxQhl2Cy9(QRE6N z<5vwDnnE?R2jY)UecboH?@o|bZb#bb^f+n!^`1M+Y{w_M@&>zboi3sI%VZ%hkVEMXGYuTkd?k*^^G(KK z8Hupa$nM{M<@eO7#|jlR@)|Dy(j~M1lCa@koCPPugN|_fRVly>3%0P4;7xTPXeh^! zEX-1@Tc0n?5WhMoqkCAUCcvg*pVBtEGPf@N2F-2TysPc3JSr~142{e~{TGewoGmT} zl1xmDmLGcbs8z=Q8XB>eygXFZZ?CpUBTQ&%{qerH3&e?T&CqtmJ-#zd%Ju^i8oS=38`7aq#S34bU%+l?yI)Co$0yZrYk-l8tfQZC_ZerW( zt1C>%*$! z_`6#<;Ve~{gBw;(NMNgDwj5cXw`5sc zc4as-1Xe;|(_j9qAsrg>ut!2?Yf~#P-U`AZGB1nt1dOQ;|WN#pI+AS5S+a<>VHe;N7>zAasS- zHEVhbQ`f3rJQYbc{|nvd>-b;x74jI~{2RZ>UD7XUn8uJ$?MwExk#7mWPvP$2Ks%lb z(a_<3Ly($f%V_br@P#q_fPkzqCD;91C6$wj{W%3v@mE*vuTfj@+rw?%xx| zWYTr#84hcWX=XCYF8E1X0jBX{M`?({qZPfnx~&_)Ny)fLDB7{c$==Wl#W&%k2osskYo|$(v zExdQnGPvCUdyg(3HsurpfA_oK)SvwuitvB1>93)T2c_ihU?t8{V}TL|Dio3R=ZIWG zIc+GOng;s+mN6mQ1?@u?V%lm(N-?Kd|FsCcxWVwE6BdQ?kGKm>c2dGi58ro#H9_&v za|Kdl_pUY*S+RBw%>AI-NTC`*U=geW_1$7qAMgQHRbyG2L>eqVkw^!HFD4mC;=FL+ zjjlcUVoOncLRl}1{DIuiB!$WJlzsPd@uldf^~FX4J3M+s^2F-XQqDJju{}7Cu>F;J zoiRNtd}wj_w2FJaRqxs)EZ!qK%wgEE1hYg?1fD@iTDB`Oh`ef|EBX@@Xp0S`+0-ci zmr=HqaFX@^9zn-md9ByG!B4s;`0Rf^M4^5-#m`I>Khed0)^Tr7QR`l zVZ*RQN{an-(8rw~73bIfh5-zglgjKr^`92FxPL+8`!vzy{W)idGkWys;K*)s(WktR zao9+=1JjcuZNUCVW)chaSNZ`623?|qE&xnSX$&)PBTTjF-> zA~FHRoNG2Bwhwge((T8j?UxANA2*S(Q~FbrGE(OvZ?6Hgti)6p}1L|6II}tw{mZS%CqH8DrXybn zg|KGgOo|2vv5g!~B~?lpJ|rW93`JKI7sW~7P^mGDbcT~>PWds-74d)b5~{~Jw=eA^ zIDgect3lrYRgVhP-t>qnFsh-}GOYz1wh1g8!rQWpjvYTt8qRvgbc%jlfm15#F0(sJqJ?L zGq1)Je>`8eDa~c#z2w|kaT|Npit1142m2o5R8>mbmc_EP_Nm;_TQS!(RYc;ruN%&oB64As9(h-x2B5kK;nhv?NMGs0J{qZeC_}J##pYEAm%o~04?J+Rv z12;X#KdtWl`TbMPd@nEe78yPau`=O|0;trYY5?IK8p$Q(4To3+7>bAN3I5N@LD-zJ4$hR!TFn`S7R{ zU4_ushgA?6!V+aHh--jjK%;c>CwPsixCX|~GjADVA1_NmZyrW@8KU6-3a4a+`)JSE zyI)$%E!M{2*=p@|(IlI1voCOx%|@Eo3b`Zbx5n4CBU@o$B$y|Xo6Cnf2Lr{K&#T^- zdB;}=N3F~K^y#K$L;v71Blo_Fnwr_xHDQ&_gI%du1=rt{wKcgr#Y9gO;}TeR5S`u- zV3!~JxhT3W>7 zpUoDA0B3?Q(%3^OvT_Lnyi+cYFwU7@78t4m#V9eE^jJa)guOe|K!(5T!(1vBZE~WA82|6{&Pqp99*)16ie9SOQigX!QuAITz zMyrpDT{wcm$S(R~qv#$*cpB@tpwS}l=?ZxQm(1Gl0W42#RZc$|| z%6Cj&-XSynN4gr4ZuD7$lzU;Y^X=I=F+e#!i(gLA;&V0O>^%5RolwuLfz5VUPuWz!xLk;8|# z*wH8KQB8V`GlRiz#_&8_>yb1=gUl2P*Z{9vQWqnVW)_*jGYztRILS{fcP(d5l48D` z@aCw~1`bN%fk|fH3jqqpzbbW5#Q>T!&Nb&>MujfZzZHt_LkuDKcMbUo&|_ff%w++$gCJAFnmRb`iFPTZHKJlf@ngkFew^H3mPvcfH4WA|})Zk^AjE zMaMLr#kLwEt1g3qelpne?vwubfaQm#%@4{%n1jxpyPPpHI9ML(Y`x}41;dADQ4k@$ z6~<|;@``)osEpTQFfl-{JQ=a+)DJeJyr9gzccrQJ03pxRadogZkUT4>%)L`h24m`z z;$E@#ybZv;Z2`jyGfZj~+uz?GqN#tYBVBJX39OI;C?$7Crt?gAOw0MMFE_}1w9Ua` zWvK5BIadORMyjs+)d`ZfGj=oOhw_OHGcs{+nrACdas$`zY@I8}#XHXz+U@PHCw~64 zbhi*;n!7+79|$56p;4T6L9M@oZD}qHeH}aU-xqB-6uFBp3#%mU z-ejbb$HX2;kAhsKDr3*K9pTfGyTjwv;yUm2yee3oB*l+Bq&&Impq8NS9P&g2Cq$SJ z9PR(O1B&(MH{>c4ztv|-9&_J3!m{on=S@mfwePcbuNQ!wbQU5F^}VKHd5~wW+#?hK zL~!wD)A6wDfZUann-YNRkV8vgr#c&}G^3|c8&^Nv8I4nNuLH^(3`%@#s6H??F1js2 zxy}lwP5DYgfSPI}aWhiqbmU1Rku1KA=>f@GzdN?$G!Iw7$ z7>XX%xNBc+S=rI87B-pVL>ua&VR=&`{l3JW{_ZaU#O50t3mYV!K7zWtoHl@`+1?wmGj?4MITuy_h=(fKy{(SdhQF1} zY{9D0Uyz+eL2J(G-nCDo)&-{V@L16TqIPP?rjy^v>PLQ{#fY{DZN3*m?H@2UZlc6$ zP*_x$;8#Vq$OQHHf&&Oq=61(%63$DcO9nbj6#C^PxPjSoc=kq*utK2 zX70>IOxf2S&VTRiL%(LREHkX^K}C#yD)*a>JV@*jHQOQXj$FlSkfxo=%Dc=}ne%DN z-Fapx$yJl)a{5b>LGh9P*Os<+{0Mq4USYMDe_4mcu&}ImJX#95(+ofx-bM1$ZnN;3 zS<`gWkFMUtwHf_VU(3GleVS%7LkocPA32OL zhq)c;Ieb#^Bcn#r3yi%vn>YF}Q5cjzMBafphq|g&cQ6kwCW>6&7OOby4k5|Ld5XzD zz+Ys!=6LIdKWZ5~b^;wR+^G3h_kiTmla@ULodY)oC|EV{^I58QWV^M+Gt&qsSxlqPx2;GdND*8s^%*?kI_33~he^4tGLU2Gp^}mkl-S1F zk?X_9{TIa9tL-N(pyB+S{X-nu<3%HVDtAlbu%;a%-jeU*0>! zCsC+ByVYxwE56R3DrY6t9@)+$XFtEV1nUVT6v(Y;p;Emw^NqgD^e~79Xyk-hU}Sb^ zr{bF4D49b{b@rHRXe2owtE{EHzV2JOx9C!;Ne=cWU|BqYTP8mmDB+~a9G>KjlMy5v zVE4eFH?Y^oXUu9qgp|-9(Ahd~Ld=7pr<8wFB&pAExR^JE5z}d^G&`Zi|5tB`Vo@ae z3@*uL<7sJU?qW*wWf^5oM@huLLq?hEB>riJPwUzv{&6L;JVfBBTkM4{_<^u{435ei zXYh$A)Ubr}S>m_1NvsThi;~(-YM}TNStCj(Y9v_NdgrX>46vN7cTDuMJU5f(os@yF zA&gW!zKA+Xy#2~b7Fg4vc0?N?Kjz#jW2|k91M7cuz())BcT&QazKoT^cv(h;(^2s1 zYSUSOv>taq(H@5%k_x1#5>L1NtGZE5=OI(q1h>WX{l^zEfl1rr5#!Od`IS4UOt3G6 z9(k%3##tY~Jz*}htF)-9cC3@Y`8E2pA-FxMgk-MC5Rry{Cw>XA_xt zLv#A=t10!Ohw}gA5ucdQ@AKu7OXC?4U;Oyea>!6!vD76&>tmcnckPF;uQQ9 z_o(@=M)&Zfa4enDEQ&zbJO=NZZr{$-T2ysuge^HV^r6-d=HwR8Q<1QWA#-BQc%oA* zqICDSwwD7!xE|lh;G;S>aiyl(1tY5dCPRPu`k?gIZVcZ4_>zysdfj}n#ZV{1NMg3} zDlz>&G4tt3G-Ndct2JkdP7W!e1gNy>?9Sr037>jmfj(6B0z7 zHl1I%`Ela6fk6%FNbO&tj}BF$3YWpu+>{?Ep4V(tE@WZ9Pj8-O>?6m;MN<_RW$??! zu$OH4g6XHej{jcWkh?MtM8J2$pJ5Q`{p63&3o>lE_7*r;);Fb_bJ&KUf>{6+Ss9W4 z*_Er@YEUCE*+v1BtU*GlA>OHU{4$f<5oP9$j;+~TpJs+m(CWtW!`>p7IwtQO#puhv z`)=nn+o8!}IOwYf^$h`&(~JzRpap$;F0?B6zjS$vcjv#474^g4c$AZ%fk%M{vXttm z0Uulj?I7{^o4ob|kw#vwpSiIhd&tWvB#|D{z_ zV8@B?s^f2;V7no=_zp;$tW$PIa*=0O6Sk<_VZG((ZBy-WbgoJWFc`rnPZsy-++URr zF;H&zm{_H9Sah5Ar5mS5hK4E|dS9(M(ZhM-q~6XW+#ZWkpyePSUTy#KQNdCkH&6)B*;ff{K_26PeqS=QJHc#0(VC{4W zp*GzJEVr8K5br7yUz}xyj4?}W8yJW&A+_967%Vc^Gj!#_h-xm^V(4ML%_Oo7CEZVT zriU+HbMP^yg={|j$lQx6FM3OLWD)iQ$d`B@*Sd;PDf!rjfL!7#u$@=Kvb^{tSb?!8 zUgA%AeZv&oQ~`s{SRVKHO&J%|#Z~O}IKa>;*8Js%;)K6>>FMQr%%O^N@@0Q_Y8a!$ zuGy!Wq+soghZyuf`$f`U0TQ^LZ%^biFe9GF`e}99#p)2tf>x*qpmOzV31t^{#qS#p z+{O3!D2Cq#Or%=vtAXn%t-mgPV7l1r(SkwV*ggjD*-sW`3)V4|El=9P>Hn5!C_!ws z797Fg(TNisAJ8_P4@GD_G9-;YrWN)l;?d%S~ z#=Hs}FE3nEl!p5?wYMn+HJa-TO3+nYu*kjfFW!1G)Es3E{-m589n*H z`!LEb2C$|5h($m5ZNqe4)hM1{eP^t_T6fFP&nOCQW9aT<5^cN^8}!BXVK_o#YZg zj*9)k?JY~$L+Qzma5{N+I-8LD1J+hzwsz%{ju-{FsILSu2dxw*~Fr|5LT+w@%mY^uJ5n>e?*hKjjQR)%M zE*-gJ+3wrXze?>8)Tn8f%@~#)hpEY?nW6oy54zBkit-PSB_2KSk9sYssrHY04QbM)6Mos{0)K{W5{MI;HHh-% z;OG%?k5{(OEba!8ZWV()03NKWbGuP4&*71*aNweW8JCDkg7d_p2O2X{XnMK>;wl3d zTl5)x7=5z(f!zDU>LX!guN-5tUQn1Ty7{-*EYrCmE4t?s2qvti5VLr*e*QAuGM49W zg-N(0+eu$Pb;{VAcV;D(`PeHasVPSf4oDU+S{%g=>?%=@;aiFXa=ZdI=PvoD#IdO zu?E{pG&xKAr{MOuS(+0L&bJx@iu9)F2i8+4UrBZ~?rBNqlkplQ{tnS!6#KEMV&t~n@;*m5L z92cH9FL7fcWl;(iKbqXNPl}xRoe9MD_QfB+xihZ&Wc4n-vn(v+AH$nwbV zz&rTz3d@T#^HGFMHML8^+yc&(Tl&UwWlt*F*G%Q9QU)FXWdTh9&a!IgVV^RL(M;C7)j>f*>S@Oqw-!mL<0an~C zcWgj}!K}t8v*$|ympKCI;MJ5ZbRFg2y)Q-$F7lStiV|Tq`s}9Q?$-a~lg33Dt3kg* zhgsqePj;?u&E;IUaIR06^XDEtagV?-Mc+0%gA9{3Uk9xtL)AaG)!xmqf1Ajnn$FmG zsNq7(p65hYQlX+knqYB{XC@mgb6Q@;T5i1-(;Z5R!ERHb}|Dek|4}}P#kjH&($S~BmJ>VbplAqGbdgI8fxfJhNl*G{j&Z@mt zE$a@voXPV{+5KP(zH5H_shtP6OPx*MEop0OYXyy&R0-9^{7+1feJHu zizmL`C-=%FQ3^evYya}dqR0(kp)y@+8v@d)NKE@_zk!$1ze)vnT@jFUEraX^ZL>7! zy_>4&m!;id@qIKG1c4GH?Y)7E7UP0qPEAx^-h}#Kwgz(e%`~J2AIZRE6!aWxdrx`1 z5j44>fdRPvxE5BPVPr00_z{=52O3Qa>8MNFO{=O=t6DXkkI^QIol2{`6<3PjRl`^T zDcG|jSMA2&#*Xs*v0r{zO3~BLs%ozuJ)Ax_h`f;(3ey?KbxfA`QjfG|}Sb3wU=bfNQj7w_BspH>N zvbdcF%IL(WW(#{VC$uCQ=fB6iAtrAJyY3#=9v`18u*`k!Wf}#9{StHa`-ll6uE6@k zuNzpt=2D$Y;O}~|TJOY2-({+^i-q*H`Lw(9wXDs2v?BIZXJ=*L#e59-@^5xq3En29 z`Gs`F((o=R6HZZ_s;EO~MyW8QmiPW!yh`#Yi{sSqem^hlrN zx`G`$PL|}D-19wbZJ6q^G*Xq-q(D!cI;Wn+_p(F-dV(i6NI=EDU`tU^$bv6stk#Vs zWua9^ta5OS_Lny~+(_8Y&h;;Jhdw?F8RV9*f;Z5>;Gi>t3!1asRMy>}^gb^R5(lO> zPfLlO@{-aqcRfXfnMdSFO!lwJpBjgZOYE28l&IU!X??iDI9=^#sYkC)WVre013&gp@JbmC6*zQWAz8-AE-hg63MZ(&C;ZUO)Z`0BuxCC=WgzJn|bQEldn#WeKqK_ ztuOkWEM`2#J)$_?lr0Gkz9r=l&-hnY&Kq@Z7vGBNPA7{meH(y9KOfdT3}pjnVq-_1 z=M+HLY?YC3v2i{WE&EcMr6h-59sE{=Qai-ZKJBGES5V8PzhA(Y>A$i zdAnDWyLo(@DRm`E?FZ^Z#L_U3uSfIWCwoj_Y}z1m+lMRdmt_WIlyKc9ZxLcN+Hd9Y z3K>cJCYVI!MTg^h+>oP(rU#?7z!%{34KDsEGyATUuFlwy0(9?BQX@$UxfID1JKM<)IL|YNsk<0$ z(;3O;XkP`DfNfdsF4WTu2F*Vz9LTrhMu%g)=Nf5y(<5b!K*E*#Yevj}!2P=a#N?u> z`!<;*g|Z8u_fFLhZ{K;ZA%Hs7wO`x=M=7pTcK)hc+I@%wmotq{BU##>Ib+o|J{Nf$ zlMrb7i4hKY?r7tqikxP9z9|v3O$bjlS%cvuFATUs7Zmz(qi_n-K)WVWM>2xDh)bBl zTNc4%vwnPQtx0rzcWZ-oJmcjRl6g7qROqKJ>6`z7z(8vpEQi#PG()UDp1P z_w1`(54{%Kv@*0;rw{=U-Z~FI(T__a5dVww`jy{MRn7kKEznG&V|sJ%&Lt$reMr$G z7JGQMj{&k+ax#3L>fSBx@x&<8A~y)lZt&CR%$FnPjK8K=V)6F+w2|_7{z+~IQP$g~ zIWB(@pG6-Yu8@@Mf6-9=ud3N-J(fsb8yMqiec1ObCVQ7)IxW+qsYo$d^Kq2F$8{45 z=%>FybnJIujdK|Hqd|?-BX^DQJ%xSb-IdzeMb$3#yB#JHCPOmhbSA7NEN{gTor}AjD0GM-H4*j3ls#QC3OOeyD*23N64SWuB zYZj*Qc(vrsR#*Opn1L-H3|ZYyRB;k4$xp92A$@E1bD+tKZ{H|#ay2VH;qzNzaMO}h z17Jw()!yG!8W*lVG6x?oV0f2}ugLtZ=M_3>{mJc~hmY-f2eEFT*2LW09Eu}G^K$|$ zj*k1Mmnoj;pfH$y$~{gzZRwNiq?4p5u`^|KIG;wi+4vL#CS>u5O+D#Udf40%9?tnL zdhofWGSRUuo)P$pVLFu0d!BFm3n{Uxr5N5vNB!0Q8*LABOp z3#RJsc1WqEUtuRSd16X~*M$o%IqJe?37x(bwm2RqZ{GNU{1{aE0&5A)2p!n!)k`UvDZ` zVfq7tMyshJ*T@9|AMv1R^iNfEQKantwd&^ulA0g({Vze&W9m}BzXdJ_*9RL)PXB0i z1XxV04}Pm1koBH2E%u!5l@KSEpO$xnXzT7=&ZH+x?OS;N-TD37uUbt<-_z!3ys}Jh zR@#hwx`Sl%!c*rilMz+%A8&y>5dt{n2k5aC*h3*W+S+rWypjb zyDkn;chE$~ZpEe=(%(UbrG&z$r$bqM3R)U0z=~6;4kpz#=nRK^E3(UC^}Zlbg=>z;30LR5SU7ilY=#?wP@+khp5l8#(rHA&vSZ|-&F7vvZNYRZ zo1B&_m|pT=a*m%!$GyxSI;A1!+hZ)I#bUe-^&1gv* z`)$d?9hhXN%&_b|xm=ku_kG{-3P@zzDff{# z84Fa?)$S>DR;i+yY}V()AS_$X@~cJLwpW7J$Z_c11sTB{9*gx+FYlTv{Cw6;L1%(x z1C~c@mb{8_LPG?x)9~j;tf0#!IDC|hXNYdpT+kI)Ge&{K50@#i39L1)YY2eI^xquT zqX-F@#nr{-@%!<$w(3Y#v=xg6k<`JMH9EIp@4b{rq+p z9B!fRRQu-Nlwoo%Xipwc&XD=5f<<;n10>s-qtLlgFr6&Q8^?RG4u&RAXpKtFxkjI< ziMS>fslAye05=YpWIi#HZ2Qe_Bwrhjx$ou^+mz6t@a+)_!A&OyC`>UOZ&E|{mAb~+ zpur*(5jp^4S+6bn`R^5ywr`bSM!i>j?&Zd|2g+De@gc3Ai5crHovHf-s%4Dsm17$Q ztd{&{?xYS34e3`^c5lC0cJL1JjnKbfgmN1cWL$iFF#8NLRd8F|E4bkZ8v-NbJ>;&E zz_@P7e6VW=Ah(3EGnt+6&fvR*YRWIOd0hEerrdG?d8JlO;1@U$yKH3 zkND!Uo!Bp!WCpjfXkf2%qvURYYHc2)*a0nOa>oJIk}VN5g@Gl!rg1rl!XUY+E8=+! zsS@7CnK;AeF#Eb14*Di!v0-_-(XVY#CZT8z$|@xoK5jfMtLgTspj%0g_*d}&F$Vd7 zwrdB+1;fTjG?!RSr%JE;(dn{?fq!~C%O_s2XWCI~=*eEVt5?^qtDzC8$66FRVRoXN z+zl89lWl-vf!T@zip8I7x^2doTt{R$+T&&=r?$fR0D^oHo$jw$1DF>CuPt?1mwH_& zb?+Vy$;s~wPz3z{nGAvKpP8(WbYDC2XNC7C*=TS>7W_kVDmO!d5AgWiK3~)hZajmK^Nfe`Sg4%KKdK8s=Ux&3gd>IwLN_~}VJ@8UA_;7~jyCGIK zUvKotwIy{zO2^`P2vLq{1odZ zslZ!I(aX+(xUJgbz|;cj98>~=c}R(|4=hd}nIr&d0A?Zbo=M$r)!#y8*|~RX&b{Tw zf!cWWl8h4P*C2A>{m{UuhZ;=l7$>{DK#i_V`Y$ zp969Z0-1^xSzBAm@FTWEErHB;dv9jsxV-D&h|7L_`8eN?++9q-Qs_D_j_Ic=w<%DGmIwCps= z$LE`I%9Uq04;wY48Ey~vnhC+;xJ3dFPfP3rcWUflRQ=T-R{uGq*xggi?{?obw-l0U z43s=hk`iLiFw39Am1iruVJRF*w$;VM=XbcbbvOF;RZ(8vjbdV=W`K<#*XEMmK&d?A zl?ou`e_$WKG9KB$@NXgMlSR9CqT_%Zz{EkO!SfqcG(v0(R+;$oJh{>pC|t1IO+MMB zhoNJpv-~@2TvQjmNO#zSc?{)`$N-!}?Yyh+jBCr`?e{X{^bt@7w z>-=Tjy*}#(sx83ucK<~Vv3HD2$fY-B8fN6EB^A%=7_BistBAmAew1B_%0Q-z)x-?I z;en^s_?|q1VE}v=sAUP4r@-$7&P?w`GK?N5peW2^Ja62JO^&$>|^PET~)6J3oWaB=oevZ8sJZe!&9- zh4m+=2C1r7-Q@*G+8ChAf%sLMtV>mam=V$s!gId3vDxpLRr!@?ijz(4taERkEghNj z-0`;-;HJkdZ^=d%y5Sw8<_Kz8dsr+Y>&2NX8l6VYT~4?}TAl(8g>%*L|JSnh1c)d=~pazf{=3wV$G1htB> z+TiMqMsjiBcYr&BorC+Ri~1i>%r2OD82J3=w4_e8B}$R4BUG8%KQkN^hGp8(n{Y-K-1F$?g-Znt)~8#&q!5@uq*&%v%!nRH`{Y~C)TX|SZlLKH zWgwlrB_8TqihyPb;})my`>evMOrupnGLi!8F#rrS3y<&Q(T^5CbN3_D6LQo}rn8b5 zs!N>`Lc6xo{QSM}aJ;HQ@-SIhoLlUxNh-!FoCM>$4b_;wSmQP+i|k87;ZaI#!crMX zV6;qABHt%S zNnSggDfRasGpncp=f=3hNZ=}1fH)kl`1##ZOUXO_c*Vr%7e82$K;?Nc->l7ye}g+4 zXicm_H7Drm(5L4lj}mYFU>sb$8?2E z7Fq41&8wHQ`yOoWAh92)9F4j*{LiFJg#*ZjR<^lYU0iZ)Jixb+zW`hvs;ls=vpG~c zutsO}w#{Lv1qWWOJ{8>&Jmz(Y!Q<5w-?3Q(O`GVQIJ^)2IM3xDf!g45IyY*`%~aEb z$l--s`Y0u}{?yG?z&SU2vgOrQ75|Hr0%Tl~k$nxXWz5z(AMq4y3I2z&7;ItbyUV#=y}U%`0y*wL)ElDJMe zqHsYN=EP$0=F%9=_H4byK}P9MZwEc-*wWKAvpSBhY~~}I9Yu+A#s_uUeR=pRAPe({ z@UFBd;`U5Fc95B=`>Q`3PjikuGa-cSI~G2vef-J-bH_(!_MwQURVbak`n?bI$Nmyw zUV@fI{`>(ny^xVsJ<5`9X*Wk70P(pu$Lo$a`G>TL{omqk+@WG>!KA!@ic?9 z{>SK6Gt>5^|7yJD(s-Wn0(UAa6yTg5i9JZ%gXzI&LJ##DfqBeLeH8sTfhkfr$B<*k4}GfnN)y}}h?1cNI26(9d4kn72@miENJO0LU)6i;Y_XI7%wBIT#o)|ooaDq(G* zjW_PSPCa^6>SZruvA)SQ9JmP1nepn5zhv*Uxy62Z>@YXp)66Y7oZmT=j_&)%q_*7P(rp_bUp;T14bkd&T z*4V^i$QDVrL%mqE_O|SW;#5_lBelcD)(*o6D6F<^-%mVeG%EexOQ zkgr00hk_`%tAvkzZqWQrQR>Ba9Xilg!RuSa0J}|3PtSpyGCXML^jEs(kXf>N!N`q9 z*n?JG$ih9p)i?&O=kn)|BE~`1;sdgLDC?KhiUx>s>*U@QMK zaf6IR?f)R7%H~-e?Iq)9@tXSk+khQn0tqH%0qAruT)&7_L5X&H42L%KOtc(;3d!bM z)+x)Ey#oWCTWd`)7K+XAyxih?eJaY$W`%}y4YLMDH&K+{*)Y&q^u(6SxgY!bLZNfH zK0fX}`Qu00nSfbB+a>OiymO0>g*0kvq2B{*&1SMk02M+*O4>V;sIZovi1rUIMhg4# zCSUYSv+i#IhpKcu)^hGL5S-kk?Q6WA@1w1_hqGPB@A0OVA#qpOe4a^6Tv9vk%gAbl zIRx5V+lp>5DOjZW2PVU=7Q#cdW|%+09AE2?l}=DmuRlBsU2%S2BVd_r9io)|X7X-y zpw~tnm4rfnp#UhOG2Ms^ z=HTG{Jp+ezait_(1jhp&_~>T6!Tu>fbmMv`f`5ZuL$_?cL^V|3DO<42AmsvqaA*T^ zvd6EiI{5}1*MPeZ?%h&3xdnNZmGE^EATwo#=@m9yGz%cwOxbNSzn0EU0DHX4cQGjc z7Wh0KqW9jS6?I~7T;1pPqe6s}qbMakzAWwheaTbynxwivIh5sU(vu)(*G z?mhH6jV0vS8K${{j}ay(uN7gp8oR>YzCRK>wZQmr*Tng)KMPsON(5Cu>zBfl?5dQR zRsHDKq2+frg<$UwqXecEmsf17=BiUpn5{VYsduNZbM-h@FD?1^CWMz-+y=V58QAYOqUH7BT>3z?6 zfB(FHbb5Q9=li|yYkbCa#bcmt8HNV1E1LoI3s+&chIdP^^PNSg;=_cc$VZVtBZj z#Z0_5Va21RGsxd_%xl7IDj@ayHGA}3>Apv*mkI%`XpOZl84inUF03s`TZsy>IKJxt>_xTw9Ba zoKx@l3@y7-_;01ovt+{$+k0XBSu?8Wc3(4eg)hLQ2mD4qz4B?^t3nfKC&zA! z@T)}lt?2?+U5?sLp#%7K*n!lAqLyU-71@88Sddo_RVlxVwgm>i!atSlu98ZaCLw)d z6Sj=*h6um6IGC%O`@;p+MDz)m#gP=SG29C zxCsk3>?M3Q3;LS2oH&~>XYF3%os33wsZuDwrGNWbv4Wgq0C2&~lWq$vQp(g?Q3JSj zYnT08f&3Yvu(m4On!NK7&#J*iG z@~IrtA>389!ylFNDq?dRDD(*%lC9YL)BEUNTb4lqyk;imohHmLcLIwMHvGNR0B zWi~q{1L9p~mF)PcBEhV`?8k;bd>!V7+*v$z?#Ii)I=ZPrtYtgY)1>30HY}im@fLq6 zKwbUbnq(QG``5dN=!ml|KmL=d%O;$%5FACY9Rx72mucwm!J~DX(IDGsS{4H8MukC* z){8S75>PY`U2{J>#|wa~zqTgH8Ki&trz!6ataL^>9xG4b|5J1Y`e5)jyS4m{Q~k4$ z+nu5EPfGAmEVGi=g!R_!_07XSRV|mbaJX@Vf_urX5;2PzbID?>-?-lJx&O8>>0Jj6 zG=k7}?f5S!vy3!bI!&4|fkb3jN6W5~0vJ^g?0DZaP6DeDm^W}yxBvqZj01vESg@^( z(rOcIxoH!(rl?t|aTDl)GCW*4)GFXW2YTNWJ4ctRL_}m{iRjfJWime<(O!ZRAaz)o z=VVP(@MT*D^tJ{q|9LcO@h_b@uxFFcArq!j5C5_5)#W*A4; zg=2U2uwOh#FkTOx3Czkpn12>@GHCch#bGkQ^O5%pd1NTKuR&46!zoK6<|7Lb6qZ#~ z`goTV@E4Fw1hEdh;o+ zxBKhlKlRMYeYT_@Zw#&l?F?{!#nXE&e>B4~Ru3oq=Q|USu0{`iE@gUh_Wm_vPFVo~ z0hG%tZoPTi6+ZWCEU3lCXDogPe%mJiY#q-dE(9SXpa&BT5!%=VDnLkrIRU*Wuzv0@ zkTQjG0tV5jad>s*Y7_Vs!t%{eU54>n{dTCmF}X`RkfiJd!m{f1&IAGi5IBz`ZkI5@ zt3B}nl|~06XnVzi;LO&=) zAzmtnqn%XXK0r>-md+#@Vyx@^?noBd+(Ca#)lqg#)u{xG6rNse#?dEd`w6kVfX09v z304o}1s1uBk7)D3$M{J>Sia?1P9Fs49=ITpGz#`bQrfBn!C;JL z#&>tYLh$JoXqljdl>-wDsEQ3_UYrtaIM87J47?>zuKEBJ4jXH%K3UbCfN+HMhKF8K z71)(AAb;t~&>>9c%z-WUD7Z;H_~<6N^qM5CJ1(DklBoc?Ah<#ZqvcQ0?3Z(ZvK<~7 zw6(J6P5l_zav85Lw`1RG%zG9qx>7I8j&DMO3hv?~B+&5t} z&-GW=pE_;{K7e{bgB8^akO~3VfcAKo%FK2`yOx8pNI{L@2J`l5zzl?n!<<{n;6BE% zJ$Z5)1~8z{gqbc+0P~(2{->=Ous19eFWZ)oD4F>#5s`ODcVoJ3kMy9A`w=N>@xZpT z=T;O~kGaSGo8_-0==YqZz>K-#3%kwq=MY=~t)UO)&5rSEzx^Y$Qe}WJz)2#%VtX97 z625jma2TLYhB61LR@f-tl}I8udzdLj2|mpv3E8$ePp3Ytl)B&$UEvMPV*H(Z!EFHi z{+8zeFpKu7KoJ2M9sNEKk_uSO{|^pHh9Q^t-^;0wUDq;QTg@f7ceNZYiqi1e(oDLC{G=!R0m5F6ymw-6;r$8Ge91OHI-tGTvVy# z`sdlNU;?;PXm11c0?ZKrVIG>!2pXEye=DW_GUB=;!t=>bcZ0vCju@TWOK7HA?Wxq%R1ivRrs*Epjp~X_ z*5JoQN$5{Wt%ONZ%iViNPaX9PV339W0jwc=(#xN882O7U|8m*^eiqd_-3;9jToNSh z+{`v2L!xy7hl}!PkcH>H3z{I`gO>slxi=Ggy zdIYaXetFYY(Voe}7=75TxyPBcas1exq5Hty0|)nPX~4cTKb2LHQLk4d_-zvm>c!G< z-p@6lHeh%_XzM4Q>K*XQJH<-<1Zo4l)OYwD7ZsD~YAXyTcTyj#4#@;O+{kjGI>6M1 z@qNjTqmTPUBK2)N-Nm=~H%PwS;;o+HkD@8?ypJP)k?!F0ClcwmV;;XE#1STN6{^Yl zGO$!ozEon(dV$8GVWYRrin20uNP;zD;`GROjV`fmN2Lus!q8heR?UghChI?^b>*gq zeFk=5qX^9WKU$xzuC8u5+2*NE^K8H6bcq(ncSX|N4CY>Di6HuDi?sa~um>`qnM>7a zDWJuEmNuf8_(wF1o#&+`I1E!9B_nwQf?IXz9O6F%AjGZ2tYWzQnzF^ykdc^fpPo}A zgNQhuQ0O_eBWEuiJ8)D>)?tf-B96h?B#BdvLy_BRA!fXLZq78Aq9T5vH;a z7z$h8A5MMGeUOAxCvzC)E2aiB)o{sP;&}M1Z;XAWVhX$t+2m4%JKwLwu7SpTaNZ_C zF5z`UHANkW7H-UGCtD3I+axIGeTF}hWXWJ2uL~*n7xxptb*r5Ztt(G@bR{Lzy6?!h z@0Vz3o;C(D6HK;0cY(E?g%l5f?zF!SM zW@l>0|14Sd&`+{NKy**kMK-#cjrc2&x*a6F&|qjdtx-;@I=pC`{W_+=%9qweW#5rg zl0hGT+?*D^^EQi_kb>KzTuY;Jc~)XEB}>nx+!#&0LvI0AKUGXDqs?8hYcTVE$lE9G z>xj>EnB<;Ul-`6ydhmtwGOHeAT=A`8vPfM758GRlq(El*k~gk*(5&V~kms(QqPX(< z(QFUdBhAe5p7!iBgy4PRXdJH#_H)GBhsJDC)6i_a`o5iJtJ$9O@Bw@`jV@3JE9a%Y zk(}vE7t=3X>MOa@M1hny zN!HS)mv5uj!tn;_CPY>F&sy}F*S&|oa?DbiGzMLw1g}QiwYZlpxkToex4!mxLV0|} zB*kx{A5n<}elyeL03K;!qVb2j<;vs1Vw|K4=?mU6UR?dfhUuptXeggo?sxC)4&U!*&$l~JUgEv!ggI>Fea}E<`uDMer10z9sa&8 zmrms!_oFyJol8YC@CmfZ1S5*1@UQvwX^hncvxVrE(v*B_PA7$~>@4VO&~Jbs;>y!d zwrtenKOS1NeOfjz{LPz_;eMVNOHw*qy`lpL)LSr3%zL}=^Ytu=s9ZUrmC?R$FDx`5 z2TpF^918(iTj^{#P1yw$NEZnoyRu?XE>28qzOignzlb&k7^W|bE1IlP^=)bE=xlHB zs|S!J#>dmaCUo^l@Ai=PM6)Z(pqEftG;9dt`PQ03S+M@|f^I{Y`BTz_$Vh0iW9OQ(F>Xt zNwSA5>FMcVKw)rqx-NYd^BHE^#-h0=aLX}ER~F_{g3n;$<-N{e@Q<==L#kb|6_=1` z;fq8^_%MY?=StowI8~51&&YO9qNII`_iJ@@yu6`j5PO-KZ_|O?21raJ* zY`SE2@$_=Cmyik4dw+u22^B9X>S3ZaMH5kx-cO&-1FkF}VBiHv63G=-fsr1ogQ^Z}bs2MX&(^)czU89{A^sJnS zzB^Wfo>XUws;*=S9o(gN`3lV=i+8eA_|a)%9FPlO_AZ@e1sIQ?DO`HIVJ!LpF>GyV z=A$Gh_wF_rOO|Cqw+Ws7!Wp*f<(0Y#R`V*Ags$#n7S^Pb$*^LN3qG3LaWfkmj9_hX z9Z0wiKU79OQLpObpWwGBgK&W&$jjt`Lo_@1_4#{MF2U5}W}aaDV*_O5XNju0Fm0n4 zW{jveA+_tOu5GVe_ZdPJ$1xK09Z?9nq*RuDSrd1;Vk$9!VLrE4sW8dmiuCv1oKt{c z*f&Mz?cSTIM)E5xmE~rzUOsjWy(MbSj!(zFT`l^p1?VXEEp>-LV7R53*s_^eAF655 z4ZISVdpxvgjSFk&r^lHtyr67^io#zd*fwJ`I-8H;G$$(zMSfdbRi#!v zT>jz|M+jK+>lb07jGBlcqft+mUx(YO^hdKF@{IM9XI-wJ#u%_>cjD^l!bK|ES)LAL zlDnl7OO|+s#~clGxn`2I{Jr}rgvynVeG-dIidiLEsh|o=MhB(RKs2uM*0+{eE2(8Q z2xT&H#>#vGk?LHs=vDTjSZ$qpclsT?U+WQvHoFCJ^r(8WOxUzrv~(In5+FFpd^k>+ zN^2%>!5UQkrYD z|6;0{IW?U!&#esmSi~0%;jMn#84`kVbn0@joAudYx%v};@g>-B^6`Zk_X(oy-VwJTsZ zU`!^M7mC?VxuJq{`@sorbxVAzvI4S1CnnVfI#v7Pe!1kWZM(2XS0)(q4cV@|6 zdlx4zt8cD4D?P)_d-=RM<`u_=%ZKak zMAZI}Z?rRetYfUr&~b+U%W&Eif0LvL$MI82Dn4*@V39)(sC?5K{l_U&RLHX$ANCrQ zV~SEGZr;>ft_zk7W|vQ}y7P~^<9wuJP1l|19J6a17veV87TNe7odb6Qmtp3+4CWU` z$}?Yc2)wGx3JdJusOYyole>4u?I2mY!sVuLP)P)pepwlCh+|g;g({!GC78_A0{7m0 zzq7%0cl`Sc2ZcK9pF%`d_h@Uo|6VGhBa=Pt3aW7V#)OUx98()d^U@$)>Ue`mJS1-pfGaO%v|zGhDZ(6R1!8)ukc!`byXc5 zZHyd%BI-x63*H;e5#i5P^D`EWLza1mjFeYC0#Q{}eSE?oi0<`5eb}cA`qjcQz@z`kajuN)Ywnw$&0=-oi|DTZN7f}hlJmc2#%d5<+;vZX$5q=;SXFe$nf)-5@tr>~5!-H0bh zMoxXZ8b_$Z70=W8a^%+&)MaoB52Vy4+iS{fc+$>YC?m7g=cSW%e41062^duqe)P&ZN@t@yX zxs4u;wLb^Zammb2wb5{tJ~ZI8OwYD0TcvbLBV&fJltlFYuNwM9F> zYJdNOl01Cj3xkTJP>O_bUxp1k-}JxP^XU@$U62}Gp6v;lK$5p^ow53?{)KC~O>=!A z9NA~2n8P}^qrRfI7pE!+i`9*~+zmu;%RlAY)b%`r(dy%>!f_^Yw1C_O8|pxC_#nio zK$L*-QD_vG>?1Eko{8(DwJeaSY698DD2`OQctr#jo@d8D2!OjKGWcAq^wlr7=HOcv|O&1XA8qU9~qlNK8<31 zwo99@m{()tVi&7>bL`pGaiN}sEEyerSur`k{X;C2l0<^h_M? z>JXhjR-XFR+ejJ0l!uvS1zi^N^|FeV_p^D=9KyFyos`3mlLvui3l@dKt=dm`=61+V zp4A;#1sU#l;ET@akYMd7ZL~n)bwZ45lN&u}U}NBi0^Nr{y=7!&5)}4kbv}fgHrtaG z%&O0tu3LYO|CZhKJJ4Km_cE*K89?q3DnwkusA_ExTMcO=0O%ZzVxpp#wYpe%AAQ$? z>#^~puyoASbUSRh1A@^xhxMh{#{-4GvbP_tlv=u6SGIa|%ce!6pik?_d&_Svs8QrH z?p2$KZ~m7WhZxs6;QD_2eG3Pj1wPW0g!z4beGxg0ZS9n;QzN?dlG} z&*sBrsw-OqZWH(u^Hc2!_j6vWQ_{C-!_=#*AQ7uX@rIt>bGGL*eZfb}igEbEwj}+o zrxU0`3}M=w-}nLjYySF0Xpx4`Kc9xT6w{kq{t_nVKmH!pVlOFq2vl|F0q{fxwo5;F zR&Hv-_E4~phU(cEH1|P29WnuP@H|Ur-+%L} z$Y91*2D|~ckFsdTrCe(ml)}(tl$1=u)cMluhqz|u=$b%FbS$*I=9#MFoe-0Sne=Qv z;~IaaLG#-~r6gD5n89H)F zj;I+br@1cQjE4jLpE`u!_GGK$ae4*7%h!uIeB?;n!z|-Nr};b}m9JAN&*gRIvMg5q zaH6Xx>&wNrgo;J|ehJ-D`*R<`m$d!5*k2VGxcsBTt;XHJ3wFlVV1lsk;lxgO zQpeIm?d*Qcy3I2?%J)RVlWN1O^HA2TIc+T#4G@2Ck2?bUm08cq4_+}H#Ef@wKiXc4 zYuO|-DfH~tiPdXk&prSO zB3TBH->#WFE4=3^R6QzAOELiFbQbM&-;);f?wN>%KwYtyK+P852RnXtVP)xqiWGd8v!_BhbVcTER*xzm=^YhO3Z4e>$0H^L6PyD4YKWWolEMEc@HZ> zFov?CCVq9#Qio`!LAHZRMEpIm2`%B?&Qot0-#TQzSXG5aQq|8H2NjWWhW#0y4dlFc zxpP^}bl6}6VuLK@8o{|~MC-S^OdGjrdk^RPWiQI}TgOny9sJ#Vt4;JlF$hs2FZnvf_7(;NFp-9Q4bM^wg z_{P3WFtW@I4SvZVNDj?lcD?idY@=K*^cN2N`!}_qOn(BopjK~rq4xMirLIXjoNs?5 zUdli6;_@BcpV872#r(C$Lmf(8F6&z=VZ4RC~JScqyQKn+Bl*P z2-?MZM7BZFSvt*uS{6vgrFGxf-UwJ-1hA%=Z|BDRaMzhfDmF_pf-%Ixej;zrz1=#l zyh$V9k&t4kcD|_<4vLv50O-*M(L{FiYkWskM?etLav%_1EMYaC|IFg|omHTv-W@K2e zRaSxYLyVPr5{>&2&C9`E>y@&xYY#%XD#t$&FM1rOmw~G#oZneX8tL?rT@`Fg`SSt> zZAl3bcG5&<1@-1Bs~IrsUVE4^3nghp!%^}ZTPxhNk3eISVzd0C{dvL0@_8(lM7oK( z>vlt(&IVEUyCR%Zqw*vCVw!msNhW+m_q)+=eApBBnSGn>UJO@wlZ8xxD6nxiaj3wT z_?lrxESnzuuX!V!C|4X;0`s*~&SS@q9kV$?IJdW{4_%KzvyqC!72c<6q3*lGlby;;O z;3M7~>v?F*z?RkwHFNIDjQFp{O!>-Vm;nP~zm%5ED@I?59zKu0t-dCZbP!$8^XJ_F zR%LzMP$`k@#j0I9ylku28{>%@I;aC+gJsR6>z;o}1$$nTx>!M?xemueaHv>csPF@| z>+MJDZS*sMHShfNYq1}>;B98Z=g;&&YCw$&M(YHpMpw>#dnYQ9h=%pK_Dn~8xhK8$ z>j|MwoLl`#2J@k`-6kNm{rSrvEk41$d#SwIk!*6A_Eoc&RqOvyBc7n8e@=svdS8ctHq73u8}~5iGei zn;fLVvP)2-L=2_U(BFRRj2<(nzeYZNUDe;Rja`GGN<$0Q^egch%=b}V`#T3*OqON5 zA5TQ10qBdyiOmd0{zqOi37|4QD&-TgqClFaaA(h_I80_=;Bet6rg(=C*XIyZ(gcT(gibpOn-6o_DRhxdOmlll37bc^Vw%=V@42gC(P zjev2e1l_7NsCX3u&nDcElq{RIOj{2%2^gR5NOb4w7aOY_ZIn9NL`c&p<#;{?vpS$r ztPlBAWcf4DF!shrfRpLq3%&B#7y?h({=Ph7ilg7%Ex(u`$h%$#xSaSuA#bR#C*i+d zf_-!qw@!~(+QnE!P5x?6+!jgc97a>@*A}?>jUkiJ0cC}(`;UI=L9Y+O`cp^AYV&5l zN=!r9BML?QqZZ6u(ZS-QLXOk~P*V~+g%=xerrWe$h+PBFvV7>#9f->4X@HiU?SlI8 zn?a0s6p~lv0xA&#k^G<$s-j4!d$N`{ewclo4HJ9}l)~R##%Nt|EBp-v)d41)`f!3d zb}dWcbD35qT2Bofkh+KDTUOJy$+KT12{9Be>x;aYjmx zx2NZqanre}hxL%v*zGgT&#MF}LUI@^J+k&z>@hWUjAWd!0%-*=ryS40s8x;OevW(uYqI%Xd+1ybrRL!8s6$*H@lRhf=d+CvG3KfklN-D3jK&`XMT z$Kr4rF+%8~%3i6LR$)QMy+!}KVL}OQAd!UjMWj#-Qzk50Np}lORuu13YW8{PRIHwE z_E+eiY7GTY(-#~1iA!!1ydWex7=trsdVF64ZrYv)9z>7Me>)gGJhIlgFeb6+^C0CV zun4lV3Mg$p{?V`9@gi6&!ud^78MUC8p7p zD6?}=DtNcGqR<}?wKlJRgK{nr1vBN^y?JO7z?A|MKt0C0KYe21wVWygd^Xl9>IS@u zb-T=Ai1+~tq<}Y;0N+t`)d8hC0Ad*BSRxOMRG3Y_hn_U5#Lbf}RBvm!2cWz!GYq3c zJ5jIjoZWSCpuiESLgV3~SAp%3GWy%GI`yCO!u;v(2v2B54Z*mW7tf{D)^sE3>jhN` zc#R{2z~nQ%TlHEGd|cm`)mjaLN}wid0#KlAjYj1~CLBY6CN`G8%Y-<^-6FeQQGSP8 z0gl6DJsYo3{Hq5TiU`xeb1NU1ggwrp{tf7#U>=8k@aTaOekXDOQtu^ByK2-BfGG$# zrel$vr2*$=Ne|jAjBC%m`eONQy%0VK^()~54yW_VYru&TgXI^Y_|UGcHV`F&N#ZXk zuLOds8AkC(*%U&(4ypJw-;zIN%K_inFuWRE{p}|nVTeswN;(BoKdJvTq!N_pe zK7*l@5hs0Y>t@mU5&9q3{5v*FM@Vs@Gk#WYI0W^h|G26_$Dz>HtJSZ~RT9zFKnQcg zOt<8k-s={F@^_+M8fgkz5G|9|9&s?cKLvSmeL9cDc+7w^4&;@4vJB5}r(tYXo%GPr zl-Wm!yMP-+bafIm!GPDoBG)K()x<|k`SbJl?KT1Jc6;`}Y0)pz@cBK3MzEgD6P#`E z&HodNfkG>s$6}v*d&RodwEs96rvc=@*xqP35LD-h;}7cXd^zu5g;QL*!Zw!#oi5RO zH9#Kev9%||UlqfwP4>o#+901_1++OVm~wahVzT)DRu`kZp0ee)lDARUJf1&C6(9Gb znUk`9JU0h&q4vuKQ0p=;l?#yi_tvXa13t*0pq8N6iQcTO0xxA_aA}MuF`VFCN)@7} z>xaWt>CM+5iu2i9yxOU9!#@oZ0ZPv3YCy1-SgcodI-J-iB`Nu$p<4JFh?fL>+(}gJ z6WGyyDn0>9m?*&a_+@mh$$heN#bR2J>-*4~=JYqgc;A@Y&%Cph$ON;SNN| zqbvfPa4LQG6_*B)auZZZ+fw1mfh82?BdRYa1;@n2K8(1eoXZY0(}b$^mtTjnHprnO ze$^U+{{8!HMT#f^dZYGqIE5He3iMww>^s7(@4J+xP`?2q(qD+5EN?k~6BGu2!f;X^ z&SvCvIC=v<^#0;_gF|_H8TYN9CKthv8V`zes?bR_hmr={VS%XhDRfw`0cJ**92)Qn zC`W(_004*6{HfC1N1)3LU?~XE=F9;-NtvG2C++l@n%8U}OYK z{hQ0t*Zso6l57fvTyS4_c*h!TJaTobK1M`B#${M+@EKXHcG2zWZ5WGx_*YRi4e{*U z>hS-H`VC3)0HXwBqdv?~C^g7hRPgHD0@TGh^MIbArN`}aeKaGIVgMvoEhFl%TuWyn z(&=J-(foMm8zb50Czw8dFof2Xj4!9pPUE7an|8;sKJ<`*bZ&?G_A+)I}E3lj?};b;^QWvSwX| zVf=Qo*ouVTcIn-K^Y&;>KrO0BT=4d@R90vwSgEHepzT?3U!TGS3HU4AKZ76%qchbW z^VlTFv!OE$=`d+^_@=$ekq56cvX~b}>uU$8o_=dtazIZY(%}i;CK(XU6(8`=;Evi# zco@Q7fJG3;{8M`*4104A0u!P2Jil6e8BK%wq}s(S`}Hq zgB??>_)%_UEt%d8R$(atc-xdBJu7tH4q6A1$M1jPJ-qz;sad` zh}F6FYpeoU?jV_iYxO~yz^Actq&*R3R*+M z0W3*W!eaO6M+Jn&9})Z#i_q1Da;FEEG_#$2v-DdF;ARCk_1Gn);(wD&U@?L~l|+&& zmQ!@e1fq(ZCKWoLO*dD~AW@l*zP0FNM&$^|S^%4&rmL>pIdmZfbMg`{cSFGub$lv{ zcR-+A28sn%FS0kv#^1&X>MU(-p-1>p$N(RLsyHx8 zuv7+j6&i)M*e`afmKvl(!WM-!e5-sEvi9?_E%q>}4AD#}cdnsVkl89^BebD#DvAtV z!KK4*4rGIdLL{CZ)~SxW@BGas-2zHx%bzj(-&zM=1ys@OB5KfJjRK7FA8()ivw)JJxn`Rx;0zI~kgK-I@{@Fd_g^y{}zxloFr z?Zsnk~!&jHNh1@W&KKRqo8KG9FN14KPXE)OhFKE z6|C^uneX2H6FUO!89oQSko@;#%<+A%@tkKgPc)SRX6_oYwXxj1;LWwuxDxpnjWc#l z@`O@{;|@QR>)^D1h^5x0iwXf4dGM?Ihms_p`Ej5ugDt3c?kB%P(F+t#?{5Xy07HG_ zW~<|x96~~jxo)W%LR1%aebFr>9eoX-2U8_Qv40t3o=jbK?Zl6z`T3ddoz)-xMxB92 zQ&W#$ygx}5caRVkHkPZWr$U?nphdrn2spA|$_138P=sPsse5xL8kBh*d}!JjB;^I; zyw3~1f};O3kQ2$T?D^CRznTz}7HZ|3-$q+@Ezo@WL`r_!Op(K(M$%cLjuVe}d!plNDs( zB)Y~#zS0ddyat~gl!eJWUo7mwC|_hu&Y$Zbgd`nYZv`O?Qd0{T`hCzqeS*eFSCLau zi+$*4qf@6qyC!3s!3;VDdr%S9Br8gWvH03pOrYjk@#7h0A9v_C5oUwbH{V{LMDmYEs`{l7$ zFvRB6728AL-4q#neDhC68+-8LDh(xCo?%88!%_{;9zUu)E3xp)tfe_5yZUtC8{WZGM9UxDepOXBe#O`hSSD%4bH;wB z@3F+<5*d5($l~49*I_$}puAFVDf9dn!e7`m-=$b9`kKd1B#^;^YtHwaH%Tr)wuRM5 zZhZzLFiG}qh)HkEWq4F+V>RE%7)3xb`4o6TiRqHFxk<9@Wk_h+9ygl@Giy^+mWOQ%m4DG2mc!$`a`WN1$MVicD{!n_# zTf@s(7W)L#b6~N(xdwg$i;cx4x(moG!aNJ?mg(xV95;-H>vRr^k#;~5y^(K<6I5Ca z;y*a=Njv8Ngp&wh0O=?GylUN5itTiAkWff#yF^#vcoR{Ref@vyb#cI7poNhbHwtAYJ$IF);Ji$c6l#HVAlg`6WQsr<~c0MCbKy_%Py(R!vm#T#zO@ZnX zxz3N|KBncP?)??;tbj2Hdz1&SstN(?+{Sza+qp;8rNei9iA7|GTz`2yCFWm{@3b zJrENU1C{T~mlcMY3p%w~F~%SDW>*GAGJ1HNr0k}t|5iPr%EHv)DPO6UBDzi-`#4WR zp?TC65fwAR>2G*#Sg}L}B{A{S`k}%0&JehudU81$dj+xp;n>%`HW3MEK$=4HSrqQH zAJ2ilOkz=*e~TTuWmr--iC#Y@LNr1>jS0f$HYaY2Jh3nzd(qA^nXF%Mw3v@UM7=M~ zeo&`rRDDt(tquAO`B))T_vPvOI4@F$WZ9(qIjsHGluHrzEvN;7?rCwtp~Q8b_(qP^ z%|-j6$&xp9Clo##pHC*BdXaj{=23OWDCX>j9o}jUTv(66$NwAhfRx-1wCa#qF33z% zL4746QpFW0Gt-+xoLF6ll|1#pNce&dQFZxbI#-u|;Rxk44)kM6ocW7K5SFng4&d6t z)lG}x0s)xE3A~}neUMC(OH4E{9~kY{HM8mUr&pAPtW32F z&Vo=>7)qW$LzOGh>6wv!_qs70HZnh&shLZ}C->HI!A+%Jg)Y6hVV&<*TK+vAG8Qna3)o*}vxV>O}!+gsnd z^GJa&aJ)h5+N5`UVJ>o39PccP2(B0=M*-MXY7UNoZ};L@E!Gcx?=MKSDg0AdzgMtN zffS3@BomPId^RpWqdQzRREnjUty8Y;f98GWD#*DJQS`4kML;Xp8zSL$@wdm`ZuuOX zzl}b*cW(v84{1d4?Xg1P)Va?2BKF2-?(VI-Qg2~^iPqf-a8M-$1NfgvtFxGo8x4Gh z72jo1Pu=0`xw)Zz70)VP#z0So9%j{(bRkipjf4p6N%V2Xcn6Blp4#?gPy4bNmu? z&l3R;R6#=8H23cjEU3ecsJoNrd*624NpcasllquFfydR@S(*|5GQ$Kk26#DH>^dY{ zT3a|8gP4_1yZ4kYUdkW*Rqtr0Dnj6IIG4`8!zx0Eg(nT!;pNsdOGjFGowd2yB&bZ(yfAz&aqhvGbt-+u1ANl2@Tr06A{z$8*Y5{nKM!je-wC zQdFY%L72cQRiUl3TVYPusnePotpIm}wh zFOD}(Zla#JE8-cY1Nm#zE6<|G?2A!a? zBr5S?#*F#mIXlxFb}sfWDIm@=Ll5rcLzqzjD-i!p{Q%eBT8X((dC9vaKZ7~#0$g$Z zd+%8uR!G8mfUP`b-z{t4BK?AA&#l@kiQj#w32tbN|_oPmgQY29(Y&wZxmz{Hloh-+PCC3aJm{GZS7kw6^9}&a={N8U&pVLn4U` zkkN-A+WsS+u~L;?dsS7?v!e*V>MQ!lSj>FYbqtkoLoTIb8NlAlGxGK6h^(6F3;m;{ zL*XIzX3$&?KcM;0Qo$sd`LYcy=qv!?(2)$Sc%k14y)gg)#p9MuGh;!3bl}gwT7Bid z<9r?-Wgr1JzCWspN_K#F_Ng5j1fdfcM__meMPv}Hq4}+TfX4*%jz6$GAU9K9v@f(@ zJ1Jnk2gYQ)YJdJ5NfGKb{sm73?2+0z9P{Moc(j2UwB-J9Q`9A8cNm( z-T?2;WzyfqrwVdZK#>=qxVy{sz&`*hw1P_eb%*E)n88Mr*v$xzRP(h3ZF`C%pt#tD zP5}(T;(>5RFw7tXdkar*&J8aQ^Nsc3QP<^}es6Gz^z+;Kk1G~!ae@-WEt=pLxGje) z7QyVEz~2D_$9QjFP-T63BmV^Ag?@<&?%VTqepGJdqa-0gNEfJzqM9e)7LL+PQJ-s5Q_QYgbHLZpwkSvyHY{Sb0Iw<}H&o-_gteXRzP z<)79LjY69X`E9&TJkoJ%vOSIqU}q>_2cZGcJb&TB@FQONt@c!UZY0{SDa0~mm2^QD4Fr#CnM(d1v&q9{Y(wSk_ni{B+1r2QFYutmDgU8 z;77~R_)N^Tb@u6zliYf*&~uc!g!d4XZ)xZQYkh?7p%2Uum%cgSmt(P}SF#7jDzZ0< ziHT``Rp2SwrE zcc{V>*t5GlxxJ)*4ns@n4(kUB9qWWK4~QF-Jp95y+EGX z$UaRm@A1}huRCizN(tuLAPJe`r;pseO$Cmpt?cFfXE@2Aqip3PJ9SDtMW6sYMUg;( zSc2oKF4gQ$k-h}*%pgQ{tPH+Pr0RWWH<+fo-(e=ZV z(mpB$9v-iDLKCYDric3;8J#)`Sd9#PUa9uuPs?_hjUDXPQ}n$mK1e+R-8SW|uqs;0 zMi~Q`fcAhesPfjxgaUP6fg>~k9FCxJFAISh{!TOMS+9iK!?24M`>lOTW_AU;QfFZg!x`S&r*5$G zdNc)Xo+l1F=F;q3iGG;f_x@Y0n{$-^sfCNv`f>|VLZIH>>`Dc#@ohLG04kepEk`fSF#G58m}L}eLtzC3=|0jd<}_mZue!QNuKGD`!kk#G-X@jYk0 zbNlEaJUbqC@$S8Hh)DP(BeWnvs`j2BC)?g?q@Y(h6I$B9kWy%%mR9_Ep_atD&ln8G z?2QuB)YIF&sdyGjXZ9b7cVNr~<^d59Fkb}4h5tspf;zA5s={6IS%QU#)%@Ui?m(2$ zlRKEf!Rtyi9Py(gDN6N+z-X24Qz>O$Hqc^01l6@na<&8*cIE^_C|AN(GIg?75?VY3 z5kjXrE)wt}`=lC8FySEu!f#8PC$V@=?3PU5YpM=`1k^PoQG#O;*p1z#eSlt98M6T5~&j% z`_lG8s|GgI-3JIGu3hRiw88ZxvDnDJ!$%kdWa!1*ze6CDB>@*7RLm~j#ZubD!h2ZA z203|M=LF%Uk>|KLIOh-2y5iq>@cJXskEMn3iAaX}2Pt>(O!5I+f4;4f%nb&yyZ7#a z-;hD}P-0)hLnf6KRNT*gFfqLnzN-ATJj>IJ`1eRzf0kSOHrE#aP)%qR3Zug zf%&$N%8ICO{!?I-yruCG#JzGeoC^8#&roOdr0lV?JrOiw@EHk*X7-sw*1@OR_Ji^d zd5~bnaE{%|$MH3+Eh|TFy~XRd0eHSVsLZawAdzHoe5~~9Q$%8;J;R{WgMtLx>&>gU z6CNVJ90sGaR;j{?sBgsJa=4U2kUHX%zvqN4As(@_92R*J?EYVpHtl)O=ew59t~8tU z7W>v9m9imoq`X5>;}>(ReKYW4{R7bHo7nS7w| z5!5IlK@BZmZDY~xkQDjE3&trA&=vaoDnq*`_MEiRAblPy>5;-eTIRS<1v7e;We+%^ z^b!wldfF4+hI&6XCWb}3<=l8(#4THe-0`&*?V7=bY@1~sp3?jCK#~+%gS7eswn?Wd zeb$_6L5m3Ol>x_616GTllXrHhBFzb@L#H@j0Kc(@j)O-mu9fo^JiiJMdkFX7s2x{B zodmTdQjQTOdV}cfA-0(X2MJjHB7ZfrSIk#gK*5mgWC+5MOdAVE&QMh10CELZ<6YAT z=!lVqAPK=-uCJS`N}X=_?Q^a=JhO)a`w7|qTHh{=NR)$gNVopYRoL|S>&Sx>QR5!U z#DB_g%taUN|CZr^o*6%Cis&|3wvi=~`WfKdFt=PNvsaWcP}9pmM+@+}2AJs1(LUVi zzx}uT>)444g75De_I|=i>@L}@ZUMeY-q?R=bM6{?e&9s_$0ur^!5*h-vp2C+3T8(E z?d^(B6)eOyCFwFmdDABv)1w4t4SGcw$jX%W=2smP=V;u1RGzX19yMO|KQ zuRSpP5{sFU*0?6Ze7_jy8z5?hxLy|~@D$t`1`(I;yxT(<e>A_azdjyzc`JDPUVKXen`yJLOdsIJ~7KgQ#@0 zYj-S$H<(@Zu|(B_$bN)EE9Gci^?aW6QPv)710#bHsuj`I|3#ldbZDn=QUZp?gNXB( z%_`}R4?CvJiDX~Weyx;1BH{G^Hqk=G3OFN@F+d;jhTV+XV!}QN%9DGa8JT@T!PYwc ztJ8x3#L7!`HNnakhAM%(zrl|D3dmIOqvBMZCvsK}W2ivYwt1=DncP{a-~biH4cO-c zh_)_x_Ih(|0GRz-eT8VPKL;1=s3doRRQ4Au`~!yQzZsD<9Qb@ozi@3jMLn|zU<$C0 z6H%AJZF-gIG+YFisca{M(iBGpg@?2vRKflstz}_lehCEEzfrzD(*cl>&~IhcKW3rR zcmZp3vJ7U0oD^ZVZG$lPvVx*-V?(N&TrC))opZRWB=N}9Ewbz%7FM^Kswod+?xDE} znP8Aj@&NzFFZJvOsL){AJ9wgj1BYR=poD(OX*3Yf;r0%7cVMmo^b~Riba${+as9}d z8(8JH6h2iK4m+j=D!w#QIDR|T#Kk{^Vo>?sT^nNZV8onPJm2){-_lsyrE`Bs-v2O^ zQ#Tj}!fyjLE>!La-;G_%U78x2U$ahn4vi$Z34`p8>^MPxtR)DJs#WRjJ;OMm*bgfG z=U9Upeg!E=tyjTUxT9*fa!N# zp2uL3%GjrZ!+DTgJBkYeomEvnoBuW3-_;?`JaMiTmb}>0=d_`~&1B+am zLGg8l)-Ps9_splgESD^aNG=dyn5xImP2glJibzCpsW^qF4VBuMY}(1!AK{+4jlS(d z?WM>Ot#7Zq5=kDCP02q@&NL5WBnOv%`FT>+lEa;U^l z&Zon#`U1{L>?O5Qc>TbIz*#-&=?w#3$PN>m;KiQpP^^AWw>_3y6!S64rJi$zvDuKF zS#MODYtz^3Qtq4Xbk-sTGdE@imi(j_ct?1vX2<1ihv$nfze{_aQn-F`q#Jg`o0SY+ z4YRDF|DOA*&7ZlXyeP1k9HVgBNL=dJEIF@7%%mebaYMN;lOAi?^PfU(~7_U34QeYk?`P#9= zTJ7H1McpO;izhG&3O%^ec<15g)c72Tbd=Dx;c4XCl9XM%GMmrVp2?B)d3}mUDv*#( zr*81cV#CBZnMs{NXZhCx+dG|2#es@O!S0sjDXFQxf;-=&mF$Py>Oz9oK6*7UBo)u4 z-6dRKO6jwrN=V?qy@K25PWY~5qK8dEp%E|IrKRcWxv>r~u;+Xad6+$%Rtq99CtnqHT`S+8VhiuRP{+d(9}Aw=?~Fao$R1T;L%xZABkdQG2OC(ng=2(qUD-BK^*B zv$A5BFsp`c#;jg*n;Q={1$H(qKGZN+PgT>x6H~7wk55R9o;ZyjCLDIt=Dnn*t&t{L zLnUsf8dD0EzqYk?rY>>zj8cW4V+!DMPM&XbVmeQN(Kf()oru%(jF6h%?p~af_Rp$2 zy*3-O^7ScM{kCo1r^O=$9ME|?!6;X})VZY|{85%MF-fgxYo+m8uBG+pkb6S%$DsjL zUB^s~>5gQc`BA@9mcwcaS;pb+majAJk7E>ZyNy)uUR=X>W?dqz*2Ivy!Dm^(($OD% zD^0gmE3@tu)>{{XzcuXg=%JTuv#I_WKX1G;%wL{L^bZPL*tYwj%SR@9)ScqdN!`dR zZRl=+|B2<@yVpfND=jZ#9VNtQ)8Iy69vvVTX=&LQ z^^=ZgWS9UUT&+Rj592)6ckiFc$jYCutZq^NnxU`6vd)(xdnm^2DveYAwk>nPs)kNu zMEJZt@C|f{@oGDGN2;#ziq~`vxb!*KMXKKYAdjI_Y>9Y|I3#Y$%cdEvrKtZ;n zBD;u3c*P$LW1SYh8}(-2PaJ{6i2SP)+S6-TwT#BRas`T?wGM{%JyGYY|09`$3$k4-en4>))+NH|qI3 z=HDtkl0D+{7{aaaBB}jsvbGw|TkTA07Q)G+5F^U?opM6gzbd?!3J;k#bSEU|UYtqi zS%`P>_qVQ67^PYH5*_&q_UrUABmsO|K2BO3MI$MWqPLWp5?5w|NB*z9 zFMot`5Br|6Obtuj44YAr*==s)>*#Buoj%zNC-v80?|q(J)Ktl$#8l+XSQkHO3~#)jdZAl zcFnrzQFn4{IggvV9iJ|&m+OoZCBVzcsp^)V_q2SK&*i>ufOC0n58Ydtu82d_cj7*I zHW1bk)r0=o792435^{pY_!E{?7A9xfQT#h#;o26Dvyr)vvkWo5;$HtkFE9Nm^@)zq;&Jy74tTBB8W z(avf<$hY^-c2(7!f(8YRlX3+ASuwJ02_-EbbxJ21eR7M0KG92trs4d6oi?yCb=2Qd z7Q!@F+H?ODZU6l;lanC+cyQW%qtCO;zBMQo!iMIoJExy`83+VSl{rgx5Qq+TtlXRu z`ZYBydW<$nKan%KApO0oeP^dCS_h``hhiT+K4=UvZ0x)5-s{7LPfSviX9E%Y4H!Qa zE9^%pS1wq1H{WV*X7j2OW2>Btj}ioC+PO6*_xRcyx||$ff5mnooHz69pXiLho-Kac zXU^{ATR`X)6rP4oT z#JW8m#~>+k&P6R>buUF3_#>+Kwc^! zoxQ$4>~g_5a?6%o;GO){=aUes!?za~FZ36?Bg#qi!*p||ubh^&Mm@tV$l=h*TrlQ( z*Sm18vY*MerKAP_KsZoQq}BIZ=k3B)iEkex8|n9-ravlplLnXpA`OACwN5->k2AN% z&1>I##~>%F-kvrTWDXt0n0XeWPMI@!JOaR6i%MsQ>de(#)!i#+k6F#H{3wxfx+CE8 z{j(~PIRMync6H9t))t*r2b~j5o=K^a2Py)_)bC?e%g{85M@OG6Atc&!q={<&g>8PQ z8r7&=ku;gN!Wt8EUuv%8dh5f^PhI}SeNXpHfW z7xn;MKx z^NSyzm`HXAR4vw49S01NSM|#V>}k4?Z^ZJB&*Ueix_T_`mQd(}Q2$3a4d@-X-b8=YSTC?fl;Z%SnNxF8v_Hck`IM)3h+@*WibJ4xEn(7OkW8_H{IkGU<+$JqJ2Wp7H;I55P3 zS3JGlCOmj`hPP$PHynNUb#Zu*dD7CK-7#<$500;7tiJx&kuoJlP zJ)!MLlCmI*GfVs#4|up|KtP|mLPLY_;-}J_Q9ku?J)_1(IP=OFah5~O^+Uy~s@kh< zj=+WMd^1(5ho)Jz>J*zufH$-C>_L{`D&c=5r1@O;7~e^bY=txL%9h@7G3I$f{`?m; zm5ru!s&y7Nzv>-@v}z0G#GygI9YSfo4p!yL$&SJPEfP9uM>$q&?S;sZ?e^G1=gYR4 zCxZEGGvnW0=ZT^FlODJEV+G>sB!iLw-7fuGDD=Npy=khM@OJkD13*mk@wrPCD=k_G z*7=m`?xb49L}O0bn6*SI=H7$EX0fdn-OF;n zV{rYg2BX^b@3(VCOZwfkT)s`7@orW{lJ$k=w3-?r`}gVYrPA5i0wFI)RRANNEB{{7 z8l+B8;5H9^ktx6YkLo@Bmq2oq`$Y6msnpC~Nltkj7g7cd{p|9dfHElHQ%>|)IlPQA zQ?Q>G#9WfK%%6 zR;>cKdaCzStIg#XcMw5%w8UnPzncyj5+jd{}DF z(&SA(Gh6#+2wG6+!LglB)2=Dh@rfEVCM#{|@8_s3qQ4(n)8|z~W~3wb=J=>TIDJMM z{EWJ@f@4Y;-_G}$*hS)md~#&9Q%lEFJdfiIr;mGw9+`8%d57HI%!0_L4+HmSGbFC{ zC8WHzxt{y-nA^>)_t7E;N@rH*%NVt($a^Md7BdPVZnG-k zPzJESJor?n&QlzH=xZ~I_`J`zwc=ps$9?{D!_m&Y#h2@-Pt#kbW3^(*$+8H>bO`uq z2|>jVO7IO-=FTfYYdc$gCYUiYAAb^*)l8$wM+RR@7}>PKtcqW_*r89fMA|DxlML>S zDf1^zz{yE_ajFoKVMmFIjLYRSS3g=J=KaJpy@m1kn0N1sk_$iIE!>@4C%^uiL#;P( zUYn9gx$uRZ^i)1_RB1xxHHW!8M7mvx0qH~PKRC283k|kA32&QH55-;1m8_o5D}}QK zlb2E^m=l#9Miy3(yH|)(=cSnEDz?C9*c@DHQM_^lzaQP z7}3_TwKhnt#k0WYo^FUvSFA|&ox6^2VOi|JLx7uFBX{mh6}Ju`bxL!Cc18$4Uc~bfvcL=EQy z5xn;42ZlE?^Vz;$75e7bPD+TCxba1^zj7E=k;6TeGktjC=oN{@{s4DCqKiHEmJ?*G z-Pe9@REW)~bswvkhfmuxR&uV{=k%R(dj33nqGaXAh8jOd=?%(9UQlWj^5l7P3SfeP z@`fJE(XHqTuQ_&Er9}1Evb9gW>LCjk|3%exu@V{q;~L_@!wE$f+jsG8jT-cB)iDOR zkRCWk*r*e@wU_1pPP-~7q3MIv=`Npi*j`0tUi?}REWH`ChM%KQw}wiE2wU5foE10n?Scvl%gJ1Gf+-?e?ff zilxlG3Fl|i83GEr?=}->*`5t267^%5QBtJdZU&5`s8XJGIj`dHTK4<8yk(!iWgp0V zlJdZ}N0x6Q(owt)Y(*mNkPH9+0^L_zG{pDK80J|eQKSy-=vIx)oXUO4*q-~AKaxH4 z#y?llsBLwgj`Xt`S6iw|DN;YbOP7i+cPYahgAr1J zdI;|O?{x%$*nSVQ5SMw;Rk`XJgn^FzJ}BJjOnFhUx>*!mnO5?WA~%B+ki|H%lo(+w!XpIUx2aYMN;@GEpj|G7#jNmU)b+g;(nQwx35cKARX)ljU6~3=38C+j6w=p{j z8^`9Qo^LTpQ%_h&sdk+G>D7u zSa!0wvBh2_yUS;FUn%J`0%fCY-HHXS^8C!{&pu7JX#N1FEtNrXEM0%C+tz)L@i7uQ zC4?(M5?WKG=a4F@{k4d&Fy3rH$nf{54b@fP=LD|VVa!nJ z;hAmu-tj1M(LLXR;MBPeVr_-0ayEmNS2Mn2&g(Vo$bdAK#A(VB08eLAt6u(oy3$wx z0rT5Q5hQ7B*5}PSp={PPq~%+Dm1>t=B9zpxdIz!vWO2r=sDNW;NsLd~;(%#30^InO z=bqxeERyW6wu%}MziF>`pR+h^ISVgAIcxVmw^Tf-&A@V``~303b_3HHg$soq1`$-g zue!f`Q!`uaQKw^pRjcH0&lMi}t-4z`yO;N0v*`L*@X6-#2$Y^# z4T>~3Gky~;k>3$2{M5$dEPDmJu|9%?8Y%*YUw?@MFkI90@DAhL6Gb2Eu#N&RK=-s8 zj1qHl3iVKEr5S&anC7ibDR55UUB&C{2`58~+2WJT5x6)~ZOj-epT3|P@=qu_O>4?d zGcR8ssjt4hK~G8I+uyexp|R+FL7=+60umz~5-4ol2Z4g-K?K&)-ypD7tnhk5$+bL( zPSu0?BUZMfP>W}^OzKt1N6JO;&K=&2-~2Xc6w_av?n#;l0jN5L1kFghWM|)3-#35g zK6G%a!3f{Y-sEV9-TDZY>h!-e{D6sjbaPM3rX7W!L4?pJ;>SI6=J& zW|!c*l|hgYE);*XY6K|phliqv4?lkXD8^b8GsZBMpFAhv5RmAxUf+wY0GNlLJ&v1=*CjNhAEPJ9N9OWMU~PZL z*dOdDJ@GmWssw#S-#MXZN@soP9AIw0*>ItPl))E{y3bvnPi#O-0$K0?pZb1)0nB>1E~xg!O0n3r?R^`awod%o6Bfx>*~z7-$qW5cE=)DSnqfoy$6p<;N;F5H3E!z+94jEt;KCWbg|;6<}K@oM0M0vNiCZ#TiF zuPQ9)vHW!npLo09QEi_93I#UP z-N^+R9Tao~k{EaPu>U6!RvYdZbAC7N6PWX|=l{K#iUqa)b5x(u!SqW2r@sB@<}i6P zDn-8BfOUuK--fRI-Lh*U;(vg3Ig}M6o$oRPlVLQy4X|f8FZuFsxBRr>Q-9EnNT#msSf~_dis+Wc>~)F5zUx2iLxTMl>>U{JkDv_hR58ag&RV z4aW@RCfw{-@PI??fL^d`(G1#FGyeWmT6PJP!>5m?y_~n$&FC)FnkE!2jUw<8hVJjIucKUzVp$&z&1}#{aZC#{-prH!M`n0az?z zYei$AtzZIU)c+o114z5E+F`^+U<~eBoqfsM1q1>aBX?od%(aIMfN6Bt+!O&!NNBLR zks3M#nNm#C(A;}7+1hM4s7!|Vvsy70N)Bw@>FSIYetRxXC*|WRtp4Hw0KpR2ZfML9 zjHNlAhrX7NB$f&P4sR(N%G5?J$>#?hx(+|l9sCC`WJiOv4^?Sj*@3ZS-ZA=7 z-q}HE0_Qn34_AIXd^G(N3dJ`*k>Y2o& zGV-8gu*GFP!;zWt#mOnB%_$twt5Q~8*c$j4&L_SNqD@lrBUZypg7|h=WN_!{V|5kO zjI;Pha(&XV&}KF7zcwcCU@ze+c*VEj+y81iLOJM-3BBQgq4Cvt_Qei+(5j(+<@^Xx zaH48OGH|`e+4$$8ZHZg+ZAg0=J1`$!U!Bx`iddDcA@52m90vLbad4Zzcz13E$x7hc zx6^v`Mi=i9aBaEv&|Gx6`wf;)`>$y)jLW3KM@5v^WpQc8=xOqiu^zK30vu53Zt+E} z7OBUspi9v95aKx7{|lss&4fvo7Wsqdm6hpeY`7}B`oYM|x}zAJ!KO#fgfm*BhWwPs z-e@)62Y7{piE<`?E>@QBho-pHDnpu;!{f)ySsyr%>ePNh$1Zm?25+`tHoh|)i7T_) zQB)NCzAyiWrqR_;K3a3|=m+30(;4<1(0n@7H?0Rx^$ixlUxMk@>szGsJ}j@CjVevj0Xv%IH~N z@(!QVuz!V&od`K0S5`m%64ve4w7F1J#`xAgUe_I(x3EB?3W_y!D|G8^_LuM*H`lSz zPtye8S28x?jT}Qj8BT_(mOv5beYVVCAf_L|0)A>j#nx0uW?iUb(Q~Q1p14Zy-wVr6 zA=tT=Ydy-D4#1&A3rjUQFtoBA)s{WZVC?O_fKW#X5&D6vp6SU2{o5^ z>o3R1z-2?1CxL8w3X)==n#l;>T?BGuZ8_}`trTWe((*+a)|?a1m-V;;?Qkqr-p+XL zGwkZH!1kec3Ov0@2)^jci!iIIWga#ZR<4gpNU{|~5oc{!OW8LTC&`_z+8A-(Kv7uO z?L+AE3*ww&>ty9(MaT%hB3*y^?+1vLD8W<{`CJ|{`7Rq%(E|xy*=^lG#mHSP6vbyr zs|{0n0O8o;)Q?^MG4!vFMrbY+?ywwd6*`vX3405W{x0R%Tnc>~iAdi=PPr8aBX;gs zl4(1HJk~i}%TmQI_ZROj>ZLMPJ)@^v^>pbcNGIV|EcH^8G^1ybPl!oWfNLGgG!xnr zL?0CR^679!l`k;HAFGAJR&crUM6-!*5MTDuaPB~`nBA%|b&MB9i0TzwV$F9zh`)3{ z1{2HvkPr3_o%O(kQfdzKxpG9a2(lqG78HgKJ2ReuT8e~$=Ve@KVjq7#m@7O-jgis# z!u$wK3rKEU%VV)ceWb0@tifnnQ%&a%1aQH8%Uge-;)@Qd$@TE$TO$unF#ThO?U^M& zrbRcX=F+7%crSB3+}=YTf?y)|xRMf9qp!`XT)GVxapo0a`)GM^FBVs`j^^H_G2uu~ zjs)(UT(t8K)EDa~Rv&|FS3$Be4C|?{j>KcgnASe5$|w#NGelqlg~FxV)y3`!t4C2T zG_dFql^57^S%O6nv%`-E(G5thKv&8kDRg`i*Exb4=QEB`L_@@v_m0mM7V|-f7zu?L zM?Sx%eZ;oP8IdVd+FQ9f2Ds9W61T$=I>jy^Za5*dI!pzTHMNXE9(KOy2)sA!<3bS_ z+gMA;QyjwKaqNcVBJ6xW}>^x{xY(Nc)oOF^|n z^QCR$d{b59-UKq66dDu18tpTyf|~{gsnlZD7Pbb#AY}saa}$SXD3=iYXaWn>MES#n z7K}RoEyQ=Ixc9Uxw7n#KkOT1_xOlM_C8V-!Nv8bylV$Ju_B=BGU(P5)&hP9bEjmeC zN{?(2sKdq)znbF>6Ul>G6|gVD%)`7gyb(z%MN#!6>XpqF z6uNS68mliV?l%)bmyAW6(_Q zG(1!}Og3Kht6hv9ETQ=Zu;G$x!*ZPEqh2dwf)jhghCQmp!r0F~HYASjL19&WUxe)l zBW45uCzP)XJZ&gDo+cg`r{Ds}^Gp$jBQdS=4dRWIuQTrSKyo;<2?n}!A5go3+V>^* z?fG8F#nFk&_QyhYAu^zL|mbT;BLE|QgBtGJjwVTFdo7Uaom-$RE8 zk)f6dvjR_4!rE!Yr89Re-UCHhcw4$UUHpxz9yw_#dRT;cIZOk2ZUCM$O0}Y$rIpc^ z;Sc0@es|AjGnF=ci&_tYH_G19eV4MOTNzx2_`xq0uCj)z+>p(RWe>%^jm6?=4%nJd zEYx5(VhylNUZDvj%geaV~Iz)E4G-*pxBrTLOhZQ36;nbejS}+5k;N zZx9(<_n=@Yzu&eq;B;7lgK)K>sg^cD`=ZwiS8*>!3aB^Pl7*_oM3Kr+6<49gM+_w7Qag8SXp%yF$*k z9V90a;T8+wWDG}q61tau^#(bmO4u(9=+mnAUMEvR!9=JtIRvkZ^e-EBKzuSFtI;-X zMIS;W90jIFdG`sUe&f7v=oq`9f<-!{#Y3#_9Kgx)R)l=*BGjwhJpwag8OGh}8Pkx*w-STLym>e__P=pfd<^6{aqBnOy| zVuwio>%!W7G-l888AVrdLNjeQ?JzcK-FfzYFhM~RNKE1tV_8vJ?j}=q#wWRPh214Q zoT!rW(}J6cl?aK;IR;*S^oQ7pt=G84juUsJptU))xwTQN8@HH4#Gv?G=9xlGu}|?V z@WLIE(U^5kZ38d+^wxP}q7jTi7F^^aE#jrh(Tx}r8JyUM(5i&AZl?T9UdAOXfxQ~k zxL|I>Vw<2Xm#>)rGgCLw;*20lg`D<@*`3)c#AX74*$`-@WPRM;eV@YJeP@{TR{s1> zT-Kjt)|H267H0Wp?Ar{;lnZZRsH7JHgciPTktKmPjQmy+Lj__CEtRGlx|{HDC|!Ji zJeKMYL}N#cc9Zo<$4R?MTp5;a2E_S;QhwpX57wR%1Xn-Yl!L5=m^QJ}2lYz2MTfUw0(~9H{I|f>sBJmiu9f5G z3h`CBf(H}e9A1nAyMygiSKbYv>C!$#45Jx}^-8R%C^41gz##4Or_MHEz%K7ImFO|} zbW=_d$d9sMn^@J;FG3w?f77mG$F}D1t^RRQV(;C^I&FFoJ)PDY6&!?F3Z<}tJgkwM z1;EEOu}-vQY>nPDKID@QNm(G*8XL7di=CdTDje_P^L(U2P}qeKaL`)dOhEhbJctp@ z0Y%QJUJLp;GJb7QN=j*YX%|VEKu(DUUI@2yS4;TE30^ZKQxcG7yN&-96&o=V#ChV( z0)uV6ynB%m2w)WvPLYo$nV%(lzS@f&{U+ z>Dv`DAlZZ?qnCY*VJ4#wuaC{UVYRjjGS4WVXd+e0_?HCF#@)t7t<(rD4~FRMJ8=R~ zY8>*w**i1U`lRrh;O}fjvbe3ute+F63@(<8xAw-1yLO9?=XZCxqW3Um2D3k8PM4G( zBQ3|R_FtmCs|nUk9JW}srrD8r_ofa%SnR=atxOB9F?{H@;&nNmrYjIZ`uz_ytG!GgVFE+5Q?K0ZnxnpfRW~9gezU?s5<~i;!8>-i$b+LEW#4mS!JjP3x zcES1Qct?KdbLy}Bw>Wj3bIKpPjDO&FHzKPs7_)=?KSp}hqtbbV_dcVsQ5d&57?^oP z%`X)Dn@wb7nsZLz9>E4eS5`N zR1Yn(NY>TJpRx!(BqyqWN}bk$!6_)45bG3tIeQJ(r@Y1b)8i>rqtrHX(4Tsb1+NK@ z&R*TBDI+v)+b6Oq)RG>^KcuSE*?9mW+cfF@O>>1S`{?MBy8~8rSij+SZ8O?o^pL*E zj6+u#335%|ThypMd&^u8xt&6Z0kff+J&(vmD;*~slA}}ak%-{cSw|Kts*3T%=d^f5 zT%^k2s4?QAg|8o1Je_*B5d(=GW=q*QE1j=CVlP!fhvXGa2pW2%oO^4Wf6v+#D(3|< zs#7T|gWW0bvP5-R_Gpc?PH1Ag>*eePeWm{PCbd;D3%lbYWlBb&sj^eBFJrcc>U|Wx>O4Y%vF(Q&x+~_1z%8S5}?cH!AGe z3UBEC-}QOhmLi|4NL$ UthP^z@jit)bXR-G*R9U_4@oN!P5=M^ diff --git a/windows/ptray/ptray.vcxproj b/windows/ptray/ptray.vcxproj deleted file mode 100644 index e015d55c1e..0000000000 --- a/windows/ptray/ptray.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {37C89E90-8C9E-4FFC-AAE7-B3695D5EB6F4} - Win32Proj - ptray - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Level3 - Disabled - _DEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/windows/ptray/resource.h b/windows/ptray/resource.h deleted file mode 100644 index 1f4b023431b96fb9c6edaf617bd5e9ac940c75c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1788 zcmb7_QEw7K6ot>TiT_~}AB|Gbr24o58X`*xONo6VmV&`F#XwOT<6pOaXQreS*ab3K zX6EjlbI;zn=W_qAqKf`7Iy%!(4K>x}>4a5Bb+y>#`pbB(XZTi>DAQCU%{9}4XQEqd z18fT|^;OsG>UzmY^i5;k@XWE_GGAevVj1DJWH)9%!E(*&^;(2;u%h>+?(q4+X=B{s zHRtq-i{}>s$0&}Jz_>yDAuKOg*ZHmv*270FpzlI$fZA1GJ*8kfTP;>?B7EA5U)70< zk#o>eu)EBCQ2U@Z_hQCxGV+^3&RIbI0LODs56^-l`oslybJ3A?B^S>yK zRgT;WNUJ;_&-t{FvypQu!?)HhWw;&HoZl59yW$>eWBYWO#mMgqk$WJUaf>?s7-}y& zqBd%KIOp6|%44OJaol|Oit4cXR!U4@H`eda3#{u2YF(mh_lBRWt@kmiw%%uGI0s)CAqto;U@Hxnob#q^WN+P#jImrIicqFWqOs9ct5`3a@MZVYUo-K+5bIP M{4Y!%B0b&z2Q6jVQ2+n{ diff --git a/windows/ptray/targetver.h b/windows/ptray/targetver.h deleted file mode 100644 index 87c0086de7..0000000000 --- a/windows/ptray/targetver.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include -- GitLab From a5190449da29790b1d69b31154c1c7e3f1f2bfed Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 6 Jun 2018 16:05:52 +0800 Subject: [PATCH 219/263] Remove UI related settings from CLI (#8783) * Remove all ui reference in dapps interface * Pass primary cli build * Add back parity wallet dapp as builtin * Clean up ui settings * Fix all tests in cli * Missed ui files to commit * Add parity-utils endpoint back * Fix non-dapp feature compiling * Inline styles * Remove parity-utils endpoint * Remove ui precompiled crate * Remove parity-ui alltogether * Remove ui feature flags * Move errors to static methods * Fix tests * Remove all reference to utils endpoint and remove server side injection According to https://github.com/paritytech/parity/pull/8539, inject.js is already handled by Parity UI. --- Cargo.lock | 56 ------- Cargo.toml | 11 +- dapps/Cargo.toml | 6 - dapps/src/apps/fetcher/installers.rs | 8 +- dapps/src/apps/fetcher/mod.rs | 33 ++--- dapps/src/apps/fs.rs | 9 +- dapps/src/apps/mod.rs | 51 +------ dapps/src/apps/ui.rs | 57 ------- dapps/src/error_tpl.html | 83 ++++++++++- dapps/src/handlers/content.rs | 19 +-- dapps/src/handlers/echo.rs | 2 +- dapps/src/handlers/errors.rs | 66 +++++++++ dapps/src/handlers/fetch.rs | 83 +---------- dapps/src/handlers/mod.rs | 46 +----- dapps/src/handlers/streaming.rs | 7 +- dapps/src/lib.rs | 125 +--------------- dapps/src/page/builtin.rs | 21 +-- dapps/src/page/handler.rs | 6 +- dapps/src/page/local.rs | 8 +- dapps/src/proxypac.rs | 11 +- dapps/src/router.rs | 43 +----- dapps/src/tests/fetch.rs | 30 ++-- dapps/src/tests/helpers/mod.rs | 43 +----- dapps/src/tests/home.rs | 62 -------- dapps/src/tests/mod.rs | 2 - dapps/src/tests/redirection.rs | 206 -------------------------- dapps/src/tests/validation.rs | 43 +----- dapps/src/web.rs | 19 +-- dapps/ui-deprecation/Cargo.toml | 18 --- dapps/ui-deprecation/build.rs | 21 --- dapps/ui-deprecation/build/index.html | 119 --------------- dapps/ui-deprecation/src/lib.rs | 21 --- dapps/ui-deprecation/src/lib.rs.in | 55 ------- dapps/ui/Cargo.toml | 20 --- dapps/ui/src/lib.rs | 45 ------ parity/cli/mod.rs | 88 ++++++----- parity/configuration.rs | 196 +----------------------- parity/dapps.rs | 48 ------ parity/lib.rs | 37 +---- parity/rpc.rs | 64 +------- parity/run.rs | 19 +-- parity/signer.rs | 36 +---- 42 files changed, 305 insertions(+), 1638 deletions(-) delete mode 100644 dapps/src/apps/ui.rs create mode 100644 dapps/src/handlers/errors.rs delete mode 100644 dapps/src/tests/home.rs delete mode 100644 dapps/src/tests/redirection.rs delete mode 100644 dapps/ui-deprecation/Cargo.toml delete mode 100644 dapps/ui-deprecation/build.rs delete mode 100644 dapps/ui-deprecation/build/index.html delete mode 100644 dapps/ui-deprecation/src/lib.rs delete mode 100644 dapps/ui-deprecation/src/lib.rs.in delete mode 100644 dapps/ui/Cargo.toml delete mode 100644 dapps/ui/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index a9d9ab7d10..a22012300b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2071,8 +2071,6 @@ dependencies = [ "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-hash-fetch 1.12.0", "parity-reactor 0.1.0", - "parity-ui 1.12.0", - "parity-ui-deprecation 1.10.0", "parity-version 1.12.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2283,56 +2281,6 @@ dependencies = [ "tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parity-ui" -version = "1.12.0" -dependencies = [ - "parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)", - "parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)", - "parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6)", - "parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079)", - "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-deprecation" -version = "1.10.0" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-dev" -version = "1.9.0" -source = "git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2#eecaadcb9e421bce31e91680d14a20bbd38f92a2" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-old-dev" -version = "1.9.0" -source = "git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87#65deb02e7c007a0fd8aab0c089c93e3fd1de6f87" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-old-precompiled" -version = "1.9.0" -source = "git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6#4b6f112412716cd05123d32eeb7fda448288a6c6" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-ui-precompiled" -version = "1.9.0" -source = "git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079#bd25b41cd642c6b822d820dded3aa601a29aa079" -dependencies = [ - "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parity-updater" version = "1.12.0" @@ -3970,10 +3918,6 @@ dependencies = [ "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "261c025c67ba416e9fe63aa9b3236520ce3c74cfbe43590c9cdcec4ccc8180e4" "checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "" -"checksum parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)" = "" -"checksum parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)" = "" -"checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6)" = "" -"checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079)" = "" "checksum parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a93ad771f67ce8a6af64c6444a99c07b15f4674203657496fc31244ffb1de2c3" "checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693" "checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" diff --git a/Cargo.toml b/Cargo.toml index 24649eff45..7795fb3b3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,16 +88,7 @@ winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] } daemonize = { git = "https://github.com/paritytech/daemonize" } [features] -default = ["ui-precompiled"] -ui = [ - "ui-enabled", - "parity-dapps/ui", -] -ui-precompiled = [ - "ui-enabled", - "parity-dapps/ui-precompiled", -] -ui-enabled = ["dapps"] +default = ["dapps"] dapps = ["parity-dapps"] json-tests = ["ethcore/json-tests"] test-heavy = ["ethcore/test-heavy"] diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index a7ce5a5489..c3fd75ddc1 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -34,8 +34,6 @@ fetch = { path = "../util/fetch" } node-health = { path = "./node-health" } parity-hash-fetch = { path = "../hash-fetch" } parity-reactor = { path = "../util/reactor" } -parity-ui = { path = "./ui" } -parity-ui-deprecation = { path = "./ui-deprecation" } keccak-hash = { path = "../util/hash" } parity-version = { path = "../util/version" } registrar = { path = "../registrar" } @@ -43,7 +41,3 @@ registrar = { path = "../registrar" } [dev-dependencies] env_logger = "0.4" ethcore-devtools = { path = "../devtools" } - -[features] -ui = ["parity-ui/no-precompiled-js"] -ui-precompiled = ["parity-ui/use-precompiled-js"] diff --git a/dapps/src/apps/fetcher/installers.rs b/dapps/src/apps/fetcher/installers.rs index 99b6be218b..9fba80aabe 100644 --- a/dapps/src/apps/fetcher/installers.rs +++ b/dapps/src/apps/fetcher/installers.rs @@ -27,7 +27,6 @@ use mime_guess::Mime; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; use handlers::{ContentValidator, ValidatorResponse}; use page::{local, PageCache}; -use Embeddable; type OnDone = Box) + Send>; @@ -124,17 +123,15 @@ pub struct Dapp { id: String, dapps_path: PathBuf, on_done: OnDone, - embeddable_on: Embeddable, pool: CpuPool, } impl Dapp { - pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, embeddable_on: Embeddable, pool: CpuPool) -> Self { + pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, pool: CpuPool) -> Self { Dapp { id, dapps_path, on_done, - embeddable_on, pool, } } @@ -170,7 +167,6 @@ impl ContentValidator for Dapp { fn validate_and_install(self, response: fetch::Response) -> Result { let id = self.id.clone(); let pool = self.pool; - let embeddable_on = self.embeddable_on; let validate = move |dapp_path: PathBuf| { let (file, zip_path) = write_response_and_check_hash(&id, dapp_path.clone(), &format!("{}.zip", id), response)?; trace!(target: "dapps", "Opening dapp bundle at {:?}", zip_path); @@ -210,7 +206,7 @@ impl ContentValidator for Dapp { let mut manifest_file = fs::File::create(manifest_path)?; manifest_file.write_all(manifest_str.as_bytes())?; // Create endpoint - let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled, embeddable_on); + let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled); Ok(endpoint) }; diff --git a/dapps/src/apps/fetcher/mod.rs b/dapps/src/apps/fetcher/mod.rs index 78be4f4cb3..a7afd91eed 100644 --- a/dapps/src/apps/fetcher/mod.rs +++ b/dapps/src/apps/fetcher/mod.rs @@ -31,7 +31,7 @@ use hash_fetch::urlhint::{URLHintContract, URLHint, URLHintResult}; use hyper::StatusCode; use ethereum_types::H256; -use {Embeddable, SyncStatus, random_filename}; +use {SyncStatus, random_filename}; use parking_lot::Mutex; use page::local; use handlers::{ContentHandler, ContentFetcherHandler}; @@ -50,7 +50,6 @@ pub struct ContentFetcher>, sync: Arc, - embeddable_on: Embeddable, fetch: F, pool: CpuPool, only_content: bool, @@ -78,7 +77,6 @@ impl ContentFetcher { resolver, sync, cache: Arc::new(Mutex::new(ContentCache::default())), - embeddable_on: None, fetch, pool, only_content: true, @@ -90,38 +88,30 @@ impl ContentFetcher { self } - pub fn embeddable_on(mut self, embeddable_on: Embeddable) -> Self { - self.embeddable_on = embeddable_on; - self - } - - fn not_found(embeddable: Embeddable) -> endpoint::Response { + fn not_found() -> endpoint::Response { Box::new(future::ok(ContentHandler::error( StatusCode::NotFound, "Resource Not Found", "Requested resource was not found.", None, - embeddable, ).into())) } - fn still_syncing(embeddable: Embeddable) -> endpoint::Response { + fn still_syncing() -> endpoint::Response { Box::new(future::ok(ContentHandler::error( StatusCode::ServiceUnavailable, "Sync In Progress", "Your node is still syncing. We cannot resolve any content before it's fully synced.", Some("Refresh"), - embeddable, ).into())) } - fn dapps_disabled(address: Embeddable) -> endpoint::Response { + fn dapps_disabled() -> endpoint::Response { Box::new(future::ok(ContentHandler::error( StatusCode::ServiceUnavailable, "Network Dapps Not Available", "This interface doesn't support network dapps for security reasons.", None, - address, ).into())) } @@ -195,10 +185,10 @@ impl Endpoint for ContentFetcher { match content { // Don't serve dapps if we are still syncing (but serve content) Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => { - (None, Self::still_syncing(self.embeddable_on.clone())) + (None, Self::still_syncing()) }, Some(URLHintResult::Dapp(_)) if self.only_content => { - (None, Self::dapps_disabled(self.embeddable_on.clone())) + (None, Self::dapps_disabled()) }, Some(content) => { let handler = match content { @@ -211,10 +201,8 @@ impl Endpoint for ContentFetcher { content_id.clone(), self.cache_path.clone(), Box::new(on_done), - self.embeddable_on.clone(), self.pool.clone(), ), - self.embeddable_on.clone(), self.fetch.clone(), self.pool.clone(), ) @@ -228,10 +216,8 @@ impl Endpoint for ContentFetcher { content_id.clone(), self.cache_path.clone(), Box::new(on_done), - self.embeddable_on.clone(), self.pool.clone(), ), - self.embeddable_on.clone(), self.fetch.clone(), self.pool.clone(), ) @@ -248,7 +234,6 @@ impl Endpoint for ContentFetcher { Box::new(on_done), self.pool.clone(), ), - self.embeddable_on.clone(), self.fetch.clone(), self.pool.clone(), ) @@ -258,12 +243,12 @@ impl Endpoint for ContentFetcher { (Some(ContentStatus::Fetching(handler.fetch_control())), Box::new(handler) as endpoint::Response) }, None if self.sync.is_major_importing() => { - (None, Self::still_syncing(self.embeddable_on.clone())) + (None, Self::still_syncing()) }, None => { // This may happen when sync status changes in between // `contains` and `to_handler` - (None, Self::not_found(self.embeddable_on.clone())) + (None, Self::not_found()) }, } }, @@ -330,7 +315,7 @@ mod tests { icon_url: "".into(), local_url: Some("".into()), allow_js_eval: None, - }, Default::default(), None); + }, Default::default()); // when fetcher.set_status("test", ContentStatus::Ready(handler)); diff --git a/dapps/src/apps/fs.rs b/dapps/src/apps/fs.rs index 0139e0ec52..975f3067ee 100644 --- a/dapps/src/apps/fs.rs +++ b/dapps/src/apps/fs.rs @@ -24,7 +24,6 @@ use futures_cpupool::CpuPool; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest}; use endpoint::{Endpoint, EndpointInfo}; use page::{local, PageCache}; -use Embeddable; struct LocalDapp { id: String, @@ -65,14 +64,14 @@ fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo { /// Returns Dapp Id and Local Dapp Endpoint for given filesystem path. /// Parses the path to extract last component (for name). /// `None` is returned when path is invalid or non-existent. -pub fn local_endpoint>(path: P, embeddable: Embeddable, pool: CpuPool) -> Option<(String, Box)> { +pub fn local_endpoint>(path: P, pool: CpuPool) -> Option<(String, Box)> { let path = path.as_ref().to_owned(); path.canonicalize().ok().and_then(|path| { let name = path.file_name().and_then(|name| name.to_str()); name.map(|name| { let dapp = local_dapp(name.into(), path.clone()); (dapp.id, Box::new(local::Dapp::new( - pool.clone(), dapp.path, dapp.info, PageCache::Disabled, embeddable.clone()) + pool.clone(), dapp.path, dapp.info, PageCache::Disabled) )) }) }) @@ -90,12 +89,12 @@ fn local_dapp(name: String, path: PathBuf) -> LocalDapp { /// Returns endpoints for Local Dapps found for given filesystem path. /// Scans the directory and collects `local::Dapp`. -pub fn local_endpoints>(dapps_path: P, embeddable: Embeddable, pool: CpuPool) -> BTreeMap> { +pub fn local_endpoints>(dapps_path: P, pool: CpuPool) -> BTreeMap> { let mut pages = BTreeMap::>::new(); for dapp in local_dapps(dapps_path.as_ref()) { pages.insert( dapp.id, - Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled, embeddable.clone())) + Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled)) ); } pages diff --git a/dapps/src/apps/mod.rs b/dapps/src/apps/mod.rs index 32bd7ee0fd..3fe394b6de 100644 --- a/dapps/src/apps/mod.rs +++ b/dapps/src/apps/mod.rs @@ -17,17 +17,15 @@ use std::path::PathBuf; use std::sync::Arc; -use endpoint::{Endpoints, Endpoint}; +use endpoint::Endpoints; use futures_cpupool::CpuPool; -use page; use proxypac::ProxyPac; use web::Web; use fetch::Fetch; -use {WebProxyTokens, ParentFrameSettings}; +use WebProxyTokens; mod app; mod cache; -mod ui; pub mod fs; pub mod fetcher; pub mod manifest; @@ -35,70 +33,37 @@ pub mod manifest; pub use self::app::App; pub const HOME_PAGE: &'static str = "home"; -pub const RPC_PATH: &'static str = "rpc"; -pub const API_PATH: &'static str = "api"; -pub const UTILS_PATH: &'static str = "parity-utils"; +pub const RPC_PATH: &'static str = "rpc"; +pub const API_PATH: &'static str = "api"; pub const WEB_PATH: &'static str = "web"; pub const URL_REFERER: &'static str = "__referer="; -pub fn utils(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::new(pool, ::parity_ui::App::default())) -} - -pub fn ui(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui::App::default())) -} - -pub fn ui_deprecation(pool: CpuPool) -> Box { - Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui_deprecation::App::default())) -} - -pub fn ui_redirection(embeddable: Option) -> Box { - Box::new(ui::Redirection::new(embeddable)) -} - pub fn all_endpoints( dapps_path: PathBuf, extra_dapps: Vec, dapps_domain: &str, - embeddable: Option, web_proxy_tokens: Arc, fetch: F, pool: CpuPool, ) -> (Vec, Endpoints) { // fetch fs dapps at first to avoid overwriting builtins - let mut pages = fs::local_endpoints(dapps_path.clone(), embeddable.clone(), pool.clone()); + let mut pages = fs::local_endpoints(dapps_path.clone(), pool.clone()); let local_endpoints: Vec = pages.keys().cloned().collect(); for path in extra_dapps { - if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), embeddable.clone(), pool.clone()) { + if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), pool.clone()) { pages.insert(id, endpoint); } else { warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display()); } } - // NOTE [ToDr] Dapps will be currently embeded on 8180 - pages.insert( - "ui".into(), - Box::new(page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::App::default(), embeddable.clone())) - ); - // old version - pages.insert( - "v1".into(), - Box::new({ - let mut page = page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::old::App::default(), embeddable.clone()); - // allow JS eval on old Wallet - page.allow_js_eval(); - page - }) - ); pages.insert( "proxy".into(), - ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()) + ProxyPac::boxed(dapps_domain.to_owned()) ); pages.insert( WEB_PATH.into(), - Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), fetch.clone(), pool.clone()) + Web::boxed(web_proxy_tokens.clone(), fetch.clone(), pool.clone()) ); (local_endpoints, pages) diff --git a/dapps/src/apps/ui.rs b/dapps/src/apps/ui.rs deleted file mode 100644 index 696ed2523d..0000000000 --- a/dapps/src/apps/ui.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015-2018 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 . - -//! UI redirections - -use hyper::StatusCode; -use futures::future; - -use endpoint::{Endpoint, Request, Response, EndpointPath}; -use {handlers, Embeddable}; - -/// Redirection to UI server. -pub struct Redirection { - embeddable_on: Embeddable, -} - -impl Redirection { - pub fn new( - embeddable_on: Embeddable, - ) -> Self { - Redirection { - embeddable_on, - } - } -} - -impl Endpoint for Redirection { - fn respond(&self, _path: EndpointPath, req: Request) -> Response { - Box::new(future::ok(if let Some(ref frame) = self.embeddable_on { - trace!(target: "dapps", "Redirecting to signer interface."); - let protocol = req.uri().scheme().unwrap_or("http"); - handlers::Redirection::new(format!("{}://{}:{}", protocol, &frame.host, frame.port)).into() - } else { - trace!(target: "dapps", "Signer disabled, returning 404."); - handlers::ContentHandler::error( - StatusCode::NotFound, - "404 Not Found", - "Your homepage is not available when Trusted Signer is disabled.", - Some("You can still access dapps by writing a correct address, though. Re-enable Signer to get your homepage back."), - None, - ).into() - })) - } -} diff --git a/dapps/src/error_tpl.html b/dapps/src/error_tpl.html index c6b4db0e7f..4b155cf35d 100644 --- a/dapps/src/error_tpl.html +++ b/dapps/src/error_tpl.html @@ -4,7 +4,88 @@ {title} - +

diff --git a/dapps/src/handlers/content.rs b/dapps/src/handlers/content.rs index ec4d4f2eff..9449f0f796 100644 --- a/dapps/src/handlers/content.rs +++ b/dapps/src/handlers/content.rs @@ -22,14 +22,12 @@ use hyper::StatusCode; use parity_version::version; use handlers::add_security_headers; -use Embeddable; #[derive(Debug, Clone)] pub struct ContentHandler { code: StatusCode, content: String, mimetype: mime::Mime, - safe_to_embed_on: Embeddable, } impl ContentHandler { @@ -37,8 +35,8 @@ impl ContentHandler { Self::new(StatusCode::Ok, content, mimetype) } - pub fn html(code: StatusCode, content: String, embeddable_on: Embeddable) -> Self { - Self::new_embeddable(code, content, mime::TEXT_HTML, embeddable_on) + pub fn html(code: StatusCode, content: String) -> Self { + Self::new(code, content, mime::TEXT_HTML) } pub fn error( @@ -46,7 +44,6 @@ impl ContentHandler { title: &str, message: &str, details: Option<&str>, - embeddable_on: Embeddable, ) -> Self { Self::html(code, format!( include_str!("../error_tpl.html"), @@ -54,24 +51,18 @@ impl ContentHandler { message=message, details=details.unwrap_or_else(|| ""), version=version(), - ), embeddable_on) + )) } - pub fn new(code: StatusCode, content: String, mimetype: mime::Mime) -> Self { - Self::new_embeddable(code, content, mimetype, None) - } - - pub fn new_embeddable( + pub fn new( code: StatusCode, content: String, mimetype: mime::Mime, - safe_to_embed_on: Embeddable, ) -> Self { ContentHandler { code, content, mimetype, - safe_to_embed_on, } } } @@ -82,7 +73,7 @@ impl Into for ContentHandler { .with_status(self.code) .with_header(header::ContentType(self.mimetype)) .with_body(self.content); - add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false); + add_security_headers(&mut res.headers_mut(), false); res } } diff --git a/dapps/src/handlers/echo.rs b/dapps/src/handlers/echo.rs index d7484b6d15..03dfd1c974 100644 --- a/dapps/src/handlers/echo.rs +++ b/dapps/src/handlers/echo.rs @@ -40,7 +40,7 @@ impl Into for EchoHandler { .with_header(content_type.unwrap_or(header::ContentType::json())) .with_body(self.request.body()); - add_security_headers(res.headers_mut(), None, false); + add_security_headers(res.headers_mut(), false); res } } diff --git a/dapps/src/handlers/errors.rs b/dapps/src/handlers/errors.rs new file mode 100644 index 0000000000..5261dc3c15 --- /dev/null +++ b/dapps/src/handlers/errors.rs @@ -0,0 +1,66 @@ +// Copyright 2015-2018 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 . + +//! Handler errors. + +use handlers::{ContentHandler, FETCH_TIMEOUT}; +use hyper::StatusCode; +use std::fmt; + +pub fn streaming() -> ContentHandler { + ContentHandler::error( + StatusCode::BadGateway, + "Streaming Error", + "This content is being streamed in other place.", + None, + ) +} + +pub fn download_error(e: E) -> ContentHandler { + ContentHandler::error( + StatusCode::BadGateway, + "Download Error", + "There was an error when fetching the content.", + Some(&format!("{:?}", e)), + ) +} + +pub fn invalid_content(e: E) -> ContentHandler { + ContentHandler::error( + StatusCode::BadGateway, + "Invalid Dapp", + "Downloaded bundle does not contain a valid content.", + Some(&format!("{:?}", e)), + ) +} + +pub fn timeout_error() -> ContentHandler { + ContentHandler::error( + StatusCode::GatewayTimeout, + "Download Timeout", + &format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT.as_secs()), + None, + ) +} + +pub fn method_not_allowed() -> ContentHandler { + ContentHandler::error( + StatusCode::MethodNotAllowed, + "Method Not Allowed", + "Only GET requests are allowed.", + None, + ) +} diff --git a/dapps/src/handlers/fetch.rs b/dapps/src/handlers/fetch.rs index 860fe998c4..3fee3b1fec 100644 --- a/dapps/src/handlers/fetch.rs +++ b/dapps/src/handlers/fetch.rs @@ -19,20 +19,17 @@ use std::{fmt, mem}; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::{Instant, Duration}; +use std::time::Instant; use fetch::{self, Fetch}; use futures::sync::oneshot; use futures::{self, Future}; use futures_cpupool::CpuPool; -use hyper::{self, StatusCode}; +use hyper; use parking_lot::Mutex; use endpoint::{self, EndpointPath}; -use handlers::{ContentHandler, StreamingHandler}; +use handlers::{ContentHandler, StreamingHandler, FETCH_TIMEOUT, errors}; use page::local; -use {Embeddable}; - -const FETCH_TIMEOUT: Duration = Duration::from_secs(300); pub enum ValidatorResponse { Local(local::Dapp), @@ -134,8 +131,7 @@ impl Future for WaitingHandler { return Ok(futures::Async::Ready(handler.into())); }, WaitResult::NonAwaitable => { - let errors = Errors { embeddable_on: None }; - return Ok(futures::Async::Ready(errors.streaming().into())); + return Ok(futures::Async::Ready(errors::streaming().into())); }, WaitResult::Done(endpoint) => { WaitState::Done(endpoint.to_response(&self.path).into()) @@ -152,63 +148,6 @@ impl Future for WaitingHandler { } } -#[derive(Debug, Clone)] -struct Errors { - embeddable_on: Embeddable, -} - -impl Errors { - fn streaming(&self) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Streaming Error", - "This content is being streamed in other place.", - None, - self.embeddable_on.clone(), - ) - } - - fn download_error(&self, e: E) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Download Error", - "There was an error when fetching the content.", - Some(&format!("{:?}", e)), - self.embeddable_on.clone(), - ) - } - - fn invalid_content(&self, e: E) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Invalid Dapp", - "Downloaded bundle does not contain a valid content.", - Some(&format!("{:?}", e)), - self.embeddable_on.clone(), - ) - } - - fn timeout_error(&self) -> ContentHandler { - ContentHandler::error( - StatusCode::GatewayTimeout, - "Download Timeout", - &format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT.as_secs()), - None, - self.embeddable_on.clone(), - ) - } - - fn method_not_allowed(&self) -> ContentHandler { - ContentHandler::error( - StatusCode::MethodNotAllowed, - "Method Not Allowed", - "Only GET requests are allowed.", - None, - self.embeddable_on.clone(), - ) - } -} - enum FetchState { Error(ContentHandler), InProgress(Box + Send>), @@ -237,7 +176,6 @@ impl fmt::Debug for FetchState { pub struct ContentFetcherHandler { fetch_control: FetchControl, status: FetchState, - errors: Errors, } impl ContentFetcherHandler { @@ -250,12 +188,10 @@ impl ContentFetcherHandler { url: &str, path: EndpointPath, installer: H, - embeddable_on: Embeddable, fetch: F, pool: CpuPool, ) -> Self { let fetch_control = FetchControl::default(); - let errors = Errors { embeddable_on }; // Validation of method let status = match *method { @@ -268,18 +204,16 @@ impl ContentFetcherHandler { url, fetch_control.abort.clone(), path, - errors.clone(), installer, )) }, // or return error - _ => FetchState::Error(errors.method_not_allowed()), + _ => FetchState::Error(errors::method_not_allowed()), }; ContentFetcherHandler { fetch_control, status, - errors, } } @@ -289,7 +223,6 @@ impl ContentFetcherHandler { url: &str, abort: Arc, path: EndpointPath, - errors: Errors, installer: H, ) -> Box + Send> { // Start fetching the content @@ -311,12 +244,12 @@ impl ContentFetcherHandler { }, Err(e) => { trace!(target: "dapps", "Error while validating content: {:?}", e); - FetchState::Error(errors.invalid_content(e)) + FetchState::Error(errors::invalid_content(e)) }, }, Err(e) => { warn!(target: "dapps", "Unable to fetch content: {:?}", e); - FetchState::Error(errors.download_error(e)) + FetchState::Error(errors::download_error(e)) }, }) }); @@ -347,7 +280,7 @@ impl Future for ContentFetcherHandler { // Request may time out FetchState::InProgress(_) if self.fetch_control.is_deadline_reached() => { trace!(target: "dapps", "Fetching dapp failed because of timeout."); - FetchState::Error(self.errors.timeout_error()) + FetchState::Error(errors::timeout_error()) }, FetchState::InProgress(ref mut receiver) => { // Check if there is a response diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs index fad9c40416..cb0eba0429 100644 --- a/dapps/src/handlers/mod.rs +++ b/dapps/src/handlers/mod.rs @@ -22,6 +22,7 @@ mod fetch; mod reader; mod redirect; mod streaming; +mod errors; pub use self::content::ContentHandler; pub use self::echo::EchoHandler; @@ -30,20 +31,16 @@ pub use self::reader::Reader; pub use self::redirect::Redirection; pub use self::streaming::StreamingHandler; -use std::iter; -use itertools::Itertools; use hyper::header; -use {apps, address, Embeddable}; +use std::time::Duration; + +const FETCH_TIMEOUT: Duration = Duration::from_secs(300); /// Adds security-related headers to the Response. -pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embeddable, allow_js_eval: bool) { +pub fn add_security_headers(headers: &mut header::Headers, allow_js_eval: bool) { headers.set_raw("X-XSS-Protection", "1; mode=block"); headers.set_raw("X-Content-Type-Options", "nosniff"); - - // Embedding header: - if let None = embeddable_on { - headers.set_raw("X-Frame-Options", "SAMEORIGIN"); - } + headers.set_raw("X-Frame-Options", "SAMEORIGIN"); // Content Security Policy headers headers.set_raw("Content-Security-Policy", String::new() @@ -70,11 +67,7 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd + "object-src 'none';" // Allow scripts + { - let script_src = embeddable_on.as_ref() - .map(|e| e.extra_script_src.iter() - .map(|&(ref host, port)| address(host, port)) - .join(" ") - ).unwrap_or_default(); + let script_src = ""; let eval = if allow_js_eval { " 'unsafe-eval'" } else { "" }; &format!( @@ -93,29 +86,6 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd // Never allow mixed content + "block-all-mixed-content;" // Specify if the site can be embedded. - + &match embeddable_on { - Some(ref embed) => { - let std = address(&embed.host, embed.port); - let proxy = format!("{}.{}", apps::HOME_PAGE, embed.dapps_domain); - let domain = format!("*.{}:{}", embed.dapps_domain, embed.port); - - let mut ancestors = vec![std, domain, proxy] - .into_iter() - .chain(embed.extra_embed_on - .iter() - .map(|&(ref host, port)| address(host, port)) - ); - - let ancestors = if embed.host == "127.0.0.1" { - let localhost = address("localhost", embed.port); - ancestors.chain(iter::once(localhost)).join(" ") - } else { - ancestors.join(" ") - }; - - format!("frame-ancestors {};", ancestors) - }, - None => format!("frame-ancestors 'self';"), - } + + "frame-ancestors 'self';" ); } diff --git a/dapps/src/handlers/streaming.rs b/dapps/src/handlers/streaming.rs index 4dfd2c4afa..b6feaa6382 100644 --- a/dapps/src/handlers/streaming.rs +++ b/dapps/src/handlers/streaming.rs @@ -20,24 +20,21 @@ use std::io; use hyper::{self, header, mime, StatusCode}; use handlers::{add_security_headers, Reader}; -use Embeddable; pub struct StreamingHandler { initial: Vec, content: R, status: StatusCode, mimetype: mime::Mime, - safe_to_embed_on: Embeddable, } impl StreamingHandler { - pub fn new(content: R, status: StatusCode, mimetype: mime::Mime, safe_to_embed_on: Embeddable) -> Self { + pub fn new(content: R, status: StatusCode, mimetype: mime::Mime) -> Self { StreamingHandler { initial: Vec::new(), content, status, mimetype, - safe_to_embed_on, } } @@ -51,7 +48,7 @@ impl StreamingHandler { .with_status(self.status) .with_header(header::ContentType(self.mimetype)) .with_body(body); - add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false); + add_security_headers(&mut res.headers_mut(), false); (reader, res) } diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index 255560e422..12a6a80508 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -38,8 +38,6 @@ extern crate fetch; extern crate node_health; extern crate parity_dapps_glue as parity_dapps; extern crate parity_hash_fetch as hash_fetch; -extern crate parity_ui; -extern crate parity_ui_deprecation; extern crate keccak_hash as hash; extern crate parity_version; extern crate registrar; @@ -84,6 +82,7 @@ use node_health::NodeHealth; pub use registrar::{RegistrarClient, Asynchronous}; pub use node_health::SyncStatus; +pub use page::builtin::Dapp; /// Validates Web Proxy tokens pub trait WebProxyTokens: Send + Sync { @@ -101,7 +100,6 @@ pub struct Endpoints { local_endpoints: Arc>>, endpoints: Arc>, dapps_path: PathBuf, - embeddable: Option, pool: Option, } @@ -119,7 +117,7 @@ impl Endpoints { None => return, Some(pool) => pool, }; - let new_local = apps::fs::local_endpoints(&self.dapps_path, self.embeddable.clone(), pool.clone()); + let new_local = apps::fs::local_endpoints(&self.dapps_path, pool.clone()); let old_local = mem::replace(&mut *self.local_endpoints.write(), new_local.keys().cloned().collect()); let (_, to_remove): (_, Vec<_>) = old_local .into_iter() @@ -151,69 +149,10 @@ impl Middleware { &self.endpoints } - /// Creates new middleware for UI server. - pub fn ui( - pool: CpuPool, - health: NodeHealth, - dapps_domain: &str, - registrar: Arc>, - sync_status: Arc, - fetch: F, - info_page_only: bool, - ) -> Self { - let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( - hash_fetch::urlhint::URLHintContract::new(registrar), - sync_status.clone(), - fetch.clone(), - pool.clone(), - ).embeddable_on(None).allow_dapps(false)); - - if info_page_only { - let mut special = HashMap::default(); - special.insert(router::SpecialEndpoint::Home, Some(apps::ui_deprecation(pool.clone()))); - - return Middleware { - endpoints: Default::default(), - router: router::Router::new( - content_fetcher, - None, - special, - None, - dapps_domain.to_owned(), - ), - } - } - - let special = { - let mut special = special_endpoints( - pool.clone(), - health, - content_fetcher.clone(), - ); - special.insert(router::SpecialEndpoint::Home, Some(apps::ui(pool.clone()))); - special - }; - let router = router::Router::new( - content_fetcher, - None, - special, - None, - dapps_domain.to_owned(), - ); - - Middleware { - endpoints: Default::default(), - router: router, - } - } - /// Creates new Dapps server middleware. pub fn dapps( pool: CpuPool, health: NodeHealth, - ui_address: Option<(String, u16)>, - extra_embed_on: Vec<(String, u16)>, - extra_script_src: Vec<(String, u16)>, dapps_path: PathBuf, extra_dapps: Vec, dapps_domain: &str, @@ -222,18 +161,16 @@ impl Middleware { web_proxy_tokens: Arc, fetch: F, ) -> Self { - let embeddable = as_embeddable(ui_address, extra_embed_on, extra_script_src, dapps_domain); let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( hash_fetch::urlhint::URLHintContract::new(registrar), sync_status.clone(), fetch.clone(), pool.clone(), - ).embeddable_on(embeddable.clone()).allow_dapps(true)); + ).allow_dapps(true)); let (local_endpoints, endpoints) = apps::all_endpoints( dapps_path.clone(), extra_dapps, dapps_domain, - embeddable.clone(), web_proxy_tokens, fetch.clone(), pool.clone(), @@ -242,28 +179,18 @@ impl Middleware { endpoints: Arc::new(RwLock::new(endpoints)), dapps_path, local_endpoints: Arc::new(RwLock::new(local_endpoints)), - embeddable: embeddable.clone(), pool: Some(pool.clone()), }; - let special = { - let mut special = special_endpoints( - pool.clone(), - health, - content_fetcher.clone(), - ); - special.insert( - router::SpecialEndpoint::Home, - Some(apps::ui_redirection(embeddable.clone())), - ); - special - }; + let special = special_endpoints( + health, + content_fetcher.clone(), + ); let router = router::Router::new( content_fetcher, Some(endpoints.clone()), special, - embeddable, dapps_domain.to_owned(), ); @@ -281,13 +208,11 @@ impl http::RequestMiddleware for Middleware { } fn special_endpoints( - pool: CpuPool, health: NodeHealth, content_fetcher: Arc, ) -> HashMap>> { let mut special = HashMap::new(); special.insert(router::SpecialEndpoint::Rpc, None); - special.insert(router::SpecialEndpoint::Utils, Some(apps::utils(pool))); special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new( content_fetcher, health, @@ -295,45 +220,9 @@ fn special_endpoints( special } -fn address(host: &str, port: u16) -> String { - format!("{}:{}", host, port) -} - -fn as_embeddable( - ui_address: Option<(String, u16)>, - extra_embed_on: Vec<(String, u16)>, - extra_script_src: Vec<(String, u16)>, - dapps_domain: &str, -) -> Option { - ui_address.map(|(host, port)| ParentFrameSettings { - host, - port, - extra_embed_on, - extra_script_src, - dapps_domain: dapps_domain.to_owned(), - }) -} - /// Random filename fn random_filename() -> String { use ::rand::Rng; let mut rng = ::rand::OsRng::new().unwrap(); rng.gen_ascii_chars().take(12).collect() } - -type Embeddable = Option; - -/// Parent frame host and port allowed to embed the content. -#[derive(Debug, Clone)] -pub struct ParentFrameSettings { - /// Hostname - pub host: String, - /// Port - pub port: u16, - /// Additional URLs the dapps can be embedded on. - pub extra_embed_on: Vec<(String, u16)>, - /// Additional URLs the dapp scripts can be loaded from. - pub extra_script_src: Vec<(String, u16)>, - /// Dapps Domain (web3.site) - pub dapps_domain: String, -} diff --git a/dapps/src/page/builtin.rs b/dapps/src/page/builtin.rs index b9f2fcdac5..685b1401d1 100644 --- a/dapps/src/page/builtin.rs +++ b/dapps/src/page/builtin.rs @@ -23,15 +23,13 @@ use parity_dapps::{WebApp, Info}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; use page::{handler, PageCache}; -use Embeddable; +/// Represents a builtin Dapp. pub struct Dapp { /// futures cpu pool pool: CpuPool, /// Content of the files app: T, - /// Safe to be loaded in frame by other origin. (use wisely!) - safe_to_embed_on: Embeddable, info: EndpointInfo, fallback_to_index_html: bool, } @@ -43,7 +41,6 @@ impl Dapp { Dapp { pool, app, - safe_to_embed_on: None, info: EndpointInfo::from(info), fallback_to_index_html: false, } @@ -56,26 +53,11 @@ impl Dapp { Dapp { pool, app, - safe_to_embed_on: None, info: EndpointInfo::from(info), fallback_to_index_html: true, } } - /// Creates new `Dapp` which can be safely used in iframe - /// even from different origin. It might be dangerous (clickjacking). - /// Use wisely! - pub fn new_safe_to_embed(pool: CpuPool, app: T, address: Embeddable) -> Self { - let info = app.info(); - Dapp { - pool, - app, - safe_to_embed_on: address, - info: EndpointInfo::from(info), - fallback_to_index_html: false, - } - } - /// Allow the dapp to use `unsafe-eval` to run JS. pub fn allow_js_eval(&mut self) { self.info.allow_js_eval = Some(true); @@ -121,7 +103,6 @@ impl Endpoint for Dapp { let (reader, response) = handler::PageHandler { file, cache: PageCache::Disabled, - safe_to_embed_on: self.safe_to_embed_on.clone(), allow_js_eval: self.info.allow_js_eval.clone().unwrap_or(false), }.into_response(); diff --git a/dapps/src/page/handler.rs b/dapps/src/page/handler.rs index 15e2b10c50..d7fcefa7f0 100644 --- a/dapps/src/page/handler.rs +++ b/dapps/src/page/handler.rs @@ -20,7 +20,6 @@ use hyper::{self, header, StatusCode}; use hyper::mime::{Mime}; use handlers::{Reader, ContentHandler, add_security_headers}; -use {Embeddable}; /// Represents a file that can be sent to client. /// Implementation should keep track of bytes already sent internally. @@ -54,8 +53,6 @@ impl Default for PageCache { pub struct PageHandler { /// File currently being served pub file: Option, - /// Flag indicating if the file can be safely embeded (put in iframe). - pub safe_to_embed_on: Embeddable, /// Cache settings for this page. pub cache: PageCache, /// Allow JS unsafe-eval. @@ -70,7 +67,6 @@ impl PageHandler { "File not found", "Requested file has not been found.", None, - self.safe_to_embed_on, ).into()), Some(file) => file, }; @@ -94,7 +90,7 @@ impl PageHandler { headers.set(header::ContentType(file.content_type().to_owned())); - add_security_headers(&mut headers, self.safe_to_embed_on, self.allow_js_eval); + add_security_headers(&mut headers, self.allow_js_eval); } let (reader, body) = Reader::pair(file.into_reader(), Vec::new()); diff --git a/dapps/src/page/local.rs b/dapps/src/page/local.rs index f30af45237..a43735d768 100644 --- a/dapps/src/page/local.rs +++ b/dapps/src/page/local.rs @@ -22,7 +22,6 @@ use futures_cpupool::CpuPool; use page::handler::{self, PageCache}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; use hyper::mime::Mime; -use Embeddable; #[derive(Clone)] pub struct Dapp { @@ -31,7 +30,6 @@ pub struct Dapp { mime: Option, info: Option, cache: PageCache, - embeddable_on: Embeddable, } impl fmt::Debug for Dapp { @@ -41,20 +39,18 @@ impl fmt::Debug for Dapp { .field("mime", &self.mime) .field("info", &self.info) .field("cache", &self.cache) - .field("embeddable_on", &self.embeddable_on) .finish() } } impl Dapp { - pub fn new(pool: CpuPool, path: PathBuf, info: EndpointInfo, cache: PageCache, embeddable_on: Embeddable) -> Self { + pub fn new(pool: CpuPool, path: PathBuf, info: EndpointInfo, cache: PageCache) -> Self { Dapp { pool, path, mime: None, info: Some(info), cache, - embeddable_on, } } @@ -65,7 +61,6 @@ impl Dapp { mime: Some(mime), info: None, cache, - embeddable_on: None, } } @@ -96,7 +91,6 @@ impl Dapp { let (reader, response) = handler::PageHandler { file: self.get_file(path), cache: self.cache, - safe_to_embed_on: self.embeddable_on.clone(), allow_js_eval: self.info.as_ref().and_then(|x| x.allow_js_eval).unwrap_or(false), }.into_response(); diff --git a/dapps/src/proxypac.rs b/dapps/src/proxypac.rs index 4e11f3ea6b..1acd7b1b9e 100644 --- a/dapps/src/proxypac.rs +++ b/dapps/src/proxypac.rs @@ -21,25 +21,20 @@ use endpoint::{Endpoint, Request, Response, EndpointPath}; use futures::future; use handlers::ContentHandler; use hyper::mime; -use {address, Embeddable}; pub struct ProxyPac { - embeddable: Embeddable, dapps_domain: String, } impl ProxyPac { - pub fn boxed(embeddable: Embeddable, dapps_domain: String) -> Box { - Box::new(ProxyPac { embeddable, dapps_domain }) + pub fn boxed(dapps_domain: String) -> Box { + Box::new(ProxyPac { dapps_domain }) } } impl Endpoint for ProxyPac { fn respond(&self, path: EndpointPath, _req: Request) -> Response { - let ui = self.embeddable - .as_ref() - .map(|ref parent| address(&parent.host, parent.port)) - .unwrap_or_else(|| format!("{}:{}", path.host, path.port)); + let ui = format!("{}:{}", path.host, path.port); let content = format!( r#" diff --git a/dapps/src/router.rs b/dapps/src/router.rs index 565874f6a8..28a3e24c3f 100644 --- a/dapps/src/router.rs +++ b/dapps/src/router.rs @@ -29,14 +29,12 @@ use apps::fetcher::Fetcher; use endpoint::{self, Endpoint, EndpointPath}; use Endpoints; use handlers; -use Embeddable; /// Special endpoints are accessible on every domain (every dapp) #[derive(Debug, PartialEq, Hash, Eq)] pub enum SpecialEndpoint { Rpc, Api, - Utils, Home, None, } @@ -52,16 +50,14 @@ pub struct Router { endpoints: Option, fetch: Arc, special: HashMap>>, - embeddable_on: Embeddable, dapps_domain: String, } impl Router { - fn resolve_request(&self, req: hyper::Request, refresh_dapps: bool) -> (bool, Response) { + fn resolve_request(&self, req: hyper::Request, refresh_dapps: bool) -> Response { // Choose proper handler depending on path / domain let endpoint = extract_endpoint(req.uri(), req.headers().get(), &self.dapps_domain); let referer = extract_referer_endpoint(&req, &self.dapps_domain); - let is_utils = endpoint.1 == SpecialEndpoint::Utils; let is_get_request = *req.method() == hyper::Method::Get; let is_head_request = *req.method() == hyper::Method::Head; let has_dapp = |dapp: &str| self.endpoints @@ -71,7 +67,7 @@ impl Router { trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", req.uri(), req); debug!(target: "dapps", "Handling endpoint request: {:?}, referer: {:?}", endpoint, referer); - (is_utils, match (endpoint.0, endpoint.1, referer) { + match (endpoint.0, endpoint.1, referer) { // Handle invalid web requests that we can recover from (ref path, SpecialEndpoint::None, Some(ref referer)) if referer.app_id == apps::WEB_PATH @@ -132,7 +128,6 @@ impl Router { "404 Not Found", "Requested content was not found.", None, - self.embeddable_on.clone(), ).into()))) } }, @@ -161,20 +156,19 @@ impl Router { "404 Not Found", "Requested content was not found.", None, - self.embeddable_on.clone(), ).into()))) }, - }) + } } } impl http::RequestMiddleware for Router { fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction { let is_origin_set = req.headers().get::().is_some(); - let (is_utils, response) = self.resolve_request(req, self.endpoints.is_some()); + let response = self.resolve_request(req, self.endpoints.is_some()); match response { Response::Some(response) => http::RequestMiddlewareAction::Respond { - should_validate_hosts: !is_utils, + should_validate_hosts: true, response, }, Response::None(request) => http::RequestMiddlewareAction::Proceed { @@ -190,14 +184,12 @@ impl Router { content_fetcher: Arc, endpoints: Option, special: HashMap>>, - embeddable_on: Embeddable, dapps_domain: String, ) -> Self { Router { endpoints: endpoints, fetch: content_fetcher, special: special, - embeddable_on: embeddable_on, dapps_domain: format!(".{}", dapps_domain), } } @@ -250,7 +242,6 @@ fn extract_endpoint(url: &Uri, extra_host: Option<&header::Host>, dapps_domain: match path[0].as_ref() { apps::RPC_PATH => SpecialEndpoint::Rpc, apps::API_PATH => SpecialEndpoint::Api, - apps::UTILS_PATH => SpecialEndpoint::Utils, apps::HOME_PAGE => SpecialEndpoint::Home, _ => SpecialEndpoint::None, } @@ -351,30 +342,6 @@ mod tests { }), SpecialEndpoint::Rpc) ); - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/parity-utils/inject.js".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "inject.js".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::Utils) - ); - - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/inject.js".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "inject.js".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::None) - ); - // By Subdomain assert_eq!( extract_endpoint(&"http://status.web3.site/test.html".parse().unwrap(), None, dapps_domain), diff --git a/dapps/src/tests/fetch.rs b/dapps/src/tests/fetch.rs index bbd766a552..444d5b656a 100644 --- a/dapps/src/tests/fetch.rs +++ b/dapps/src/tests/fetch.rs @@ -19,7 +19,7 @@ use rustc_hex::FromHex; use tests::helpers::{ serve_with_registrar, serve_with_registrar_and_sync, serve_with_fetch, serve_with_registrar_and_fetch, - request, assert_security_headers_for_embed, + request, assert_security_headers }; #[test] @@ -40,7 +40,7 @@ fn should_resolve_dapp() { // then response.assert_status("HTTP/1.1 404 Not Found"); assert_eq!(registrar.calls.lock().len(), 4); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); } #[test] @@ -61,7 +61,7 @@ fn should_return_503_when_syncing_but_should_make_the_calls() { // then response.assert_status("HTTP/1.1 503 Service Unavailable"); assert_eq!(registrar.calls.lock().len(), 2); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); } const GAVCOIN_DAPP: &'static str = "00000000000000000000000000000000000000000000000000000000000000609faf32e1e3845e237cc6efd27187cee13b3b99db000000000000000000000000000000000000000000000000d8bd350823e28ff75e74a34215faefdc8a52fd8e00000000000000000000000000000000000000000000000000000000000000116761766f66796f726b2f676176636f696e000000000000000000000000000000"; @@ -95,7 +95,7 @@ fn should_return_502_on_hash_mismatch() { response.assert_status("HTTP/1.1 502 Bad Gateway"); assert!(response.body.contains("HashMismatch"), "Expected hash mismatch response, got: {:?}", response.body); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); } #[test] @@ -126,7 +126,7 @@ fn should_return_error_for_invalid_dapp_zip() { response.assert_status("HTTP/1.1 502 Bad Gateway"); assert!(response.body.contains("InvalidArchive"), "Expected invalid zip response, got: {:?}", response.body); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); } #[test] @@ -165,7 +165,7 @@ fn should_return_fetched_dapp_content() { fetch.assert_no_more_requests(); response1.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response1.headers); + assert_security_headers(&response1.headers); assert!( response1.body.contains(r#"18

Hello Gavcoin!

@@ -178,7 +178,7 @@ fn should_return_fetched_dapp_content() { ); response2.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response2.headers); + assert_security_headers(&response2.headers); assert_eq!( response2.body, r#"EA @@ -331,7 +331,7 @@ fn should_stream_web_content() { // then response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_requested("https://parity.io/"); fetch.assert_no_more_requests(); @@ -354,7 +354,7 @@ fn should_support_base32_encoded_web_urls() { // then response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_requested("https://parity.io/styles.css?test=123"); fetch.assert_no_more_requests(); @@ -377,7 +377,7 @@ fn should_correctly_handle_long_label_when_splitted() { // then response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_requested("https://contribution.melonport.com/styles.css?test=123"); fetch.assert_no_more_requests(); @@ -400,7 +400,7 @@ fn should_support_base32_encoded_web_urls_as_path() { // then response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_requested("https://parity.io/styles.css?test=123"); fetch.assert_no_more_requests(); @@ -423,7 +423,7 @@ fn should_return_error_on_non_whitelisted_domain() { // then response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_no_more_requests(); } @@ -445,7 +445,7 @@ fn should_return_error_on_invalid_token() { // then response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_no_more_requests(); } @@ -467,7 +467,7 @@ fn should_return_error_on_invalid_protocol() { // then response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_no_more_requests(); } @@ -492,7 +492,7 @@ fn should_disallow_non_get_requests() { // then response.assert_status("HTTP/1.1 405 Method Not Allowed"); - assert_security_headers_for_embed(&response.headers); + assert_security_headers(&response.headers); fetch.assert_no_more_requests(); } diff --git a/dapps/src/tests/helpers/mod.rs b/dapps/src/tests/helpers/mod.rs index aa76089794..58ec71d733 100644 --- a/dapps/src/tests/helpers/mod.rs +++ b/dapps/src/tests/helpers/mod.rs @@ -36,8 +36,6 @@ mod fetch; use self::registrar::FakeRegistrar; use self::fetch::FakeFetch; -const SIGNER_PORT: u16 = 18180; - #[derive(Debug)] struct FakeSync(bool); impl SyncStatus for FakeSync { @@ -63,8 +61,7 @@ pub fn init_server(process: F, io: IoHandler) -> (Server, Arc Server { init_server(|builder| builder, Default::default()).0 } -pub fn serve_ui() -> Server { - init_server(|mut builder| { - builder.serve_ui = true; - builder - }, Default::default()).0 -} - pub fn request(server: Server, request: &str) -> http_client::Response { http_client::request(server.addr(), request) } @@ -136,9 +126,6 @@ pub fn request(server: Server, request: &str) -> http_client::Response { pub fn assert_security_headers(headers: &[String]) { http_client::assert_security_headers_present(headers, None) } -pub fn assert_security_headers_for_embed(headers: &[String]) { - http_client::assert_security_headers_present(headers, Some(SIGNER_PORT)) -} /// Webapps HTTP+RPC server build. pub struct ServerBuilder { @@ -146,10 +133,8 @@ pub struct ServerBuilder { registrar: Arc>, sync_status: Arc, web_proxy_tokens: Arc, - signer_address: Option<(String, u16)>, allowed_hosts: DomainsValidation, fetch: T, - serve_ui: bool, } impl ServerBuilder { @@ -160,10 +145,8 @@ impl ServerBuilder { registrar: registrar, sync_status: Arc::new(FakeSync(false)), web_proxy_tokens: Arc::new(|_| None), - signer_address: None, allowed_hosts: DomainsValidation::Disabled, fetch: fetch, - serve_ui: false, } } } @@ -176,10 +159,8 @@ impl ServerBuilder { registrar: self.registrar, sync_status: self.sync_status, web_proxy_tokens: self.web_proxy_tokens, - signer_address: self.signer_address, allowed_hosts: self.allowed_hosts, fetch: fetch, - serve_ui: self.serve_ui, } } @@ -190,7 +171,6 @@ impl ServerBuilder { addr, io, self.allowed_hosts, - self.signer_address, self.dapps_path, vec![], self.registrar, @@ -198,7 +178,6 @@ impl ServerBuilder { self.web_proxy_tokens, Remote::new_sync(), self.fetch, - self.serve_ui, ) } } @@ -215,7 +194,6 @@ impl Server { addr: &SocketAddr, io: IoHandler, allowed_hosts: DomainsValidation, - signer_address: Option<(String, u16)>, dapps_path: PathBuf, extra_dapps: Vec, registrar: Arc>, @@ -223,7 +201,6 @@ impl Server { web_proxy_tokens: Arc, remote: Remote, fetch: F, - serve_ui: bool, ) -> io::Result { let health = NodeHealth::new( sync_status.clone(), @@ -231,23 +208,10 @@ impl Server { remote.clone(), ); let pool = ::futures_cpupool::CpuPool::new(1); - let middleware = if serve_ui { - Middleware::ui( - pool, - health, - DAPPS_DOMAIN.into(), - registrar, - sync_status, - fetch, - false, - ) - } else { + let middleware = Middleware::dapps( pool, health, - signer_address, - vec![], - vec![], dapps_path, extra_dapps, DAPPS_DOMAIN.into(), @@ -255,8 +219,7 @@ impl Server { sync_status, web_proxy_tokens, fetch, - ) - }; + ); let mut allowed_hosts: Option> = allowed_hosts.into(); allowed_hosts.as_mut().map(|hosts| { diff --git a/dapps/src/tests/home.rs b/dapps/src/tests/home.rs deleted file mode 100644 index 024261d5df..0000000000 --- a/dapps/src/tests/home.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015-2018 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 . - -use tests::helpers::{serve_ui, request, assert_security_headers}; - -#[test] -fn should_serve_home_js() { - // given - let server = serve_ui(); - - // when - let response = request(server, - "\ - GET /inject.js HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "application/javascript"); - assert_eq!(response.body.contains("function(){"), true, "Expected function in: {}", response.body); - assert_security_headers(&response.headers); -} - -#[test] -fn should_serve_home() { - // given - let server = serve_ui(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "text/html"); - assert_security_headers(&response.headers); -} diff --git a/dapps/src/tests/mod.rs b/dapps/src/tests/mod.rs index 38a1d6f17a..c4d88cf9f1 100644 --- a/dapps/src/tests/mod.rs +++ b/dapps/src/tests/mod.rs @@ -20,7 +20,5 @@ mod helpers; mod api; mod fetch; -mod home; -mod redirection; mod rpc; mod validation; diff --git a/dapps/src/tests/redirection.rs b/dapps/src/tests/redirection.rs deleted file mode 100644 index 722ade25b9..0000000000 --- a/dapps/src/tests/redirection.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2015-2018 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 . - -use tests::helpers::{serve, request, assert_security_headers, assert_security_headers_for_embed}; - -#[test] -fn should_redirect_to_home() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180"); -} - -#[test] -fn should_redirect_to_home_with_domain() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: home.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180"); -} - -#[test] -fn should_redirect_to_home_when_trailing_slash_is_missing() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /app HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180"); -} - -#[test] -fn should_display_404_on_invalid_dapp() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /invaliddapp/ HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_security_headers_for_embed(&response.headers); -} - -#[test] -fn should_display_404_on_invalid_dapp_with_domain() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: invaliddapp.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_security_headers_for_embed(&response.headers); -} - -#[test] -fn should_serve_rpc() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - POST / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - Content-Type: application/json\r\n - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, format!("4C\n{}\n\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#)); -} - -#[test] -fn should_serve_rpc_at_slash_rpc() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - POST /rpc HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - Content-Type: application/json\r\n - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, format!("4C\n{}\n\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#)); -} - -#[test] -fn should_serve_proxy_pac() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /proxy/proxy.pac HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, "DB\n\nfunction FindProxyForURL(url, host) {\n\tif (shExpMatch(host, \"home.web3.site\"))\n\t{\n\t\treturn \"PROXY 127.0.0.1:18180\";\n\t}\n\n\tif (shExpMatch(host, \"*.web3.site\"))\n\t{\n\t\treturn \"PROXY 127.0.0.1:8080\";\n\t}\n\n\treturn \"DIRECT\";\n}\n\n0\n\n".to_owned()); - assert_security_headers(&response.headers); -} - -#[test] -fn should_serve_utils() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /parity-utils/inject.js HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "application/javascript"); - assert_eq!(response.body.contains("function(){"), true, "Expected function in: {}", response.body); - assert_security_headers(&response.headers); -} diff --git a/dapps/src/tests/validation.rs b/dapps/src/tests/validation.rs index ed4a3dc2f0..f9d22f802d 100644 --- a/dapps/src/tests/validation.rs +++ b/dapps/src/tests/validation.rs @@ -37,26 +37,6 @@ fn should_reject_invalid_host() { assert!(response.body.contains("Provided Host header is not whitelisted."), response.body); } -#[test] -fn should_allow_valid_host() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET /ui/ HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); -} - #[test] fn should_serve_dapps_domains() { // given @@ -66,28 +46,7 @@ fn should_serve_dapps_domains() { let response = request(server, "\ GET / HTTP/1.1\r\n\ - Host: ui.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); -} - -#[test] -// NOTE [todr] This is required for error pages to be styled properly. -fn should_allow_parity_utils_even_on_invalid_domain() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET /parity-utils/styles.css HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ + Host: proxy.web3.site\r\n\ Connection: close\r\n\ \r\n\ {} diff --git a/dapps/src/web.rs b/dapps/src/web.rs index 14f215ca45..fac0dca1af 100644 --- a/dapps/src/web.rs +++ b/dapps/src/web.rs @@ -30,10 +30,9 @@ use handlers::{ ContentFetcherHandler, ContentHandler, ContentValidator, ValidatorResponse, StreamingHandler, }; -use {Embeddable, WebProxyTokens}; +use WebProxyTokens; pub struct Web { - embeddable_on: Embeddable, web_proxy_tokens: Arc, fetch: F, pool: CpuPool, @@ -41,13 +40,11 @@ pub struct Web { impl Web { pub fn boxed( - embeddable_on: Embeddable, web_proxy_tokens: Arc, fetch: F, pool: CpuPool, ) -> Box { Box::new(Web { - embeddable_on, web_proxy_tokens, fetch, pool, @@ -64,7 +61,6 @@ impl Web { "Invalid parameter", "Couldn't parse given parameter:", path.app_params.get(0).map(String::as_str), - self.embeddable_on.clone() ))?; let mut token_it = token_and_url.split('+'); @@ -76,7 +72,7 @@ impl Web { Some(domain) => domain, _ => { return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Access Token", "Invalid or old web proxy access token supplied.", Some("Try refreshing the page."), self.embeddable_on.clone() + StatusCode::BadRequest, "Invalid Access Token", "Invalid or old web proxy access token supplied.", Some("Try refreshing the page."), )); } }; @@ -86,14 +82,14 @@ impl Web { Some(url) if url.starts_with("http://") || url.starts_with("https://") => url.to_owned(), _ => { return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Protocol", "Invalid protocol used.", None, self.embeddable_on.clone() + StatusCode::BadRequest, "Invalid Protocol", "Invalid protocol used.", None, )); } }; if !target_url.starts_with(&*domain) { return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Domain", "Dapp attempted to access invalid domain.", Some(&target_url), self.embeddable_on.clone(), + StatusCode::BadRequest, "Invalid Domain", "Dapp attempted to access invalid domain.", Some(&target_url), )); } @@ -128,10 +124,8 @@ impl Endpoint for Web { &target_url, path, WebInstaller { - embeddable_on: self.embeddable_on.clone(), token, }, - self.embeddable_on.clone(), self.fetch.clone(), self.pool.clone(), )) @@ -139,7 +133,6 @@ impl Endpoint for Web { } struct WebInstaller { - embeddable_on: Embeddable, token: String, } @@ -154,12 +147,10 @@ impl ContentValidator for WebInstaller { fetch::BodyReader::new(response), status, mime, - self.embeddable_on, ); if is_html { handler.set_initial_content(&format!( - r#""#, - apps::UTILS_PATH, + r#""#, apps::URL_REFERER, apps::WEB_PATH, &self.token, diff --git a/dapps/ui-deprecation/Cargo.toml b/dapps/ui-deprecation/Cargo.toml deleted file mode 100644 index f4479c2367..0000000000 --- a/dapps/ui-deprecation/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -description = "Parity UI deprecation notice." -name = "parity-ui-deprecation" -version = "1.10.0" -license = "GPL-3.0" -authors = ["Parity Technologies "] -build = "build.rs" - -[features] -default = ["with-syntex", "use-precompiled-js"] -use-precompiled-js = ["parity-dapps-glue/use-precompiled-js"] -with-syntex = ["parity-dapps-glue/with-syntex"] - -[build-dependencies] -parity-dapps-glue = "1.9" - -[dependencies] -parity-dapps-glue = "1.9" diff --git a/dapps/ui-deprecation/build.rs b/dapps/ui-deprecation/build.rs deleted file mode 100644 index c427f3d54d..0000000000 --- a/dapps/ui-deprecation/build.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015-2018 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 . - -extern crate parity_dapps_glue; - -fn main() { - parity_dapps_glue::generate(); -} diff --git a/dapps/ui-deprecation/build/index.html b/dapps/ui-deprecation/build/index.html deleted file mode 100644 index 07059743c6..0000000000 --- a/dapps/ui-deprecation/build/index.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - Parity - - - -
-
-
-

The Parity UI has been split off into a standalone project.

-

Get the standalone Parity UI from here

-

- -

-
-
-
- - diff --git a/dapps/ui-deprecation/src/lib.rs b/dapps/ui-deprecation/src/lib.rs deleted file mode 100644 index 79a4a42497..0000000000 --- a/dapps/ui-deprecation/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015-2018 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 . - -#[cfg(feature = "with-syntex")] -include!(concat!(env!("OUT_DIR"), "/lib.rs")); - -#[cfg(not(feature = "with-syntex"))] -include!("lib.rs.in"); diff --git a/dapps/ui-deprecation/src/lib.rs.in b/dapps/ui-deprecation/src/lib.rs.in deleted file mode 100644 index 892ebbded2..0000000000 --- a/dapps/ui-deprecation/src/lib.rs.in +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015-2018 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 . - -extern crate parity_dapps_glue; - -use std::collections::HashMap; -use parity_dapps_glue::{WebApp, File, Info}; - -#[derive(WebAppFiles)] -#[webapp(path = "../build")] -pub struct App { - pub files: HashMap<&'static str, File>, -} - -impl Default for App { - fn default() -> App { - App { - files: Self::files(), - } - } -} - -impl WebApp for App { - fn file(&self, path: &str) -> Option<&File> { - self.files.get(path) - } - - fn info(&self) -> Info { - Info { - name: "Parity Wallet info page", - version: env!("CARGO_PKG_VERSION"), - author: "Parity ", - description: "Deprecation notice for Parity Wallet", - icon_url: "icon.png", - } - } -} - -#[test] -fn test_js() { - parity_dapps_glue::js::build(env!("CARGO_MANIFEST_DIR"), "build"); -} diff --git a/dapps/ui/Cargo.toml b/dapps/ui/Cargo.toml deleted file mode 100644 index acb7a91735..0000000000 --- a/dapps/ui/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -description = "Ethcore Parity UI" -homepage = "http://parity.io" -license = "GPL-3.0" -name = "parity-ui" -version = "1.12.0" -authors = ["Parity Technologies "] - -[build-dependencies] -rustc_version = "0.2" - -[dependencies] -parity-ui-dev = { git = "https://github.com/parity-js/shell.git", rev = "eecaadcb9e421bce31e91680d14a20bbd38f92a2", optional = true } -parity-ui-old-dev = { git = "https://github.com/parity-js/dapp-wallet.git", rev = "65deb02e7c007a0fd8aab0c089c93e3fd1de6f87", optional = true } -parity-ui-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-10-shell.git", rev="bd25b41cd642c6b822d820dded3aa601a29aa079", optional = true } -parity-ui-old-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git", rev="4b6f112412716cd05123d32eeb7fda448288a6c6", optional = true } - -[features] -no-precompiled-js = ["parity-ui-dev", "parity-ui-old-dev"] -use-precompiled-js = ["parity-ui-precompiled", "parity-ui-old-precompiled"] diff --git a/dapps/ui/src/lib.rs b/dapps/ui/src/lib.rs deleted file mode 100644 index f04f755a99..0000000000 --- a/dapps/ui/src/lib.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015-2018 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 . - -#[cfg(feature = "parity-ui-dev")] -mod inner { - extern crate parity_ui_dev; - - pub use self::parity_ui_dev::*; -} - -#[cfg(feature = "parity-ui-precompiled")] -mod inner { - extern crate parity_ui_precompiled; - - pub use self::parity_ui_precompiled::*; -} - -#[cfg(feature = "parity-ui-old-dev")] -pub mod old { - extern crate parity_ui_old_dev; - - pub use self::parity_ui_old_dev::*; -} - -#[cfg(feature = "parity-ui-old-precompiled")] -pub mod old { - extern crate parity_ui_old_precompiled; - - pub use self::parity_ui_old_precompiled::*; -} - -pub use self::inner::*; diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index facd01dbfb..a3f3d4887f 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -26,10 +26,6 @@ usage! { // Arguments must start with arg_ // Flags must start with flag_ - CMD cmd_ui { - "Manage ui", - } - CMD cmd_dapp { "Manage dapps", @@ -376,35 +372,10 @@ usage! { "Provide a file containing passwords for unlocking accounts (signer, private account, validators).", ["UI options"] - FLAG flag_force_ui: (bool) = false, or |c: &Config| c.ui.as_ref()?.force.clone(), - "--force-ui", - "Enable Trusted UI WebSocket endpoint, even when --unlock is in use.", - - FLAG flag_no_ui: (bool) = false, or |c: &Config| c.ui.as_ref()?.disable.clone(), - "--no-ui", - "Disable Trusted UI WebSocket endpoint.", - - // NOTE [todr] For security reasons don't put this to config files - FLAG flag_ui_no_validation: (bool) = false, or |_| None, - "--ui-no-validation", - "Disable Origin and Host headers validation for Trusted UI. WARNING: INSECURE. Used only for development.", - - ARG arg_ui_interface: (String) = "local", or |c: &Config| c.ui.as_ref()?.interface.clone(), - "--ui-interface=[IP]", - "Specify the hostname portion of the Trusted UI server, IP should be an interface's IP address, or local.", - - ARG arg_ui_hosts: (String) = "none", or |c: &Config| c.ui.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), - "--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\",.", - ARG arg_ui_path: (String) = "$BASE/signer", or |c: &Config| c.ui.as_ref()?.path.clone(), "--ui-path=[PATH]", "Specify directory where Trusted UIs tokens should be stored.", - ARG arg_ui_port: (u16) = 8180u16, or |c: &Config| c.ui.as_ref()?.port.clone(), - "--ui-port=[PORT]", - "Specify the port of Trusted UI server.", - ["Networking options"] FLAG flag_no_warp: (bool) = false, or |c: &Config| c.network.as_ref()?.warp.clone().map(|w| !w), "--no-warp", @@ -948,6 +919,30 @@ usage! { "--public-node", "Does nothing; Public node is removed from Parity.", + FLAG flag_force_ui: (bool) = false, or |_| None, + "--force-ui", + "Does nothing; UI is now a separate project.", + + FLAG flag_no_ui: (bool) = false, or |_| None, + "--no-ui", + "Does nothing; UI is now a separate project.", + + FLAG flag_ui_no_validation: (bool) = false, or |_| None, + "--ui-no-validation", + "Does nothing; UI is now a separate project.", + + ARG arg_ui_interface: (String) = "local", or |_| None, + "--ui-interface=[IP]", + "Does nothing; UI is now a separate project.", + + ARG arg_ui_hosts: (String) = "none", or |_| None, + "--ui-hosts=[HOSTS]", + "Does nothing; UI is now a separate project.", + + ARG arg_ui_port: (u16) = 8180u16, or |_| None, + "--ui-port=[PORT]", + "Does nothing; UI is now a separate project.", + ARG arg_dapps_port: (Option) = None, or |c: &Config| c.dapps.as_ref()?.port.clone(), "--dapps-port=[PORT]", "Dapps server is merged with RPC server. Use --jsonrpc-port.", @@ -1111,12 +1106,18 @@ struct PrivateTransactions { #[derive(Default, Debug, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] struct Ui { - force: Option, - disable: Option, - port: Option, - interface: Option, - hosts: Option>, path: Option, + + #[serde(rename="force")] + _legacy_force: Option, + #[serde(rename="disable")] + _legacy_disable: Option, + #[serde(rename="port")] + _legacy_port: Option, + #[serde(rename="interface")] + _legacy_interface: Option, + #[serde(rename="hosts")] + _legacy_hosts: Option>, } #[derive(Default, Debug, PartialEq, Deserialize)] @@ -1404,15 +1405,13 @@ mod tests { let args = Args::parse(&["parity", "--secretstore-nodes", "abc@127.0.0.1:3333,cde@10.10.10.10:4444"]).unwrap(); assert_eq!(args.arg_secretstore_nodes, "abc@127.0.0.1:3333,cde@10.10.10.10:4444"); - let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123", "ui"]).unwrap(); + let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123"]).unwrap(); assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]); assert_eq!(args.arg_ui_port, 8123); - assert_eq!(args.cmd_ui, true); - let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123", "ui"]).unwrap(); + let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123"]).unwrap(); assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]); assert_eq!(args.arg_ui_port, 8123); - assert_eq!(args.cmd_ui, true); } #[test] @@ -1476,7 +1475,6 @@ mod tests { // then assert_eq!(args, Args { // Commands - cmd_ui: false, cmd_dapp: false, cmd_daemon: false, cmd_account: false, @@ -1566,7 +1564,7 @@ mod tests { flag_force_ui: false, flag_no_ui: false, arg_ui_port: 8180u16, - arg_ui_interface: "127.0.0.1".into(), + arg_ui_interface: "local".into(), arg_ui_hosts: "none".into(), arg_ui_path: "$HOME/.parity/signer".into(), flag_ui_no_validation: false, @@ -1820,12 +1818,12 @@ mod tests { fast_unlock: None, }), ui: Some(Ui { - force: None, - disable: Some(true), - port: None, - interface: None, - hosts: None, path: None, + _legacy_force: None, + _legacy_disable: Some(true), + _legacy_port: None, + _legacy_interface: None, + _legacy_hosts: None, }), network: Some(Network { warp: Some(false), diff --git a/parity/configuration.rs b/parity/configuration.rs index 6f475aa83c..ec73046a49 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -20,7 +20,6 @@ use std::net::SocketAddr; use std::path::{Path, PathBuf}; use std::collections::BTreeMap; use std::cmp; -use std::str::FromStr; use cli::{Args, ArgsError}; use hash::keccak; use ethereum_types::{U256, H256, Address}; @@ -34,7 +33,7 @@ use ethcore::miner::{stratum, MinerOptions}; use ethcore::verification::queue::VerifierSettings; use miner::pool; -use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}; +use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration}; use parity_rpc::NetworkSettings; use cache::CacheConfig; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files}; @@ -65,7 +64,7 @@ pub enum Cmd { Account(AccountCmd), ImportPresaleWallet(ImportWallet), Blockchain(BlockchainCmd), - SignerToken(WsConfiguration, UiConfiguration, LogConfig), + SignerToken(WsConfiguration, LogConfig), SignerSign { id: Option, pwfile: Option, @@ -130,7 +129,6 @@ impl Configuration { let http_conf = self.http_config()?; let ipc_conf = self.ipc_config()?; let net_conf = self.net_config()?; - let ui_conf = self.ui_config(); let network_id = self.network_id(); let cache_config = self.cache_config(); let tracing = self.args.arg_tracing.parse()?; @@ -150,7 +148,7 @@ impl Configuration { let authfile = ::signer::codes_path(&ws_conf.signer_path); if self.args.cmd_signer_new_token { - Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone()) + Cmd::SignerToken(ws_conf, logger_config.clone()) } else if self.args.cmd_signer_sign { let pwfile = self.accounts_config()?.password_files.first().map(|pwfile| { PathBuf::from(pwfile) @@ -381,13 +379,11 @@ impl Configuration { net_settings: self.network_settings()?, dapps_conf: dapps_conf, ipfs_conf: ipfs_conf, - ui_conf: ui_conf, secretstore_conf: secretstore_conf, private_provider_conf: private_provider_conf, private_encryptor_conf: private_enc_conf, private_tx_enabled, dapp: self.dapp_to_open()?, - ui: self.args.cmd_ui, name: self.args.arg_identity, custom_bootnodes: self.args.arg_bootnodes.is_some(), no_periodic_snapshot: self.args.flag_no_periodic_snapshot, @@ -588,29 +584,11 @@ impl Configuration { }) } - fn ui_port(&self) -> u16 { - self.args.arg_ports_shift + self.args.arg_ui_port - } - fn ntp_servers(&self) -> Vec { self.args.arg_ntp_servers.split(",").map(str::to_owned).collect() } - fn ui_config(&self) -> UiConfiguration { - let ui = self.ui_enabled(); - UiConfiguration { - enabled: ui.enabled, - interface: self.ui_interface(), - port: self.ui_port(), - hosts: self.ui_hosts(), - info_page_only: ui.info_page_only, - } - } - fn dapps_config(&self) -> DappsConfiguration { - let dev_ui = if self.args.flag_ui_no_validation { vec![("127.0.0.1".to_owned(), 3000)] } else { vec![] }; - let ui_port = self.ui_port(); - DappsConfiguration { enabled: self.dapps_enabled(), dapps_path: PathBuf::from(self.directories().dapps), @@ -619,31 +597,6 @@ impl Configuration { } else { vec![] }, - extra_embed_on: { - let mut extra_embed = dev_ui.clone(); - match self.ui_hosts() { - // In case host validation is disabled allow all frame ancestors - None => { - // NOTE Chrome does not seem to support "*:" - // we use `http(s)://*:` instead. - extra_embed.push(("http://*".to_owned(), ui_port)); - extra_embed.push(("https://*".to_owned(), ui_port)); - }, - Some(hosts) => extra_embed.extend(hosts.into_iter().filter_map(|host| { - let mut it = host.split(":"); - let host = it.next(); - let port = it.next().and_then(|v| u16::from_str(v).ok()); - - match (host, port) { - (Some(host), Some(port)) => Some((host.into(), port)), - (Some(host), None) => Some((host.into(), ui_port)), - _ => None, - } - })), - } - extra_embed - }, - extra_script_src: dev_ui, } } @@ -863,10 +816,6 @@ impl Configuration { Some(hosts) } - fn ui_hosts(&self) -> Option> { - self.hosts(&self.args.arg_ui_hosts, &self.ui_interface()) - } - fn rpc_hosts(&self) -> Option> { self.hosts(&self.args.arg_jsonrpc_hosts, &self.rpc_interface()) } @@ -876,7 +825,7 @@ impl Configuration { } fn ws_origins(&self) -> Option> { - if self.args.flag_unsafe_expose || self.args.flag_ui_no_validation { + if self.args.flag_unsafe_expose { return None; } @@ -925,7 +874,6 @@ impl Configuration { } fn ws_config(&self) -> Result { - let ui = self.ui_config(); let http = self.http_config()?; let support_token_api = @@ -941,7 +889,6 @@ impl Configuration { origins: self.ws_origins(), signer_path: self.directories().signer.into(), support_token_api, - ui_address: ui.address(), dapps_address: http.address(), max_connections: self.args.arg_ws_max_connections, }; @@ -1065,10 +1012,6 @@ impl Configuration { }.into() } - fn ui_interface(&self) -> String { - self.interface(&self.args.arg_ui_interface) - } - fn rpc_interface(&self) -> String { let rpc_interface = self.args.arg_rpcaddr.clone().unwrap_or(self.args.arg_jsonrpc_interface.clone()); self.interface(&rpc_interface) @@ -1184,24 +1127,6 @@ impl Configuration { into_secretstore_service_contract_address(self.args.arg_secretstore_doc_sretr_contract.as_ref()) } - fn ui_enabled(&self) -> UiEnabled { - if self.args.flag_force_ui { - return UiEnabled { - enabled: true, - info_page_only: false, - }; - } - - let ui_disabled = self.args.arg_unlock.is_some() || - self.args.flag_geth || - self.args.flag_no_ui; - - return UiEnabled { - enabled: (self.args.cmd_ui || !ui_disabled) && cfg!(feature = "ui-enabled"), - info_page_only: !self.args.cmd_ui, - } - } - fn verifier_settings(&self) -> VerifierSettings { let mut settings = VerifierSettings::default(); settings.scale_verifiers = self.args.flag_scale_verifiers; @@ -1220,12 +1145,6 @@ impl Configuration { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -struct UiEnabled { - pub enabled: bool, - pub info_page_only: bool, -} - fn into_secretstore_service_contract_address(s: &str) -> Result, String> { match s { "none" => Ok(None), @@ -1254,7 +1173,7 @@ mod tests { use helpers::{default_network_config}; use params::SpecType; use presale::ImportWallet; - use rpc::{WsConfiguration, UiConfiguration}; + use rpc::WsConfiguration; use rpc_apis::ApiSet; use run::RunCmd; @@ -1438,16 +1357,9 @@ mod tests { origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]), hosts: Some(vec![]), signer_path: expected.into(), - ui_address: Some("127.0.0.1:8180".into()), dapps_address: Some("127.0.0.1:8545".into()), support_token_api: true, max_connections: 100, - }, UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, }, LogConfig { color: true, mode: None, @@ -1516,12 +1428,10 @@ mod tests { net_settings: Default::default(), dapps_conf: Default::default(), ipfs_conf: Default::default(), - ui_conf: Default::default(), secretstore_conf: Default::default(), private_provider_conf: Default::default(), private_encryptor_conf: Default::default(), private_tx_enabled: false, - ui: false, dapp: None, name: "".into(), custom_bootnodes: false, @@ -1704,49 +1614,6 @@ mod tests { assert_eq!(conf2.ipfs_cors(), Some(vec!["http://parity.io".into(),"http://something.io".into()])); } - #[test] - fn should_disable_signer_in_geth_compat() { - // given - - // when - let conf0 = parse(&["parity", "--geth"]); - let conf1 = parse(&["parity", "--geth", "--force-ui"]); - let conf2 = parse(&["parity", "--geth", "ui"]); - let conf3 = parse(&["parity"]); - - // then - assert_eq!(conf0.ui_enabled(), UiEnabled { - enabled: false, - info_page_only: true, - }); - assert_eq!(conf1.ui_enabled(), UiEnabled { - enabled: true, - info_page_only: false, - }); - assert_eq!(conf2.ui_enabled(), UiEnabled { - enabled: true, - info_page_only: false, - }); - assert_eq!(conf3.ui_enabled(), UiEnabled { - enabled: true, - info_page_only: true, - }); - } - - #[test] - fn should_disable_signer_when_account_is_unlocked() { - // given - - // when - let conf0 = parse(&["parity", "--unlock", "0x0"]); - - // then - assert_eq!(conf0.ui_enabled(), UiEnabled { - enabled: false, - info_page_only: true, - }); - } - #[test] fn should_parse_ui_configuration() { // given @@ -1757,69 +1624,22 @@ mod tests { let conf2 = parse(&["parity", "--ui-path=signer", "--ui-port", "3123"]); let conf3 = parse(&["parity", "--ui-path=signer", "--ui-interface", "test"]); let conf4 = parse(&["parity", "--ui-path=signer", "--force-ui"]); - let conf5 = parse(&["parity", "--ui-path=signer", "ui"]); // then assert_eq!(conf0.directories().signer, "signer".to_owned()); - assert_eq!(conf0.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, - }); assert!(conf1.ws_config().unwrap().hosts.is_some()); - assert_eq!(conf1.ws_config().unwrap().origins, None); + assert_eq!(conf1.ws_config().unwrap().origins, Some(vec!["parity://*".into(), "chrome-extension://*".into(), "moz-extension://*".into()])); assert_eq!(conf1.directories().signer, "signer".to_owned()); - assert_eq!(conf1.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, - }); - assert_eq!(conf1.dapps_config().extra_embed_on, vec![("127.0.0.1".to_owned(), 3000)]); assert!(conf2.ws_config().unwrap().hosts.is_some()); assert_eq!(conf2.directories().signer, "signer".to_owned()); - assert_eq!(conf2.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 3123, - hosts: Some(vec![]), - info_page_only: true, - }); assert!(conf3.ws_config().unwrap().hosts.is_some()); assert_eq!(conf3.directories().signer, "signer".to_owned()); - assert_eq!(conf3.ui_config(), UiConfiguration { - enabled: true, - interface: "test".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: true, - }); assert!(conf4.ws_config().unwrap().hosts.is_some()); assert_eq!(conf4.directories().signer, "signer".to_owned()); - assert_eq!(conf4.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: false, - }); - - assert!(conf5.ws_config().unwrap().hosts.is_some()); - assert_eq!(conf5.directories().signer, "signer".to_owned()); - assert_eq!(conf5.ui_config(), UiConfiguration { - enabled: true, - interface: "127.0.0.1".into(), - port: 8180, - hosts: Some(vec![]), - info_page_only: false, - }); } #[test] @@ -1976,7 +1796,6 @@ mod tests { assert_eq!(conf0.network_settings().unwrap().rpc_port, 8546); assert_eq!(conf0.http_config().unwrap().port, 8546); assert_eq!(conf0.ws_config().unwrap().port, 8547); - assert_eq!(conf0.ui_config().port, 8181); assert_eq!(conf0.secretstore_config().unwrap().port, 8084); assert_eq!(conf0.secretstore_config().unwrap().http_port, 8083); assert_eq!(conf0.ipfs_config().port, 5002); @@ -1987,7 +1806,6 @@ mod tests { assert_eq!(conf1.network_settings().unwrap().rpc_port, 8545); assert_eq!(conf1.http_config().unwrap().port, 8545); assert_eq!(conf1.ws_config().unwrap().port, 8547); - assert_eq!(conf1.ui_config().port, 8181); assert_eq!(conf1.secretstore_config().unwrap().port, 8084); assert_eq!(conf1.secretstore_config().unwrap().http_port, 8083); assert_eq!(conf1.ipfs_config().port, 5002); @@ -2007,8 +1825,6 @@ mod tests { assert_eq!(&conf0.ws_config().unwrap().interface, "0.0.0.0"); assert_eq!(conf0.ws_config().unwrap().hosts, None); assert_eq!(conf0.ws_config().unwrap().origins, None); - assert_eq!(&conf0.ui_config().interface, "0.0.0.0"); - assert_eq!(conf0.ui_config().hosts, None); assert_eq!(&conf0.secretstore_config().unwrap().interface, "0.0.0.0"); assert_eq!(&conf0.secretstore_config().unwrap().http_interface, "0.0.0.0"); assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0"); diff --git a/parity/dapps.rs b/parity/dapps.rs index 427bfa53b3..ce5b3a8daa 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -39,8 +39,6 @@ pub struct Configuration { pub enabled: bool, pub dapps_path: PathBuf, pub extra_dapps: Vec, - pub extra_embed_on: Vec<(String, u16)>, - pub extra_script_src: Vec<(String, u16)>, } impl Default for Configuration { @@ -50,8 +48,6 @@ impl Default for Configuration { enabled: true, dapps_path: replace_home(&data_dir, "$BASE/dapps").into(), extra_dapps: vec![], - extra_embed_on: vec![], - extra_script_src: vec![], } } } @@ -163,8 +159,6 @@ pub struct Dependencies { pub fetch: FetchClient, pub pool: CpuPool, pub signer: Arc, - pub ui_address: Option<(String, u16)>, - pub info_page_only: bool, } pub fn new(configuration: Configuration, deps: Dependencies) -> Result, String> { @@ -177,19 +171,6 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result Result, String> { - if !enabled { - return Ok(None); - } - - server::ui_middleware( - deps, - rpc::DAPPS_DOMAIN, ).map(Some) } @@ -215,19 +196,10 @@ mod server { _dapps_path: PathBuf, _extra_dapps: Vec, _dapps_domain: &str, - _extra_embed_on: Vec<(String, u16)>, - _extra_script_src: Vec<(String, u16)>, ) -> Result { Err("Your Parity version has been compiled without WebApps support.".into()) } - pub fn ui_middleware( - _deps: Dependencies, - _dapps_domain: &str, - ) -> Result { - Err("Your Parity version has been compiled without UI support.".into()) - } - pub fn service(_: &Option) -> Option> { None } @@ -249,8 +221,6 @@ mod server { dapps_path: PathBuf, extra_dapps: Vec, dapps_domain: &str, - extra_embed_on: Vec<(String, u16)>, - extra_script_src: Vec<(String, u16)>, ) -> Result { let signer = deps.signer; let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token)); @@ -258,9 +228,6 @@ mod server { Ok(parity_dapps::Middleware::dapps( deps.pool, deps.node_health, - deps.ui_address, - extra_embed_on, - extra_script_src, dapps_path, extra_dapps, dapps_domain, @@ -271,21 +238,6 @@ mod server { )) } - pub fn ui_middleware( - deps: Dependencies, - dapps_domain: &str, - ) -> Result { - Ok(parity_dapps::Middleware::ui( - deps.pool, - deps.node_health, - dapps_domain, - deps.contract_client, - deps.sync_status, - deps.fetch, - deps.info_page_only, - )) - } - pub fn service(middleware: &Option) -> Option> { middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper { endpoints: m.endpoints().clone(), diff --git a/parity/lib.rs b/parity/lib.rs index c768722552..8c3242afb4 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -118,15 +118,13 @@ mod user_defaults; mod whisper; mod db; -use std::net::{TcpListener}; use std::io::BufReader; use std::fs::File; -use ansi_term::Style; use hash::keccak_buffer; use cli::Args; use configuration::{Cmd, Execute}; use deprecated::find_deprecated; -use ethcore_logger::{Config as LogConfig, setup_log}; +use ethcore_logger::setup_log; pub use self::configuration::Configuration; pub use self::run::RunningClient; @@ -195,24 +193,6 @@ fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res match command.cmd { Cmd::Run(run_cmd) => { - if run_cmd.ui_conf.enabled && !run_cmd.ui_conf.info_page_only { - warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead.")); - warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases")); - } - - if run_cmd.ui && run_cmd.dapps_conf.enabled { - // Check if Parity is already running - let addr = format!("{}:{}", run_cmd.ui_conf.interface, run_cmd.ui_conf.port); - if !TcpListener::bind(&addr as &str).is_ok() { - return open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config).map(|_| ExecutionAction::Instant(None)); - } - } - - // start ui - if run_cmd.ui { - open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config)?; - } - if let Some(ref dapp) = run_cmd.dapp { open_dapp(&run_cmd.dapps_conf, &run_cmd.http_conf, dapp)?; } @@ -225,7 +205,7 @@ fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| ExecutionAction::Instant(Some(s))), Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| ExecutionAction::Instant(Some(s))), Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| ExecutionAction::Instant(None)), - Cmd::SignerToken(ws_conf, ui_conf, logger_config) => signer::execute(ws_conf, ui_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))), + Cmd::SignerToken(ws_conf, logger_config) => signer::execute(ws_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), @@ -257,19 +237,6 @@ pub fn start(conf: Configuration, on_client_rq: Cr, on_updater_rq: Rr) - execute(conf.into_command()?, on_client_rq, on_updater_rq) } -fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> { - if !ui_conf.enabled { - return Err("Cannot use UI command with UI turned off.".into()) - } - - let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?; - // Open a browser - url::open(&token.url).map_err(|e| format!("{}", e))?; - // Print a message - println!("{}", token.message); - Ok(()) -} - fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { if !dapps_conf.enabled { return Err("Cannot use DAPP command with Dapps turned off.".into()) diff --git a/parity/rpc.rs b/parity/rpc.rs index cdc8e7ca5b..3e71cc6295 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -68,58 +68,6 @@ impl Default for HttpConfiguration { } } -#[derive(Debug, PartialEq, Clone)] -pub struct UiConfiguration { - pub enabled: bool, - pub interface: String, - pub port: u16, - pub hosts: Option>, - pub info_page_only: bool, -} - -impl UiConfiguration { - pub fn address(&self) -> Option { - address(self.enabled, &self.interface, self.port, &self.hosts) - } - - pub fn redirection_address(&self) -> Option<(String, u16)> { - self.address().map(|host| { - let mut it = host.split(':'); - let hostname: Option = it.next().map(|s| s.to_owned()); - let port: Option = it.next().and_then(|s| s.parse().ok()); - - (hostname.unwrap_or_else(|| "localhost".into()), port.unwrap_or(8180)) - }) - } -} - -impl From for HttpConfiguration { - fn from(conf: UiConfiguration) -> Self { - HttpConfiguration { - enabled: conf.enabled, - interface: conf.interface, - port: conf.port, - apis: rpc_apis::ApiSet::UnsafeContext, - cors: Some(vec![]), - hosts: conf.hosts, - server_threads: 1, - processing_threads: 0, - } - } -} - -impl Default for UiConfiguration { - fn default() -> Self { - UiConfiguration { - enabled: cfg!(feature = "ui-enabled"), - port: 8180, - interface: "127.0.0.1".into(), - hosts: Some(vec![]), - info_page_only: true, - } - } -} - #[derive(Debug, PartialEq)] pub struct IpcConfiguration { pub enabled: bool, @@ -153,7 +101,6 @@ pub struct WsConfiguration { pub hosts: Option>, pub signer_path: PathBuf, pub support_token_api: bool, - pub ui_address: Option, pub dapps_address: Option, } @@ -170,7 +117,6 @@ impl Default for WsConfiguration { hosts: Some(Vec::new()), signer_path: replace_home(&data_dir, "$BASE/signer").into(), support_token_api: true, - ui_address: Some("127.0.0.1:8180".into()), dapps_address: Some("127.0.0.1:8545".into()), } } @@ -225,9 +171,8 @@ pub fn new_ws( }; let remote = deps.remote.clone(); - let ui_address = conf.ui_address.clone(); - let allowed_origins = into_domains(with_domain(conf.origins, domain, &ui_address, &conf.dapps_address)); - let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()), &None)); + let allowed_origins = into_domains(with_domain(conf.origins, domain, &conf.dapps_address)); + let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()))); let signer_path; let path = match conf.support_token_api { @@ -276,7 +221,7 @@ pub fn new_http( let remote = deps.remote.clone(); let cors_domains = into_domains(conf.cors); - let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()), &None)); + let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()))); let start_result = rpc::start_http( &addr, @@ -328,7 +273,7 @@ fn into_domains>(items: Option>) -> DomainsValidatio items.map(|vals| vals.into_iter().map(T::from).collect()).into() } -fn with_domain(items: Option>, domain: &str, ui_address: &Option, dapps_address: &Option) -> Option> { +fn with_domain(items: Option>, domain: &str, dapps_address: &Option) -> Option> { fn extract_port(s: &str) -> Option { s.split(':').nth(1).and_then(|s| s.parse().ok()) } @@ -347,7 +292,6 @@ fn with_domain(items: Option>, domain: &str, ui_address: &Option, - pub ui: bool, pub name: String, pub custom_bootnodes: bool, pub stratum: Option, @@ -185,7 +183,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result) -> Result) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?; + cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.acc_conf.unlocked_accounts.len() == 0, cmd.secretstore_conf.enabled)?; // run in daemon mode if let Some(pid_file) = cmd.daemon { @@ -756,12 +750,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: fetch: fetch.clone(), pool: cpu_pool.clone(), signer: signer_service.clone(), - ui_address: cmd.ui_conf.redirection_address(), - info_page_only: cmd.ui_conf.info_page_only, }) }; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; - let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?; let dapps_service = dapps::service(&dapps_middleware); let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies { @@ -807,8 +798,6 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies, dapps_middleware)?; - // the ui server - let ui_server = rpc::new_http("UI WALLET", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?; // secret store key server let secretstore_deps = secretstore::Dependencies { @@ -881,7 +870,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: informant, client, client_service: Arc::new(service), - keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), + keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, secretstore_key_server, ipfs_server, event_loop)), } }) } diff --git a/parity/signer.rs b/parity/signer.rs index 4388e11aa8..e9a636bf8b 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -28,7 +28,6 @@ pub const CODES_FILENAME: &'static str = "authcodes"; pub struct NewToken { pub token: String, - pub url: String, pub message: String, } @@ -49,45 +48,26 @@ pub fn codes_path(path: &Path) -> PathBuf { p } -pub fn execute(ws_conf: rpc::WsConfiguration, ui_conf: rpc::UiConfiguration, logger_config: LogConfig) -> Result { - Ok(generate_token_and_url(&ws_conf, &ui_conf, &logger_config)?.message) +pub fn execute(ws_conf: rpc::WsConfiguration, logger_config: LogConfig) -> Result { + Ok(generate_token_and_url(&ws_conf, &logger_config)?.message) } -pub fn generate_token_and_url(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result { +pub fn generate_token_and_url(ws_conf: &rpc::WsConfiguration, logger_config: &LogConfig) -> Result { let code = generate_new_token(&ws_conf.signer_path, logger_config.color).map_err(|err| format!("Error generating token: {:?}", err))?; - let auth_url = format!("http://{}:{}/#/auth?token={}", ui_conf.interface, ui_conf.port, code); let colored = |s: String| match logger_config.color { true => format!("{}", White.bold().paint(s)), false => s, }; - if !ui_conf.enabled { - return Ok(NewToken { - token: code.clone(), - url: auth_url.clone(), - message: format!( - r#" -Generated token: -{} -"#, - colored(code) - ), - }) - } - - // And print in to the console Ok(NewToken { token: code.clone(), - url: auth_url.clone(), message: format!( r#" -Open: {} -to authorize your browser. -Or use the generated token: -{}"#, - colored(auth_url), - code - ) +Generated token: +{} +"#, + colored(code) + ), }) } -- GitLab From 107f0fa4c6738e857e0d14fbe26648bb44d82555 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 6 Jun 2018 14:14:45 +0200 Subject: [PATCH 220/263] Removed obsolete IpcMode enum (#8819) --- ethcore/src/client/client.rs | 11 +++++------ ethcore/src/client/config.rs | 23 ---------------------- ethcore/src/client/test_client.rs | 3 +-- ethcore/src/client/traits.rs | 2 +- ethcore/types/src/lib.rs | 1 - ethcore/types/src/mode.rs | 32 ------------------------------- rpc/src/v1/impls/parity.rs | 8 +------- rpc/src/v1/impls/parity_set.rs | 8 ++++---- 8 files changed, 12 insertions(+), 76 deletions(-) delete mode 100644 ethcore/types/src/mode.rs diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index f3a3dda103..3f19f491ba 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -72,7 +72,6 @@ use trace; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, Action}; use types::filter::Filter; -use types::mode::Mode as IpcMode; use types::ancestry_action::AncestryAction; use verification; use verification::{PreverifiedBlock, Verifier}; @@ -1570,19 +1569,19 @@ impl BlockChainClient for Client { }))) } - fn mode(&self) -> IpcMode { + fn mode(&self) -> Mode { let r = self.mode.lock().clone().into(); trace!(target: "mode", "Asked for mode = {:?}. returning {:?}", &*self.mode.lock(), r); r } fn disable(&self) { - self.set_mode(IpcMode::Off); + self.set_mode(Mode::Off); self.enabled.store(false, AtomicOrdering::Relaxed); self.clear_queue(); } - fn set_mode(&self, new_mode: IpcMode) { + fn set_mode(&self, new_mode: Mode) { trace!(target: "mode", "Client::set_mode({:?})", new_mode); if !self.enabled.load(AtomicOrdering::Relaxed) { return; @@ -1597,8 +1596,8 @@ impl BlockChainClient for Client { } } match new_mode { - IpcMode::Active => self.wake_up(), - IpcMode::Off => self.sleep(), + Mode::Active => self.wake_up(), + Mode::Off => self.sleep(), _ => {(*self.sleep_state.lock()).last_activity = Some(Instant::now()); } } } diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 288de25e4b..dbba4f4a96 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -17,7 +17,6 @@ use std::str::FromStr; use std::fmt::{Display, Formatter, Error as FmtError}; -use mode::Mode as IpcMode; use verification::{VerifierType, QueueConfig}; use journaldb; @@ -88,28 +87,6 @@ impl Display for Mode { } } -impl Into for Mode { - fn into(self) -> IpcMode { - match self { - Mode::Off => IpcMode::Off, - Mode::Dark(timeout) => IpcMode::Dark(timeout.as_secs()), - Mode::Passive(timeout, alarm) => IpcMode::Passive(timeout.as_secs(), alarm.as_secs()), - Mode::Active => IpcMode::Active, - } - } -} - -impl From for Mode { - fn from(mode: IpcMode) -> Self { - match mode { - IpcMode::Off => Mode::Off, - IpcMode::Dark(timeout) => Mode::Dark(Duration::from_secs(timeout)), - IpcMode::Passive(timeout, alarm) => Mode::Passive(Duration::from_secs(timeout), Duration::from_secs(alarm)), - IpcMode::Active => Mode::Active, - } - } -} - /// Client configuration. Includes configs for all sub-systems. #[derive(Debug, PartialEq, Default)] pub struct ClientConfig { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 8acbde4f97..4bd76b4495 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -36,7 +36,7 @@ use transaction::{self, Transaction, LocalizedTransaction, SignedTransaction, Ac use blockchain::{TreeRoute, BlockReceipts}; use client::{ Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, CallContract, TransactionInfo, RegistryInfo, - PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, + PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, Mode, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock, Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, IoClient @@ -51,7 +51,6 @@ use vm::Schedule; use miner::{Miner, MinerService}; use spec::Spec; use types::basic_account::BasicAccount; -use types::mode::Mode; use types::pruning_info::PruningInfo; use verification::queue::QueueInfo; diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index f0fae4b498..d3a20dcff8 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -21,6 +21,7 @@ use itertools::Itertools; use block::{OpenBlock, SealedBlock, ClosedBlock}; use blockchain::TreeRoute; +use client::Mode; use encoded; use vm::LastHashes; use error::{ImportResult, CallError, BlockImportError}; @@ -48,7 +49,6 @@ use types::trace_filter::Filter as TraceFilter; use types::call_analytics::CallAnalytics; use types::blockchain_info::BlockChainInfo; use types::block_status::BlockStatus; -use types::mode::Mode; use types::pruning_info::PruningInfo; /// State information to be used during client query diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 8db6163bbf..5ac8ff12ad 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -36,7 +36,6 @@ pub mod call_analytics; pub mod filter; pub mod ids; pub mod log_entry; -pub mod mode; pub mod pruning_info; pub mod receipt; pub mod restoration_status; diff --git a/ethcore/types/src/mode.rs b/ethcore/types/src/mode.rs deleted file mode 100644 index ee4f9fbf2c..0000000000 --- a/ethcore/types/src/mode.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2018 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 . - -//! Mode type - -pub use std::time::Duration; - -/// IPC-capable shadow-type for `client::config::Mode` -#[derive(Clone, Debug)] -pub enum Mode { - /// Same as `ClientMode::Off`. - Off, - /// Same as `ClientMode::Dark`; values in seconds. - Dark(u64), - /// Same as `ClientMode::Passive`; values in seconds. - Passive(u64, u64), - /// Same as `ClientMode::Active`. - Active, -} diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 5707104212..f18723eafe 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -30,7 +30,6 @@ use ethcore::account_provider::AccountProvider; use ethcore::client::{BlockChainClient, StateClient, Call}; use ethcore::ids::BlockId; use ethcore::miner::{self, MinerService}; -use ethcore::mode::Mode; use ethcore::state::StateInfo; use ethcore_logger::RotatingLogger; use node_health::{NodeHealth, Health}; @@ -365,12 +364,7 @@ impl Parity for ParityClient where } fn mode(&self) -> Result { - Ok(match self.client.mode() { - Mode::Off => "offline", - Mode::Dark(..) => "dark", - Mode::Passive(..) => "passive", - Mode::Active => "active", - }.into()) + Ok(self.client.mode().to_string()) } fn enode(&self) -> Result { diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 4ba9ab658e..18f5776c69 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -17,10 +17,10 @@ /// Parity-specific rpc interface for operations altering the settings. use std::io; use std::sync::Arc; +use std::time::Duration; -use ethcore::client::BlockChainClient; +use ethcore::client::{BlockChainClient, Mode}; use ethcore::miner::MinerService; -use ethcore::mode::Mode; use sync::ManageNetwork; use fetch::{self, Fetch}; use futures_cpupool::CpuPool; @@ -160,8 +160,8 @@ impl ParitySet for ParitySetClient where fn set_mode(&self, mode: String) -> Result { self.client.set_mode(match mode.as_str() { "offline" => Mode::Off, - "dark" => Mode::Dark(300), - "passive" => Mode::Passive(300, 3600), + "dark" => Mode::Dark(Duration::from_secs(300)), + "passive" => Mode::Passive(Duration::from_secs(300), Duration::from_secs(3600)), "active" => Mode::Active, e => { return Err(errors::invalid_params("mode", e.to_owned())); }, }); -- GitLab From bc2f86e806f70d23c1b5123c43be0d4cc73819bc Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 6 Jun 2018 14:15:13 +0200 Subject: [PATCH 221/263] parity: fix indentation in sync logging (#8794) --- parity/informant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/informant.rs b/parity/informant.rs index 43788bc9d9..1840be3bad 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -304,7 +304,7 @@ impl Informant { paint(White.bold(), format!("{}", chain_info.best_block_hash)), if self.target.executes_transactions() { format!("{} blk/s {} tx/s {} Mgas/s", - paint(Yellow.bold(), format!("{:5.2}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)), + paint(Yellow.bold(), format!("{:7.2}", (client_report.blocks_imported * 1000) as f64 / elapsed.as_milliseconds() as f64)), paint(Yellow.bold(), format!("{:6.1}", (client_report.transactions_applied * 1000) as f64 / elapsed.as_milliseconds() as f64)), paint(Yellow.bold(), format!("{:4}", (client_report.gas_processed / From::from(elapsed.as_milliseconds() * 1000)).low_u64())) ) -- GitLab From 1318f536c9d13acc1740b401e304e9b88a540d87 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Wed, 6 Jun 2018 15:45:55 +0200 Subject: [PATCH 222/263] CI: Fix docker tags (#8822) * scripts: enable docker builds for beta and stable * scripts: docker latest should be beta not master * scripts: docker latest is master --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6be6b45838..d4add41721 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -201,6 +201,8 @@ docker-build: stage: build only: - tags + - beta + - stable - triggers before_script: - docker info -- GitLab From c8877d40989fa69822b7c4764af7e67ddb4cfb52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 7 Jun 2018 10:15:21 +0100 Subject: [PATCH 223/263] ethcore: fix ancient block error msg handling (#8832) --- ethcore/src/client/client.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 3f19f491ba..ea8fa88630 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2073,15 +2073,16 @@ impl IoClient for Client { let first = queued.write().1.pop_front(); if let Some((header, block_bytes, receipts_bytes)) = first { let hash = header.hash(); - client.importer.import_old_block( + let result = client.importer.import_old_block( &header, &block_bytes, &receipts_bytes, &**client.db.read(), - &*client.chain.read() - ).ok().map_or((), |e| { + &*client.chain.read(), + ); + if let Err(e) = result { error!(target: "client", "Error importing ancient block: {}", e); - }); + } // remove from pending queued.write().0.remove(&hash); } else { -- GitLab From a6d267abc04bd268a7c9330a9b225244b36f5e5c Mon Sep 17 00:00:00 2001 From: Alex Baranov Date: Thu, 7 Jun 2018 10:47:41 -0400 Subject: [PATCH 224/263] added from and to to Receipt (#8756) --- ethcore/src/client/client.rs | 10 ++++++++++ ethcore/types/src/receipt.rs | 6 +++++- rpc/src/v1/tests/mocked/eth.rs | 6 ++++-- rpc/src/v1/types/receipt.rs | 14 +++++++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ea8fa88630..2d0201067f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2336,6 +2336,11 @@ fn transaction_receipt(machine: &::machine::EthereumMachine, mut tx: LocalizedTr let transaction_index = tx.transaction_index; LocalizedReceipt { + from: sender, + to: match tx.action { + Action::Create => None, + Action::Call(ref address) => Some(address.clone().into()) + }, transaction_hash: transaction_hash, transaction_index: transaction_index, block_hash: block_hash, @@ -2461,6 +2466,11 @@ mod tests { // then assert_eq!(receipt, LocalizedReceipt { + from: tx1.sender().into(), + to: match tx1.action { + Action::Create => None, + Action::Call(ref address) => Some(address.clone().into()) + }, transaction_hash: tx1.hash(), transaction_index: 1, block_hash: block_hash, diff --git a/ethcore/types/src/receipt.rs b/ethcore/types/src/receipt.rs index b4f105afab..81233d212a 100644 --- a/ethcore/types/src/receipt.rs +++ b/ethcore/types/src/receipt.rs @@ -16,7 +16,7 @@ //! Receipt -use ethereum_types::{H256, U256, Address, Bloom}; +use ethereum_types::{H160, H256, U256, Address, Bloom}; use heapsize::HeapSizeOf; use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError}; @@ -157,6 +157,10 @@ pub struct LocalizedReceipt { pub log_bloom: Bloom, /// Transaction outcome. pub outcome: TransactionOutcome, + /// Receiver address + pub to: Option, + /// Sender + pub from: H160 } #[cfg(test)] diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index a8875a3354..c0ed3306fe 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH}; -use ethereum_types::{H256, U256, Address}; +use ethereum_types::{H160, H256, U256, Address}; use parking_lot::Mutex; use ethcore::account_provider::AccountProvider; use ethcore::client::{BlockChainClient, BlockId, EachBlockWith, Executed, TestBlockChainClient, TransactionId}; @@ -1004,6 +1004,8 @@ fn rpc_eth_send_raw_transaction() { #[test] fn rpc_eth_transaction_receipt() { let receipt = LocalizedReceipt { + from: H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap(), + to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), transaction_hash: H256::zero(), transaction_index: 0, block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), @@ -1041,7 +1043,7 @@ fn rpc_eth_transaction_receipt() { "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","status":null,"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","from":"0xb60e8dd61c5d32be8058bb8eb970870f07233155","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","status":null,"to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index f8d111887a..e46b640f14 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -29,6 +29,10 @@ pub struct Receipt { /// Block hash #[serde(rename="blockHash")] pub block_hash: Option, + /// Sender + pub from: Option, + /// Recipient + pub to: Option, /// Block number #[serde(rename="blockNumber")] pub block_number: Option, @@ -73,6 +77,8 @@ impl Receipt { impl From for Receipt { fn from(r: LocalizedReceipt) -> Self { Receipt { + to: r.to.map(Into::into), + from: Some(r.from.into()), transaction_hash: Some(r.transaction_hash.into()), transaction_index: Some(r.transaction_index.into()), block_hash: Some(r.block_hash.into()), @@ -91,6 +97,8 @@ impl From for Receipt { impl From for Receipt { fn from(r: RichReceipt) -> Self { Receipt { + from: None, + to: None, transaction_hash: Some(r.transaction_hash.into()), transaction_index: Some(r.transaction_index.into()), block_hash: None, @@ -109,6 +117,8 @@ impl From for Receipt { impl From for Receipt { fn from(r: EthReceipt) -> Self { Receipt { + from: None, + to: None, transaction_hash: None, transaction_index: None, block_hash: None, @@ -131,9 +141,11 @@ mod tests { #[test] fn receipt_serialization() { - let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":null,"type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","status":"0x1"}"#; + let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","from":null,"to":null,"blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":null,"type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","status":"0x1"}"#; let receipt = Receipt { + from: None, + to: None, transaction_hash: Some(0.into()), transaction_index: Some(0.into()), block_hash: Some("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5".parse().unwrap()), -- GitLab From 24c43513a64a9795129c35ee95c6e1db30012f2b Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Thu, 7 Jun 2018 17:48:01 +0300 Subject: [PATCH 225/263] Use system allocator when profiling memory (#8831) --- Cargo.toml | 7 +++++++ parity/lib.rs | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7795fb3b3b..8df37d5942 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,13 @@ slow-blocks = ["ethcore/slow-blocks"] secretstore = ["ethcore-secretstore"] final = ["parity-version/final"] deadlock_detection = ["parking_lot/deadlock_detection"] +# to create a memory profile (requires nightly rust), use e.g. +# `heaptrack /path/to/parity `, +# to visualize a memory profile, use `heaptrack_gui` +# or +# `valgrind --tool=massif /path/to/parity ` +# and `massif-visualizer` for visualization +memory_profiling = [] [lib] path = "parity/lib.rs" diff --git a/parity/lib.rs b/parity/lib.rs index 8c3242afb4..5d0c80289d 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -17,6 +17,7 @@ //! Ethcore client application. #![warn(missing_docs)] +#![cfg_attr(feature = "memory_profiling", feature(alloc_system, global_allocator, allocator_api))] extern crate ansi_term; extern crate docopt; @@ -91,6 +92,9 @@ extern crate pretty_assertions; #[cfg(test)] extern crate tempdir; +#[cfg(feature = "memory_profiling")] +extern crate alloc_system; + mod account; mod blockchain; mod cache; @@ -125,10 +129,16 @@ use cli::Args; use configuration::{Cmd, Execute}; use deprecated::find_deprecated; use ethcore_logger::setup_log; +#[cfg(feature = "memory_profiling")] +use alloc_system::System; pub use self::configuration::Configuration; pub use self::run::RunningClient; +#[cfg(feature = "memory_profiling")] +#[global_allocator] +static A: System = System; + fn print_hash_of(maybe_file: Option) -> Result { if let Some(file) = maybe_file { let mut f = BufReader::new(File::open(&file).map_err(|_| "Unable to open file".to_owned())?); -- GitLab From a48ed024333df586e64c0648e52b297cb1c8583f Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Fri, 8 Jun 2018 11:04:12 +0300 Subject: [PATCH 226/263] Fix `deadlock_detection` feature branch compilation (#8824) --- parity/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/parity/lib.rs b/parity/lib.rs index 5d0c80289d..a4f7d7963f 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -154,6 +154,7 @@ fn run_deadlock_detection_thread() { use std::thread; use std::time::Duration; use parking_lot::deadlock; + use ansi_term::Style; info!("Starting deadlock detection thread."); // Create a background thread which checks for deadlocks every 10s -- GitLab From 13efb6586dde45fba7a28a95d3a15e3f3981e680 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Jun 2018 14:54:23 +0100 Subject: [PATCH 227/263] Specify critical release flag per network (#8821) --- util/version/Cargo.toml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/util/version/Cargo.toml b/util/version/Cargo.toml index 297211b2bd..c7bd4f581e 100644 --- a/util/version/Cargo.toml +++ b/util/version/Cargo.toml @@ -12,14 +12,13 @@ build = "build.rs" # Used by auto-updater and for Parity version string. track = "nightly" -# Indicates a critical release in this track (i.e. consensus issue) -critical = false - -# Latest supported fork blocks for various networks. Used ONLY by auto-updater. -[package.metadata.forks] -foundation = 4370000 -ropsten = 10 -kovan = 6600000 +# Network specific settings, used ONLY by auto-updater. +# Latest supported fork blocks. +# Indicates a critical release in this track (i.e. consensus issue). +[package.metadata.networks] +foundation = { forkBlock = 4370000, critical = false } +ropsten = { forkBlock = 10, critical = false } +kovan = { forkBlock = 6600000, critical = false } [dependencies] ethcore-bytes = { path = "../bytes" } -- GitLab From 1f39a1bd768ae8b490068313bb41ca78bccf964b Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 8 Jun 2018 16:30:44 +0200 Subject: [PATCH 228/263] Fixed AuthorityRound deadlock on shutdown, closes #8088 (#8803) --- ethcore/src/engines/authority_round/mod.rs | 90 ++++++++++++---------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 067c754c7f..e2e88c8178 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -382,12 +382,16 @@ impl Decodable for SealedEmptyStep { } } +struct PermissionedStep { + inner: Step, + can_propose: AtomicBool, +} + /// Engine using `AuthorityRound` proof-of-authority BFT consensus. pub struct AuthorityRound { transition_service: IoService<()>, - step: Arc, - can_propose: AtomicBool, - client: RwLock>>, + step: Arc, + client: Arc>>>, signer: RwLock, validators: Box, validate_score_transition: u64, @@ -407,7 +411,7 @@ pub struct AuthorityRound { // header-chain validator. struct EpochVerifier { - step: Arc, + step: Arc, subchain_validators: SimpleList, empty_steps_transition: u64, } @@ -415,7 +419,7 @@ struct EpochVerifier { impl super::EpochVerifier for EpochVerifier { fn verify_light(&self, header: &Header) -> Result<(), Error> { // Validate the timestamp - verify_timestamp(&*self.step, header_step(header, self.empty_steps_transition)?)?; + verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?)?; // always check the seal since it's fast. // nothing heavier to do. verify_external(header, &self.subchain_validators, self.empty_steps_transition) @@ -615,13 +619,15 @@ impl AuthorityRound { let engine = Arc::new( AuthorityRound { transition_service: IoService::<()>::start()?, - step: Arc::new(Step { - inner: AtomicUsize::new(initial_step), - calibrate: our_params.start_step.is_none(), - duration: our_params.step_duration, + step: Arc::new(PermissionedStep { + inner: Step { + inner: AtomicUsize::new(initial_step), + calibrate: our_params.start_step.is_none(), + duration: our_params.step_duration, + }, + can_propose: AtomicBool::new(true), }), - can_propose: AtomicBool::new(true), - client: RwLock::new(None), + client: Arc::new(RwLock::new(None)), signer: Default::default(), validators: our_params.validators, validate_score_transition: our_params.validate_score_transition, @@ -641,7 +647,10 @@ impl AuthorityRound { // Do not initialize timeouts for tests. if should_timeout { - let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; + let handler = TransitionHandler { + step: engine.step.clone(), + client: engine.client.clone(), + }; engine.transition_service.register_handler(Arc::new(handler))?; } Ok(engine) @@ -666,7 +675,7 @@ impl AuthorityRound { } fn generate_empty_step(&self, parent_hash: &H256) { - let step = self.step.load(); + let step = self.step.inner.load(); let empty_step_rlp = empty_step_rlp(step, parent_hash); if let Ok(signature) = self.sign(keccak(&empty_step_rlp)).map(Into::into) { @@ -698,34 +707,37 @@ fn unix_now() -> Duration { } struct TransitionHandler { - engine: Weak, + step: Arc, + client: Arc>>>, } const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; impl IoHandler<()> for TransitionHandler { fn initialize(&self, io: &IoContext<()>) { - if let Some(engine) = self.engine.upgrade() { - let remaining = engine.step.duration_remaining().as_millis(); - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining)) - .unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e)) - } + let remaining = self.step.inner.duration_remaining().as_millis(); + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining)) + .unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e)) } fn timeout(&self, io: &IoContext<()>, timer: TimerToken) { if timer == ENGINE_TIMEOUT_TOKEN { - if let Some(engine) = self.engine.upgrade() { - // NOTE we might be lagging by couple of steps in case the timeout - // has not been called fast enough. - // Make sure to advance up to the actual step. - while engine.step.duration_remaining().as_millis() == 0 { - engine.step(); + // NOTE we might be lagging by couple of steps in case the timeout + // has not been called fast enough. + // Make sure to advance up to the actual step. + while self.step.inner.duration_remaining().as_millis() == 0 { + self.step.inner.increment(); + self.step.can_propose.store(true, AtomicOrdering::SeqCst); + if let Some(ref weak) = *self.client.read() { + if let Some(c) = weak.upgrade() { + c.update_sealing(); + } } - - let next_run_at = engine.step.duration_remaining().as_millis() >> 2; - io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at)) - .unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e)) } + + let next_run_at = self.step.inner.duration_remaining().as_millis() >> 2; + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at)) + .unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e)) } } } @@ -742,8 +754,8 @@ impl Engine for AuthorityRound { } fn step(&self) { - self.step.increment(); - self.can_propose.store(true, AtomicOrdering::SeqCst); + self.step.inner.increment(); + self.step.can_propose.store(true, AtomicOrdering::SeqCst); if let Some(ref weak) = *self.client.read() { if let Some(c) = weak.upgrade() { c.update_sealing(); @@ -790,7 +802,7 @@ impl Engine for AuthorityRound { fn populate_from_parent(&self, header: &mut Header, parent: &Header) { let parent_step = header_step(parent, self.empty_steps_transition).expect("Header has been verified; qed"); - let current_step = self.step.load(); + let current_step = self.step.inner.load(); let current_empty_steps_len = if header.number() >= self.empty_steps_transition { self.empty_steps(parent_step.into(), current_step.into(), parent.hash()).len() @@ -816,7 +828,7 @@ impl Engine for AuthorityRound { let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;; if empty_step.verify(&*self.validators).unwrap_or(false) { - if self.step.check_future(empty_step.step).is_ok() { + if self.step.inner.check_future(empty_step.step).is_ok() { trace!(target: "engine", "handle_message: received empty step message {:?}", empty_step); self.handle_empty_step_message(empty_step); } else { @@ -836,7 +848,7 @@ impl Engine for AuthorityRound { fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal { // first check to avoid generating signature most of the time // (but there's still a race to the `compare_and_swap`) - if !self.can_propose.load(AtomicOrdering::SeqCst) { + if !self.step.can_propose.load(AtomicOrdering::SeqCst) { trace!(target: "engine", "Aborting seal generation. Can't propose."); return Seal::None; } @@ -845,7 +857,7 @@ impl Engine for AuthorityRound { let parent_step: U256 = header_step(parent, self.empty_steps_transition) .expect("Header has been verified; qed").into(); - let step = self.step.load(); + let step = self.step.inner.load(); // filter messages from old and future steps and different parents let empty_steps = if header.number() >= self.empty_steps_transition { @@ -922,7 +934,7 @@ impl Engine for AuthorityRound { trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step); // only issue the seal if we were the first to reach the compare_and_swap. - if self.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) { + if self.step.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) { self.clear_empty_steps(parent_step); @@ -999,7 +1011,7 @@ impl Engine for AuthorityRound { .decode()?; let parent_step = header_step(&parent, self.empty_steps_transition)?; - let current_step = self.step.load(); + let current_step = self.step.inner.load(); self.empty_steps(parent_step.into(), current_step.into(), parent.hash()) } else { // we're verifying a block, extract empty steps from the seal @@ -1052,7 +1064,7 @@ impl Engine for AuthorityRound { // If yes then probably benign reporting needs to be moved further in the verification. let set_number = header.number(); - match verify_timestamp(&*self.step, header_step(header, self.empty_steps_transition)?) { + match verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?) { Err(BlockError::InvalidSeal) => { self.validators.report_benign(header.author(), set_number, header.number()); Err(BlockError::InvalidSeal.into()) @@ -1294,7 +1306,7 @@ impl Engine for AuthorityRound { // This way, upon encountering an epoch change, the proposer from the // new set will be forced to wait until the next step to avoid sealing a // block that breaks the invariant that the parent's step < the block's step. - self.can_propose.store(false, AtomicOrdering::SeqCst); + self.step.can_propose.store(false, AtomicOrdering::SeqCst); return Some(combine_proofs(signal_number, &pending.proof, &*finality_proof)); } } -- GitLab From 13bc922e546351e962c414b8adcf59eeb1041753 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 8 Jun 2018 07:31:48 -0700 Subject: [PATCH 229/263] devp2p: Move UDP socket handling from Discovery to Host. (#8790) * devp2p: Move UDP socket handling from Discovery to Host. * devp2p: Fix bug with potentially incorrect UDP registration. This works right now because the Host handler happens to be the first one registered on the IoService. * devp2p: Use 0-initialized memory buffer instead of unsafe. * Remove send_queue field from public interface of Discovery. * Rename Datagramm to Datagram. sed -i 's/Datagramm/Datagram/g' util/network-devp2p/src/discovery.rs util/network-devp2p/src/host.rs sed -i 's/datagramm/datagram/g' util/network-devp2p/src/discovery.rs util/network-devp2p/src/host.rs * Include target in log statements. --- util/network-devp2p/src/discovery.rs | 122 ++++++++------------------- util/network-devp2p/src/host.rs | 107 +++++++++++++++++++---- 2 files changed, 125 insertions(+), 104 deletions(-) diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index 8e8a3d6cc6..b7cce2832f 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -17,18 +17,13 @@ use ethcore_bytes::Bytes; use std::net::SocketAddr; use std::collections::{HashSet, HashMap, VecDeque}; -use std::mem; use std::default::Default; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use mio::*; -use mio::deprecated::{Handler, EventLoop}; -use mio::udp::*; use hash::keccak; use ethereum_types::{H256, H520}; use rlp::{Rlp, RlpStream, encode_list}; use node_table::*; use network::{Error, ErrorKind}; -use io::{StreamToken, IoContext}; use ethkey::{Secret, KeyPair, sign, recover}; use network::IpFilter; @@ -39,7 +34,7 @@ const ADDRESS_BITS: usize = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademl const DISCOVERY_MAX_STEPS: u16 = 8; // Max iterations of discovery. (discover) const BUCKET_SIZE: usize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. const ALPHA: usize = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. -const MAX_DATAGRAM_SIZE: usize = 1280; +pub const MAX_DATAGRAM_SIZE: usize = 1280; const PACKET_PING: u8 = 1; const PACKET_PONG: u8 = 2; @@ -79,9 +74,9 @@ impl NodeBucket { } } -struct Datagramm { - payload: Bytes, - address: SocketAddr, +pub struct Datagram { + pub payload: Bytes, + pub address: SocketAddr, } pub struct Discovery { @@ -89,13 +84,11 @@ pub struct Discovery { id_hash: H256, secret: Secret, public_endpoint: NodeEndpoint, - udp_socket: UdpSocket, - token: StreamToken, discovery_round: u16, discovery_id: NodeId, discovery_nodes: HashSet, node_buckets: Vec, - send_queue: VecDeque, + send_queue: VecDeque, check_timestamps: bool, adding_nodes: Vec, ip_filter: IpFilter, @@ -107,19 +100,16 @@ pub struct TableUpdates { } impl Discovery { - pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken, ip_filter: IpFilter) -> Discovery { - let socket = UdpSocket::bind(&listen).expect("Error binding UDP socket"); + pub fn new(key: &KeyPair, public: NodeEndpoint, ip_filter: IpFilter) -> Discovery { Discovery { id: key.public().clone(), id_hash: keccak(key.public()), secret: key.secret().clone(), public_endpoint: public, - token: token, discovery_round: 0, discovery_id: NodeId::new(), discovery_nodes: HashSet::new(), node_buckets: (0..ADDRESS_BITS).map(|_| NodeBucket::new()).collect(), - udp_socket: socket, send_queue: VecDeque::new(), check_timestamps: true, adding_nodes: Vec::new(), @@ -352,53 +342,12 @@ impl Discovery { ret } - pub fn writable(&mut self, io: &IoContext) where Message: Send + Sync + Clone { - while let Some(data) = self.send_queue.pop_front() { - match self.udp_socket.send_to(&data.payload, &data.address) { - Ok(Some(size)) if size == data.payload.len() => { - }, - Ok(Some(_)) => { - warn!("UDP sent incomplete datagramm"); - }, - Ok(None) => { - self.send_queue.push_front(data); - return; - } - Err(e) => { - debug!("UDP send error: {:?}, address: {:?}", e, &data.address); - return; - } - } - } - io.update_registration(self.token).unwrap_or_else(|e| debug!("Error updating discovery registration: {:?}", e)); - } - fn send_to(&mut self, payload: Bytes, address: SocketAddr) { - self.send_queue.push_back(Datagramm { payload: payload, address: address }); - } - - pub fn readable(&mut self, io: &IoContext) -> Option where Message: Send + Sync + Clone { - let mut buf: [u8; MAX_DATAGRAM_SIZE] = unsafe { mem::uninitialized() }; - let writable = !self.send_queue.is_empty(); - let res = match self.udp_socket.recv_from(&mut buf) { - Ok(Some((len, address))) => self.on_packet(&buf[0..len], address).unwrap_or_else(|e| { - debug!("Error processing UDP packet: {:?}", e); - None - }), - Ok(_) => None, - Err(e) => { - debug!("Error reading UPD socket: {:?}", e); - None - } - }; - let new_writable = !self.send_queue.is_empty(); - if writable != new_writable { - io.update_registration(self.token).unwrap_or_else(|e| debug!("Error updating discovery registration: {:?}", e)); - } - res + self.send_queue.push_back(Datagram { payload: payload, address: address }); } - fn on_packet(&mut self, packet: &[u8], from: SocketAddr) -> Result, Error> { + + pub fn on_packet(&mut self, packet: &[u8], from: SocketAddr) -> Result, Error> { // validate packet if packet.len() < 32 + 65 + 4 + 1 { return Err(ErrorKind::BadProtocol.into()); @@ -571,19 +520,16 @@ impl Discovery { self.start(); } - pub fn register_socket(&self, event_loop: &mut EventLoop) -> Result<(), Error> { - event_loop.register(&self.udp_socket, Token(self.token), Ready::all(), PollOpt::edge()).expect("Error registering UDP socket"); - Ok(()) + pub fn any_sends_queued(&self) -> bool { + !self.send_queue.is_empty() } - pub fn update_registration(&self, event_loop: &mut EventLoop) -> Result<(), Error> { - let registration = if !self.send_queue.is_empty() { - Ready::readable() | Ready::writable() - } else { - Ready::readable() - }; - event_loop.reregister(&self.udp_socket, Token(self.token), registration, PollOpt::edge()).expect("Error reregistering UDP socket"); - Ok(()) + pub fn dequeue_send(&mut self) -> Option { + self.send_queue.pop_front() + } + + pub fn requeue_send(&mut self, datagram: Datagram) { + self.send_queue.push_front(datagram) } } @@ -620,8 +566,8 @@ mod tests { let key2 = Random.generate().unwrap(); let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 }; let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 }; - let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0, IpFilter::default()); - let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0, IpFilter::default()); + let mut discovery1 = Discovery::new(&key1, ep1.clone(), IpFilter::default()); + let mut discovery2 = Discovery::new(&key2, ep2.clone(), IpFilter::default()); let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap(); @@ -632,16 +578,14 @@ mod tests { discovery2.refresh(); for _ in 0 .. 10 { - while !discovery1.send_queue.is_empty() { - let datagramm = discovery1.send_queue.pop_front().unwrap(); - if datagramm.address == ep2.address { - discovery2.on_packet(&datagramm.payload, ep1.address.clone()).ok(); + while let Some(datagram) = discovery1.dequeue_send() { + if datagram.address == ep2.address { + discovery2.on_packet(&datagram.payload, ep1.address.clone()).ok(); } } - while !discovery2.send_queue.is_empty() { - let datagramm = discovery2.send_queue.pop_front().unwrap(); - if datagramm.address == ep1.address { - discovery1.on_packet(&datagramm.payload, ep2.address.clone()).ok(); + while let Some(datagram) = discovery2.dequeue_send() { + if datagram.address == ep1.address { + discovery1.on_packet(&datagram.payload, ep2.address.clone()).ok(); } } discovery2.round(); @@ -653,7 +597,7 @@ mod tests { fn removes_expired() { let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40447 }; - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); for _ in 0..1200 { discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); } @@ -668,7 +612,7 @@ mod tests { let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); for _ in 0..(16 + 10) { discovery.node_buckets[0].nodes.push_back(BucketEntry { @@ -728,7 +672,7 @@ mod tests { let key = Secret::from_str(secret_hex) .and_then(|secret| KeyPair::from_secret(secret)) .unwrap(); - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); node_entries.iter().for_each(|entry| discovery.update_node(entry.clone())); @@ -773,7 +717,7 @@ mod tests { fn packets() { let key = Random.generate().unwrap(); let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40449").unwrap(), udp_port: 40449 }; - let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0, IpFilter::default()); + let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default()); discovery.check_timestamps = false; let from = SocketAddr::from_str("99.99.99.99:40445").unwrap(); @@ -840,13 +784,13 @@ mod tests { let key2 = Random.generate().unwrap(); let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40344").unwrap(), udp_port: 40344 }; let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40345").unwrap(), udp_port: 40345 }; - let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0, IpFilter::default()); - let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0, IpFilter::default()); + let mut discovery1 = Discovery::new(&key1, ep1.clone(), IpFilter::default()); + let mut discovery2 = Discovery::new(&key2, ep2.clone(), IpFilter::default()); discovery1.ping(&ep2); - let ping_data = discovery1.send_queue.pop_front().unwrap(); + let ping_data = discovery1.dequeue_send().unwrap(); discovery2.on_packet(&ping_data.payload, ep1.address.clone()).ok(); - let pong_data = discovery2.send_queue.pop_front().unwrap(); + let pong_data = discovery2.dequeue_send().unwrap(); let data = &pong_data.payload[(32 + 65)..]; let rlp = Rlp::new(&data[1..]); assert_eq!(ping_data.payload[0..32], rlp.val_at::>(1).unwrap()[..]) diff --git a/util/network-devp2p/src/host.rs b/util/network-devp2p/src/host.rs index 6d28a838c2..0fbd64b420 100644 --- a/util/network-devp2p/src/host.rs +++ b/util/network-devp2p/src/host.rs @@ -30,6 +30,7 @@ use hash::keccak; use mio::*; use mio::deprecated::{EventLoop}; use mio::tcp::*; +use mio::udp::*; use ethereum_types::H256; use rlp::{RlpStream, Encodable}; @@ -40,7 +41,7 @@ use node_table::*; use network::{NetworkConfiguration, NetworkIoMessage, ProtocolId, PeerId, PacketId}; use network::{NonReservedPeerMode, NetworkContext as NetworkContextTrait}; use network::{SessionInfo, Error, ErrorKind, DisconnectReason, NetworkProtocolHandler}; -use discovery::{Discovery, TableUpdates, NodeEntry}; +use discovery::{Discovery, TableUpdates, NodeEntry, MAX_DATAGRAM_SIZE}; use ip_utils::{map_external_address, select_public_address}; use path::restrict_permissions_owner; use parking_lot::{Mutex, RwLock}; @@ -239,6 +240,7 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host { pub info: RwLock, + udp_socket: Mutex>, tcp_listener: Mutex, sessions: Arc>>, discovery: Mutex>, @@ -295,6 +297,7 @@ impl Host { local_endpoint: local_endpoint, }), discovery: Mutex::new(None), + udp_socket: Mutex::new(None), tcp_listener: Mutex::new(tcp_listener), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), @@ -458,13 +461,16 @@ impl Host { let discovery = { let info = self.info.read(); if info.config.discovery_enabled && info.config.non_reserved_mode == NonReservedPeerMode::Accept { - let mut udp_addr = local_endpoint.address.clone(); - udp_addr.set_port(local_endpoint.udp_port); - Some(Discovery::new(&info.keys, udp_addr, public_endpoint, DISCOVERY, allow_ips)) + Some(Discovery::new(&info.keys, public_endpoint, allow_ips)) } else { None } }; if let Some(mut discovery) = discovery { + let mut udp_addr = local_endpoint.address; + udp_addr.set_port(local_endpoint.udp_port); + let socket = UdpSocket::bind(&udp_addr).expect("Error binding UDP socket"); + *self.udp_socket.lock() = Some(socket); + discovery.init_node_list(self.nodes.read().entries()); discovery.add_node_list(self.nodes.read().entries()); *self.discovery.lock() = Some(discovery); @@ -819,6 +825,67 @@ impl Host { } } + fn discovery_readable(&self, io: &IoContext) { + let node_changes = match (self.udp_socket.lock().as_ref(), self.discovery.lock().as_mut()) { + (Some(udp_socket), Some(discovery)) => { + let mut buf = [0u8; MAX_DATAGRAM_SIZE]; + let writable = discovery.any_sends_queued(); + let res = match udp_socket.recv_from(&mut buf) { + Ok(Some((len, address))) => discovery.on_packet(&buf[0..len], address).unwrap_or_else(|e| { + debug!(target: "network", "Error processing UDP packet: {:?}", e); + None + }), + Ok(_) => None, + Err(e) => { + debug!(target: "network", "Error reading UPD socket: {:?}", e); + None + } + }; + let new_writable = discovery.any_sends_queued(); + if writable != new_writable { + io.update_registration(DISCOVERY) + .unwrap_or_else(|e| { + debug!(target: "network" ,"Error updating discovery registration: {:?}", e) + }); + } + res + }, + _ => None, + }; + if let Some(node_changes) = node_changes { + self.update_nodes(io, node_changes); + } + } + + fn discovery_writable(&self, io: &IoContext) { + match (self.udp_socket.lock().as_ref(), self.discovery.lock().as_mut()) { + (Some(udp_socket), Some(discovery)) => { + while let Some(data) = discovery.dequeue_send() { + match udp_socket.send_to(&data.payload, &data.address) { + Ok(Some(size)) if size == data.payload.len() => { + }, + Ok(Some(_)) => { + warn!(target: "network", "UDP sent incomplete datagram"); + }, + Ok(None) => { + discovery.requeue_send(data); + return; + } + Err(e) => { + debug!(target: "network", "UDP send error: {:?}, address: {:?}", e, &data.address); + return; + } + } + } + io.update_registration(DISCOVERY) + .unwrap_or_else(|e| { + debug!(target: "network", "Error updating discovery registration: {:?}", e) + }); + }, + _ => (), + } + } + fn connection_timeout(&self, token: StreamToken, io: &IoContext) { trace!(target: "network", "Connection timeout: {}", token); self.kill_connection(token, io, true) @@ -920,12 +987,7 @@ impl IoHandler for Host { } match stream { FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), - DISCOVERY => { - let node_changes = { self.discovery.lock().as_mut().map_or(None, |d| d.readable(io)) }; - if let Some(node_changes) = node_changes { - self.update_nodes(io, node_changes); - } - }, + DISCOVERY => self.discovery_readable(io), TCP_ACCEPT => self.accept(io), _ => panic!("Received unknown readable token"), } @@ -937,9 +999,7 @@ impl IoHandler for Host { } match stream { FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io), - DISCOVERY => { - self.discovery.lock().as_mut().map(|d| d.writable(io)); - } + DISCOVERY => self.discovery_writable(io), _ => panic!("Received unknown writable token"), } } @@ -1055,7 +1115,13 @@ impl IoHandler for Host { session.lock().register_socket(reg, event_loop).expect("Error registering socket"); } } - DISCOVERY => self.discovery.lock().as_ref().and_then(|d| d.register_socket(event_loop).ok()).expect("Error registering discovery socket"), + DISCOVERY => match self.udp_socket.lock().as_ref() { + Some(udp_socket) => { + event_loop.register(udp_socket, reg, Ready::all(), PollOpt::edge()) + .expect("Error registering UDP socket"); + }, + _ => panic!("Error registering discovery socket"), + } TCP_ACCEPT => event_loop.register(&*self.tcp_listener.lock(), Token(TCP_ACCEPT), Ready::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } @@ -1086,7 +1152,18 @@ impl IoHandler for Host { connection.lock().update_socket(reg, event_loop).expect("Error updating socket"); } } - DISCOVERY => self.discovery.lock().as_ref().and_then(|d| d.update_registration(event_loop).ok()).expect("Error reregistering discovery socket"), + DISCOVERY => match (self.udp_socket.lock().as_ref(), self.discovery.lock().as_ref()) { + (Some(udp_socket), Some(discovery)) => { + let registration = if discovery.any_sends_queued() { + Ready::readable() | Ready::writable() + } else { + Ready::readable() + }; + event_loop.reregister(udp_socket, reg, registration, PollOpt::edge()) + .expect("Error reregistering UDP socket"); + }, + _ => panic!("Error reregistering discovery socket"), + } TCP_ACCEPT => event_loop.reregister(&*self.tcp_listener.lock(), Token(TCP_ACCEPT), Ready::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } -- GitLab From af1088ef61323f171915555023d8e993aaaed755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 8 Jun 2018 17:05:46 +0200 Subject: [PATCH 230/263] Disable parallel verification and skip verifiying already imported txs. (#8834) * Reject transactions that are already in pool without verifying them. * Avoid verifying already imported transactions. --- Cargo.lock | 1 - miner/Cargo.toml | 1 - miner/src/lib.rs | 1 - miner/src/pool/queue.rs | 11 ++++++++--- miner/src/pool/tests/client.rs | 9 +++++++++ miner/src/pool/tests/mod.rs | 34 ++++++++++++++++++++++++++++++++++ miner/src/pool/verifier.rs | 4 +++- 7 files changed, 54 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a22012300b..9334d01028 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -691,7 +691,6 @@ dependencies = [ "parity-reactor 0.1.0", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "price-info 1.12.0", - "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 707352484e..e692d2f708 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -27,7 +27,6 @@ linked-hash-map = "0.5" log = "0.3" parking_lot = "0.5" price-info = { path = "../price-info" } -rayon = "1.0" rlp = { path = "../util/rlp" } trace-time = { path = "../util/trace-time" } transaction-pool = { path = "../transaction-pool" } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 107b9b22b5..9dc180fefe 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -29,7 +29,6 @@ extern crate keccak_hash as hash; extern crate linked_hash_map; extern crate parking_lot; extern crate price_info; -extern crate rayon; extern crate rlp; extern crate trace_time; extern crate transaction_pool as txpool; diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index 4ebdf9e3f1..cf4a956f42 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -23,7 +23,6 @@ use std::collections::BTreeMap; use ethereum_types::{H256, U256, Address}; use parking_lot::RwLock; -use rayon::prelude::*; use transaction; use txpool::{self, Verifier}; @@ -179,8 +178,14 @@ impl TransactionQueue { let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone()); let results = transactions - .into_par_iter() - .map(|transaction| verifier.verify_transaction(transaction)) + .into_iter() + .map(|transaction| { + if self.pool.read().find(&transaction.hash()).is_some() { + bail!(transaction::Error::AlreadyImported) + } + + verifier.verify_transaction(transaction) + }) .map(|result| result.and_then(|verified| { self.pool.write().import(verified) .map(|_imported| ()) diff --git a/miner/src/pool/tests/client.rs b/miner/src/pool/tests/client.rs index 101b6cdc21..08b43f12ad 100644 --- a/miner/src/pool/tests/client.rs +++ b/miner/src/pool/tests/client.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::sync::{atomic, Arc}; + use ethereum_types::{U256, H256, Address}; use rlp::Rlp; use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; @@ -25,6 +27,7 @@ const MAX_TRANSACTION_SIZE: usize = 15 * 1024; #[derive(Debug, Clone)] pub struct TestClient { + verification_invoked: Arc, account_details: AccountDetails, gas_required: U256, is_service_transaction: bool, @@ -35,6 +38,7 @@ pub struct TestClient { impl Default for TestClient { fn default() -> Self { TestClient { + verification_invoked: Default::default(), account_details: AccountDetails { nonce: 123.into(), balance: 63_100.into(), @@ -88,6 +92,10 @@ impl TestClient { insertion_id: 1, } } + + pub fn was_verification_triggered(&self) -> bool { + self.verification_invoked.load(atomic::Ordering::SeqCst) + } } impl pool::client::Client for TestClient { @@ -98,6 +106,7 @@ impl pool::client::Client for TestClient { fn verify_transaction(&self, tx: UnverifiedTransaction) -> Result { + self.verification_invoked.store(true, atomic::Ordering::SeqCst); Ok(SignedTransaction::new(tx)?) } diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index 552903a4bb..ac2e6b008e 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -796,3 +796,37 @@ fn should_include_local_transaction_to_a_full_pool() { // then assert_eq!(txq.status().status.transaction_count, 1); } + +#[test] +fn should_avoid_verifying_transaction_already_in_pool() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 1, + max_per_sender: 2, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let client = TestClient::new(); + let tx1 = Tx::default().signed().unverified(); + + let res = txq.import(client.clone(), vec![tx1.clone()]); + assert_eq!(res, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 1); + assert!(client.was_verification_triggered()); + + // when + let client = TestClient::new(); + let res = txq.import(client.clone(), vec![tx1]); + assert_eq!(res, vec![Err(transaction::Error::AlreadyImported)]); + assert!(!client.was_verification_triggered()); + + // then + assert_eq!(txq.status().status.transaction_count, 1); +} diff --git a/miner/src/pool/verifier.rs b/miner/src/pool/verifier.rs index 4675303928..5e6e22077a 100644 --- a/miner/src/pool/verifier.rs +++ b/miner/src/pool/verifier.rs @@ -57,6 +57,7 @@ impl Default for Options { } /// Transaction to verify. +#[cfg_attr(test, derive(Clone))] pub enum Transaction { /// Fresh, never verified transaction. /// @@ -75,7 +76,8 @@ pub enum Transaction { } impl Transaction { - fn hash(&self) -> H256 { + /// Return transaction hash + pub fn hash(&self) -> H256 { match *self { Transaction::Unverified(ref tx) => tx.hash(), Transaction::Retracted(ref tx) => tx.hash(), -- GitLab From 986f485b3e66ec4724c0d026a19894cbc91ef9a3 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 11 Jun 2018 11:02:46 +0300 Subject: [PATCH 231/263] Clearing up a comment about the prefix for signing (#8828) --- rpc/src/v1/helpers/dispatch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 9bec8e1d31..dbfdd51bc5 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -237,7 +237,7 @@ pub fn fetch_gas_price_corpus( /// Returns a eth_sign-compatible hash of data to sign. /// The data is prepended with special message to prevent -/// chosen-plaintext attacks. +/// malicious DApps from using the function to sign forged transactions. pub fn eth_data_hash(mut data: Bytes) -> H256 { let mut message_data = format!("\x19Ethereum Signed Message:\n{}", data.len()) -- GitLab From 10fc74eb8119330ff3a065e0d3e5400e9de18240 Mon Sep 17 00:00:00 2001 From: Afri Schoedon <5chdn@users.noreply.github.com> Date: Mon, 11 Jun 2018 10:03:16 +0200 Subject: [PATCH 232/263] network-devp2p: downgrade logging to debug, add target (#8784) * network-devp2p: downgrade logging to debug, add target * network-devp2p: rename s/datagramm/datagram --- util/network-devp2p/src/discovery.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/network-devp2p/src/discovery.rs b/util/network-devp2p/src/discovery.rs index b7cce2832f..5f8f0cdbc2 100644 --- a/util/network-devp2p/src/discovery.rs +++ b/util/network-devp2p/src/discovery.rs @@ -147,7 +147,7 @@ impl Discovery { let dist = match Discovery::distance(&self.id_hash, &id_hash) { Some(dist) => dist, None => { - warn!(target: "discovery", "Attempted to update own entry: {:?}", e); + debug!(target: "discovery", "Attempted to update own entry: {:?}", e); return; } }; @@ -181,7 +181,7 @@ impl Discovery { let dist = match Discovery::distance(&self.id_hash, &keccak(id)) { Some(dist) => dist, None => { - warn!(target: "discovery", "Received ping from self"); + debug!(target: "discovery", "Received ping from self"); return } }; @@ -370,7 +370,7 @@ impl Discovery { PACKET_FIND_NODE => self.on_find_node(&rlp, &node_id, &from), PACKET_NEIGHBOURS => self.on_neighbours(&rlp, &node_id, &from), _ => { - debug!("Unknown UDP packet: {}", packet_id); + debug!(target: "discovery", "Unknown UDP packet: {}", packet_id); Ok(None) } } -- GitLab From 09ee6e147750f4ea22be7e87157598539f5032b7 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 11 Jun 2018 18:26:49 +0800 Subject: [PATCH 233/263] Fix subcrate test compile (#8862) * Fix test compile for light, node_filter, service in ethcore * Fix ipfs, local-store, rpc, secret_store, updater subcrate test compile --- ethcore/light/Cargo.toml | 1 + ethcore/node_filter/Cargo.toml | 1 + ethcore/service/Cargo.toml | 1 + ipfs/Cargo.toml | 3 +++ local-store/Cargo.toml | 1 + rpc/Cargo.toml | 1 + secret_store/Cargo.toml | 1 + updater/Cargo.toml | 1 + 8 files changed, 10 insertions(+) diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index 3853ad910f..ab347c62e8 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -38,6 +38,7 @@ memory-cache = { path = "../../util/memory_cache" } error-chain = { version = "0.11", default-features = false } [dev-dependencies] +ethcore = { path = "..", features = ["test-helpers"] } kvdb-memorydb = { path = "../../util/kvdb-memorydb" } tempdir = "0.3" diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index 0d204e29ff..11be807652 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -19,6 +19,7 @@ ethabi-contract = "5.0" lru-cache = "0.1" [dev-dependencies] +ethcore = { path = "..", features = ["test-helpers"] } kvdb-memorydb = { path = "../../util/kvdb-memorydb" } ethcore-io = { path = "../../util/io" } tempdir = "0.3" diff --git a/ethcore/service/Cargo.toml b/ethcore/service/Cargo.toml index 3a10849b61..634ee55dba 100644 --- a/ethcore/service/Cargo.toml +++ b/ethcore/service/Cargo.toml @@ -16,5 +16,6 @@ stop-guard = { path = "../../util/stop-guard" } trace-time = { path = "../../util/trace-time" } [dev-dependencies] +ethcore = { path = "..", features = ["test-helpers"] } tempdir = "0.3" kvdb-rocksdb = { path = "../../util/kvdb-rocksdb" } diff --git a/ipfs/Cargo.toml b/ipfs/Cargo.toml index 9c7b5f3b00..5a72048134 100644 --- a/ipfs/Cargo.toml +++ b/ipfs/Cargo.toml @@ -15,3 +15,6 @@ rlp = { path = "../util/rlp" } cid = "0.2" multihash = "0.7" unicase = "2.0" + +[dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } diff --git a/local-store/Cargo.toml b/local-store/Cargo.toml index 6d09eb76f6..d2c3469ca4 100644 --- a/local-store/Cargo.toml +++ b/local-store/Cargo.toml @@ -16,5 +16,6 @@ serde_derive = "1.0" serde_json = "1.0" [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } ethkey = { path = "../ethkey" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 8a0b689c65..338a892682 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -65,6 +65,7 @@ stats = { path = "../util/stats" } vm = { path = "../ethcore/vm" } [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } ethcore-network = { path = "../util/network" } fake-fetch = { path = "../util/fake-fetch" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index 261658903c..a8aed83127 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -39,5 +39,6 @@ ethabi-derive = "5.0" ethabi-contract = "5.0" [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } tempdir = "0.3" kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } diff --git a/updater/Cargo.toml b/updater/Cargo.toml index d76db6ec0e..8d94680335 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -25,5 +25,6 @@ path = { path = "../util/path" } rand = "0.4" [dev-dependencies] +ethcore = { path = "../ethcore", features = ["test-helpers"] } tempdir = "0.3" matches = "0.1" -- GitLab From 861d829420ff28e387642659ffe256955352d939 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 11 Jun 2018 20:38:01 +0200 Subject: [PATCH 234/263] Fix Cli Return Code on --help for ethkey, ethstore & whisper (#8863) Docopt handles `--help` automatically for us, however we've handled those Errors the same as all others: by exiting with Return Code `1`, which is wrong for a totally appropriate a quit on `--help`. Fortunately `docopt:Error` provides an `exit` helper function that discriminates properly between fatal and non-fatal errors and exist appropriately. This patch makes sure we use that handy function in case we encounter such an error in the CLI of ethkey, ethstore and whisper. Thus those are now giving the appropriate Return code on `--help`. fixes #8851 --- ethkey/cli/src/main.rs | 3 ++- ethstore/cli/src/main.rs | 1 + whisper/cli/src/main.rs | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ethkey/cli/src/main.rs b/ethkey/cli/src/main.rs index c8f5e2e64e..af50f86b31 100644 --- a/ethkey/cli/src/main.rs +++ b/ethkey/cli/src/main.rs @@ -166,10 +166,11 @@ fn main() { match execute(env::args()) { Ok(ok) => println!("{}", ok), + Err(Error::Docopt(ref e)) => e.exit(), Err(err) => { println!("{}", err); process::exit(1); - }, + } } } diff --git a/ethstore/cli/src/main.rs b/ethstore/cli/src/main.rs index 416b64d43e..922d857149 100644 --- a/ethstore/cli/src/main.rs +++ b/ethstore/cli/src/main.rs @@ -149,6 +149,7 @@ fn main() { match execute(env::args()) { Ok(result) => println!("{}", result), + Err(Error::Docopt(ref e)) => e.exit(), Err(err) => { println!("{}", err); process::exit(1); diff --git a/whisper/cli/src/main.rs b/whisper/cli/src/main.rs index 6f3aec8594..1d57691418 100644 --- a/whisper/cli/src/main.rs +++ b/whisper/cli/src/main.rs @@ -190,11 +190,12 @@ fn main() { Ok(_) => { println!("whisper-cli terminated"); process::exit(1); - } + }, + Err(Error::Docopt(ref e)) => e.exit(), Err(err) => { println!("{}", err); process::exit(1); - }, + } } } -- GitLab From 2a470deeafa194dbb53d277d7839cd8c78deed28 Mon Sep 17 00:00:00 2001 From: Andronik Ordian Date: Tue, 12 Jun 2018 09:15:52 +0300 Subject: [PATCH 235/263] Don't allocate in expect_valid_rlp unless necessary (#8867) * don't allocate via format! in case there's no error * fix test? --- ethcore/src/views/view_rlp.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ethcore/src/views/view_rlp.rs b/ethcore/src/views/view_rlp.rs index 2ecc4dbdd3..2dd1b33a94 100644 --- a/ethcore/src/views/view_rlp.rs +++ b/ethcore/src/views/view_rlp.rs @@ -39,10 +39,10 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view { /// Returns a new instance replacing existing rlp with new rlp, maintaining debug info fn new_from_rlp(&self, rlp: Rlp<'a>) -> Self { - ViewRlp { - rlp, + ViewRlp { + rlp, file: self.file, - line: self.line + line: self.line } } @@ -53,7 +53,12 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view { } fn expect_valid_rlp(&self, r: Result) -> T { - r.expect(&format!("View rlp is trusted and should be valid. Constructed in {} on line {}", self.file, self.line)) + r.unwrap_or_else(|e| panic!( + "View rlp is trusted and should be valid. Constructed in {} on line {}: {}", + self.file, + self.line, + e + )) } /// Returns rlp at the given index, panics if no rlp at that index @@ -75,7 +80,7 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view { /// Returns decoded value at the given index, panics not present or valid at that index pub fn val_at(&self, index: usize) -> T where T : Decodable { self.expect_valid_rlp(self.rlp.val_at(index)) - } + } /// Returns decoded list of values, panics if rlp is invalid pub fn list_at(&self, index: usize) -> Vec where T: Decodable { -- GitLab From 4817b94d0bb23356a5ee9b659ab8f4c4cbbd660d Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 12 Jun 2018 14:21:55 +0800 Subject: [PATCH 236/263] Use sealing.enabled to emit eth_mining information (#8844) * Use sealing.enabled to emit eth_mining information * Be more accurate on last_requests by using Option * Add tests for internal sealing * Add test for pow non-mining * Add test for mining pow --- ethcore/src/miner/miner.rs | 71 +++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index bf51d0b135..e91e03e8bc 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -180,7 +180,7 @@ struct SealingWork { next_allowed_reseal: Instant, next_mandatory_reseal: Instant, // block number when sealing work was last requested - last_request: u64, + last_request: Option, } impl SealingWork { @@ -231,7 +231,7 @@ impl Miner { || spec.engine.seals_internally().is_some(), next_allowed_reseal: Instant::now(), next_mandatory_reseal: Instant::now() + options.reseal_max_period, - last_request: 0, + last_request: None, }), params: RwLock::new(AuthoringParams::default()), listeners: RwLock::new(vec![]), @@ -496,8 +496,10 @@ impl Miner { trace!(target: "miner", "requires_reseal: sealing enabled"); // Disable sealing if there were no requests for SEALING_TIMEOUT_IN_BLOCKS - let had_requests = best_block > sealing.last_request - && best_block - sealing.last_request <= SEALING_TIMEOUT_IN_BLOCKS; + let had_requests = sealing.last_request.map(|last_request| { + best_block > last_request + && best_block - last_request <= SEALING_TIMEOUT_IN_BLOCKS + }).unwrap_or(false); // keep sealing enabled if any of the conditions is met let sealing_enabled = self.forced_sealing() @@ -516,7 +518,7 @@ impl Miner { ); if should_disable_sealing { - trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, sealing.last_request); + trace!(target: "miner", "Miner sleeping (current {}, last {})", best_block, sealing.last_request.unwrap_or(0)); sealing.enabled = false; sealing.queue.reset(); false @@ -676,13 +678,13 @@ impl Miner { let best_number = client.chain_info().best_block_number; let mut sealing = self.sealing.lock(); - if sealing.last_request != best_number { + if sealing.last_request != Some(best_number) { trace!( target: "miner", "prepare_pending_block: Miner received request (was {}, now {}) - waking up.", - sealing.last_request, best_number + sealing.last_request.unwrap_or(0), best_number ); - sealing.last_request = best_number; + sealing.last_request = Some(best_number); } // Return if we restarted @@ -954,7 +956,7 @@ impl miner::MinerService for Miner { } fn is_currently_sealing(&self) -> bool { - self.sealing.lock().queue.is_in_use() + self.sealing.lock().enabled } fn work_package(&self, chain: &C) -> Option<(H256, BlockNumber, u64, U256)> where @@ -1266,4 +1268,55 @@ mod tests { let client = generate_dummy_client_with_spec_and_accounts(spec, None); assert!(match client.miner().set_author(addr, Some("".into())) { Err(AccountError::NotFound) => true, _ => false }); } + + #[test] + fn should_mine_if_internal_sealing_is_enabled() { + let spec = Spec::new_instant(); + let miner = Miner::new_for_tests(&spec, None); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(miner.is_currently_sealing()); + } + + #[test] + fn should_not_mine_if_internal_sealing_is_disabled() { + let spec = Spec::new_test_round(); + let miner = Miner::new_for_tests(&spec, None); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(!miner.is_currently_sealing()); + } + + #[test] + fn should_not_mine_if_no_fetch_work_request() { + let spec = Spec::new_test(); + let miner = Miner::new_for_tests(&spec, None); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(!miner.is_currently_sealing()); + } + + #[test] + fn should_mine_if_fetch_work_request() { + struct DummyNotifyWork; + + impl NotifyWork for DummyNotifyWork { + fn notify(&self, _pow_hash: H256, _difficulty: U256, _number: u64) { } + } + + let spec = Spec::new_test(); + let miner = Miner::new_for_tests(&spec, None); + miner.add_work_listener(Box::new(DummyNotifyWork)); + + let client = generate_dummy_client(2); + miner.update_sealing(&*client); + + assert!(miner.is_currently_sealing()); + } } -- GitLab From 4938d5dde5c83403e6cffc7301ebd35cbdcf04a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 12 Jun 2018 08:22:54 +0200 Subject: [PATCH 237/263] Limit the number of transactions in pending set (#8777) * Unordered iterator. * Use unordered and limited set if full not required. * Split timeout work into smaller timers. * Avoid collecting all pending transactions when mining * Remove println. * Use priority ordering in eth-filter. * Fix ethcore-miner tests and tx propagation. * Review grumbles addressed. * Add test for unordered not populating the cache. * Fix ethcore tests. * Fix light tests. * Fix ethcore-sync tests. * Fix RPC tests. --- Cargo.lock | 6 +- ethcore/light/src/net/mod.rs | 5 +- ethcore/light/src/net/tests/mod.rs | 4 +- ethcore/light/src/provider.rs | 13 ++- ethcore/src/client/client.rs | 4 +- ethcore/src/client/test_client.rs | 6 +- ethcore/src/client/traits.rs | 2 +- ethcore/src/miner/miner.rs | 51 ++++++--- ethcore/src/miner/mod.rs | 7 +- ethcore/src/tests/client.rs | 10 +- ethcore/sync/src/api.rs | 21 +++- ethcore/sync/src/chain/mod.rs | 10 +- ethcore/sync/src/chain/propagator.rs | 3 +- miner/src/lib.rs | 3 +- miner/src/pool/mod.rs | 39 ++++++- miner/src/pool/queue.rs | 71 ++++++++++--- miner/src/pool/tests/mod.rs | 124 ++++++++++++++++------ parity/rpc_apis.rs | 4 +- rpc/Cargo.toml | 2 +- rpc/src/v1/impls/eth_filter.rs | 2 +- rpc/src/v1/impls/eth_pubsub.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 3 +- rpc/src/v1/impls/parity.rs | 10 +- rpc/src/v1/tests/helpers/miner_service.rs | 4 +- rpc/src/v1/tests/mocked/eth_pubsub.rs | 2 +- rpc/src/v1/traits/parity.rs | 2 +- transaction-pool/Cargo.toml | 2 +- transaction-pool/src/pool.rs | 58 +++++++++- transaction-pool/src/tests/mod.rs | 60 +++++++++++ 29 files changed, 415 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9334d01028..60565f1758 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -694,7 +694,7 @@ dependencies = [ "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace-time 0.1.0", - "transaction-pool 1.12.0", + "transaction-pool 1.12.1", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2241,7 +2241,7 @@ dependencies = [ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "transaction-pool 1.12.0", + "transaction-pool 1.12.1", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -3422,7 +3422,7 @@ dependencies = [ [[package]] name = "transaction-pool" -version = "1.12.0" +version = "1.12.1" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 39f53445ad..179f709003 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -72,6 +72,9 @@ const PROPAGATE_TIMEOUT_INTERVAL: Duration = Duration::from_secs(5); const RECALCULATE_COSTS_TIMEOUT: TimerToken = 3; const RECALCULATE_COSTS_INTERVAL: Duration = Duration::from_secs(60 * 60); +/// Max number of transactions in a single packet. +const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; + // minimum interval between updates. const UPDATE_INTERVAL: Duration = Duration::from_millis(5000); @@ -647,7 +650,7 @@ impl LightProtocol { fn propagate_transactions(&self, io: &IoContext) { if self.capabilities.read().tx_relay { return } - let ready_transactions = self.provider.ready_transactions(); + let ready_transactions = self.provider.ready_transactions(MAX_TRANSACTIONS_TO_PROPAGATE); if ready_transactions.is_empty() { return } trace!(target: "pip", "propagate transactions: {} ready", ready_transactions.len()); diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index 305ef9b354..e182f38b8a 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -173,8 +173,8 @@ impl Provider for TestProvider { }) } - fn ready_transactions(&self) -> Vec { - self.0.client.ready_transactions() + fn ready_transactions(&self, max_len: usize) -> Vec { + self.0.client.ready_transactions(max_len) } } diff --git a/ethcore/light/src/provider.rs b/ethcore/light/src/provider.rs index 0e518ea772..e75915e8cf 100644 --- a/ethcore/light/src/provider.rs +++ b/ethcore/light/src/provider.rs @@ -125,7 +125,7 @@ pub trait Provider: Send + Sync { fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option; /// Provide pending transactions. - fn ready_transactions(&self) -> Vec; + fn ready_transactions(&self, max_len: usize) -> Vec; /// Provide a proof-of-execution for the given transaction proof request. /// Returns a vector of all state items necessary to execute the transaction. @@ -280,8 +280,8 @@ impl Provider for T { .map(|(_, proof)| ::request::ExecutionResponse { items: proof }) } - fn ready_transactions(&self) -> Vec { - BlockChainClient::ready_transactions(self) + fn ready_transactions(&self, max_len: usize) -> Vec { + BlockChainClient::ready_transactions(self, max_len) .into_iter() .map(|tx| tx.pending().clone()) .collect() @@ -367,9 +367,12 @@ impl Provider for LightProvider { None } - fn ready_transactions(&self) -> Vec { + fn ready_transactions(&self, max_len: usize) -> Vec { let chain_info = self.chain_info(); - self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) + let mut transactions = self.txqueue.read() + .ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp); + transactions.truncate(max_len); + transactions } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 2d0201067f..d47d1afa49 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1956,8 +1956,8 @@ impl BlockChainClient for Client { (*self.build_last_hashes(&self.chain.read().best_block_hash())).clone() } - fn ready_transactions(&self) -> Vec> { - self.importer.miner.ready_transactions(self) + fn ready_transactions(&self, max_len: usize) -> Vec> { + self.importer.miner.ready_transactions(self, max_len, ::miner::PendingOrdering::Priority) } fn signing_chain_id(&self) -> Option { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 4bd76b4495..620f1af333 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -48,7 +48,7 @@ use log_entry::LocalizedLogEntry; use receipt::{Receipt, LocalizedReceipt, TransactionOutcome}; use error::ImportResult; use vm::Schedule; -use miner::{Miner, MinerService}; +use miner::{self, Miner, MinerService}; use spec::Spec; use types::basic_account::BasicAccount; use types::pruning_info::PruningInfo; @@ -806,8 +806,8 @@ impl BlockChainClient for TestBlockChainClient { self.traces.read().clone() } - fn ready_transactions(&self) -> Vec> { - self.miner.ready_transactions(self) + fn ready_transactions(&self, max_len: usize) -> Vec> { + self.miner.ready_transactions(self, max_len, miner::PendingOrdering::Priority) } fn signing_chain_id(&self) -> Option { None } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index d3a20dcff8..29876fe80a 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -321,7 +321,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn last_hashes(&self) -> LastHashes; /// List all transactions that are allowed into the next block. - fn ready_transactions(&self) -> Vec>; + fn ready_transactions(&self, max_len: usize) -> Vec>; /// Sorted list of transaction gas prices from at least last sample_size blocks. fn gas_price_corpus(&self, sample_size: usize) -> ::stats::Corpus { diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index e91e03e8bc..2547fea62b 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -364,18 +364,28 @@ impl Miner { let client = self.pool_client(chain); let engine_params = self.engine.params(); - let min_tx_gas = self.engine.schedule(chain_info.best_block_number).tx_gas.into(); + let min_tx_gas: U256 = self.engine.schedule(chain_info.best_block_number).tx_gas.into(); let nonce_cap: Option = if chain_info.best_block_number + 1 >= engine_params.dust_protection_transition { Some((engine_params.nonce_cap_increment * (chain_info.best_block_number + 1)).into()) } else { None }; + // we will never need more transactions than limit divided by min gas + let max_transactions = if min_tx_gas.is_zero() { + usize::max_value() + } else { + (*open_block.block().header().gas_limit() / min_tx_gas).as_u64() as usize + }; let pending: Vec> = self.transaction_queue.pending( client.clone(), - chain_info.best_block_number, - chain_info.best_block_timestamp, - nonce_cap, + pool::PendingSettings { + block_number: chain_info.best_block_number, + current_timestamp: chain_info.best_block_timestamp, + nonce_cap, + max_len: max_transactions, + ordering: miner::PendingOrdering::Priority, + } ); let took_ms = |elapsed: &Duration| { @@ -807,20 +817,28 @@ impl miner::MinerService for Miner { self.transaction_queue.all_transactions() } - fn ready_transactions(&self, chain: &C) -> Vec> where + fn ready_transactions(&self, chain: &C, max_len: usize, ordering: miner::PendingOrdering) + -> Vec> + where C: ChainInfo + Nonce + Sync, { let chain_info = chain.chain_info(); let from_queue = || { + // We propagate transactions over the nonce cap. + // The mechanism is only to limit number of transactions in pending block + // those transactions are valid and will just be ready to be included in next block. + let nonce_cap = None; + self.transaction_queue.pending( CachedNonceClient::new(chain, &self.nonce_cache), - chain_info.best_block_number, - chain_info.best_block_timestamp, - // We propagate transactions over the nonce cap. - // The mechanism is only to limit number of transactions in pending block - // those transactions are valid and will just be ready to be included in next block. - None, + pool::PendingSettings { + block_number: chain_info.best_block_number, + current_timestamp: chain_info.best_block_timestamp, + nonce_cap, + max_len, + ordering, + }, ) }; @@ -830,6 +848,7 @@ impl miner::MinerService for Miner { .iter() .map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone())) .map(Arc::new) + .take(max_len) .collect() }, chain_info.best_block_number) }; @@ -1083,7 +1102,7 @@ mod tests { use rustc_hex::FromHex; use client::{TestBlockChainClient, EachBlockWith, ChainInfo, ImportSealedBlock}; - use miner::MinerService; + use miner::{MinerService, PendingOrdering}; use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts}; use transaction::{Transaction}; @@ -1179,7 +1198,7 @@ mod tests { assert_eq!(res.unwrap(), ()); assert_eq!(miner.pending_transactions(best_block).unwrap().len(), 1); assert_eq!(miner.pending_receipts(best_block).unwrap().len(), 1); - assert_eq!(miner.ready_transactions(&client).len(), 1); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); // This method will let us know if pending block was created (before calling that method) assert!(!miner.prepare_pending_block(&client)); } @@ -1198,7 +1217,7 @@ mod tests { assert_eq!(res.unwrap(), ()); assert_eq!(miner.pending_transactions(best_block), None); assert_eq!(miner.pending_receipts(best_block), None); - assert_eq!(miner.ready_transactions(&client).len(), 1); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); } #[test] @@ -1217,11 +1236,11 @@ mod tests { assert_eq!(miner.pending_transactions(best_block), None); assert_eq!(miner.pending_receipts(best_block), None); // By default we use PendingSet::AlwaysSealing, so no transactions yet. - assert_eq!(miner.ready_transactions(&client).len(), 0); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 0); // This method will let us know if pending block was created (before calling that method) assert!(miner.prepare_pending_block(&client)); // After pending block is created we should see a transaction. - assert_eq!(miner.ready_transactions(&client).len(), 1); + assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); } #[test] diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index dd5f28feb6..631941de61 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -26,6 +26,7 @@ pub mod pool_client; pub mod stratum; pub use self::miner::{Miner, MinerOptions, Penalization, PendingSet, AuthoringParams}; +pub use ethcore_miner::pool::PendingOrdering; use std::sync::Arc; use std::collections::BTreeMap; @@ -156,10 +157,12 @@ pub trait MinerService : Send + Sync { fn next_nonce(&self, chain: &C, address: &Address) -> U256 where C: Nonce + Sync; - /// Get a list of all ready transactions. + /// Get a list of all ready transactions either ordered by priority or unordered (cheaper). /// /// Depending on the settings may look in transaction pool or only in pending block. - fn ready_transactions(&self, chain: &C) -> Vec> + /// If you don't need a full set of transactions, you can add `max_len` and create only a limited set of + /// transactions. + fn ready_transactions(&self, chain: &C, max_len: usize, ordering: PendingOrdering) -> Vec> where C: ChainInfo + Nonce + Sync; /// Get a list of all transactions in the pool (some of them might not be ready for inclusion yet). diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index ccafcf6613..e18b4db983 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -30,7 +30,7 @@ use test_helpers::{ use types::filter::Filter; use ethereum_types::{U256, Address}; use kvdb_rocksdb::{Database, DatabaseConfig}; -use miner::Miner; +use miner::{Miner, PendingOrdering}; use spec::Spec; use views::BlockView; use ethkey::KeyPair; @@ -343,12 +343,12 @@ fn does_not_propagate_delayed_transactions() { client.miner().import_own_transaction(&*client, tx0).unwrap(); client.miner().import_own_transaction(&*client, tx1).unwrap(); - assert_eq!(0, client.ready_transactions().len()); - assert_eq!(0, client.miner().ready_transactions(&*client).len()); + assert_eq!(0, client.ready_transactions(10).len()); + assert_eq!(0, client.miner().ready_transactions(&*client, 10, PendingOrdering::Priority).len()); push_blocks_to_client(&client, 53, 2, 2); client.flush_queue(); - assert_eq!(2, client.ready_transactions().len()); - assert_eq!(2, client.miner().ready_transactions(&*client).len()); + assert_eq!(2, client.ready_transactions(10).len()); + assert_eq!(2, client.miner().ready_transactions(&*client, 10, PendingOrdering::Priority).len()); } #[test] diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index b759fb734a..56bc579ad8 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -359,6 +359,10 @@ impl SyncProvider for EthSync { } } +const PEERS_TIMER: TimerToken = 0; +const SYNC_TIMER: TimerToken = 1; +const TX_TIMER: TimerToken = 2; + struct SyncProtocolHandler { /// Shared blockchain client. chain: Arc, @@ -373,7 +377,9 @@ struct SyncProtocolHandler { impl NetworkProtocolHandler for SyncProtocolHandler { fn initialize(&self, io: &NetworkContext) { if io.subprotocol_name() != WARP_SYNC_PROTOCOL_ID { - io.register_timer(0, Duration::from_secs(1)).expect("Error registering sync timer"); + io.register_timer(PEERS_TIMER, Duration::from_millis(700)).expect("Error registering peers timer"); + io.register_timer(SYNC_TIMER, Duration::from_millis(1100)).expect("Error registering sync timer"); + io.register_timer(TX_TIMER, Duration::from_millis(1300)).expect("Error registering transactions timer"); } } @@ -399,12 +405,17 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } } - fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { + fn timeout(&self, io: &NetworkContext, timer: TimerToken) { trace_time!("sync::timeout"); let mut io = NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay); - self.sync.write().maintain_peers(&mut io); - self.sync.write().maintain_sync(&mut io); - self.sync.write().propagate_new_transactions(&mut io); + match timer { + PEERS_TIMER => self.sync.write().maintain_peers(&mut io), + SYNC_TIMER => self.sync.write().maintain_sync(&mut io), + TX_TIMER => { + self.sync.write().propagate_new_transactions(&mut io); + }, + _ => warn!("Unknown timer {} triggered.", timer), + } } } diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 8f0aff7514..84e6344e68 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -149,6 +149,10 @@ const MAX_NEW_HASHES: usize = 64; const MAX_NEW_BLOCK_AGE: BlockNumber = 20; // maximal packet size with transactions (cannot be greater than 16MB - protocol limitation). const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024; +// Maximal number of transactions queried from miner to propagate. +// This set is used to diff with transactions known by the peer and +// we will send a difference of length up to `MAX_TRANSACTIONS_TO_PROPAGATE`. +const MAX_TRANSACTIONS_TO_QUERY: usize = 4096; // Maximal number of transactions in sent in single packet. const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64; // Min number of blocks to be behind for a snapshot sync @@ -1143,7 +1147,7 @@ pub mod tests { use super::{PeerInfo, PeerAsking}; use ethcore::header::*; use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo}; - use ethcore::miner::MinerService; + use ethcore::miner::{MinerService, PendingOrdering}; use private_tx::NoopPrivateTxHandler; pub fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { @@ -1355,7 +1359,7 @@ pub mod tests { let mut io = TestIo::new(&mut client, &ss, &queue, None); io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks, false); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, &[], &[]); - assert_eq!(io.chain.miner.ready_transactions(io.chain).len(), 1); + assert_eq!(io.chain.miner.ready_transactions(io.chain, 10, PendingOrdering::Priority).len(), 1); } // We need to update nonce status (because we say that the block has been imported) for h in &[good_blocks[0]] { @@ -1371,7 +1375,7 @@ pub mod tests { } // then - assert_eq!(client.miner.ready_transactions(&client).len(), 1); + assert_eq!(client.miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1); } #[test] diff --git a/ethcore/sync/src/chain/propagator.rs b/ethcore/sync/src/chain/propagator.rs index 4ae0518a53..75cf550f28 100644 --- a/ethcore/sync/src/chain/propagator.rs +++ b/ethcore/sync/src/chain/propagator.rs @@ -33,6 +33,7 @@ use super::{ MAX_PEERS_PROPAGATION, MAX_TRANSACTION_PACKET_SIZE, MAX_TRANSACTIONS_TO_PROPAGATE, + MAX_TRANSACTIONS_TO_QUERY, MIN_PEERS_PROPAGATION, CONSENSUS_DATA_PACKET, NEW_BLOCK_HASHES_PACKET, @@ -114,7 +115,7 @@ impl SyncPropagator { return 0; } - let transactions = io.chain().ready_transactions(); + let transactions = io.chain().ready_transactions(MAX_TRANSACTIONS_TO_QUERY); if transactions.is_empty() { return 0; } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 9dc180fefe..6b61df4de4 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -30,13 +30,14 @@ extern crate linked_hash_map; extern crate parking_lot; extern crate price_info; extern crate rlp; -extern crate trace_time; extern crate transaction_pool as txpool; #[macro_use] extern crate error_chain; #[macro_use] extern crate log; +#[macro_use] +extern crate trace_time; #[cfg(test)] extern crate rustc_hex; diff --git a/miner/src/pool/mod.rs b/miner/src/pool/mod.rs index 57f813157b..fd4ef6ef2e 100644 --- a/miner/src/pool/mod.rs +++ b/miner/src/pool/mod.rs @@ -16,7 +16,7 @@ //! Transaction Pool -use ethereum_types::{H256, Address}; +use ethereum_types::{U256, H256, Address}; use heapsize::HeapSizeOf; use transaction; use txpool; @@ -45,6 +45,43 @@ pub enum PrioritizationStrategy { GasPriceOnly, } +/// Transaction ordering when requesting pending set. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PendingOrdering { + /// Get pending transactions ordered by their priority (potentially expensive) + Priority, + /// Get pending transactions without any care of particular ordering (cheaper). + Unordered, +} + +/// Pending set query settings +#[derive(Debug, Clone)] +pub struct PendingSettings { + /// Current block number (affects readiness of some transactions). + pub block_number: u64, + /// Current timestamp (affects readiness of some transactions). + pub current_timestamp: u64, + /// Nonce cap (for dust protection; EIP-168) + pub nonce_cap: Option, + /// Maximal number of transactions in pending the set. + pub max_len: usize, + /// Ordering of transactions. + pub ordering: PendingOrdering, +} + +impl PendingSettings { + /// Get all transactions (no cap or len limit) prioritized. + pub fn all_prioritized(block_number: u64, current_timestamp: u64) -> Self { + PendingSettings { + block_number, + current_timestamp, + nonce_cap: None, + max_len: usize::max_value(), + ordering: PendingOrdering::Priority, + } + } +} + /// Transaction priority. #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub(crate) enum Priority { diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index cf4a956f42..4351087b29 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -26,7 +26,10 @@ use parking_lot::RwLock; use transaction; use txpool::{self, Verifier}; -use pool::{self, scoring, verifier, client, ready, listener, PrioritizationStrategy}; +use pool::{ + self, scoring, verifier, client, ready, listener, + PrioritizationStrategy, PendingOrdering, PendingSettings, +}; use pool::local_transactions::LocalTransactionsList; type Listener = (LocalTransactionsList, (listener::Notifier, listener::Logger)); @@ -74,6 +77,7 @@ struct CachedPending { nonce_cap: Option, has_local_pending: bool, pending: Option>>, + max_len: usize, } impl CachedPending { @@ -85,6 +89,7 @@ impl CachedPending { has_local_pending: false, pending: None, nonce_cap: None, + max_len: 0, } } @@ -99,6 +104,7 @@ impl CachedPending { block_number: u64, current_timestamp: u64, nonce_cap: Option<&U256>, + max_len: usize, ) -> Option>> { // First check if we have anything in cache. let pending = self.pending.as_ref()?; @@ -123,7 +129,12 @@ impl CachedPending { return None; } - Some(pending.clone()) + // It's fine to just take a smaller subset, but not other way around. + if max_len > self.max_len { + return None; + } + + Some(pending.iter().take(max_len).cloned().collect()) } } @@ -173,7 +184,7 @@ impl TransactionQueue { transactions: Vec, ) -> Vec> { // Run verification - let _timer = ::trace_time::PerfTimer::new("pool::verify_and_import"); + trace_time!("pool::verify_and_import"); let options = self.options.read().clone(); let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone()); @@ -203,13 +214,13 @@ impl TransactionQueue { results } - /// Returns all transactions in the queue ordered by priority. + /// Returns all transactions in the queue without explicit ordering. pub fn all_transactions(&self) -> Vec> { let ready = |_tx: &pool::VerifiedTransaction| txpool::Readiness::Ready; - self.pool.read().pending(ready).collect() + self.pool.read().unordered_pending(ready).collect() } - /// Returns current pneding transactions. + /// Returns current pending transactions ordered by priority. /// /// NOTE: This may return a cached version of pending transaction set. /// Re-computing the pending set is possible with `#collect_pending` method, @@ -217,24 +228,31 @@ impl TransactionQueue { pub fn pending( &self, client: C, - block_number: u64, - current_timestamp: u64, - nonce_cap: Option, + settings: PendingSettings, ) -> Vec> where C: client::NonceClient, { - - if let Some(pending) = self.cached_pending.read().pending(block_number, current_timestamp, nonce_cap.as_ref()) { + let PendingSettings { block_number, current_timestamp, nonce_cap, max_len, ordering } = settings; + if let Some(pending) = self.cached_pending.read().pending(block_number, current_timestamp, nonce_cap.as_ref(), max_len) { return pending; } // Double check after acquiring write lock let mut cached_pending = self.cached_pending.write(); - if let Some(pending) = cached_pending.pending(block_number, current_timestamp, nonce_cap.as_ref()) { + if let Some(pending) = cached_pending.pending(block_number, current_timestamp, nonce_cap.as_ref(), max_len) { return pending; } - let pending: Vec<_> = self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| i.collect()); + // In case we don't have a cached set, but we don't care about order + // just return the unordered set. + if let PendingOrdering::Unordered = ordering { + let ready = Self::ready(client, block_number, current_timestamp, nonce_cap); + return self.pool.read().unordered_pending(ready).take(max_len).collect(); + } + + let pending: Vec<_> = self.collect_pending(client, block_number, current_timestamp, nonce_cap, |i| { + i.take(max_len).collect() + }); *cached_pending = CachedPending { block_number, @@ -242,6 +260,7 @@ impl TransactionQueue { nonce_cap, has_local_pending: self.has_local_pending_transactions(), pending: Some(pending.clone()), + max_len, }; pending @@ -266,15 +285,27 @@ impl TransactionQueue { scoring::NonceAndGasPrice, Listener, >) -> T, + { + debug!(target: "txqueue", "Re-computing pending set for block: {}", block_number); + trace_time!("pool::collect_pending"); + let ready = Self::ready(client, block_number, current_timestamp, nonce_cap); + collect(self.pool.read().pending(ready)) + } + + fn ready( + client: C, + block_number: u64, + current_timestamp: u64, + nonce_cap: Option, + ) -> (ready::Condition, ready::State) where + C: client::NonceClient, { let pending_readiness = ready::Condition::new(block_number, current_timestamp); // don't mark any transactions as stale at this point. let stale_id = None; let state_readiness = ready::State::new(client, stale_id, nonce_cap); - let ready = (pending_readiness, state_readiness); - - collect(self.pool.read().pending(ready)) + (pending_readiness, state_readiness) } /// Culls all stalled transactions from the pool. @@ -415,6 +446,12 @@ impl TransactionQueue { let mut pool = self.pool.write(); (pool.listener_mut().1).0.add(f); } + + /// Check if pending set is cached. + #[cfg(test)] + pub fn is_pending_cached(&self) -> bool { + self.cached_pending.read().pending.is_some() + } } fn convert_error(err: txpool::Error) -> transaction::Error { @@ -440,7 +477,7 @@ mod tests { fn should_get_pending_transactions() { let queue = TransactionQueue::new(txpool::Options::default(), verifier::Options::default(), PrioritizationStrategy::GasPriceOnly); - let pending: Vec<_> = queue.pending(TestClient::default(), 0, 0, None); + let pending: Vec<_> = queue.pending(TestClient::default(), PendingSettings::all_prioritized(0, 0)); for tx in pending { assert!(tx.signed().nonce > 0.into()); diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index ac2e6b008e..ef83db4a90 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -18,7 +18,7 @@ use ethereum_types::U256; use transaction::{self, PendingTransaction}; use txpool; -use pool::{verifier, TransactionQueue, PrioritizationStrategy}; +use pool::{verifier, TransactionQueue, PrioritizationStrategy, PendingSettings, PendingOrdering}; pub mod tx; pub mod client; @@ -108,7 +108,7 @@ fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { // and then there should be only one transaction in current (the one with higher gas_price) assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 1); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); } @@ -133,7 +133,7 @@ fn should_move_all_transactions_from_future() { // then assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); assert_eq!(top[1].hash, hash2); } @@ -207,7 +207,7 @@ fn should_import_txs_from_same_sender() { txq.import(TestClient::new(), txs.local().into_vec()); // then - let top = txq.pending(TestClient::new(), 0 ,0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0 ,0)); assert_eq!(top[0].hash, hash); assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -229,7 +229,7 @@ fn should_prioritize_local_transactions_within_same_nonce_height() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(client, 0, 0, None); + let top = txq.pending(client, PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); // local should be first assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -251,7 +251,7 @@ fn should_prioritize_reimported_transactions_within_same_nonce_height() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); // retracted should be first assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -270,7 +270,7 @@ fn should_not_prioritize_local_transactions_with_different_nonce_height() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top[0].hash, hash); assert_eq!(top[1].hash, hash2); assert_eq!(top.len(), 2); @@ -288,7 +288,7 @@ fn should_put_transaction_to_futures_if_gap_detected() { // then assert_eq!(res, vec![Ok(()), Ok(())]); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top.len(), 1); assert_eq!(top[0].hash, hash); } @@ -308,9 +308,9 @@ fn should_handle_min_block() { assert_eq!(res, vec![Ok(()), Ok(())]); // then - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top.len(), 0); - let top = txq.pending(TestClient::new(), 1, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(1, 0)); assert_eq!(top.len(), 2); } @@ -341,7 +341,7 @@ fn should_move_transactions_if_gap_filled() { let res = txq.import(TestClient::new(), vec![tx, tx2].local()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); // when let res = txq.import(TestClient::new(), vec![tx1.local()]); @@ -349,7 +349,7 @@ fn should_move_transactions_if_gap_filled() { // then assert_eq!(txq.status().status.transaction_count, 3); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 3); } #[test] @@ -361,12 +361,12 @@ fn should_remove_transaction() { let res = txq.import(TestClient::default(), vec![tx, tx2].local()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); // when txq.cull(TestClient::new().with_nonce(124)); assert_eq!(txq.status().status.transaction_count, 1); - assert_eq!(txq.pending(TestClient::new().with_nonce(125), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new().with_nonce(125), PendingSettings::all_prioritized(0, 0)).len(), 1); txq.cull(TestClient::new().with_nonce(126)); // then @@ -384,19 +384,19 @@ fn should_move_transactions_to_future_if_gap_introduced() { let res = txq.import(TestClient::new(), vec![tx3, tx2].local()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); let res = txq.import(TestClient::new(), vec![tx].local()); assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 3); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 3); // when txq.remove(vec![&hash], true); // then assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); } #[test] @@ -447,7 +447,7 @@ fn should_prefer_current_transactions_when_hitting_the_limit() { assert_eq!(res, vec![Ok(())]); assert_eq!(txq.status().status.transaction_count, 1); - let top = txq.pending(TestClient::new(), 0, 0, None); + let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); assert_eq!(top.len(), 1); assert_eq!(top[0].hash, hash); assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(124.into())); @@ -494,19 +494,19 @@ fn should_accept_same_transaction_twice_if_removed() { let res = txq.import(TestClient::new(), txs.local().into_vec()); assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 2); // when txq.remove(vec![&hash], true); assert_eq!(txq.status().status.transaction_count, 1); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 0); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 0); let res = txq.import(TestClient::new(), vec![tx1].local()); assert_eq!(res, vec![Ok(())]); // then assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 2); } #[test] @@ -526,8 +526,8 @@ fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() { // then assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace), Ok(())]); assert_eq!(txq.status().status.transaction_count, 2); - assert_eq!(txq.pending(client.clone(), 0, 0, None)[0].signed().gas_price, U256::from(20)); - assert_eq!(txq.pending(client.clone(), 0, 0, None)[1].signed().gas_price, U256::from(2)); + assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[0].signed().gas_price, U256::from(20)); + assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[1].signed().gas_price, U256::from(2)); } #[test] @@ -569,7 +569,7 @@ fn should_return_valid_last_nonce_after_cull() { let client = TestClient::new().with_nonce(124); txq.cull(client.clone()); // tx2 should be not be promoted to current - assert_eq!(txq.pending(client.clone(), 0, 0, None).len(), 0); + assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0)).len(), 0); // then assert_eq!(txq.next_nonce(client.clone(), &sender), None); @@ -667,7 +667,7 @@ fn should_accept_local_transactions_below_min_gas_price() { assert_eq!(res, vec![Ok(())]); // then - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); } #[test] @@ -685,7 +685,7 @@ fn should_accept_local_service_transaction() { assert_eq!(res, vec![Ok(())]); // then - assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1); } #[test] @@ -726,15 +726,77 @@ fn should_not_return_transactions_over_nonce_cap() { assert_eq!(res, vec![Ok(()), Ok(()), Ok(())]); // when - let all = txq.pending(TestClient::new(), 0, 0, None); + let all = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); // This should invalidate the cache! - let limited = txq.pending(TestClient::new(), 0, 0, Some(123.into())); + let limited = txq.pending(TestClient::new(), PendingSettings { + block_number: 0, + current_timestamp: 0, + nonce_cap: Some(123.into()), + max_len: usize::max_value(), + ordering: PendingOrdering::Priority, + }); // then assert_eq!(all.len(), 3); assert_eq!(limited.len(), 1); } +#[test] +fn should_return_cached_pending_even_if_unordered_is_requested() { + // given + let txq = new_queue(); + let tx1 = Tx::default().signed(); + let (tx2_1, tx2_2)= Tx::default().signed_pair(); + let tx2_1_hash = tx2_1.hash(); + let res = txq.import(TestClient::new(), vec![tx1].unverified()); + assert_eq!(res, vec![Ok(())]); + let res = txq.import(TestClient::new(), vec![tx2_1, tx2_2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // when + let all = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)); + assert_eq!(all[0].hash, tx2_1_hash); + assert_eq!(all.len(), 3); + + // This should not invalidate the cache! + let limited = txq.pending(TestClient::new(), PendingSettings { + block_number: 0, + current_timestamp: 0, + nonce_cap: None, + max_len: 3, + ordering: PendingOrdering::Unordered, + }); + + // then + assert_eq!(all, limited); +} + +#[test] +fn should_return_unordered_and_not_populate_the_cache() { + // given + let txq = new_queue(); + let tx1 = Tx::default().signed(); + let (tx2_1, tx2_2)= Tx::default().signed_pair(); + let res = txq.import(TestClient::new(), vec![tx1].unverified()); + assert_eq!(res, vec![Ok(())]); + let res = txq.import(TestClient::new(), vec![tx2_1, tx2_2].local()); + assert_eq!(res, vec![Ok(()), Ok(())]); + + // when + // This should not invalidate the cache! + let limited = txq.pending(TestClient::new(), PendingSettings { + block_number: 0, + current_timestamp: 0, + nonce_cap: None, + max_len: usize::max_value(), + ordering: PendingOrdering::Unordered, + }); + + // then + assert_eq!(limited.len(), 3); + assert!(!txq.is_pending_cached()); +} + #[test] fn should_clear_cache_after_timeout_for_local() { // given @@ -748,12 +810,12 @@ fn should_clear_cache_after_timeout_for_local() { // This should populate cache and set timestamp to 1 // when - assert_eq!(txq.pending(TestClient::new(), 0, 1, None).len(), 0); - assert_eq!(txq.pending(TestClient::new(), 0, 1000, None).len(), 0); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1)).len(), 0); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1000)).len(), 0); // This should invalidate the cache and trigger transaction ready. // then - assert_eq!(txq.pending(TestClient::new(), 0, 1002, None).len(), 2); + assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1002)).len(), 2); } #[test] diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index ce30f3cd85..31af69eaa0 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -304,7 +304,7 @@ impl FullDependencies { let client = EthPubSubClient::new(self.client.clone(), self.remote.clone()); let h = client.handler(); self.miner.add_transactions_listener(Box::new(move |hashes| if let Some(h) = h.upgrade() { - h.new_transactions(hashes); + h.notify_new_transactions(hashes); })); if let Some(h) = client.handler().upgrade() { @@ -525,7 +525,7 @@ impl LightDependencies { let h = client.handler(); self.transaction_queue.write().add_listener(Box::new(move |transactions| { if let Some(h) = h.upgrade() { - h.new_transactions(transactions); + h.notify_new_transactions(transactions); } })); handler.extend_with(EthPubSub::to_delegate(client)); diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 338a892682..d227f45f53 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -36,7 +36,7 @@ jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = " jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } ethash = { path = "../ethash" } -ethcore = { path = "../ethcore" } +ethcore = { path = "../ethcore", features = ["test-helpers"] } ethcore-bytes = { path = "../util/bytes" } ethcore-crypto = { path = "../ethcore/crypto" } ethcore-devtools = { path = "../devtools" } diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index bbad2fe27d..c91070cbfb 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -85,7 +85,7 @@ impl Filterable for EthFilterClient where } fn pending_transactions_hashes(&self) -> Vec { - self.miner.ready_transactions(&*self.client) + self.miner.ready_transactions(&*self.client, usize::max_value(), miner::PendingOrdering::Priority) .into_iter() .map(|tx| tx.signed().hash()) .collect() diff --git a/rpc/src/v1/impls/eth_pubsub.rs b/rpc/src/v1/impls/eth_pubsub.rs index 11fef2e0bd..38162e8ea1 100644 --- a/rpc/src/v1/impls/eth_pubsub.rs +++ b/rpc/src/v1/impls/eth_pubsub.rs @@ -175,7 +175,7 @@ impl ChainNotificationHandler { } /// Notify all subscribers about new transaction hashes. - pub fn new_transactions(&self, hashes: &[H256]) { + pub fn notify_new_transactions(&self, hashes: &[H256]) { for subscriber in self.transactions_subscribers.read().values() { for hash in hashes { Self::notify(&self.remote, subscriber, pubsub::Result::TransactionHash((*hash).into())); diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 91db00ca30..6e93132b92 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -264,12 +264,13 @@ impl Parity for ParityClient { .map(Into::into) } - fn pending_transactions(&self) -> Result> { + fn pending_transactions(&self, limit: Trailing) -> Result> { let txq = self.light_dispatch.transaction_queue.read(); let chain_info = self.light_dispatch.client.chain_info(); Ok( txq.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) .into_iter() + .take(limit.unwrap_or_else(usize::max_value)) .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) .collect::>() ) diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index f18723eafe..d7c26014ed 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -303,15 +303,19 @@ impl Parity for ParityClient where .map(Into::into) } - fn pending_transactions(&self) -> Result> { + fn pending_transactions(&self, limit: Trailing) -> Result> { let block_number = self.client.chain_info().best_block_number; - let ready_transactions = self.miner.ready_transactions(&*self.client); + let ready_transactions = self.miner.ready_transactions( + &*self.client, + limit.unwrap_or_else(usize::max_value), + miner::PendingOrdering::Priority, + ); Ok(ready_transactions .into_iter() .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) .collect() - ) + ) } fn all_transactions(&self) -> Result> { diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 90201e346a..8d0ec23ae1 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -27,7 +27,7 @@ use ethcore::engines::EthEngine; use ethcore::error::Error; use ethcore::header::{BlockNumber, Header}; use ethcore::ids::BlockId; -use ethcore::miner::{MinerService, AuthoringParams}; +use ethcore::miner::{self, MinerService, AuthoringParams}; use ethcore::receipt::{Receipt, RichReceipt}; use ethereum_types::{H256, U256, Address}; use miner::pool::local_transactions::Status as LocalTransactionStatus; @@ -208,7 +208,7 @@ impl MinerService for TestMinerService { self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect() } - fn ready_transactions(&self, _chain: &C) -> Vec> { + fn ready_transactions(&self, _chain: &C, _max_len: usize, _ordering: miner::PendingOrdering) -> Vec> { self.queued_transactions() } diff --git a/rpc/src/v1/tests/mocked/eth_pubsub.rs b/rpc/src/v1/tests/mocked/eth_pubsub.rs index 0d886fe2f1..30c99fc67a 100644 --- a/rpc/src/v1/tests/mocked/eth_pubsub.rs +++ b/rpc/src/v1/tests/mocked/eth_pubsub.rs @@ -181,7 +181,7 @@ fn should_subscribe_to_pending_transactions() { assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); // Send new transactions - handler.new_transactions(&[5.into(), 7.into()]); + handler.notify_new_transactions(&[5.into(), 7.into()]); let (res, receiver) = receiver.into_future().wait().unwrap(); let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":"0x0000000000000000000000000000000000000000000000000000000000000005","subscription":"0x416d77337e24399d"}}"#; diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index f78cf8052e..1b9a7d09f5 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -141,7 +141,7 @@ build_rpc_trait! { /// Returns all pending transactions from transaction queue. #[rpc(name = "parity_pendingTransactions")] - fn pending_transactions(&self) -> Result>; + fn pending_transactions(&self, Trailing) -> Result>; /// Returns all transactions from transaction queue. /// diff --git a/transaction-pool/Cargo.toml b/transaction-pool/Cargo.toml index 8965c8cee0..0ba1790a47 100644 --- a/transaction-pool/Cargo.toml +++ b/transaction-pool/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Generic transaction pool." name = "transaction-pool" -version = "1.12.0" +version = "1.12.1" license = "GPL-3.0" authors = ["Parity Technologies "] diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index dcd52a3e7e..4bbf00ef24 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -15,7 +15,8 @@ // along with Parity. If not, see . use std::sync::Arc; -use std::collections::{HashMap, BTreeSet}; +use std::slice; +use std::collections::{hash_map, HashMap, BTreeSet}; use error; use listener::{Listener, NoopListener}; @@ -416,7 +417,16 @@ impl Pool where PendingIterator { ready, best_transactions, - pool: self + pool: self, + } + } + + /// Returns unprioritized list of ready transactions. + pub fn unordered_pending>(&self, ready: R) -> UnorderedIterator { + UnorderedIterator { + ready, + senders: self.transactions.iter(), + transactions: None, } } @@ -482,6 +492,50 @@ impl Pool where } } +/// An iterator over all pending (ready) transactions in unoredered fashion. +/// +/// NOTE: Current implementation will iterate over all transactions from particular sender +/// ordered by nonce, but that might change in the future. +/// +/// NOTE: the transactions are not removed from the queue. +/// You might remove them later by calling `cull`. +pub struct UnorderedIterator<'a, T, R, S> where + T: VerifiedTransaction + 'a, + S: Scoring + 'a, +{ + ready: R, + senders: hash_map::Iter<'a, T::Sender, Transactions>, + transactions: Option>>, +} + +impl<'a, T, R, S> Iterator for UnorderedIterator<'a, T, R, S> where + T: VerifiedTransaction, + R: Ready, + S: Scoring, +{ + type Item = Arc; + + fn next(&mut self) -> Option { + loop { + if let Some(transactions) = self.transactions.as_mut() { + if let Some(tx) = transactions.next() { + match self.ready.is_ready(&tx) { + Readiness::Ready => { + return Some(tx.transaction.clone()); + }, + state => trace!("[{:?}] Ignoring {:?} transaction.", tx.hash(), state), + } + } + } + + // otherwise fallback and try next sender + let next_sender = self.senders.next()?; + self.transactions = Some(next_sender.1.iter()); + } + } +} + + /// An iterator over all pending (ready) transactions. /// NOTE: the transactions are not removed from the queue. /// You might remove them later by calling `cull`. diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index 6edd60e60e..77c2528757 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -250,6 +250,66 @@ fn should_construct_pending() { assert_eq!(pending.next(), None); } +#[test] +fn should_return_unordered_iterator() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::default(); + + let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap(); + let tx2 = txq.import(b.tx().nonce(2).new()).unwrap(); + let tx3 = txq.import(b.tx().nonce(3).gas_price(4).new()).unwrap(); + //gap + txq.import(b.tx().nonce(5).new()).unwrap(); + + let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap(); + let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap(); + let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap(); + let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap(); + // gap + txq.import(b.tx().sender(1).nonce(5).new()).unwrap(); + + let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap(); + assert_eq!(txq.light_status().transaction_count, 11); + assert_eq!(txq.status(NonceReady::default()), Status { + stalled: 0, + pending: 9, + future: 2, + }); + assert_eq!(txq.status(NonceReady::new(1)), Status { + stalled: 3, + pending: 6, + future: 2, + }); + + // when + let all: Vec<_> = txq.unordered_pending(NonceReady::default()).collect(); + + let chain1 = vec![tx0, tx1, tx2, tx3]; + let chain2 = vec![tx5, tx6, tx7, tx8]; + let chain3 = vec![tx9]; + + assert_eq!(all.len(), chain1.len() + chain2.len() + chain3.len()); + + let mut options = vec![ + vec![chain1.clone(), chain2.clone(), chain3.clone()], + vec![chain2.clone(), chain1.clone(), chain3.clone()], + vec![chain2.clone(), chain3.clone(), chain1.clone()], + vec![chain3.clone(), chain2.clone(), chain1.clone()], + vec![chain3.clone(), chain1.clone(), chain2.clone()], + vec![chain1.clone(), chain3.clone(), chain2.clone()], + ].into_iter().map(|mut v| { + let mut first = v.pop().unwrap(); + for mut x in v { + first.append(&mut x); + } + first + }); + + assert!(options.any(|opt| all == opt)); +} + #[test] fn should_update_scoring_correctly() { // given -- GitLab From 0bb78814a60d1abc759ded380906a79cf3474f78 Mon Sep 17 00:00:00 2001 From: Vladyslav Lupashevskyi Date: Tue, 12 Jun 2018 10:31:14 +0300 Subject: [PATCH 238/263] Tx permission contract improvement (#8400) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Tx permission contract improvement * Use tuple for to address * Introduced ABI for deprecated tx permission contract * Improved ABI for tx permission contract with contract name, name hash and version * Introduced support for deprecated tx permission contract + fixed cache for the new version + introduced `target` for tx filter loging * Introduced test for the new tx permission contract version + old test renamed as deprecated * Removed empty lines * Introduced filter_only_sender return value in allowedTxTypes fn + improved caching * Introduced version checking for tx permission contract * Moved tx permission contract test genesis specs to separate files * handle queue import errors a bit more gracefully (#8385) * Some tweaks to main.rs for parity as a library (#8370) * Some tweaks to main.rs for parity as a library * Remove pub from PostExecutionAction * New Transaction Queue implementation (#8074) * Implementation of Verifier, Scoring and Ready. * Queue in progress. * TransactionPool. * Prepare for txpool release. * Miner refactor [WiP] * WiP reworking miner. * Make it compile. * Add some docs. * Split blockchain access to a separate file. * Work on miner API. * Fix ethcore tests. * Refactor miner interface for sealing/work packages. * Implement next nonce. * RPC compiles. * Implement couple of missing methdods for RPC. * Add transaction queue listeners. * Compiles! * Clean-up and parallelize. * Get rid of RefCell in header. * Revert "Get rid of RefCell in header." This reverts commit 0f2424c9b7319a786e1565ea2a8a6d801a21b4fb. * Override Sync requirement. * Fix status display. * Unify logging. * Extract some cheap checks. * Measurements and optimizations. * Fix scoring bug, heap size of bug and add cache * Disable tx queueing and parallel verification. * Make ethcore and ethcore-miner compile again. * Make RPC compile again. * Bunch of txpool tests. * Migrate transaction queue tests. * Nonce Cap * Nonce cap cache and tests. * Remove stale future transactions from the queue. * Optimize scoring and write some tests. * Simple penalization. * Clean up and support for different scoring algorithms. * Add CLI parameters for the new queue. * Remove banning queue. * Disable debug build. * Change per_sender limit to be 1% instead of 5% * Avoid cloning when propagating transactions. * Remove old todo. * Post-review fixes. * Fix miner options default. * Implement back ready transactions for light client. * Get rid of from_pending_block * Pass rejection reason. * Add more details to drop. * Rollback heap size of. * Avoid cloning hashes when propagating and include more details on rejection. * Fix tests. * Introduce nonces cache. * Remove uneccessary hashes allocation. * Lower the mem limit. * Re-enable parallel verification. * Add miner log. Don't check the type if not below min_gas_price. * Add more traces, fix disabling miner. * Fix creating pending blocks twice on AuRa authorities. * Fix tests. * re-use pending blocks in AuRa * Use reseal_min_period to prevent too frequent update_sealing. * Fix log to contain hash not sender. * Optimize local transactions. * Fix aura tests. * Update locks comments. * Get rid of unsafe Sync impl. * Review fixes. * Remove excessive matches. * Fix compilation errors. * Use new pool in private transactions. * Fix private-tx test. * Fix secret store tests. * Actually use gas_floor_target * Fix config tests. * Fix pool tests. * Address grumbles. * clarify that windows need perl and yasm (#8402) * Unify and limit rocksdb dependency places (#8371) * secret_store: remove kvdb_rocksdb dependency * cli: init db mod for open dispatch * cli: move db, client_db, restoration_db, secretstore_db to a separate mod * migration: rename to migration-rocksdb and remove ethcore-migrations * ethcore: re-move kvdb-rocksdb dep to test * mark test_helpers as test only and fix migration mod naming * Move restoration_db_handler to test_helpers_internal * Fix missing preambles in test_helpers_internal and rocksdb/helpers * Move test crates downward * Fix missing docs * cli, db::open_db: move each argument to a separate line * Use featuregate instead of dead code for `open_secretstore_db` * Move pathbuf import to open_secretstore_db Because it's only used there behind a feature gate * Use tokio::spawn in secret_store listener and fix Uri (#8373) * Directly wait for future to resolve in a threadpool * Ignore return value * Use path.starts_with instead of req_uri.is_absolute The later now means something else in hyper 0.11.. * Use tokio::spawn * typo: remove accidential unsafe impl * remove Tendermint extra_info due to seal inconsistencies (#8367) * More code refactoring to integrate Duration (#8322) * More code refactoring to integrate Duration * Fix typo * Fix tests * More test fix * tokio-core v0.1.16 -> v0.1.17 (#8408) * Replace legacy Rlp with UntrustedRlp and use in ethcore rlp views (#8316) * WIP * Replace Rlp with UntrustedRlp in views, explicity unwrap with expect First pass to get it to compile. Need to figure out whether to do this or to propogate Errors upstream, which would require many more changes to dependent code. If we do this way we are assuming that the views are always used in a context where the rlp is trusted to be valid e.g. when reading from our own DB. So need to fid out whether views are used with data received from an untrusted (e.g. extrernal peer). * Remove original Rlp impl, rename UntrustedRlp -> Rlp * Create rlp views with view! macro to record debug info Views are assumed to be over valid rlp, so if there is a decoding error we record where the view was created in the first place and report it in the expect * Use $crate in view! macro to avoid import, fix tests * Expect valid rlp in decode functions for now * Replace spaces with tabs in new file * Add doc tests for creating views with macro * Update rlp docs to reflect removing of UntrustedRlp * Replace UntrustedRlp usages in private-tx merge * Fix TODO comments (#8413) * update zip to 0.3 (#8381) * update zip to 0.3 * enable zip deflate feature * typo, docs parity_chainId: empty string -> None (#8434) * Fix receipts stripping. (#8414) * Changelogs for 1.9.6 and 1.10.1 (#8411) * Add changelog for 1.9.6 * Add Changelog for 1.10.1 * Move ethcore::Error to error_chain (#8386) * WIP * Convert Ethcore error to use error_chain * Use error_chain for ImportError and BlockImportError * Fix error pattern matches for error_chain in miner * Implement explicit From for AccountsError * Fix pattern matches for ErrorKinds * Handle ethcore error_chain in light client * Explicitly define Result type to avoid shadowing * Fix remaining Error pattern matches * Fix tab space formatting * Helps if the tests compile * Fix error chain matching after merge * remove From::from. (#8390) * Some tiny modifications. 1. fix some typo in the comment. 2. sort the order of methods in 'impl state::Backend for StateDB` * Remove the clone of code_cache, as it has been done in clone_basic. * remove From::from. It seems not necessary. * Use forked app_dirs crate for reverted Windows dir behavior (#8438) * Remove unused appdirs dependency in CLI * Use forked app_dirs crate for reverted Windows dir behavior * Permission fix (#8441) * Block reward contract (#8419) * engine: add block reward contract abi and helper client * aura: add support for block reward contract * engine: test block reward contract client * aura: test block reward contract * engine + aura: add missing docs * engine: share SystemCall type alias * aura: add transition for block reward contract * engine: fix example block reward contract source link and bytecode * Improve VM executor stack size estimation rules (#8439) * Improve VM executor stack size estimation rules * typo: docs add "(Debug build)" comment * Fix an off by one typo and set minimal stack size This avoids the case if `depth_threshold == max_depth`. Usually setting stack size to zero will just rebound it to platform minimal stack size, but we set it here just in case. * Use saturating_sub to avoid potential overflow * Private transactions processing error handling (#8431) * Integration test for private transaction returned * Do not interrupt verification in case of errors * Helpers use specified * Review comments fixed * Update Cargo hidapi-rs dependency (#8447) * Allow 32 bit pipelines to fail (#8454) * Disable 32bit tragets for gitlab * Rename linux pipelines * Update wasmi (#8452) * Return error in case eth_call returns VM errors (#8448) * Add VMError generator * Return executed exceptions in eth_call * ParityShell::open `Return result` (#8377) * start * add error handling for winapi * fix typo * fix warnings and windows errors * formatting * Address review comments * fix docker build (#8462) * Add changelog for 1.9.7 and 1.10.2 (#8460) * Add changelog for 1.9.7 * Add Changelog for 1.10.2 * Apply proper markdown * Run a spellchecker :) * Be pedantic about the 32-bit pipelines :) * fix typos in vm description comment (#8446) * Use rename_all for RichBlock and RichHeader serialization (#8471) * typo: fix a resolved TODO comment * Use rename_all instead of individual renames * Don't require write lock when fetching status. (#8481) * Bump master to 1.12 (#8477) * Bump master to 1.12 * Bump crates to 1.12 * Bump mac installer version to 1.12 * Update Gitlab scripts * Fix snap builds (#8483) * Update hardcodedSync for Ethereum, Kovan, and Ropsten (#8489) * Update wasmi and pwasm-utils (#8493) * Update wasmi to 0.2 New wasmi supports 32bit platforms and no longer requires a special feature to build for such platforms. * Update pwasm-utils to 0.1.5 * Remove three old warp boot nodes. (#8497) * Return error if RLP size of transaction exceeds the limit (#8473) * Return error if RLP size of transaction exceeds the limit * Review comments fixed * RLP check moved to verifier, corresponding pool test added * `duration_ns: u64 -> duration: Duration` (#8457) * duration_ns: u64 -> duration: Duration * format on millis {:.2} -> {} * Remove unused dependency `bigint` (#8505) * remove unused dependency bigint in * remove bigint in rpc_cli * Show imported messages for light client (#8517) * Directly return None if tracing is disabled (#8504) * Directly return None if tracing is disabled * Address gumbles: release read locks as fast as possible * Hardware Wallet trait (#8071) * getting started with replacing HardwareWalletManager * trezor and ledger impls the new trait with some drawbacks * Everything move to the new trait * It required lifetime annotations in the trait because [u8] in unsized * Lets now start moving entry point from HardwareWalletManager * rename trait to Wallet * move thread management to the actual wallets * Moved thread management to each respective Wallet * Cleaned up pub items that is needed to be pub * Wallet trait more or less finished * Cleaned up docs * fix tests * omit removed docs * fix spelling, naming och remove old comments * ledger test is broken, add correct logging format * So locally on my machine Linux Ubuntu 17.10 the test doesn't panic but on the CI server libusb::Context::new() fails which I don't understand because it has worked before * Additionally the ledger test is optional so I lean toward ignoring it the CI Server * ignore hardware tests by default * more verbose checking in ledger test * SecretStore: merge two types of errors into single one + Error::is_non_fatal (#8357) * SecretStore: error unify initial commit SecretStore: pass real error in error messages SecretStore: is_internal_error -> Error::is_non_fatal warnings SecretStore: ConsensusTemporaryUnreachable fix after merge removed comments removed comments SecretStore: updated HTTP error responses SecretStore: more ConsensusTemporaryUnreachable tests fix after rebase * fixed grumbles * use HashSet in tests * Enable WebAssembly and Byzantium for Ellaism (#8520) * Enable WebAssembly and Byzantium for Ellaism * Fix indentation * Remove empty lines * More changes for Android (#8421) * Transaction Pool improvements (#8470) * Don't use ethereum_types in transaction pool. * Hide internal insertion_id. * Fix tests. * Review grumbles. * Fetching logs by hash in blockchain database (#8463) * Fetch logs by hash in blockchain database * Fix tests * Add unit test for branch block logs fetching * Add docs that blocks must already be sorted * Handle branch block cases properly * typo: empty -> is_empty * Remove return_empty_if_none by using a closure * Use BTreeSet to avoid sorting again * Move is_canon to BlockChain * typo: pass value by reference * Use loop and wrap inside blocks to simplify the code Borrowed from https://github.com/paritytech/parity/pull/8463#discussion_r183453326 * typo: missed a comment * Pass on storage keys tracing to handle the case when it is not modified (#8491) * Pass on storage keys even if it is not modified * typo: account and storage query `to_pod_diff` builds both `touched_addresses` merge and storage keys merge. * Fix tests * Use state query directly because of suicided accounts * Fix a RefCell borrow issue * Add tests for unmodified storage trace * Address grumbles * typo: remove unwanted empty line * ensure_cached compiles with the original signature * Don't panic in import_block if invalid rlp (#8522) * Don't panic in import_block if invalid rlp * Remove redundant type annotation * Replace RLP header view usage with safe decoding Using the view will panic with invalid RLP. Here we use Rlp decoding directly which will return a `Result<_, DecoderError>`. While this path currently should not have any invalid RLP - it makes it safer if ever called with invalid RLP from other code paths. * Remove expect (#8536) * Remove expect and propagate rlp::DecoderErrors as TrieErrors * EIP 145: Bitwise shifting instructions in EVM (#8451) * Add SHL, SHR, SAR opcodes * Add have_bitwise_shifting schedule flag * Add all EIP tests for SHL * Add SHR implementation and tests * Implement SAR and add tests * Add eip145transition config param * Change map_or to map_or_else when possible * Consolidate crypto functionality in `ethcore-crypto`. (#8432) * Consolidate crypto functionality in `ethcore-crypto`. - Move `ecdh`/`ecies` modules to `ethkey`. - Refactor `ethcore-crypto` to use file per module. - Replace `subtle` with `ethcore_crypto::is_equal`. - Add `aes_gcm` module to `ethcore-crypto`. * Rename `aes::{encrypt,decrypt,decrypt_cbc}` ... ... to `aes::{encrypt_128_ctr,decrypt_128_ctr,decrypt_128_cbc}`. * ethcore, rpc, machine: refactor block reward application and tracing (#8490) * Keep all enacted blocks notify in order (#8524) * Keep all enacted blocks notify in order * Collect is unnecessary * Update ChainNotify to use ChainRouteType * Fix all ethcore fn defs * Wrap the type within ChainRoute * Fix private-tx and sync api * Fix secret_store API * Fix updater API * Fix rpc api * Fix informant api * Eagerly cache enacted/retracted and remove contain_enacted/retracted * Fix indent * tests: should use full expr form for struct constructor * Use into_enacted_retracted to further avoid copy * typo: not a function * rpc/tests: ChainRoute -> ChainRoute::new * Node table sorting according to last contact data (#8541) * network-devp2p: sort nodes in node table using last contact data * network-devp2p: rename node contact types in node table json output * network-devp2p: fix node table tests * network-devp2p: note node failure when failed to establish connection * network-devp2p: handle UselessPeer error * network-devp2p: note failure when marking node as useless * Rlp decode returns Result (#8527) rlp::decode returns Result Make a best effort to handle decoding errors gracefully throughout the code, using `expect` where the value is guaranteed to be valid (and in other places where it makes sense). * Parity as a library (#8412) * Parity as a library * Fix concerns * Allow using a null on_client_restart_cb * Fix more concerns * Test the C library in test.sh * Reduce CMake version to 3.5 * Move the clib test before cargo test * Add println in test * Trace precompiled contracts when the transfer value is not zero (#8486) * Trace precompiled contracts when the transfer value is not zero * Add tests for precompiled CALL tracing * Use byzantium test machine for the new test * Add notes in comments on why we don't trace all precompileds * Use is_transferred instead of transferred * Don't block sync when importing old blocks (#8530) * Alter IO queueing. * Don't require IoMessages to be Clone * Ancient blocks imported via IoChannel. * Get rid of private transactions io message. * Get rid of deadlock and fix disconnected handler. * Revert to old disconnect condition. * Fix tests. * Fix deadlock. * Make trace-time publishable. (#8568) * Remove State::replace_backend (#8569) * Refactoring `ethcore-sync` - Fixing warp-sync barrier (#8543) * Start dividing sync chain : first supplier method * WIP - updated chain sync supplier * Finish refactoring the Chain Sync Supplier * Create Chain Sync Requester * Add Propagator for Chain Sync * Add the Chain Sync Handler * Move tests from mod -> handler * Move tests to propagator * Refactor SyncRequester arguments * Refactoring peer fork header handler * Fix wrong highest block number in snapshot sync * Small refactor... * Address PR grumbles * Retry failed CI job * Fix tests * PR Grumbles * Decoding headers can fail (#8570) * rlp::decode returns Result * Fix journaldb to handle rlp::decode Result * Fix ethcore to work with rlp::decode returning Result * Light client handles rlp::decode returning Result * Fix tests in rlp_derive * Fix tests * Cleanup * cleanup * Allow panic rather than breaking out of iterator * Let decoding failures when reading from disk blow up * syntax * Fix the trivial grumbles * Fix failing tests * Make Account::from_rlp return Result * Syntx, sigh * Temp-fix for decoding failures * Header::decode returns Result Handle new return type throughout the code base. * Do not continue reading from the DB when a value could not be read * Fix tests * Handle header decoding in light_sync * Handling header decoding errors * Let the DecodeError bubble up unchanged * Remove redundant error conversion * Update CHANGELOG for 1.9, 1.10, and 1.11 (#8556) * Move changelog for 1.10.x * Mark 1.9 EOL * Prepare changelog for 1.10.3 stable * Prepare changelog for 1.11.0 stable * Update changelogs * Update CHANGELOG for 1.10.3 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Format changelog * Handle socket address parsing errors (#8545) Unpack errors and check for io::ErrorKind::InvalidInput and return our own AddressParse error. Remove the foreign link to std::net::AddrParseError and add an `impl From` for that error. Test parsing properly. * Remove unnecessary cloning in overwrite_with (#8580) * Remove unnecessary cloning in overwrite_with * Remove into_iter * changelog nit (#8585) * Rename `whisper-cli binary` to `whisper` (#8579) * rename whisper-cli binary to whisper * fix tests * Add whisper CLI to the pipelines (#8578) * Add whisper CLI to the pipelines * Address todo, ref #8579 * Added Dockerfile for alpine linux by @andresilva, closes #3565 (#8587) * Changelog and Readme (#8591) * Move changelog for 1.10.x * Mark 1.9 EOL * Prepare changelog for 1.10.3 stable * Prepare changelog for 1.11.0 stable * Update changelogs * Update CHANGELOG for 1.10.3 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Update CHANGELOG for 1.11.0 beta * Format changelog * Update README for 1.11 * Fix typo * Attempt to fix intermittent test failures (#8584) Occasionally should_return_correct_nonces_when_dropped_because_of_limit fails, possibly because of multiple threads competing to finish. See CI logs here for an example: https://gitlab.parity.io/parity/parity/-/jobs/86738 * Make mio optional in ethcore-io (#8537) * Make mio optional in ethcore-io * Add some annotations, plus a check for features * Increase timer for test * Fix Parity UI link (#8600) Fix link https://github.com/paritytech/parity/issues/8599 * fix compiler warning (#8590) * Block::decode() returns Result (#8586) * block_header can fail so return Result (#8581) * block_header can fail so return Result * Restore previous return type based on feedback * Fix failing doc tests running on non-code * Remove inject.js server-side injection for dapps (#8539) * Remove inject.js server-side injection for dapps * Remove dapps test `should_inject_js` Parity doesn't inject a