commit
e179b0e0c2
58
Cargo.lock
generated
58
Cargo.lock
generated
@ -244,7 +244,7 @@ dependencies = [
|
|||||||
"ethminer 1.0.0",
|
"ethminer 1.0.0",
|
||||||
"ethsync 1.0.2",
|
"ethsync 1.0.2",
|
||||||
"jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-http-server 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-http-server 5.0.0 (git+https://github.com/debris/jsonrpc-http-server.git)",
|
||||||
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -395,22 +395,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.8.0"
|
version = "0.9.0-mio"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/hyperium/hyper?branch=mio#bf42e7563b7d52f334a1b25ec3dccf031febb990"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cookie 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cookie 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"httparse 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"httparse 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"language-tags 0.2.2 (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.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rotor 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"typeable 0.1.2 (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.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -451,10 +452,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-http-server"
|
name = "jsonrpc-http-server"
|
||||||
version = "3.0.1"
|
version = "5.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/debris/jsonrpc-http-server.git#76fa443982b40665721fe6b1ece42fc0a53be996"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.9.0-mio (git+https://github.com/hyperium/hyper?branch=mio)",
|
||||||
"jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -531,14 +532,6 @@ dependencies = [
|
|||||||
"serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mime"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -689,6 +682,11 @@ dependencies = [
|
|||||||
"syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.3.14"
|
version = "0.3.14"
|
||||||
@ -732,6 +730,18 @@ dependencies = [
|
|||||||
"librocksdb-sys 0.2.3 (git+https://github.com/arkpar/rust-rocksdb.git)",
|
"librocksdb-sys 0.2.3 (git+https://github.com/arkpar/rust-rocksdb.git)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rotor"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quick-error 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"void 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rpassword"
|
name = "rpassword"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@ -987,6 +997,15 @@ dependencies = [
|
|||||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.18 (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.6 (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]]
|
[[package]]
|
||||||
name = "vergen"
|
name = "vergen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -996,6 +1015,11 @@ dependencies = [
|
|||||||
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
||||||
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
||||||
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
||||||
"enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@parity-node-zero.ethcore.io:30303"
|
"enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@zero.parity.io:30303"
|
||||||
],
|
],
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
@ -138,7 +138,7 @@ impl Account {
|
|||||||
/// get someone who knows to call `note_code`.
|
/// get someone who knows to call `note_code`.
|
||||||
pub fn code(&self) -> Option<&[u8]> {
|
pub fn code(&self) -> Option<&[u8]> {
|
||||||
match self.code_hash {
|
match self.code_hash {
|
||||||
Some(SHA3_EMPTY) | None if self.code_cache.is_empty() => Some(&self.code_cache),
|
Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache),
|
||||||
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
|
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
|
||||||
None => Some(&self.code_cache),
|
None => Some(&self.code_cache),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -116,6 +116,7 @@ struct VerifyingBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct QueueSignal {
|
struct QueueSignal {
|
||||||
|
deleting: Arc<AtomicBool>,
|
||||||
signalled: AtomicBool,
|
signalled: AtomicBool,
|
||||||
message_channel: IoChannel<NetSyncMessage>,
|
message_channel: IoChannel<NetSyncMessage>,
|
||||||
}
|
}
|
||||||
@ -123,10 +124,16 @@ struct QueueSignal {
|
|||||||
impl QueueSignal {
|
impl QueueSignal {
|
||||||
#[cfg_attr(feature="dev", allow(bool_comparison))]
|
#[cfg_attr(feature="dev", allow(bool_comparison))]
|
||||||
fn set(&self) {
|
fn set(&self) {
|
||||||
|
// Do not signal when we are about to close
|
||||||
|
if self.deleting.load(AtomicOrdering::Relaxed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
|
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
|
||||||
self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message");
|
self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&self) {
|
fn reset(&self) {
|
||||||
self.signalled.store(false, AtomicOrdering::Relaxed);
|
self.signalled.store(false, AtomicOrdering::Relaxed);
|
||||||
}
|
}
|
||||||
@ -150,8 +157,12 @@ impl BlockQueue {
|
|||||||
bad: Mutex::new(HashSet::new()),
|
bad: Mutex::new(HashSet::new()),
|
||||||
});
|
});
|
||||||
let more_to_verify = Arc::new(Condvar::new());
|
let more_to_verify = Arc::new(Condvar::new());
|
||||||
let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel });
|
|
||||||
let deleting = Arc::new(AtomicBool::new(false));
|
let deleting = Arc::new(AtomicBool::new(false));
|
||||||
|
let ready_signal = Arc::new(QueueSignal {
|
||||||
|
deleting: deleting.clone(),
|
||||||
|
signalled: AtomicBool::new(false),
|
||||||
|
message_channel: message_channel
|
||||||
|
});
|
||||||
let empty = Arc::new(Condvar::new());
|
let empty = Arc::new(Condvar::new());
|
||||||
let panic_handler = PanicHandler::new_in_arc();
|
let panic_handler = PanicHandler::new_in_arc();
|
||||||
|
|
||||||
@ -431,12 +442,14 @@ impl MayPanic for BlockQueue {
|
|||||||
|
|
||||||
impl Drop for BlockQueue {
|
impl Drop for BlockQueue {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
trace!(target: "shutdown", "[BlockQueue] Closing...");
|
||||||
self.clear();
|
self.clear();
|
||||||
self.deleting.store(true, AtomicOrdering::Release);
|
self.deleting.store(true, AtomicOrdering::Release);
|
||||||
self.more_to_verify.notify_all();
|
self.more_to_verify.notify_all();
|
||||||
for t in self.verifiers.drain(..) {
|
for t in self.verifiers.drain(..) {
|
||||||
t.join().unwrap();
|
t.join().unwrap();
|
||||||
}
|
}
|
||||||
|
trace!(target: "shutdown", "[BlockQueue] Closed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ use service::{NetSyncMessage, SyncMessage};
|
|||||||
use env_info::LastHashes;
|
use env_info::LastHashes;
|
||||||
use verification::*;
|
use verification::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use transaction::{LocalizedTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, SignedTransaction, Action};
|
||||||
use extras::TransactionAddress;
|
use extras::TransactionAddress;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
@ -38,7 +38,7 @@ use block_queue::{BlockQueue, BlockQueueInfo};
|
|||||||
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
||||||
use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient};
|
use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient};
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use executive::{Executive, Executed};
|
use executive::{Executive, Executed, TransactOptions, contract_address};
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
pub use blockchain::CacheSize as BlockChainCacheSize;
|
pub use blockchain::CacheSize as BlockChainCacheSize;
|
||||||
|
|
||||||
@ -419,7 +419,8 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
// give the sender max balance
|
// give the sender max balance
|
||||||
state.sub_balance(&sender, &balance);
|
state.sub_balance(&sender, &balance);
|
||||||
state.add_balance(&sender, &U256::max_value());
|
state.add_balance(&sender, &U256::max_value());
|
||||||
Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t)
|
let options = TransactOptions { tracing: false, check_nonce: false };
|
||||||
|
Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO [todr] Should be moved to miner crate eventually.
|
// TODO [todr] Should be moved to miner crate eventually.
|
||||||
@ -573,8 +574,10 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
// TODO: to fix this, query all previous transaction receipts and retrieve their gas usage
|
// TODO: to fix this, query all previous transaction receipts and retrieve their gas usage
|
||||||
cumulative_gas_used: receipt.gas_used,
|
cumulative_gas_used: receipt.gas_used,
|
||||||
gas_used: receipt.gas_used,
|
gas_used: receipt.gas_used,
|
||||||
// TODO: to fix this, store created contract address in db
|
contract_address: match tx.action {
|
||||||
contract_address: None,
|
Action::Call(_) => None,
|
||||||
|
Action::Create => Some(contract_address(&tx.sender().unwrap(), &tx.nonce))
|
||||||
|
},
|
||||||
logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry {
|
logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry {
|
||||||
entry: log,
|
entry: log,
|
||||||
block_hash: block_hash.clone(),
|
block_hash: block_hash.clone(),
|
||||||
|
@ -36,6 +36,14 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
|||||||
From::from(stream.out().sha3())
|
From::from(stream.out().sha3())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transaction execution options.
|
||||||
|
pub struct TransactOptions {
|
||||||
|
/// Enable call tracing.
|
||||||
|
pub tracing: bool,
|
||||||
|
/// Check transaction nonce before execution.
|
||||||
|
pub check_nonce: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Transaction execution receipt.
|
/// Transaction execution receipt.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Executed {
|
pub struct Executed {
|
||||||
@ -104,7 +112,7 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This funtion should be used to execute transaction.
|
/// This funtion should be used to execute transaction.
|
||||||
pub fn transact(&'a mut self, t: &SignedTransaction) -> Result<Executed, Error> {
|
pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, Error> {
|
||||||
let sender = try!(t.sender());
|
let sender = try!(t.sender());
|
||||||
let nonce = self.state.nonce(&sender);
|
let nonce = self.state.nonce(&sender);
|
||||||
|
|
||||||
@ -118,9 +126,11 @@ impl<'a> Executive<'a> {
|
|||||||
let init_gas = t.gas - base_gas_required;
|
let init_gas = t.gas - base_gas_required;
|
||||||
|
|
||||||
// validate transaction nonce
|
// validate transaction nonce
|
||||||
|
if options.check_nonce {
|
||||||
if t.nonce != nonce {
|
if t.nonce != nonce {
|
||||||
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
|
return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce }));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// validate if transaction fits into given block
|
// validate if transaction fits into given block
|
||||||
if self.info.gas_used + t.gas > self.info.gas_limit {
|
if self.info.gas_used + t.gas > self.info.gas_limit {
|
||||||
@ -703,7 +713,8 @@ mod tests {
|
|||||||
|
|
||||||
let executed = {
|
let executed = {
|
||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t).unwrap()
|
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||||
|
ex.transact(&t, opts).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(executed.gas, U256::from(100_000));
|
assert_eq!(executed.gas, U256::from(100_000));
|
||||||
@ -736,7 +747,8 @@ mod tests {
|
|||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t)
|
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||||
|
ex.transact(&t, opts)
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
@ -767,7 +779,8 @@ mod tests {
|
|||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t)
|
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||||
|
ex.transact(&t, opts)
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
@ -800,7 +813,8 @@ mod tests {
|
|||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t)
|
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||||
|
ex.transact(&t, opts)
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
@ -833,7 +847,8 @@ mod tests {
|
|||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
ex.transact(&t)
|
let opts = TransactOptions { check_nonce: true, tracing: false };
|
||||||
|
ex.transact(&t, opts)
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use engine::Engine;
|
use engine::Engine;
|
||||||
use executive::Executive;
|
use executive::{Executive, TransactOptions};
|
||||||
use account_db::*;
|
use account_db::*;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[cfg(feature = "json-tests")]
|
#[cfg(feature = "json-tests")]
|
||||||
@ -212,7 +212,8 @@ impl State {
|
|||||||
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction) -> ApplyResult {
|
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction) -> ApplyResult {
|
||||||
// let old = self.to_pod();
|
// let old = self.to_pod();
|
||||||
|
|
||||||
let e = try!(Executive::new(self, env_info, engine).transact(t));
|
let options = TransactOptions { tracing: false, check_nonce: true };
|
||||||
|
let e = try!(Executive::new(self, env_info, engine).transact(t, options));
|
||||||
|
|
||||||
// TODO uncomment once to_pod() works correctly.
|
// TODO uncomment once to_pod() works correctly.
|
||||||
// trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
|
// trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
|
||||||
|
@ -109,6 +109,12 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Query pending transactions for hash
|
/// Query pending transactions for hash
|
||||||
fn transaction(&self, hash: &H256) -> Option<SignedTransaction>;
|
fn transaction(&self, hash: &H256) -> Option<SignedTransaction>;
|
||||||
|
|
||||||
|
/// Get a list of all pending transactions.
|
||||||
|
fn pending_transactions(&self) -> Vec<SignedTransaction>;
|
||||||
|
|
||||||
|
/// Returns highest transaction nonce for given address.
|
||||||
|
fn last_nonce(&self, address: &Address) -> Option<U256>;
|
||||||
|
|
||||||
/// Suggested gas price
|
/// Suggested gas price
|
||||||
fn sensible_gas_price(&self) -> U256 { x!(20000000000u64) }
|
fn sensible_gas_price(&self) -> U256 { x!(20000000000u64) }
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,15 @@ impl MinerService for Miner {
|
|||||||
queue.find(hash)
|
queue.find(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
|
let queue = self.transaction_queue.lock().unwrap();
|
||||||
|
queue.top_transactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_nonce(&self, address: &Address) -> Option<U256> {
|
||||||
|
self.transaction_queue.lock().unwrap().last_nonce(address)
|
||||||
|
}
|
||||||
|
|
||||||
fn update_sealing(&self, chain: &BlockChainClient) {
|
fn update_sealing(&self, chain: &BlockChainClient) {
|
||||||
if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
|
||||||
let current_no = chain.chain_info().best_block_number;
|
let current_no = chain.chain_info().best_block_number;
|
||||||
|
@ -213,14 +213,15 @@ impl TransactionSet {
|
|||||||
self.by_priority
|
self.by_priority
|
||||||
.iter()
|
.iter()
|
||||||
.skip(self.limit)
|
.skip(self.limit)
|
||||||
.map(|order| by_hash.get(&order.hash).expect("Inconsistency in queue detected."))
|
.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()))
|
.map(|tx| (tx.sender(), tx.nonce()))
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
for (sender, nonce) in to_drop {
|
for (sender, nonce) in to_drop {
|
||||||
let order = self.drop(&sender, &nonce).expect("Dropping transaction found in priority queue failed.");
|
let order = self.drop(&sender, &nonce).expect("Transaction has just been found in `by_priority`; so it is in `by_address` also.");
|
||||||
by_hash.remove(&order.hash).expect("Inconsistency in queue.");
|
by_hash.remove(&order.hash).expect("Hash found in `by_priorty` matches the one dropped; so it is included in `by_hash`");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +498,7 @@ impl TransactionQueue {
|
|||||||
pub fn top_transactions(&self) -> Vec<SignedTransaction> {
|
pub fn top_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
self.current.by_priority
|
self.current.by_priority
|
||||||
.iter()
|
.iter()
|
||||||
.map(|t| self.by_hash.get(&t.hash).expect("Transaction Queue Inconsistency"))
|
.map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"))
|
||||||
.map(|t| t.transaction.clone())
|
.map(|t| t.transaction.clone())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -523,6 +524,11 @@ impl TransactionQueue {
|
|||||||
self.last_nonces.clear();
|
self.last_nonces.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns highest transaction nonce for given address.
|
||||||
|
pub fn last_nonce(&self, address: &Address) -> Option<U256> {
|
||||||
|
self.last_nonces.get(address).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if there are any transactions in `future` that should actually be promoted to `current`
|
/// Checks if there are any transactions in `future` that should actually be promoted to `current`
|
||||||
/// (because nonce matches).
|
/// (because nonce matches).
|
||||||
fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) {
|
fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) {
|
||||||
@ -1255,4 +1261,29 @@ mod test {
|
|||||||
assert_eq!(stats.future, 0);
|
assert_eq!(stats.future, 0);
|
||||||
assert_eq!(stats.pending, 1);
|
assert_eq!(stats.pending, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_none_when_transaction_from_given_address_does_not_exist() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::new();
|
||||||
|
|
||||||
|
// 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::new();
|
||||||
|
let tx = new_tx();
|
||||||
|
let from = tx.sender().unwrap();
|
||||||
|
let nonce = tx.nonce;
|
||||||
|
let details = |a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
|
||||||
|
|
||||||
|
// when
|
||||||
|
txq.add(tx, &details).unwrap();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(txq.last_nonce(&from), Some(nonce));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,8 @@ use ethminer::{Miner, MinerService};
|
|||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use daemonize::Daemonize;
|
use daemonize::Daemonize;
|
||||||
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
||||||
|
#[cfg(feature = "rpc")]
|
||||||
|
use rpc::Server as RpcServer;
|
||||||
|
|
||||||
fn die_with_message(msg: &str) -> ! {
|
fn die_with_message(msg: &str) -> ! {
|
||||||
println!("ERROR: {}", msg);
|
println!("ERROR: {}", msg);
|
||||||
@ -77,7 +79,7 @@ Parity. Ethereum Client.
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
parity daemon <pid-file> [options]
|
parity daemon <pid-file> [options]
|
||||||
parity account (new | list)
|
parity account (new | list) [options]
|
||||||
parity [options]
|
parity [options]
|
||||||
|
|
||||||
Protocol Options:
|
Protocol Options:
|
||||||
@ -88,7 +90,7 @@ Protocol Options:
|
|||||||
-d --db-path PATH Specify the database & configuration directory path
|
-d --db-path PATH Specify the database & configuration directory path
|
||||||
[default: $HOME/.parity].
|
[default: $HOME/.parity].
|
||||||
--keys-path PATH Specify the path for JSON key files to be found
|
--keys-path PATH Specify the path for JSON key files to be found
|
||||||
[default: $HOME/.web3/keys].
|
[default: $HOME/.parity/keys].
|
||||||
--identity NAME Specify your node's name.
|
--identity NAME Specify your node's name.
|
||||||
|
|
||||||
Account Options:
|
Account Options:
|
||||||
@ -258,10 +260,10 @@ fn setup_rpc_server(
|
|||||||
sync: Arc<EthSync>,
|
sync: Arc<EthSync>,
|
||||||
secret_store: Arc<AccountService>,
|
secret_store: Arc<AccountService>,
|
||||||
miner: Arc<Miner>,
|
miner: Arc<Miner>,
|
||||||
url: &str,
|
url: &SocketAddr,
|
||||||
cors_domain: &str,
|
cors_domain: &str,
|
||||||
apis: Vec<&str>
|
apis: Vec<&str>
|
||||||
) -> Option<Arc<PanicHandler>> {
|
) -> RpcServer {
|
||||||
use rpc::v1::*;
|
use rpc::v1::*;
|
||||||
|
|
||||||
let server = rpc::RpcServer::new();
|
let server = rpc::RpcServer::new();
|
||||||
@ -279,8 +281,16 @@ fn setup_rpc_server(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(server.start_http(url, cors_domain, ::num_cpus::get()))
|
let start_result = server.start_http(url, cors_domain);
|
||||||
|
match start_result {
|
||||||
|
Err(rpc::RpcServerError::IoError(err)) => die_with_io_error(err),
|
||||||
|
Err(e) => die!("{:?}", e),
|
||||||
|
Ok(server) => server,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "rpc"))]
|
||||||
|
struct RpcServer;
|
||||||
|
|
||||||
#[cfg(not(feature = "rpc"))]
|
#[cfg(not(feature = "rpc"))]
|
||||||
fn setup_rpc_server(
|
fn setup_rpc_server(
|
||||||
@ -291,8 +301,8 @@ fn setup_rpc_server(
|
|||||||
_url: &str,
|
_url: &str,
|
||||||
_cors_domain: &str,
|
_cors_domain: &str,
|
||||||
_apis: Vec<&str>
|
_apis: Vec<&str>
|
||||||
) -> Option<Arc<PanicHandler>> {
|
) -> ! {
|
||||||
None
|
die!("Your Parity version has been compiled without JSON-RPC support.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_version() {
|
fn print_version() {
|
||||||
@ -327,7 +337,7 @@ impl Configuration {
|
|||||||
fn author(&self) -> Address {
|
fn author(&self) -> Address {
|
||||||
let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author);
|
let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author);
|
||||||
Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
|
Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
|
||||||
die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", d)
|
die!("{}: Invalid address for --author. Must be 40 hex characters, with or without the 0x at the beginning.", d)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +363,7 @@ impl Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _keys_path(&self) -> String {
|
fn keys_path(&self) -> String {
|
||||||
self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap())
|
self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +485,7 @@ impl Configuration {
|
|||||||
fn execute_account_cli(&self) {
|
fn execute_account_cli(&self) {
|
||||||
use util::keys::store::SecretStore;
|
use util::keys::store::SecretStore;
|
||||||
use rpassword::read_password;
|
use rpassword::read_password;
|
||||||
let mut secret_store = SecretStore::new();
|
let mut secret_store = SecretStore::new_in(Path::new(&self.keys_path()));
|
||||||
if self.args.cmd_new {
|
if self.args.cmd_new {
|
||||||
println!("Please note that password is NOT RECOVERABLE.");
|
println!("Please note that password is NOT RECOVERABLE.");
|
||||||
println!("Type password: ");
|
println!("Type password: ");
|
||||||
@ -509,7 +519,7 @@ impl Configuration {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
let account_service = AccountService::new();
|
let account_service = AccountService::new_in(Path::new(&self.keys_path()));
|
||||||
for d in &self.args.flag_unlock {
|
for d in &self.args.flag_unlock {
|
||||||
let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| {
|
let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| {
|
||||||
die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d)
|
die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d)
|
||||||
@ -539,7 +549,10 @@ impl Configuration {
|
|||||||
let account_service = Arc::new(self.account_service());
|
let account_service = Arc::new(self.account_service());
|
||||||
|
|
||||||
// Build client
|
// Build client
|
||||||
let mut service = ClientService::start(self.client_config(), spec, net_settings, &Path::new(&self.path())).unwrap();
|
let mut service = ClientService::start(
|
||||||
|
self.client_config(), spec, net_settings, &Path::new(&self.path())
|
||||||
|
).unwrap_or_else(|e| die_with_error(e));
|
||||||
|
|
||||||
panic_handler.forward_from(&service);
|
panic_handler.forward_from(&service);
|
||||||
let client = service.client();
|
let client = service.client();
|
||||||
|
|
||||||
@ -554,7 +567,8 @@ impl Configuration {
|
|||||||
let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone());
|
let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone());
|
||||||
|
|
||||||
// Setup rpc
|
// Setup rpc
|
||||||
if self.args.flag_jsonrpc || self.args.flag_rpc {
|
let rpc_server = if self.args.flag_jsonrpc || self.args.flag_rpc {
|
||||||
|
let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis);
|
||||||
let url = format!("{}:{}",
|
let url = format!("{}:{}",
|
||||||
match self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_interface).as_str() {
|
match self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_interface).as_str() {
|
||||||
"all" => "0.0.0.0",
|
"all" => "0.0.0.0",
|
||||||
@ -563,23 +577,21 @@ impl Configuration {
|
|||||||
},
|
},
|
||||||
self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port)
|
self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port)
|
||||||
);
|
);
|
||||||
SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url));
|
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url));
|
||||||
let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors);
|
let cors_domain = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors);
|
||||||
// TODO: use this as the API list.
|
|
||||||
let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis);
|
Some(setup_rpc_server(
|
||||||
let server_handler = setup_rpc_server(
|
|
||||||
service.client(),
|
service.client(),
|
||||||
sync.clone(),
|
sync.clone(),
|
||||||
account_service.clone(),
|
account_service.clone(),
|
||||||
miner.clone(),
|
miner.clone(),
|
||||||
&url,
|
&addr,
|
||||||
cors,
|
&cors_domain,
|
||||||
apis.split(',').collect()
|
apis.split(',').collect()
|
||||||
);
|
))
|
||||||
if let Some(handler) = server_handler {
|
} else {
|
||||||
panic_handler.forward_from(handler.deref());
|
None
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Register IO handler
|
// Register IO handler
|
||||||
let io_handler = Arc::new(ClientIoHandler {
|
let io_handler = Arc::new(ClientIoHandler {
|
||||||
@ -591,11 +603,11 @@ impl Configuration {
|
|||||||
service.io().register_handler(io_handler).expect("Error registering IO handler");
|
service.io().register_handler(io_handler).expect("Error registering IO handler");
|
||||||
|
|
||||||
// Handle exit
|
// Handle exit
|
||||||
wait_for_exit(panic_handler);
|
wait_for_exit(panic_handler, rpc_server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_exit(panic_handler: Arc<PanicHandler>) {
|
fn wait_for_exit(panic_handler: Arc<PanicHandler>, _rpc_server: Option<RpcServer>) {
|
||||||
let exit = Arc::new(Condvar::new());
|
let exit = Arc::new(Condvar::new());
|
||||||
|
|
||||||
// Handle possible exits
|
// Handle possible exits
|
||||||
@ -609,6 +621,30 @@ fn wait_for_exit(panic_handler: Arc<PanicHandler>) {
|
|||||||
// Wait for signal
|
// Wait for signal
|
||||||
let mutex = Mutex::new(());
|
let mutex = Mutex::new(());
|
||||||
let _ = exit.wait(mutex.lock().unwrap()).unwrap();
|
let _ = exit.wait(mutex.lock().unwrap()).unwrap();
|
||||||
|
info!("Finishing work, please wait...");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn die_with_error(e: ethcore::error::Error) -> ! {
|
||||||
|
use ethcore::error::Error;
|
||||||
|
|
||||||
|
match e {
|
||||||
|
Error::Util(UtilError::StdIo(e)) => die_with_io_error(e),
|
||||||
|
_ => die!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn die_with_io_error(e: std::io::Error) -> ! {
|
||||||
|
match e.kind() {
|
||||||
|
std::io::ErrorKind::PermissionDenied => {
|
||||||
|
die!("No permissions to bind to specified port.")
|
||||||
|
},
|
||||||
|
std::io::ErrorKind::AddrInUse => {
|
||||||
|
die!("Specified address is already in use. Please make sure that nothing is listening on the same port or try using a different one.")
|
||||||
|
},
|
||||||
|
std::io::ErrorKind::AddrNotAvailable => {
|
||||||
|
die!("Could not use specified interface or given address is invalid.")
|
||||||
|
},
|
||||||
|
_ => die!("{:?}", e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -13,7 +13,7 @@ log = "0.3"
|
|||||||
serde = "0.7.0"
|
serde = "0.7.0"
|
||||||
serde_json = "0.7.0"
|
serde_json = "0.7.0"
|
||||||
jsonrpc-core = "2.0"
|
jsonrpc-core = "2.0"
|
||||||
jsonrpc-http-server = "3.0"
|
jsonrpc-http-server = { git = "https://github.com/debris/jsonrpc-http-server.git" }
|
||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
ethcore = { path = "../ethcore" }
|
ethcore = { path = "../ethcore" }
|
||||||
ethash = { path = "../ethash" }
|
ethash = { path = "../ethash" }
|
||||||
|
@ -33,10 +33,10 @@ extern crate ethminer;
|
|||||||
extern crate transient_hashmap;
|
extern crate transient_hashmap;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::net::SocketAddr;
|
||||||
use util::panics::PanicHandler;
|
|
||||||
use self::jsonrpc_core::{IoHandler, IoDelegate};
|
use self::jsonrpc_core::{IoHandler, IoDelegate};
|
||||||
|
|
||||||
|
pub use jsonrpc_http_server::{Server, RpcServerError};
|
||||||
pub mod v1;
|
pub mod v1;
|
||||||
|
|
||||||
/// Http server.
|
/// Http server.
|
||||||
@ -45,7 +45,7 @@ pub struct RpcServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RpcServer {
|
impl RpcServer {
|
||||||
/// Construct new http server object with given number of threads.
|
/// Construct new http server object.
|
||||||
pub fn new() -> RpcServer {
|
pub fn new() -> RpcServer {
|
||||||
RpcServer {
|
RpcServer {
|
||||||
handler: Arc::new(IoHandler::new()),
|
handler: Arc::new(IoHandler::new()),
|
||||||
@ -57,18 +57,9 @@ impl RpcServer {
|
|||||||
self.handler.add_delegate(delegate);
|
self.handler.add_delegate(delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start server asynchronously in new thread and returns panic handler.
|
/// Start server asynchronously and returns result with `Server` handle on success or an error.
|
||||||
pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Arc<PanicHandler> {
|
pub fn start_http(&self, addr: &SocketAddr, cors_domain: &str) -> Result<Server, RpcServerError> {
|
||||||
let addr = addr.to_owned();
|
|
||||||
let cors_domain = cors_domain.to_owned();
|
let cors_domain = cors_domain.to_owned();
|
||||||
let panic_handler = PanicHandler::new_in_arc();
|
Server::start(addr, self.handler.clone(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain))
|
||||||
let ph = panic_handler.clone();
|
|
||||||
let server = jsonrpc_http_server::Server::new(self.handler.clone());
|
|
||||||
thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || {
|
|
||||||
ph.catch_panic(move || {
|
|
||||||
server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads);
|
|
||||||
}).unwrap()
|
|
||||||
}).expect("Error while creating jsonrpc http thread");
|
|
||||||
panic_handler
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,10 @@ fn default_gas() -> U256 {
|
|||||||
U256::from(21_000)
|
U256::from(21_000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_call_gas() -> U256 {
|
||||||
|
U256::from(50_000_000)
|
||||||
|
}
|
||||||
|
|
||||||
/// Eth rpc implementation.
|
/// Eth rpc implementation.
|
||||||
pub struct EthClient<C, S, A, M, EM = ExternalMiner>
|
pub struct EthClient<C, S, A, M, EM = ExternalMiner>
|
||||||
where C: BlockChainClient,
|
where C: BlockChainClient,
|
||||||
@ -169,27 +173,30 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
|||||||
Ok(EthTransaction {
|
Ok(EthTransaction {
|
||||||
nonce: request.nonce.unwrap_or_else(|| client.nonce(&from)),
|
nonce: request.nonce.unwrap_or_else(|| client.nonce(&from)),
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
gas: request.gas.unwrap_or_else(default_gas),
|
gas: request.gas.unwrap_or_else(default_call_gas),
|
||||||
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
||||||
value: request.value.unwrap_or_else(U256::zero),
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
|
||||||
}.fake_sign(from))
|
}.fake_sign(from))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch_transaction(&self, signed_transaction: SignedTransaction, raw_transaction: Vec<u8>) -> Result<Value, Error> {
|
fn dispatch_transaction(&self, signed_transaction: SignedTransaction) -> Result<Value, Error> {
|
||||||
let hash = signed_transaction.hash();
|
let hash = signed_transaction.hash();
|
||||||
|
|
||||||
let import = {
|
let import = {
|
||||||
|
let miner = take_weak!(self.miner);
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
take_weak!(self.miner).import_transactions(vec![signed_transaction], |a: &Address| AccountDetails {
|
take_weak!(self.miner).import_transactions(vec![signed_transaction], |a: &Address| AccountDetails {
|
||||||
nonce: client.nonce(a),
|
nonce: miner
|
||||||
|
.last_nonce(a)
|
||||||
|
.map(|nonce| nonce + U256::one())
|
||||||
|
.unwrap_or_else(|| client.nonce(a)),
|
||||||
balance: client.balance(a),
|
balance: client.balance(a),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
match import.into_iter().collect::<Result<Vec<_>, _>>() {
|
match import.into_iter().collect::<Result<Vec<_>, _>>() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
take_weak!(self.sync).new_transaction(raw_transaction);
|
|
||||||
to_value(&hash)
|
to_value(&hash)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -483,7 +490,11 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
let miner = take_weak!(self.miner);
|
let miner = take_weak!(self.miner);
|
||||||
EthTransaction {
|
EthTransaction {
|
||||||
nonce: request.nonce.unwrap_or_else(|| client.nonce(&request.from)),
|
nonce: request.nonce
|
||||||
|
.or_else(|| miner
|
||||||
|
.last_nonce(&request.from)
|
||||||
|
.map(|nonce| nonce + U256::one()))
|
||||||
|
.unwrap_or_else(|| client.nonce(&request.from)),
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
gas: request.gas.unwrap_or_else(default_gas),
|
gas: request.gas.unwrap_or_else(default_gas),
|
||||||
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
||||||
@ -491,8 +502,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
data: request.data.map_or_else(Vec::new, |d| d.to_vec()),
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec()),
|
||||||
}.sign(&secret)
|
}.sign(&secret)
|
||||||
};
|
};
|
||||||
let raw_transaction = encode(&signed_transaction).to_vec();
|
self.dispatch_transaction(signed_transaction)
|
||||||
self.dispatch_transaction(signed_transaction, raw_transaction)
|
|
||||||
},
|
},
|
||||||
Err(_) => { to_value(&H256::zero()) }
|
Err(_) => { to_value(&H256::zero()) }
|
||||||
}
|
}
|
||||||
@ -504,7 +514,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
.and_then(|(raw_transaction, )| {
|
.and_then(|(raw_transaction, )| {
|
||||||
let raw_transaction = raw_transaction.to_vec();
|
let raw_transaction = raw_transaction.to_vec();
|
||||||
match UntrustedRlp::new(&raw_transaction).as_val() {
|
match UntrustedRlp::new(&raw_transaction).as_val() {
|
||||||
Ok(signed_transaction) => self.dispatch_transaction(signed_transaction, raw_transaction),
|
Ok(signed_transaction) => self.dispatch_transaction(signed_transaction),
|
||||||
Err(_) => to_value(&H256::zero()),
|
Err(_) => to_value(&H256::zero()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -49,7 +49,7 @@ impl<A> Personal for PersonalClient<A> where A: AccountProvider + 'static {
|
|||||||
|(pass, )| {
|
|(pass, )| {
|
||||||
let store = take_weak!(self.accounts);
|
let store = take_weak!(self.accounts);
|
||||||
match store.new_account(&pass) {
|
match store.new_account(&pass) {
|
||||||
Ok(address) => Ok(Value::String(format!("0x{:?}", address))),
|
Ok(address) => to_value(&address),
|
||||||
Err(_) => Err(Error::internal_error())
|
Err(_) => Err(Error::internal_error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use util::numbers::{Uint, U256};
|
|||||||
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId};
|
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId};
|
||||||
use ethcore::log_entry::{LocalizedLogEntry, LogEntry};
|
use ethcore::log_entry::{LocalizedLogEntry, LogEntry};
|
||||||
use ethcore::receipt::LocalizedReceipt;
|
use ethcore::receipt::LocalizedReceipt;
|
||||||
|
use ethcore::transaction::{Transaction, Action};
|
||||||
use v1::{Eth, EthClient};
|
use v1::{Eth, EthClient};
|
||||||
use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner};
|
use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner};
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ fn miner_service() -> Arc<TestMinerService> {
|
|||||||
struct EthTester {
|
struct EthTester {
|
||||||
pub client: Arc<TestBlockChainClient>,
|
pub client: Arc<TestBlockChainClient>,
|
||||||
pub sync: Arc<TestSyncProvider>,
|
pub sync: Arc<TestSyncProvider>,
|
||||||
_accounts_provider: Arc<TestAccountProvider>,
|
pub accounts_provider: Arc<TestAccountProvider>,
|
||||||
miner: Arc<TestMinerService>,
|
miner: Arc<TestMinerService>,
|
||||||
hashrates: Arc<RwLock<HashMap<H256, U256>>>,
|
hashrates: Arc<RwLock<HashMap<H256, U256>>>,
|
||||||
pub io: IoHandler,
|
pub io: IoHandler,
|
||||||
@ -72,7 +73,7 @@ impl Default for EthTester {
|
|||||||
EthTester {
|
EthTester {
|
||||||
client: client,
|
client: client,
|
||||||
sync: sync,
|
sync: sync,
|
||||||
_accounts_provider: ap,
|
accounts_provider: ap,
|
||||||
miner: miner,
|
miner: miner,
|
||||||
io: io,
|
io: io,
|
||||||
hashrates: hashrates,
|
hashrates: hashrates,
|
||||||
@ -449,9 +450,53 @@ fn rpc_eth_estimate_gas_default_block() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn rpc_eth_send_transaction() {
|
fn rpc_eth_send_transaction() {
|
||||||
unimplemented!()
|
let account = TestAccount::new("123");
|
||||||
|
let address = account.address();
|
||||||
|
let secret = account.secret.clone();
|
||||||
|
|
||||||
|
let tester = EthTester::default();
|
||||||
|
tester.accounts_provider.accounts.write().unwrap().insert(address.clone(), account);
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_sendTransaction",
|
||||||
|
"params": [{
|
||||||
|
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
|
||||||
|
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||||
|
"gas": "0x76c0",
|
||||||
|
"gasPrice": "0x9184e72a000",
|
||||||
|
"value": "0x9184e72a"
|
||||||
|
}],
|
||||||
|
"id": 1
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let t = Transaction {
|
||||||
|
nonce: U256::zero(),
|
||||||
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
|
gas: U256::from(0x76c0),
|
||||||
|
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
|
value: U256::from(0x9184e72au64),
|
||||||
|
data: vec![]
|
||||||
|
}.sign(&secret);
|
||||||
|
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
|
||||||
|
|
||||||
|
tester.miner.last_nonces.write().unwrap().insert(address.clone(), U256::zero());
|
||||||
|
|
||||||
|
let t = Transaction {
|
||||||
|
nonce: U256::one(),
|
||||||
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
|
gas: U256::from(0x76c0),
|
||||||
|
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
|
value: U256::from(0x9184e72au64),
|
||||||
|
data: vec![]
|
||||||
|
}.sign(&secret);
|
||||||
|
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -20,7 +20,7 @@ use std::sync::RwLock;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use util::hash::{Address, H256, FixedHash};
|
use util::hash::{Address, H256, FixedHash};
|
||||||
use util::crypto::{Secret, Signature};
|
use util::crypto::{Secret, Signature, KeyPair};
|
||||||
use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError};
|
use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError};
|
||||||
|
|
||||||
/// Account mock.
|
/// Account mock.
|
||||||
@ -30,23 +30,31 @@ pub struct TestAccount {
|
|||||||
pub unlocked: bool,
|
pub unlocked: bool,
|
||||||
/// Account's password.
|
/// Account's password.
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
/// Account's secret.
|
||||||
|
pub secret: Secret,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestAccount {
|
impl TestAccount {
|
||||||
/// Creates new test account.
|
/// Creates new test account.
|
||||||
pub fn new(password: &str) -> Self {
|
pub fn new(password: &str) -> Self {
|
||||||
|
let pair = KeyPair::create().unwrap();
|
||||||
TestAccount {
|
TestAccount {
|
||||||
unlocked: false,
|
unlocked: false,
|
||||||
password: password.to_owned(),
|
password: password.to_owned(),
|
||||||
|
secret: pair.secret().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns account address.
|
||||||
|
pub fn address(&self) -> Address {
|
||||||
|
KeyPair::from_secret(self.secret.clone()).unwrap().address()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test account provider.
|
/// Test account provider.
|
||||||
pub struct TestAccountProvider {
|
pub struct TestAccountProvider {
|
||||||
accounts: RwLock<HashMap<Address, TestAccount>>,
|
/// Test provider accounts.
|
||||||
/// Added accounts passwords.
|
pub accounts: RwLock<HashMap<Address, TestAccount>>,
|
||||||
pub adds: RwLock<Vec<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestAccountProvider {
|
impl TestAccountProvider {
|
||||||
@ -54,7 +62,6 @@ impl TestAccountProvider {
|
|||||||
pub fn new(accounts: HashMap<Address, TestAccount>) -> Self {
|
pub fn new(accounts: HashMap<Address, TestAccount>) -> Self {
|
||||||
TestAccountProvider {
|
TestAccountProvider {
|
||||||
accounts: RwLock::new(accounts),
|
accounts: RwLock::new(accounts),
|
||||||
adds: RwLock::new(vec![]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,14 +83,20 @@ impl AccountProvider for TestAccountProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_account(&self, pass: &str) -> Result<Address, io::Error> {
|
fn new_account(&self, pass: &str) -> Result<Address, io::Error> {
|
||||||
let mut adds = self.adds.write().unwrap();
|
let account = TestAccount::new(pass);
|
||||||
let address = Address::from(adds.len() as u64 + 2);
|
let address = KeyPair::from_secret(account.secret.clone()).unwrap().address();
|
||||||
adds.push(pass.to_owned());
|
self.accounts.write().unwrap().insert(address.clone(), account);
|
||||||
Ok(address)
|
Ok(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn account_secret(&self, _account: &Address) -> Result<Secret, SigningError> {
|
fn account_secret(&self, address: &Address) -> Result<Secret, SigningError> {
|
||||||
Ok(Secret::random())
|
// todo: consider checking if account is unlock. some test may need alteration then.
|
||||||
|
self.accounts
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get(address)
|
||||||
|
.ok_or(SigningError::NoAccount)
|
||||||
|
.map(|acc| acc.secret.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign(&self, _account: &Address, _message: &H256) -> Result<Signature, SigningError> {
|
fn sign(&self, _account: &Address, _message: &H256) -> Result<Signature, SigningError> {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Test implementation of miner service.
|
//! Test implementation of miner service.
|
||||||
|
|
||||||
use util::{Address, H256, Bytes};
|
use util::{Address, H256, Bytes, U256};
|
||||||
use util::standard::*;
|
use util::standard::*;
|
||||||
use ethcore::error::Error;
|
use ethcore::error::Error;
|
||||||
use ethcore::client::BlockChainClient;
|
use ethcore::client::BlockChainClient;
|
||||||
@ -27,19 +27,22 @@ use ethminer::{MinerService, MinerStatus, AccountDetails};
|
|||||||
/// Test miner service.
|
/// Test miner service.
|
||||||
pub struct TestMinerService {
|
pub struct TestMinerService {
|
||||||
/// Imported transactions.
|
/// Imported transactions.
|
||||||
pub imported_transactions: RwLock<Vec<H256>>,
|
pub imported_transactions: Mutex<Vec<SignedTransaction>>,
|
||||||
/// Latest closed block.
|
/// Latest closed block.
|
||||||
pub latest_closed_block: Mutex<Option<ClosedBlock>>,
|
pub latest_closed_block: Mutex<Option<ClosedBlock>>,
|
||||||
/// Pre-existed pending transactions
|
/// Pre-existed pending transactions
|
||||||
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
|
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
|
||||||
|
/// Last nonces.
|
||||||
|
pub last_nonces: RwLock<HashMap<Address, U256>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TestMinerService {
|
impl Default for TestMinerService {
|
||||||
fn default() -> TestMinerService {
|
fn default() -> TestMinerService {
|
||||||
TestMinerService {
|
TestMinerService {
|
||||||
imported_transactions: RwLock::new(Vec::new()),
|
imported_transactions: Mutex::new(Vec::new()),
|
||||||
latest_closed_block: Mutex::new(None),
|
latest_closed_block: Mutex::new(None),
|
||||||
pending_transactions: Mutex::new(HashMap::new()),
|
pending_transactions: Mutex::new(HashMap::new()),
|
||||||
|
last_nonces: RwLock::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,20 +59,36 @@ impl MinerService for TestMinerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Imports transactions to transaction queue.
|
/// Imports transactions to transaction queue.
|
||||||
fn import_transactions<T>(&self, _transactions: Vec<SignedTransaction>, _fetch_account: T) -> Vec<Result<(), Error>>
|
fn import_transactions<T>(&self, transactions: Vec<SignedTransaction>, _fetch_account: T) -> Vec<Result<(), Error>>
|
||||||
where T: Fn(&Address) -> AccountDetails { unimplemented!(); }
|
where T: Fn(&Address) -> AccountDetails {
|
||||||
|
// lets assume that all txs are valid
|
||||||
|
self.imported_transactions.lock().unwrap().extend_from_slice(&transactions);
|
||||||
|
|
||||||
|
transactions
|
||||||
|
.iter()
|
||||||
|
.map(|_| Ok(()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns hashes of transactions currently in pending
|
/// Returns hashes of transactions currently in pending
|
||||||
fn pending_transactions_hashes(&self) -> Vec<H256> { vec![] }
|
fn pending_transactions_hashes(&self) -> Vec<H256> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes all transactions from the queue and restart mining operation.
|
/// Removes all transactions from the queue and restart mining operation.
|
||||||
fn clear_and_reset(&self, _chain: &BlockChainClient) { unimplemented!(); }
|
fn clear_and_reset(&self, _chain: &BlockChainClient) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
/// Called when blocks are imported to chain, updates transactions queue.
|
/// Called when blocks are imported to chain, updates transactions queue.
|
||||||
fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); }
|
fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
/// New chain head event. Restart mining operation.
|
/// New chain head event. Restart mining operation.
|
||||||
fn update_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); }
|
fn update_sealing(&self, _chain: &BlockChainClient) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
/// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock.
|
/// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock.
|
||||||
fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex<Option<ClosedBlock>> {
|
fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex<Option<ClosedBlock>> {
|
||||||
@ -77,10 +96,20 @@ impl MinerService for TestMinerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
|
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
|
||||||
self.pending_transactions.lock().unwrap().get(hash).and_then(|tx_ref| Some(tx_ref.clone()))
|
self.pending_transactions.lock().unwrap().get(hash).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pending_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
|
self.pending_transactions.lock().unwrap().values().cloned().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_nonce(&self, address: &Address) -> Option<U256> {
|
||||||
|
self.last_nonces.read().unwrap().get(address).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Submit `seal` as a valid solution for the header of `pow_hash`.
|
/// 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.
|
/// Will check the seal, but not actually insert the block into the chain.
|
||||||
fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> { unimplemented!(); }
|
fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Test implementation of SyncProvider.
|
//! Test implementation of SyncProvider.
|
||||||
|
|
||||||
use util::{U256, Bytes};
|
use util::{U256};
|
||||||
use ethsync::{SyncProvider, SyncStatus, SyncState};
|
use ethsync::{SyncProvider, SyncStatus, SyncState};
|
||||||
use std::sync::{RwLock};
|
use std::sync::{RwLock};
|
||||||
|
|
||||||
@ -59,8 +59,5 @@ impl SyncProvider for TestSyncProvider {
|
|||||||
fn status(&self) -> SyncStatus {
|
fn status(&self) -> SyncStatus {
|
||||||
self.status.read().unwrap().clone()
|
self.status.read().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_transaction(&self, _raw_transaction: Bytes) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,8 +22,7 @@ use util::numbers::*;
|
|||||||
use std::collections::*;
|
use std::collections::*;
|
||||||
|
|
||||||
fn accounts_provider() -> Arc<TestAccountProvider> {
|
fn accounts_provider() -> Arc<TestAccountProvider> {
|
||||||
let mut accounts = HashMap::new();
|
let accounts = HashMap::new();
|
||||||
accounts.insert(Address::from(1), TestAccount::new("test"));
|
|
||||||
let ap = TestAccountProvider::new(accounts);
|
let ap = TestAccountProvider::new(accounts);
|
||||||
Arc::new(ap)
|
Arc::new(ap)
|
||||||
}
|
}
|
||||||
@ -38,7 +37,11 @@ fn setup() -> (Arc<TestAccountProvider>, IoHandler) {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn accounts() {
|
fn accounts() {
|
||||||
let (_test_provider, io) = setup();
|
let (test_provider, io) = setup();
|
||||||
|
test_provider.accounts
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.insert(Address::from(1), TestAccount::new("test"));
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#;
|
||||||
let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#;
|
let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#;
|
||||||
@ -49,11 +52,22 @@ fn accounts() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_account() {
|
fn new_account() {
|
||||||
let (_test_provider, io) = setup();
|
let (test_provider, io) = setup();
|
||||||
|
|
||||||
let request = r#"{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["pass"], "id": 1}"#;
|
let request = r#"{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["pass"], "id": 1}"#;
|
||||||
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000002","id":1}"#;
|
|
||||||
|
|
||||||
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
let res = io.handle_request(request);
|
||||||
|
|
||||||
|
let accounts = test_provider.accounts.read().unwrap();
|
||||||
|
assert_eq!(accounts.len(), 1);
|
||||||
|
|
||||||
|
let address = accounts
|
||||||
|
.keys()
|
||||||
|
.nth(0)
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"","id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(res, Some(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,9 +190,6 @@ pub trait EthFilter: Sized + Send + Sync + 'static {
|
|||||||
/// Returns filter changes since last poll.
|
/// Returns filter changes since last poll.
|
||||||
fn filter_changes(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn filter_changes(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
/// Returns filter logs.
|
|
||||||
fn filter_logs(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
|
||||||
|
|
||||||
/// Uninstalls filter.
|
/// Uninstalls filter.
|
||||||
fn uninstall_filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn uninstall_filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
@ -203,7 +200,7 @@ pub trait EthFilter: Sized + Send + Sync + 'static {
|
|||||||
delegate.add_method("eth_newBlockFilter", EthFilter::new_block_filter);
|
delegate.add_method("eth_newBlockFilter", EthFilter::new_block_filter);
|
||||||
delegate.add_method("eth_newPendingTransactionFilter", EthFilter::new_pending_transaction_filter);
|
delegate.add_method("eth_newPendingTransactionFilter", EthFilter::new_pending_transaction_filter);
|
||||||
delegate.add_method("eth_getFilterChanges", EthFilter::filter_changes);
|
delegate.add_method("eth_getFilterChanges", EthFilter::filter_changes);
|
||||||
delegate.add_method("eth_getFilterLogs", EthFilter::filter_logs);
|
delegate.add_method("eth_getFilterLogs", EthFilter::filter_changes);
|
||||||
delegate.add_method("eth_uninstallFilter", EthFilter::uninstall_filter);
|
delegate.add_method("eth_uninstallFilter", EthFilter::uninstall_filter);
|
||||||
delegate
|
delegate
|
||||||
}
|
}
|
||||||
|
@ -217,10 +217,6 @@ pub struct ChainSync {
|
|||||||
network_id: U256,
|
network_id: U256,
|
||||||
/// Miner
|
/// Miner
|
||||||
miner: Arc<Miner>,
|
miner: Arc<Miner>,
|
||||||
|
|
||||||
/// Transactions to propagate
|
|
||||||
// TODO: reconsider where this is in the codebase - seems a little dodgy to have here.
|
|
||||||
transactions_to_send: Vec<Bytes>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RlpResponseResult = Result<Option<(PacketId, RlpStream)>, PacketDecodeError>;
|
type RlpResponseResult = Result<Option<(PacketId, RlpStream)>, PacketDecodeError>;
|
||||||
@ -247,7 +243,6 @@ impl ChainSync {
|
|||||||
max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks),
|
max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks),
|
||||||
network_id: config.network_id,
|
network_id: config.network_id,
|
||||||
miner: miner,
|
miner: miner,
|
||||||
transactions_to_send: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,11 +954,6 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Place a new transaction on the wire.
|
|
||||||
pub fn new_transaction(&mut self, raw_transaction: Bytes) {
|
|
||||||
self.transactions_to_send.push(raw_transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when peer sends us new transactions
|
/// 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: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
// accepting transactions once only fully synced
|
// accepting transactions once only fully synced
|
||||||
@ -1305,11 +1295,16 @@ impl ChainSync {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut packet = RlpStream::new_list(self.transactions_to_send.len());
|
let mut transactions = self.miner.pending_transactions();
|
||||||
for tx in self.transactions_to_send.iter() {
|
if transactions.is_empty() {
|
||||||
packet.append_raw(tx, 1);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut packet = RlpStream::new_list(transactions.len());
|
||||||
|
let tx_count = transactions.len();
|
||||||
|
for tx in transactions.drain(..) {
|
||||||
|
packet.append(&tx);
|
||||||
}
|
}
|
||||||
self.transactions_to_send.clear();
|
|
||||||
let rlp = packet.out();
|
let rlp = packet.out();
|
||||||
|
|
||||||
let lucky_peers = {
|
let lucky_peers = {
|
||||||
@ -1328,13 +1323,12 @@ impl ChainSync {
|
|||||||
for peer_id in lucky_peers {
|
for peer_id in lucky_peers {
|
||||||
self.send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp.clone());
|
self.send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp.clone());
|
||||||
}
|
}
|
||||||
|
trace!(target: "sync", "Sent {} transactions to {} peers.", tx_count, sent);
|
||||||
sent
|
sent
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_latest_blocks(&mut self, io: &mut SyncIo) {
|
fn propagate_latest_blocks(&mut self, io: &mut SyncIo) {
|
||||||
if !self.transactions_to_send.is_empty() {
|
|
||||||
self.propagate_new_transactions(io);
|
self.propagate_new_transactions(io);
|
||||||
}
|
|
||||||
let chain_info = io.chain().chain_info();
|
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 {
|
if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION {
|
||||||
let blocks = self.propagate_blocks(&chain_info, io);
|
let blocks = self.propagate_blocks(&chain_info, io);
|
||||||
|
@ -66,7 +66,7 @@ use std::ops::*;
|
|||||||
use std::sync::*;
|
use std::sync::*;
|
||||||
use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId};
|
use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId};
|
||||||
use util::TimerToken;
|
use util::TimerToken;
|
||||||
use util::{U256, Bytes, ONE_U256};
|
use util::{U256, ONE_U256};
|
||||||
use ethcore::client::Client;
|
use ethcore::client::Client;
|
||||||
use ethcore::service::SyncMessage;
|
use ethcore::service::SyncMessage;
|
||||||
use ethminer::Miner;
|
use ethminer::Miner;
|
||||||
@ -101,9 +101,6 @@ impl Default for SyncConfig {
|
|||||||
pub trait SyncProvider: Send + Sync {
|
pub trait SyncProvider: Send + Sync {
|
||||||
/// Get sync status
|
/// Get sync status
|
||||||
fn status(&self) -> SyncStatus;
|
fn status(&self) -> SyncStatus;
|
||||||
|
|
||||||
/// Note that a user has submitted a new transaction.
|
|
||||||
fn new_transaction(&self, raw_transaction: Bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ethereum network protocol handler
|
/// Ethereum network protocol handler
|
||||||
@ -143,11 +140,6 @@ impl SyncProvider for EthSync {
|
|||||||
fn status(&self) -> SyncStatus {
|
fn status(&self) -> SyncStatus {
|
||||||
self.sync.read().unwrap().status()
|
self.sync.read().unwrap().status()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note that a user has submitted a new transaction.
|
|
||||||
fn new_transaction(&self, raw_transaction: Bytes) {
|
|
||||||
self.sync.write().unwrap().new_transaction(raw_transaction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkProtocolHandler<SyncMessage> for EthSync {
|
impl NetworkProtocolHandler<SyncMessage> for EthSync {
|
||||||
|
@ -340,31 +340,31 @@ macro_rules! uint_overflowing_mul {
|
|||||||
cmpq $$0, %rcx
|
cmpq $$0, %rcx
|
||||||
jne 2f
|
jne 2f
|
||||||
|
|
||||||
popcnt $8, %rcx
|
mov $8, %rcx
|
||||||
jrcxz 12f
|
jrcxz 12f
|
||||||
|
|
||||||
popcnt $12, %rcx
|
mov $12, %rcx
|
||||||
popcnt $11, %rax
|
mov $11, %rax
|
||||||
add %rax, %rcx
|
or %rax, %rcx
|
||||||
popcnt $10, %rax
|
mov $10, %rax
|
||||||
add %rax, %rcx
|
or %rax, %rcx
|
||||||
jmp 2f
|
jmp 2f
|
||||||
|
|
||||||
12:
|
12:
|
||||||
popcnt $12, %rcx
|
mov $12, %rcx
|
||||||
jrcxz 11f
|
jrcxz 11f
|
||||||
|
|
||||||
popcnt $7, %rcx
|
mov $7, %rcx
|
||||||
popcnt $6, %rax
|
mov $6, %rax
|
||||||
add %rax, %rcx
|
or %rax, %rcx
|
||||||
|
|
||||||
cmpq $$0, %rcx
|
cmpq $$0, %rcx
|
||||||
jne 2f
|
jne 2f
|
||||||
|
|
||||||
11:
|
11:
|
||||||
popcnt $11, %rcx
|
mov $11, %rcx
|
||||||
jrcxz 2f
|
jrcxz 2f
|
||||||
popcnt $7, %rcx
|
mov $7, %rcx
|
||||||
|
|
||||||
2:
|
2:
|
||||||
"
|
"
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
{"address":"63121b431a52f8043c16fcf0d1df9cb7b5f66649","crypto":{"cipher":"aes-128-ctr","ciphertext":"1dd21926c644b9983916d646f3a4f2c7f9362f7e1c9fb1abcb42494dae06fa01","cipherparams":{"iv":"c52c6ee66d89a7aa8c6839f4b6ed29c8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"96f17c17bbf48db2dc4da00b3e7decce8e21f44a5d7963dadeeff70e1d38ad75"},"mac":"f279f3444585c2817701225e2196c1176386ad549ebaec2bcc4f94f309727fe6"},"id":"15e49cd2-51fb-4316-ba46-c3cf8db4ae44","version":3}
|
@ -376,8 +376,10 @@ impl<Message> IoService<Message> where Message: Send + Sync + Clone + 'static {
|
|||||||
|
|
||||||
impl<Message> Drop for IoService<Message> where Message: Send + Sync + Clone {
|
impl<Message> Drop for IoService<Message> where Message: Send + Sync + Clone {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
trace!(target: "shutdown", "[IoService] Closing...");
|
||||||
self.host_channel.send(IoMessage::Shutdown).unwrap();
|
self.host_channel.send(IoMessage::Shutdown).unwrap();
|
||||||
self.thread.take().unwrap().join().ok();
|
self.thread.take().unwrap().join().ok();
|
||||||
|
trace!(target: "shutdown", "[IoService] Closed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,10 +120,12 @@ impl Worker {
|
|||||||
|
|
||||||
impl Drop for Worker {
|
impl Drop for Worker {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
trace!(target: "shutdown", "[IoWorker] Closing...");
|
||||||
let _ = self.wait_mutex.lock();
|
let _ = self.wait_mutex.lock();
|
||||||
self.deleting.store(true, AtomicOrdering::Release);
|
self.deleting.store(true, AtomicOrdering::Release);
|
||||||
self.wait.notify_all();
|
self.wait.notify_all();
|
||||||
let thread = mem::replace(&mut self.thread, None).unwrap();
|
let thread = mem::replace(&mut self.thread, None).unwrap();
|
||||||
thread.join().ok();
|
thread.join().ok();
|
||||||
|
trace!(target: "shutdown", "[IoWorker] Closed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,10 @@
|
|||||||
use common::*;
|
use common::*;
|
||||||
use keys::store::SecretStore;
|
use keys::store::SecretStore;
|
||||||
use keys::directory::KeyFileContent;
|
use keys::directory::KeyFileContent;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)`
|
/// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)`
|
||||||
pub fn enumerate_geth_keys(path: &Path) -> Result<Vec<(Address, String)>, io::Error> {
|
pub fn enumerate_geth_keys(path: &Path) -> Result<Vec<(Address, String)>, ImportError> {
|
||||||
let mut entries = Vec::new();
|
let mut entries = Vec::new();
|
||||||
for entry in try!(fs::read_dir(path)) {
|
for entry in try!(fs::read_dir(path)) {
|
||||||
let entry = try!(entry);
|
let entry = try!(entry);
|
||||||
@ -30,10 +31,8 @@ pub fn enumerate_geth_keys(path: &Path) -> Result<Vec<(Address, String)>, io::Er
|
|||||||
Some(name) => {
|
Some(name) => {
|
||||||
let parts: Vec<&str> = name.split("--").collect();
|
let parts: Vec<&str> = name.split("--").collect();
|
||||||
if parts.len() != 3 { continue; }
|
if parts.len() != 3 { continue; }
|
||||||
match Address::from_str(parts[2]) {
|
let account_id = try!(Address::from_str(parts[2]).map_err(|_| ImportError::Format));
|
||||||
Ok(account_id) => { entries.push((account_id, name.to_owned())); }
|
entries.push((account_id, name.to_owned()));
|
||||||
Err(e) => { panic!("error: {:?}", e); }
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
None => { continue; }
|
None => { continue; }
|
||||||
};
|
};
|
||||||
@ -68,9 +67,10 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path)
|
|||||||
Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::Format)),
|
Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::Format)),
|
||||||
Err(_) => { return Err(ImportError::Format); }
|
Err(_) => { return Err(ImportError::Format); }
|
||||||
};
|
};
|
||||||
let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::Format)).clone();
|
if let Some(crypto_object) = json.get("Crypto").and_then(|crypto| crypto.as_object()).cloned() {
|
||||||
json.insert("crypto".to_owned(), Json::Object(crypto_object));
|
json.insert("crypto".to_owned(), Json::Object(crypto_object));
|
||||||
json.remove("Crypto");
|
json.remove("Crypto");
|
||||||
|
}
|
||||||
match KeyFileContent::load(&Json::Object(json.clone())) {
|
match KeyFileContent::load(&Json::Object(json.clone())) {
|
||||||
Ok(key_file) => try!(secret_store.import_key(key_file)),
|
Ok(key_file) => try!(secret_store.import_key(key_file)),
|
||||||
Err(_) => { return Err(ImportError::Format); }
|
Err(_) => { return Err(ImportError::Format); }
|
||||||
@ -93,6 +93,37 @@ pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory:
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Gets the default geth keystore directory.
|
||||||
|
///
|
||||||
|
/// Based on https://github.com/ethereum/go-ethereum/blob/e553215/common/path.go#L75
|
||||||
|
pub fn keystore_dir() -> PathBuf {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn data_dir(mut home: PathBuf) -> PathBuf {
|
||||||
|
home.push("Library");
|
||||||
|
home.push("Ethereum");
|
||||||
|
home
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn data_dir(mut home: PathBuf) -> PathBuf {
|
||||||
|
home.push("AppData");
|
||||||
|
home.push("Roaming");
|
||||||
|
home.push("Ethereum");
|
||||||
|
home
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
fn data_dir(mut home: PathBuf) -> PathBuf {
|
||||||
|
home.push(".ethereum");
|
||||||
|
home
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut data_dir = data_dir(::std::env::home_dir().expect("Failed to get home dir"));
|
||||||
|
data_dir.push("keystore");
|
||||||
|
data_dir
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -113,11 +144,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_enumerate() {
|
fn can_enumerate() {
|
||||||
let keys = enumerate_geth_keys(Path::new(test_path())).unwrap();
|
let keys = enumerate_geth_keys(Path::new(test_path())).unwrap();
|
||||||
assert_eq!(2, keys.len());
|
assert_eq!(3, keys.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_import() {
|
fn can_import_geth_old() {
|
||||||
let temp = ::devtools::RandomTempPath::create_dir();
|
let temp = ::devtools::RandomTempPath::create_dir();
|
||||||
let mut secret_store = SecretStore::new_in(temp.as_path());
|
let mut secret_store = SecretStore::new_in(temp.as_path());
|
||||||
import_geth_key(&mut secret_store, Path::new(&test_path_param("/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9"))).unwrap();
|
import_geth_key(&mut secret_store, Path::new(&test_path_param("/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9"))).unwrap();
|
||||||
@ -125,6 +156,15 @@ mod tests {
|
|||||||
assert!(key.is_some());
|
assert!(key.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_import_geth140() {
|
||||||
|
let temp = ::devtools::RandomTempPath::create_dir();
|
||||||
|
let mut secret_store = SecretStore::new_in(temp.as_path());
|
||||||
|
import_geth_key(&mut secret_store, Path::new(&test_path_param("/UTC--2016-04-03T08-58-49.834202900Z--63121b431a52f8043c16fcf0d1df9cb7b5f66649"))).unwrap();
|
||||||
|
let key = secret_store.account(&Address::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap());
|
||||||
|
assert!(key.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_import_directory() {
|
fn can_import_directory() {
|
||||||
let temp = ::devtools::RandomTempPath::create_dir();
|
let temp = ::devtools::RandomTempPath::create_dir();
|
||||||
|
@ -128,7 +128,7 @@ impl Default for AccountService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AccountService {
|
impl AccountService {
|
||||||
/// New account service with the default location
|
/// New account service with the keys store in default location
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let secret_store = RwLock::new(SecretStore::new());
|
let secret_store = RwLock::new(SecretStore::new());
|
||||||
secret_store.write().unwrap().try_import_existing();
|
secret_store.write().unwrap().try_import_existing();
|
||||||
@ -137,6 +137,15 @@ impl AccountService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// New account service with the keys store in specific location
|
||||||
|
pub fn new_in(path: &Path) -> Self {
|
||||||
|
let secret_store = RwLock::new(SecretStore::new_in(path));
|
||||||
|
secret_store.write().unwrap().try_import_existing();
|
||||||
|
AccountService {
|
||||||
|
secret_store: secret_store
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn new_test(temp: &::devtools::RandomTempPath) -> Self {
|
fn new_test(temp: &::devtools::RandomTempPath) -> Self {
|
||||||
let secret_store = RwLock::new(SecretStore::new_test(temp));
|
let secret_store = RwLock::new(SecretStore::new_test(temp));
|
||||||
@ -183,13 +192,9 @@ impl SecretStore {
|
|||||||
|
|
||||||
/// trys to import keys in the known locations
|
/// trys to import keys in the known locations
|
||||||
pub fn try_import_existing(&mut self) {
|
pub fn try_import_existing(&mut self) {
|
||||||
use std::path::PathBuf;
|
|
||||||
use keys::geth_import;
|
use keys::geth_import;
|
||||||
|
|
||||||
let mut import_path = PathBuf::new();
|
let import_path = geth_import::keystore_dir();
|
||||||
import_path.push(::std::env::home_dir().expect("Failed to get home dir"));
|
|
||||||
import_path.push(".ethereum");
|
|
||||||
import_path.push("keystore");
|
|
||||||
if let Err(e) = geth_import::import_geth_keys(self, &import_path) {
|
if let Err(e) = geth_import::import_geth_keys(self, &import_path) {
|
||||||
trace!(target: "sstore", "Geth key not imported: {:?}", e);
|
trace!(target: "sstore", "Geth key not imported: {:?}", e);
|
||||||
}
|
}
|
||||||
|
@ -381,7 +381,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
|
|
||||||
pub fn add_node(&mut self, id: &str) {
|
pub fn add_node(&mut self, id: &str) {
|
||||||
match Node::from_str(id) {
|
match Node::from_str(id) {
|
||||||
Err(e) => { warn!("Could not add node: {:?}", e); },
|
Err(e) => { debug!("Could not add node {}: {:?}", id, e); },
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() };
|
let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() };
|
||||||
self.pinned_nodes.push(n.id.clone());
|
self.pinned_nodes.push(n.id.clone());
|
||||||
|
Loading…
Reference in New Issue
Block a user