Merge branch 'master' of github.com:ethcore/parity
This commit is contained in:
commit
90a272c519
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -357,7 +357,7 @@ dependencies = [
|
|||||||
"jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
|
"jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-daodapp 0.2.1 (git+https://github.com/ethcore/parity-daodapp-rs.git)",
|
"parity-daodapp 0.2.1 (git+https://github.com/ethcore/parity-daodapp-rs.git)",
|
||||||
"parity-idmanager 0.2.2 (git+https://github.com/ethcore/parity-idmanager-rs.git)",
|
"parity-idmanager 0.3.2 (git+https://github.com/ethcore/parity-idmanager-rs.git)",
|
||||||
"parity-makerotc 0.1.3 (git+https://github.com/ethcore/parity-makerotc-rs.git)",
|
"parity-makerotc 0.1.3 (git+https://github.com/ethcore/parity-makerotc-rs.git)",
|
||||||
"parity-status 0.4.3 (git+https://github.com/ethcore/parity-status.git)",
|
"parity-status 0.4.3 (git+https://github.com/ethcore/parity-status.git)",
|
||||||
"parity-wallet 0.4.1 (git+https://github.com/ethcore/parity-wallet.git)",
|
"parity-wallet 0.4.1 (git+https://github.com/ethcore/parity-wallet.git)",
|
||||||
@ -846,8 +846,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-idmanager"
|
name = "parity-idmanager"
|
||||||
version = "0.2.2"
|
version = "0.3.2"
|
||||||
source = "git+https://github.com/ethcore/parity-idmanager-rs.git#19dd79ca7b7afb8824ad072b43ca63babe2ba9bc"
|
source = "git+https://github.com/ethcore/parity-idmanager-rs.git#5bc85d456455f7b9f6f257021dab9394de9e66b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-webapp 0.2.0 (git+https://github.com/ethcore/parity-webapp.git)",
|
"parity-webapp 0.2.0 (git+https://github.com/ethcore/parity-webapp.git)",
|
||||||
]
|
]
|
||||||
@ -863,7 +863,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-status"
|
name = "parity-status"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
source = "git+https://github.com/ethcore/parity-status.git#1d383d74010f6ebcd712b60b8fc5ff547b44f4e5"
|
source = "git+https://github.com/ethcore/parity-status.git#606dfe6d272792f2fdb90909318f2439d58330a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-webapp 0.2.0 (git+https://github.com/ethcore/parity-webapp.git)",
|
"parity-webapp 0.2.0 (git+https://github.com/ethcore/parity-webapp.git)",
|
||||||
]
|
]
|
||||||
|
@ -374,6 +374,16 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
self.chain.configure_cache(pref_cache_size, max_cache_size);
|
self.chain.configure_cache(pref_cache_size, max_cache_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Look up the block number for the given block ID.
|
||||||
|
pub fn block_number(&self, id: BlockID) -> Option<BlockNumber> {
|
||||||
|
match id {
|
||||||
|
BlockID::Number(number) => Some(number),
|
||||||
|
BlockID::Hash(ref hash) => self.chain.block_number(hash),
|
||||||
|
BlockID::Earliest => Some(0),
|
||||||
|
BlockID::Latest => Some(self.chain.best_block_number())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn block_hash(chain: &BlockChain, id: BlockID) -> Option<H256> {
|
fn block_hash(chain: &BlockChain, id: BlockID) -> Option<H256> {
|
||||||
match id {
|
match id {
|
||||||
BlockID::Hash(hash) => Some(hash),
|
BlockID::Hash(hash) => Some(hash),
|
||||||
@ -383,15 +393,6 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_number(&self, id: BlockID) -> Option<BlockNumber> {
|
|
||||||
match id {
|
|
||||||
BlockID::Number(number) => Some(number),
|
|
||||||
BlockID::Hash(ref hash) => self.chain.block_number(hash),
|
|
||||||
BlockID::Earliest => Some(0),
|
|
||||||
BlockID::Latest => Some(self.chain.best_block_number())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transaction_address(&self, id: TransactionID) -> Option<TransactionAddress> {
|
fn transaction_address(&self, id: TransactionID) -> Option<TransactionAddress> {
|
||||||
match id {
|
match id {
|
||||||
TransactionID::Hash(ref hash) => self.chain.transaction_address(hash),
|
TransactionID::Hash(ref hash) => self.chain.transaction_address(hash),
|
||||||
|
@ -24,7 +24,6 @@ use syntax::ast::{
|
|||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
use syntax::ext::build::AstBuilder;
|
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
pub struct Error;
|
pub struct Error;
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
//! Engine deserialization.
|
//! Engine deserialization.
|
||||||
|
|
||||||
use serde::Deserializer;
|
|
||||||
use serde::de::Visitor;
|
|
||||||
use spec::Ethash;
|
use spec::Ethash;
|
||||||
use spec::BasicAuthority;
|
use spec::BasicAuthority;
|
||||||
|
|
||||||
|
@ -459,9 +459,11 @@ impl MinerService for Miner {
|
|||||||
if let Some(b) = self.sealing_work.lock().unwrap().take_used_if(|b| &b.hash() == &pow_hash) {
|
if let Some(b) = self.sealing_work.lock().unwrap().take_used_if(|b| &b.hash() == &pow_hash) {
|
||||||
match chain.try_seal(b.lock(), seal) {
|
match chain.try_seal(b.lock(), seal) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
info!(target: "miner", "Mined block rejected, PoW was invalid.");
|
||||||
Err(Error::PowInvalid)
|
Err(Error::PowInvalid)
|
||||||
}
|
}
|
||||||
Ok(sealed) => {
|
Ok(sealed) => {
|
||||||
|
info!(target: "miner", "New block mined, hash: {}", sealed.header().hash());
|
||||||
// TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice.
|
// TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice.
|
||||||
let b = sealed.rlp_bytes();
|
let b = sealed.rlp_bytes();
|
||||||
let h = b.sha3();
|
let h = b.sha3();
|
||||||
@ -471,6 +473,7 @@ impl MinerService for Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
info!(target: "miner", "Mined block rejected, PoW hash invalid or out of date.");
|
||||||
Err(Error::PowHashInvalid)
|
Err(Error::PowHashInvalid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ Parity. Ethereum Client.
|
|||||||
Usage:
|
Usage:
|
||||||
parity daemon <pid-file> [options]
|
parity daemon <pid-file> [options]
|
||||||
parity account (new | list) [options]
|
parity account (new | list) [options]
|
||||||
|
parity export [ <file> ] [options]
|
||||||
parity [options]
|
parity [options]
|
||||||
|
|
||||||
Protocol Options:
|
Protocol Options:
|
||||||
@ -42,9 +43,9 @@ Account Options:
|
|||||||
ACCOUNTS is a comma-delimited list of addresses.
|
ACCOUNTS is a comma-delimited list of addresses.
|
||||||
--password FILE Provide a file containing a password for unlocking
|
--password FILE Provide a file containing a password for unlocking
|
||||||
an account.
|
an account.
|
||||||
--keys-iterations NUM Specify the number of iterations to use when deriving key
|
--keys-iterations NUM Specify the number of iterations to use when
|
||||||
from the password (bigger is more secure)
|
deriving key from the password (bigger is more
|
||||||
[default: 10240].
|
secure) [default: 10240].
|
||||||
--no-import-keys Do not import keys from legacy clients.
|
--no-import-keys Do not import keys from legacy clients.
|
||||||
|
|
||||||
Networking Options:
|
Networking Options:
|
||||||
@ -142,6 +143,14 @@ Footprint Options:
|
|||||||
the entire system, overrides other cache and queue
|
the entire system, overrides other cache and queue
|
||||||
options.
|
options.
|
||||||
|
|
||||||
|
Export Options:
|
||||||
|
--from BLOCK Export from block BLOCK, which may be an index or
|
||||||
|
hash [default: 0].
|
||||||
|
--to BLOCK Export to (including) block NUMBER, which may be an
|
||||||
|
index, hash or 'latest' [default: latest].
|
||||||
|
--format FORMAT Export in given format. FORMAT must be one of 'hex'
|
||||||
|
and 'binary' [default: hex].
|
||||||
|
|
||||||
Virtual Machine Options:
|
Virtual Machine Options:
|
||||||
--jitvm Enable the JIT VM.
|
--jitvm Enable the JIT VM.
|
||||||
|
|
||||||
@ -186,7 +195,9 @@ pub struct Args {
|
|||||||
pub cmd_account: bool,
|
pub cmd_account: bool,
|
||||||
pub cmd_new: bool,
|
pub cmd_new: bool,
|
||||||
pub cmd_list: bool,
|
pub cmd_list: bool,
|
||||||
|
pub cmd_export: bool,
|
||||||
pub arg_pid_file: String,
|
pub arg_pid_file: String,
|
||||||
|
pub arg_file: Option<String>,
|
||||||
pub flag_chain: String,
|
pub flag_chain: String,
|
||||||
pub flag_db_path: String,
|
pub flag_db_path: String,
|
||||||
pub flag_identity: String,
|
pub flag_identity: String,
|
||||||
@ -230,6 +241,9 @@ pub struct Args {
|
|||||||
pub flag_tx_limit: usize,
|
pub flag_tx_limit: usize,
|
||||||
pub flag_logging: Option<String>,
|
pub flag_logging: Option<String>,
|
||||||
pub flag_version: bool,
|
pub flag_version: bool,
|
||||||
|
pub flag_from: String,
|
||||||
|
pub flag_to: String,
|
||||||
|
pub flag_format: String,
|
||||||
pub flag_jitvm: bool,
|
pub flag_jitvm: bool,
|
||||||
// legacy...
|
// legacy...
|
||||||
pub flag_geth: bool,
|
pub flag_geth: bool,
|
||||||
|
@ -65,7 +65,9 @@ mod configuration;
|
|||||||
|
|
||||||
use ctrlc::CtrlC;
|
use ctrlc::CtrlC;
|
||||||
use util::*;
|
use util::*;
|
||||||
|
use std::fs::File;
|
||||||
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
|
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
|
||||||
|
use ethcore::client::{BlockID, BlockChainClient};
|
||||||
use ethcore::service::ClientService;
|
use ethcore::service::ClientService;
|
||||||
use ethsync::EthSync;
|
use ethsync::EthSync;
|
||||||
use ethminer::{Miner, MinerService, ExternalMiner};
|
use ethminer::{Miner, MinerService, ExternalMiner};
|
||||||
@ -104,6 +106,11 @@ fn execute(conf: Configuration) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.args.cmd_export {
|
||||||
|
execute_export(conf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
execute_client(conf);
|
execute_client(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,6 +223,80 @@ fn flush_stdout() {
|
|||||||
::std::io::stdout().flush().expect("stdout is flushable; qed");
|
::std::io::stdout().flush().expect("stdout is flushable; qed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DataFormat {
|
||||||
|
Hex,
|
||||||
|
Binary,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_export(conf: Configuration) {
|
||||||
|
println!("Exporting to {:?} from {}, to {}", conf.args.arg_file, conf.args.flag_from, conf.args.flag_to);
|
||||||
|
|
||||||
|
// Setup panic handler
|
||||||
|
let panic_handler = PanicHandler::new_in_arc();
|
||||||
|
|
||||||
|
// Raise fdlimit
|
||||||
|
unsafe { ::fdlimit::raise_fd_limit(); }
|
||||||
|
|
||||||
|
let spec = conf.spec();
|
||||||
|
let net_settings = NetworkConfiguration {
|
||||||
|
config_path: None,
|
||||||
|
listen_address: None,
|
||||||
|
public_address: None,
|
||||||
|
udp_port: None,
|
||||||
|
nat_enabled: false,
|
||||||
|
discovery_enabled: false,
|
||||||
|
pin: true,
|
||||||
|
boot_nodes: Vec::new(),
|
||||||
|
use_secret: None,
|
||||||
|
ideal_peers: 0,
|
||||||
|
};
|
||||||
|
let client_config = conf.client_config(&spec);
|
||||||
|
|
||||||
|
// Build client
|
||||||
|
let service = ClientService::start(
|
||||||
|
client_config, spec, net_settings, Path::new(&conf.path())
|
||||||
|
).unwrap_or_else(|e| die_with_error("Client", e));
|
||||||
|
|
||||||
|
panic_handler.forward_from(&service);
|
||||||
|
let client = service.client();
|
||||||
|
|
||||||
|
// we have a client!
|
||||||
|
let parse_block_id = |s: &str, arg: &str| -> u64 {
|
||||||
|
if s == "latest" {
|
||||||
|
client.chain_info().best_block_number
|
||||||
|
} else if let Ok(n) = s.parse::<u64>() {
|
||||||
|
n
|
||||||
|
} else if let Ok(h) = H256::from_str(s) {
|
||||||
|
client.block_number(BlockID::Hash(h)).unwrap_or_else(|| {
|
||||||
|
die!("Unknown block hash passed to {} parameter: {:?}", arg, s);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
die!("Invalid {} parameter given: {:?}", arg, s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let from = parse_block_id(&conf.args.flag_from, "--from");
|
||||||
|
let to = parse_block_id(&conf.args.flag_to, "--to");
|
||||||
|
let format = match conf.args.flag_format.deref() {
|
||||||
|
"binary" | "bin" => DataFormat::Binary,
|
||||||
|
"hex" => DataFormat::Hex,
|
||||||
|
x => die!("Invalid --format parameter given: {:?}", x),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut out: Box<Write> = if let Some(f) = conf.args.arg_file {
|
||||||
|
Box::new(File::create(&f).unwrap_or_else(|_| die!("Cannot write to file given: {}", f)))
|
||||||
|
} else {
|
||||||
|
Box::new(::std::io::stdout())
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in from..(to + 1) {
|
||||||
|
let b = client.deref().block(BlockID::Number(i)).unwrap();
|
||||||
|
match format {
|
||||||
|
DataFormat::Binary => { out.write(&b).expect("Couldn't write to stream."); }
|
||||||
|
DataFormat::Hex => { out.write_fmt(format_args!("{}", b.pretty())).expect("Couldn't write to stream."); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn execute_account_cli(conf: Configuration) {
|
fn execute_account_cli(conf: Configuration) {
|
||||||
use util::keys::store::SecretStore;
|
use util::keys::store::SecretStore;
|
||||||
use rpassword::read_password;
|
use rpassword::read_password;
|
||||||
|
@ -41,12 +41,13 @@ use util::keys::store::AccountProvider;
|
|||||||
use serde;
|
use serde;
|
||||||
|
|
||||||
/// Eth rpc implementation.
|
/// Eth rpc implementation.
|
||||||
pub struct EthClient<C, S, A, M, EM>
|
pub struct EthClient<C, S, A, M, EM> where
|
||||||
where C: BlockChainClient,
|
C: BlockChainClient,
|
||||||
S: SyncProvider,
|
S: SyncProvider,
|
||||||
A: AccountProvider,
|
A: AccountProvider,
|
||||||
M: MinerService,
|
M: MinerService,
|
||||||
EM: ExternalMinerService {
|
EM: ExternalMinerService {
|
||||||
|
|
||||||
client: Weak<C>,
|
client: Weak<C>,
|
||||||
sync: Weak<S>,
|
sync: Weak<S>,
|
||||||
accounts: Weak<A>,
|
accounts: Weak<A>,
|
||||||
@ -55,8 +56,8 @@ pub struct EthClient<C, S, A, M, EM>
|
|||||||
seed_compute: Mutex<SeedHashCompute>,
|
seed_compute: Mutex<SeedHashCompute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
impl<C, S, A, M, EM> EthClient<C, S, A, M, EM> where
|
||||||
where C: BlockChainClient,
|
C: BlockChainClient,
|
||||||
S: SyncProvider,
|
S: SyncProvider,
|
||||||
A: AccountProvider,
|
A: AccountProvider,
|
||||||
M: MinerService,
|
M: MinerService,
|
||||||
@ -152,6 +153,27 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sign_and_dispatch(&self, request: TransactionRequest, secret: H256) -> Result<Value, Error> {
|
||||||
|
let signed_transaction = {
|
||||||
|
let client = take_weak!(self.client);
|
||||||
|
let miner = take_weak!(self.miner);
|
||||||
|
EthTransaction {
|
||||||
|
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),
|
||||||
|
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
||||||
|
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
||||||
|
value: request.value.unwrap_or_else(U256::zero),
|
||||||
|
data: request.data.map_or_else(Vec::new, |d| d.to_vec()),
|
||||||
|
}.sign(&secret)
|
||||||
|
};
|
||||||
|
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
|
||||||
|
self.dispatch_transaction(signed_transaction)
|
||||||
|
}
|
||||||
|
|
||||||
fn sign_call(&self, request: CallRequest) -> Result<SignedTransaction, Error> {
|
fn sign_call(&self, request: CallRequest) -> Result<SignedTransaction, Error> {
|
||||||
let client = take_weak!(self.client);
|
let client = take_weak!(self.client);
|
||||||
let miner = take_weak!(self.miner);
|
let miner = take_weak!(self.miner);
|
||||||
@ -214,8 +236,8 @@ fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNum
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
|
||||||
where C: BlockChainClient + 'static,
|
C: BlockChainClient + 'static,
|
||||||
S: SyncProvider + 'static,
|
S: SyncProvider + 'static,
|
||||||
A: AccountProvider + 'static,
|
A: AccountProvider + 'static,
|
||||||
M: MinerService + 'static,
|
M: MinerService + 'static,
|
||||||
@ -252,7 +274,6 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do not hardcode author.
|
|
||||||
fn author(&self, params: Params) -> Result<Value, Error> {
|
fn author(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => to_value(&take_weak!(self.miner).author()),
|
Params::None => to_value(&take_weak!(self.miner).author()),
|
||||||
@ -260,7 +281,6 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return real value of mining once it's implemented.
|
|
||||||
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => to_value(&self.external_miner.is_mining()),
|
Params::None => to_value(&self.external_miner.is_mining()),
|
||||||
@ -268,7 +288,6 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return real hashrate once we have mining
|
|
||||||
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
||||||
match params {
|
match params {
|
||||||
Params::None => to_value(&self.external_miner.hashrate()),
|
Params::None => to_value(&self.external_miner.hashrate()),
|
||||||
@ -485,27 +504,19 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
.and_then(|(request, )| {
|
.and_then(|(request, )| {
|
||||||
let accounts = take_weak!(self.accounts);
|
let accounts = take_weak!(self.accounts);
|
||||||
match accounts.account_secret(&request.from) {
|
match accounts.account_secret(&request.from) {
|
||||||
Ok(secret) => {
|
Ok(secret) => self.sign_and_dispatch(request, secret),
|
||||||
let signed_transaction = {
|
Err(_) => to_value(&H256::zero())
|
||||||
let client = take_weak!(self.client);
|
}
|
||||||
let miner = take_weak!(self.miner);
|
})
|
||||||
EthTransaction {
|
}
|
||||||
nonce: request.nonce
|
|
||||||
.or_else(|| miner
|
fn sign_and_send_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||||
.last_nonce(&request.from)
|
from_params::<(TransactionRequest, String)>(params)
|
||||||
.map(|nonce| nonce + U256::one()))
|
.and_then(|(request, password)| {
|
||||||
.unwrap_or_else(|| client.nonce(&request.from)),
|
let accounts = take_weak!(self.accounts);
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
match accounts.locked_account_secret(&request.from, &password) {
|
||||||
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
Ok(secret) => self.sign_and_dispatch(request, secret),
|
||||||
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
|
Err(_) => to_value(&H256::zero()),
|
||||||
value: request.value.unwrap_or_else(U256::zero),
|
|
||||||
data: request.data.map_or_else(Vec::new, |d| d.to_vec()),
|
|
||||||
}.sign(&secret)
|
|
||||||
};
|
|
||||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
|
|
||||||
self.dispatch_transaction(signed_transaction)
|
|
||||||
},
|
|
||||||
Err(_) => { to_value(&H256::zero()) }
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -550,8 +561,8 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Eth filter rpc implementation.
|
/// Eth filter rpc implementation.
|
||||||
pub struct EthFilterClient<C, M>
|
pub struct EthFilterClient<C, M> where
|
||||||
where C: BlockChainClient,
|
C: BlockChainClient,
|
||||||
M: MinerService {
|
M: MinerService {
|
||||||
|
|
||||||
client: Weak<C>,
|
client: Weak<C>,
|
||||||
@ -559,8 +570,8 @@ pub struct EthFilterClient<C, M>
|
|||||||
polls: Mutex<PollManager<PollFilter>>,
|
polls: Mutex<PollManager<PollFilter>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, M> EthFilterClient<C, M>
|
impl<C, M> EthFilterClient<C, M> where
|
||||||
where C: BlockChainClient,
|
C: BlockChainClient,
|
||||||
M: MinerService {
|
M: MinerService {
|
||||||
|
|
||||||
/// Creates new Eth filter client.
|
/// Creates new Eth filter client.
|
||||||
@ -573,8 +584,8 @@ impl<C, M> EthFilterClient<C, M>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, M> EthFilter for EthFilterClient<C, M>
|
impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||||
where C: BlockChainClient + 'static,
|
C: BlockChainClient + 'static,
|
||||||
M: MinerService + 'static {
|
M: MinerService + 'static {
|
||||||
|
|
||||||
fn new_filter(&self, params: Params) -> Result<Value, Error> {
|
fn new_filter(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
@ -521,6 +521,81 @@ fn rpc_eth_send_transaction() {
|
|||||||
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
|
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_eth_sign_and_send_transaction_with_invalid_password() {
|
||||||
|
let account = TestAccount::new("password123");
|
||||||
|
let address = account.address();
|
||||||
|
|
||||||
|
let tester = EthTester::default();
|
||||||
|
tester.accounts_provider.accounts.write().unwrap().insert(address.clone(), account);
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_signAndSendTransaction",
|
||||||
|
"params": [{
|
||||||
|
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
|
||||||
|
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||||
|
"gas": "0x76c0",
|
||||||
|
"gasPrice": "0x9184e72a000",
|
||||||
|
"value": "0x9184e72a"
|
||||||
|
}, "password321"],
|
||||||
|
"id": 1
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000","id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_eth_sign_and_send_transaction() {
|
||||||
|
let account = TestAccount::new("password123");
|
||||||
|
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_signAndSendTransaction",
|
||||||
|
"params": [{
|
||||||
|
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
|
||||||
|
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||||
|
"gas": "0x76c0",
|
||||||
|
"gasPrice": "0x9184e72a000",
|
||||||
|
"value": "0x9184e72a"
|
||||||
|
}, "password123"],
|
||||||
|
"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]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn rpc_eth_send_raw_transaction() {
|
fn rpc_eth_send_raw_transaction() {
|
||||||
|
@ -80,6 +80,9 @@ pub trait Eth: Sized + Send + Sync + 'static {
|
|||||||
/// Sends transaction.
|
/// Sends transaction.
|
||||||
fn send_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn send_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Sends transaction and signs it in single call. The account is not unlocked in such case.
|
||||||
|
fn sign_and_send_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
/// Sends signed transaction.
|
/// Sends signed transaction.
|
||||||
fn send_raw_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn send_raw_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
@ -152,6 +155,7 @@ pub trait Eth: Sized + Send + Sync + 'static {
|
|||||||
delegate.add_method("eth_getCode", Eth::code_at);
|
delegate.add_method("eth_getCode", Eth::code_at);
|
||||||
delegate.add_method("eth_sign", Eth::sign);
|
delegate.add_method("eth_sign", Eth::sign);
|
||||||
delegate.add_method("eth_sendTransaction", Eth::send_transaction);
|
delegate.add_method("eth_sendTransaction", Eth::send_transaction);
|
||||||
|
delegate.add_method("eth_signAndSendTransaction", Eth::sign_and_send_transaction);
|
||||||
delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction);
|
delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction);
|
||||||
delegate.add_method("eth_call", Eth::call);
|
delegate.add_method("eth_call", Eth::call);
|
||||||
delegate.add_method("eth_estimateGas", Eth::estimate_gas);
|
delegate.add_method("eth_estimateGas", Eth::estimate_gas);
|
||||||
|
@ -18,11 +18,8 @@ use std::sync::*;
|
|||||||
use std::thread::{self, JoinHandle};
|
use std::thread::{self, JoinHandle};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use mio::*;
|
use mio::*;
|
||||||
use hash::*;
|
|
||||||
use rlp::*;
|
|
||||||
use error::*;
|
use error::*;
|
||||||
use io::{IoError, IoHandler};
|
use io::{IoError, IoHandler};
|
||||||
use arrayvec::*;
|
|
||||||
use crossbeam::sync::chase_lev;
|
use crossbeam::sync::chase_lev;
|
||||||
use io::worker::{Worker, Work, WorkType};
|
use io::worker::{Worker, Work, WorkType};
|
||||||
use panics::*;
|
use panics::*;
|
||||||
|
@ -58,13 +58,15 @@ pub enum EncryptedHashMapError {
|
|||||||
InvalidValueFormat(FromBytesError),
|
InvalidValueFormat(FromBytesError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error retrieving value from encrypted hashmap
|
/// Error while signing a message
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SigningError {
|
pub enum SigningError {
|
||||||
/// Account passed does not exist
|
/// Account passed does not exist
|
||||||
NoAccount,
|
NoAccount,
|
||||||
/// Account passed is not unlocked
|
/// Account passed is not unlocked
|
||||||
AccountNotUnlocked,
|
AccountNotUnlocked,
|
||||||
|
/// Invalid passphrase
|
||||||
|
InvalidPassword,
|
||||||
/// Invalid secret in store
|
/// Invalid secret in store
|
||||||
InvalidSecret
|
InvalidSecret
|
||||||
}
|
}
|
||||||
@ -96,6 +98,8 @@ pub trait AccountProvider : Send + Sync {
|
|||||||
fn new_account(&self, pass: &str) -> Result<Address, ::std::io::Error>;
|
fn new_account(&self, pass: &str) -> Result<Address, ::std::io::Error>;
|
||||||
/// Returns secret for unlocked `account`.
|
/// Returns secret for unlocked `account`.
|
||||||
fn account_secret(&self, account: &Address) -> Result<crypto::Secret, SigningError>;
|
fn account_secret(&self, account: &Address) -> Result<crypto::Secret, SigningError>;
|
||||||
|
/// Returns secret for locked account given passphrase.
|
||||||
|
fn locked_account_secret(&self, account: &Address, pass: &str) -> Result<crypto::Secret, SigningError>;
|
||||||
/// Returns signature when unlocked `account` signs `message`.
|
/// Returns signature when unlocked `account` signs `message`.
|
||||||
fn sign(&self, account: &Address, message: &H256) -> Result<crypto::Signature, SigningError> {
|
fn sign(&self, account: &Address, message: &H256) -> Result<crypto::Signature, SigningError> {
|
||||||
self.account_secret(account).and_then(|s| crypto::ec::sign(&s, message).map_err(|_| SigningError::InvalidSecret))
|
self.account_secret(account).and_then(|s| crypto::ec::sign(&s, message).map_err(|_| SigningError::InvalidSecret))
|
||||||
@ -127,7 +131,11 @@ impl AccountProvider for AccountService {
|
|||||||
fn account_secret(&self, account: &Address) -> Result<crypto::Secret, SigningError> {
|
fn account_secret(&self, account: &Address) -> Result<crypto::Secret, SigningError> {
|
||||||
self.secret_store.read().unwrap().account_secret(account)
|
self.secret_store.read().unwrap().account_secret(account)
|
||||||
}
|
}
|
||||||
/// Returns secret for unlocked account
|
/// Returns secret for locked account given passphrase.
|
||||||
|
fn locked_account_secret(&self, account: &Address, pass: &str) -> Result<crypto::Secret, SigningError> {
|
||||||
|
self.secret_store.read().unwrap().locked_account_secret(account, pass)
|
||||||
|
}
|
||||||
|
/// Signs a message using key of given unlocked account address.
|
||||||
fn sign(&self, account: &Address, message: &H256) -> Result<crypto::Signature, SigningError> {
|
fn sign(&self, account: &Address, message: &H256) -> Result<crypto::Signature, SigningError> {
|
||||||
self.secret_store.read().unwrap().sign(account, message)
|
self.secret_store.read().unwrap().sign(account, message)
|
||||||
}
|
}
|
||||||
@ -317,6 +325,16 @@ impl SecretStore {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns secret for unlocked account.
|
||||||
|
pub fn locked_account_secret(&self, account: &Address, pass: &str) -> Result<crypto::Secret, SigningError> {
|
||||||
|
let secret_id = try!(self.account(&account).ok_or(SigningError::NoAccount));
|
||||||
|
self.get(&secret_id, pass).or_else(|e| Err(match e {
|
||||||
|
EncryptedHashMapError::InvalidPassword => SigningError::InvalidPassword,
|
||||||
|
EncryptedHashMapError::UnknownIdentifier => SigningError::NoAccount,
|
||||||
|
EncryptedHashMapError::InvalidValueFormat(_) => SigningError::InvalidSecret,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes account unlocks expire and removes unused key files from memory
|
/// Makes account unlocks expire and removes unused key files from memory
|
||||||
pub fn collect_garbage(&mut self) {
|
pub fn collect_garbage(&mut self) {
|
||||||
let mut garbage_lock = self.unlocks.write().unwrap();
|
let mut garbage_lock = self.unlocks.write().unwrap();
|
||||||
@ -679,6 +697,29 @@ mod tests {
|
|||||||
assert_eq!(Address::from(kp.public().sha3()), addr);
|
assert_eq!(Address::from(kp.public().sha3()), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn secret_for_locked_account() {
|
||||||
|
// given
|
||||||
|
let temp = RandomTempPath::create_dir();
|
||||||
|
let mut sstore = SecretStore::new_test(&temp);
|
||||||
|
let addr = sstore.new_account("test-pass").unwrap();
|
||||||
|
|
||||||
|
// when
|
||||||
|
// Invalid pass
|
||||||
|
let secret1 = sstore.locked_account_secret(&addr, "test-pass123");
|
||||||
|
// Valid pass
|
||||||
|
let secret2 = sstore.locked_account_secret(&addr, "test-pass");
|
||||||
|
// Account not unlocked
|
||||||
|
let secret3 = sstore.account_secret(&addr);
|
||||||
|
|
||||||
|
|
||||||
|
assert!(secret1.is_err(), "Invalid password should not return secret.");
|
||||||
|
assert!(secret2.is_ok(), "Should return secret provided valid passphrase.");
|
||||||
|
assert!(secret3.is_err(), "Account should still be locked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_create_service() {
|
fn can_create_service() {
|
||||||
let temp = RandomTempPath::create_dir();
|
let temp = RandomTempPath::create_dir();
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use hash::{Address, FixedHash};
|
use hash::Address;
|
||||||
use crypto::{Secret, KeyPair};
|
use crypto::{Secret, KeyPair};
|
||||||
use super::store::{AccountProvider, SigningError, EncryptedHashMapError};
|
use super::store::{AccountProvider, SigningError, EncryptedHashMapError};
|
||||||
|
|
||||||
@ -103,5 +103,16 @@ impl AccountProvider for TestAccountProvider {
|
|||||||
.ok_or(SigningError::NoAccount)
|
.ok_or(SigningError::NoAccount)
|
||||||
.map(|acc| acc.secret.clone())
|
.map(|acc| acc.secret.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn locked_account_secret(&self, address: &Address, pass: &str) -> Result<Secret, SigningError> {
|
||||||
|
let accounts = self.accounts.read().unwrap();
|
||||||
|
match accounts.get(address) {
|
||||||
|
Some(ref acc) if acc.password == pass => {
|
||||||
|
Ok(acc.secret.clone())
|
||||||
|
},
|
||||||
|
Some(ref _acc) => Err(SigningError::InvalidPassword),
|
||||||
|
_ => Err(SigningError::NoAccount),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +512,6 @@ mod tests {
|
|||||||
use crypto::KeyPair;
|
use crypto::KeyPair;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use rustc_serialize::hex::FromHex;
|
use rustc_serialize::hex::FromHex;
|
||||||
use rlp::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn find_node() {
|
fn find_node() {
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
use std::net::{SocketAddr};
|
use std::net::{SocketAddr};
|
||||||
use std::collections::{HashMap};
|
use std::collections::{HashMap};
|
||||||
use std::hash::{Hasher};
|
|
||||||
use std::str::{FromStr};
|
use std::str::{FromStr};
|
||||||
use std::sync::*;
|
use std::sync::*;
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::io;
|
use std::io;
|
||||||
use mio::*;
|
use mio::*;
|
||||||
use hash::*;
|
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use network::connection::{EncryptedConnection, Packet};
|
use network::connection::{EncryptedConnection, Packet};
|
||||||
use network::handshake::Handshake;
|
use network::handshake::Handshake;
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use hash::*;
|
|
||||||
use nibbleslice::*;
|
use nibbleslice::*;
|
||||||
use bytes::*;
|
use bytes::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
use hash::*;
|
use hash::*;
|
||||||
use sha3::*;
|
use sha3::*;
|
||||||
use hashdb::*;
|
use hashdb::*;
|
||||||
use rlp::*;
|
|
||||||
use super::triedb::*;
|
use super::triedb::*;
|
||||||
use super::trietraits::*;
|
use super::trietraits::*;
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
use hash::*;
|
use hash::*;
|
||||||
use sha3::*;
|
use sha3::*;
|
||||||
use hashdb::*;
|
use hashdb::*;
|
||||||
use rlp::*;
|
|
||||||
use super::triedbmut::*;
|
use super::triedbmut::*;
|
||||||
use super::trietraits::*;
|
use super::trietraits::*;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ ethcore-util = { path = "../util" }
|
|||||||
parity-webapp = { git = "https://github.com/ethcore/parity-webapp.git", version = "0.2" }
|
parity-webapp = { git = "https://github.com/ethcore/parity-webapp.git", version = "0.2" }
|
||||||
# List of apps
|
# List of apps
|
||||||
parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.4.3" }
|
parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.4.3" }
|
||||||
parity-idmanager = { git = "https://github.com/ethcore/parity-idmanager-rs.git", version = "0.2.2" }
|
parity-idmanager = { git = "https://github.com/ethcore/parity-idmanager-rs.git", version = "0.3.2" }
|
||||||
parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.4.1", optional = true }
|
parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.4.1", optional = true }
|
||||||
parity-daodapp = { git = "https://github.com/ethcore/parity-daodapp-rs.git", version = "0.2.1", optional = true }
|
parity-daodapp = { git = "https://github.com/ethcore/parity-daodapp-rs.git", version = "0.2.1", optional = true }
|
||||||
parity-makerotc = { git = "https://github.com/ethcore/parity-makerotc-rs.git", version = "0.1.3", optional = true }
|
parity-makerotc = { git = "https://github.com/ethcore/parity-makerotc-rs.git", version = "0.1.3", optional = true }
|
||||||
|
Loading…
Reference in New Issue
Block a user