Refactoring Signer to auto_args + eth_signTransaction (#3261)
* Sign transaction initial * Refactoring signer to auto_args
This commit is contained in:
parent
3c6f148a16
commit
b33b237f76
@ -14,84 +14,153 @@
|
|||||||
// 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 rlp;
|
||||||
use util::{Address, H256, U256, Uint, Bytes};
|
use util::{Address, H256, U256, Uint, Bytes};
|
||||||
use util::bytes::ToPretty;
|
use util::bytes::ToPretty;
|
||||||
|
|
||||||
use ethkey::Signature;
|
use ethkey::Signature;
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use ethcore::client::MiningBlockChainClient;
|
use ethcore::client::MiningBlockChainClient;
|
||||||
use ethcore::transaction::{Action, SignedTransaction, Transaction};
|
use ethcore::transaction::{Action, SignedTransaction, Transaction};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use jsonrpc_core::{Error, Value, to_value};
|
|
||||||
use v1::helpers::TransactionRequest;
|
use jsonrpc_core::Error;
|
||||||
use v1::types::{H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes};
|
use v1::helpers::{errors, TransactionRequest, FilledTransactionRequest, ConfirmationPayload};
|
||||||
use v1::helpers::errors;
|
use v1::types::{
|
||||||
|
H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes,
|
||||||
|
ConfirmationPayload as RpcConfirmationPayload,
|
||||||
|
ConfirmationResponse,
|
||||||
|
SignRequest as RpcSignRequest,
|
||||||
|
DecryptRequest as RpcDecryptRequest,
|
||||||
|
};
|
||||||
|
|
||||||
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
|
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
|
||||||
|
|
||||||
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<RpcH256, Error>
|
pub fn execute<C, M>(client: &C, miner: &M, accounts: &AccountProvider, payload: ConfirmationPayload, pass: Option<String>) -> Result<ConfirmationResponse, Error>
|
||||||
where C: MiningBlockChainClient, M: MinerService {
|
where C: MiningBlockChainClient, M: MinerService
|
||||||
let hash = RpcH256::from(signed_transaction.hash());
|
{
|
||||||
|
match payload {
|
||||||
miner.import_own_transaction(client, signed_transaction)
|
ConfirmationPayload::SendTransaction(request) => {
|
||||||
.map_err(errors::from_transaction_error)
|
sign_and_dispatch(client, miner, accounts, request, pass)
|
||||||
.map(|_| hash)
|
.map(RpcH256::from)
|
||||||
|
.map(ConfirmationResponse::SendTransaction)
|
||||||
|
},
|
||||||
|
ConfirmationPayload::SignTransaction(request) => {
|
||||||
|
sign_no_dispatch(client, miner, accounts, request, pass)
|
||||||
|
.map(|tx| rlp::encode(&tx).to_vec())
|
||||||
|
.map(RpcBytes)
|
||||||
|
.map(ConfirmationResponse::SignTransaction)
|
||||||
|
},
|
||||||
|
ConfirmationPayload::Signature(address, hash) => {
|
||||||
|
signature(accounts, address, hash, pass)
|
||||||
|
.map(RpcH520::from)
|
||||||
|
.map(ConfirmationResponse::Signature)
|
||||||
|
},
|
||||||
|
ConfirmationPayload::Decrypt(address, data) => {
|
||||||
|
decrypt(accounts, address, data, pass)
|
||||||
|
.map(RpcBytes)
|
||||||
|
.map(ConfirmationResponse::Decrypt)
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(accounts: &AccountProvider, address: Address, password: Option<String>, hash: H256) -> Result<Signature, Error> {
|
fn signature(accounts: &AccountProvider, address: Address, hash: H256, password: Option<String>) -> Result<Signature, Error> {
|
||||||
accounts.sign(address, password.clone(), hash).map_err(|e| match password {
|
accounts.sign(address, password.clone(), hash).map_err(|e| match password {
|
||||||
Some(_) => errors::from_password_error(e),
|
Some(_) => errors::from_password_error(e),
|
||||||
None => errors::from_signing_error(e),
|
None => errors::from_signing_error(e),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign(accounts: &AccountProvider, address: Address, password: Option<String>, hash: H256) -> Result<Value, Error> {
|
fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: Option<String>) -> Result<Bytes, Error> {
|
||||||
signature(accounts, address, password, hash)
|
|
||||||
.map(RpcH520::from)
|
|
||||||
.map(to_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decrypt(accounts: &AccountProvider, address: Address, password: Option<String>, msg: Bytes) -> Result<Value, Error> {
|
|
||||||
accounts.decrypt(address, password.clone(), &DEFAULT_MAC, &msg)
|
accounts.decrypt(address, password.clone(), &DEFAULT_MAC, &msg)
|
||||||
.map_err(|e| match password {
|
.map_err(|e| match password {
|
||||||
Some(_) => errors::from_password_error(e),
|
Some(_) => errors::from_password_error(e),
|
||||||
None => errors::from_signing_error(e),
|
None => errors::from_signing_error(e),
|
||||||
})
|
})
|
||||||
.map(RpcBytes::from)
|
|
||||||
.map(to_value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, request: TransactionRequest, password: Option<String>) -> Result<RpcH256, Error>
|
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<H256, Error>
|
||||||
|
where C: MiningBlockChainClient, M: MinerService {
|
||||||
|
let hash = signed_transaction.hash();
|
||||||
|
|
||||||
|
miner.import_own_transaction(client, signed_transaction)
|
||||||
|
.map_err(errors::from_transaction_error)
|
||||||
|
.map(|_| hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign_no_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, filled: FilledTransactionRequest, password: Option<String>) -> Result<SignedTransaction, Error>
|
||||||
where C: MiningBlockChainClient, M: MinerService {
|
where C: MiningBlockChainClient, M: MinerService {
|
||||||
|
|
||||||
let network_id = client.signing_network_id();
|
let network_id = client.signing_network_id();
|
||||||
let address = request.from;
|
let address = filled.from;
|
||||||
let signed_transaction = {
|
let signed_transaction = {
|
||||||
let t = prepare_transaction(client, miner, request);
|
let t = Transaction {
|
||||||
|
nonce: filled.nonce
|
||||||
|
.or_else(|| miner
|
||||||
|
.last_nonce(&filled.from)
|
||||||
|
.map(|nonce| nonce + U256::one()))
|
||||||
|
.unwrap_or_else(|| client.latest_nonce(&filled.from)),
|
||||||
|
|
||||||
|
action: filled.to.map_or(Action::Create, Action::Call),
|
||||||
|
gas: filled.gas,
|
||||||
|
gas_price: filled.gas_price,
|
||||||
|
value: filled.value,
|
||||||
|
data: filled.data,
|
||||||
|
};
|
||||||
|
|
||||||
let hash = t.hash(network_id);
|
let hash = t.hash(network_id);
|
||||||
let signature = try!(signature(accounts, address, password, hash));
|
let signature = try!(signature(accounts, address, hash, password));
|
||||||
t.with_signature(signature, network_id)
|
t.with_signature(signature, network_id)
|
||||||
};
|
};
|
||||||
|
Ok(signed_transaction)
|
||||||
|
}
|
||||||
|
|
||||||
trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", ::rlp::encode(&signed_transaction).to_vec().pretty(), network_id);
|
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, filled: FilledTransactionRequest, password: Option<String>) -> Result<H256, Error>
|
||||||
|
where C: MiningBlockChainClient, M: MinerService
|
||||||
|
{
|
||||||
|
|
||||||
|
let network_id = client.signing_network_id();
|
||||||
|
let signed_transaction = try!(sign_no_dispatch(client, miner, accounts, filled, password));
|
||||||
|
|
||||||
|
trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", rlp::encode(&signed_transaction).to_vec().pretty(), network_id);
|
||||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_transaction<C, M>(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService {
|
pub fn fill_optional_fields<C, M>(request: TransactionRequest, client: &C, miner: &M) -> FilledTransactionRequest
|
||||||
Transaction {
|
where C: MiningBlockChainClient, M: MinerService
|
||||||
nonce: request.nonce
|
{
|
||||||
.or_else(|| miner
|
FilledTransactionRequest {
|
||||||
.last_nonce(&request.from)
|
from: request.from,
|
||||||
.map(|nonce| nonce + U256::one()))
|
to: request.to,
|
||||||
.unwrap_or_else(|| client.latest_nonce(&request.from)),
|
nonce: request.nonce,
|
||||||
|
|
||||||
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(|| default_gas_price(client, miner)),
|
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
|
||||||
value: request.value.unwrap_or_else(U256::zero),
|
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
||||||
data: request.data.map_or_else(Vec::new, |b| b.to_vec()),
|
value: request.value.unwrap_or_else(|| 0.into()),
|
||||||
|
data: request.data.unwrap_or_else(Vec::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService {
|
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256
|
||||||
|
where C: MiningBlockChainClient, M: MinerService
|
||||||
|
{
|
||||||
client.gas_price_median(100).unwrap_or_else(|| miner.sensible_gas_price())
|
client.gas_price_median(100).unwrap_or_else(|| miner.sensible_gas_price())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_rpc<C, M>(payload: RpcConfirmationPayload, client: &C, miner: &M) -> ConfirmationPayload
|
||||||
|
where C: MiningBlockChainClient, M: MinerService {
|
||||||
|
|
||||||
|
match payload {
|
||||||
|
RpcConfirmationPayload::SendTransaction(request) => {
|
||||||
|
ConfirmationPayload::SendTransaction(fill_optional_fields(request.into(), client, miner))
|
||||||
|
},
|
||||||
|
RpcConfirmationPayload::SignTransaction(request) => {
|
||||||
|
ConfirmationPayload::SignTransaction(fill_optional_fields(request.into(), client, miner))
|
||||||
|
},
|
||||||
|
RpcConfirmationPayload::Decrypt(RpcDecryptRequest { address, msg }) => {
|
||||||
|
ConfirmationPayload::Decrypt(address.into(), msg.into())
|
||||||
|
},
|
||||||
|
RpcConfirmationPayload::Signature(RpcSignRequest { address, hash }) => {
|
||||||
|
ConfirmationPayload::Signature(address.into(), hash.into())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -100,9 +100,22 @@ pub struct ConfirmationRequest {
|
|||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum ConfirmationPayload {
|
pub enum ConfirmationPayload {
|
||||||
/// Transaction
|
/// Transaction
|
||||||
Transaction(FilledTransactionRequest),
|
SendTransaction(FilledTransactionRequest),
|
||||||
|
/// Sign Transaction
|
||||||
|
SignTransaction(FilledTransactionRequest),
|
||||||
/// Sign request
|
/// Sign request
|
||||||
Sign(Address, H256),
|
Signature(Address, H256),
|
||||||
/// Decrypt request
|
/// Decrypt request
|
||||||
Decrypt(Address, Bytes),
|
Decrypt(Address, Bytes),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ConfirmationPayload {
|
||||||
|
pub fn sender(&self) -> Address {
|
||||||
|
match *self {
|
||||||
|
ConfirmationPayload::SendTransaction(ref request) => request.from,
|
||||||
|
ConfirmationPayload::SignTransaction(ref request) => request.from,
|
||||||
|
ConfirmationPayload::Signature(ref address, _) => *address,
|
||||||
|
ConfirmationPayload::Decrypt(ref address, _) => *address,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,9 +21,10 @@ use std::collections::BTreeMap;
|
|||||||
use jsonrpc_core;
|
use jsonrpc_core;
|
||||||
use util::{Mutex, RwLock, U256};
|
use util::{Mutex, RwLock, U256};
|
||||||
use v1::helpers::{ConfirmationRequest, ConfirmationPayload};
|
use v1::helpers::{ConfirmationRequest, ConfirmationPayload};
|
||||||
|
use v1::types::ConfirmationResponse;
|
||||||
|
|
||||||
/// Result that can be returned from JSON RPC.
|
/// Result that can be returned from JSON RPC.
|
||||||
pub type RpcResult = Result<jsonrpc_core::Value, jsonrpc_core::Error>;
|
pub type RpcResult = Result<ConfirmationResponse, jsonrpc_core::Error>;
|
||||||
|
|
||||||
/// Possible events happening in the queue that can be listened to.
|
/// Possible events happening in the queue that can be listened to.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -314,13 +315,12 @@ mod test {
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::sync::{mpsc, Arc};
|
use std::sync::{mpsc, Arc};
|
||||||
use util::{Address, U256, H256, Mutex};
|
use util::{Address, U256, Mutex};
|
||||||
use v1::helpers::{SigningQueue, ConfirmationsQueue, QueueEvent, FilledTransactionRequest, ConfirmationPayload};
|
use v1::helpers::{SigningQueue, ConfirmationsQueue, QueueEvent, FilledTransactionRequest, ConfirmationPayload};
|
||||||
use v1::types::H256 as NH256;
|
use v1::types::ConfirmationResponse;
|
||||||
use jsonrpc_core::to_value;
|
|
||||||
|
|
||||||
fn request() -> ConfirmationPayload {
|
fn request() -> ConfirmationPayload {
|
||||||
ConfirmationPayload::Transaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
to: Some(Address::from(2)),
|
to: Some(Address::from(2)),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
@ -353,10 +353,10 @@ mod test {
|
|||||||
// Just wait for the other thread to start
|
// Just wait for the other thread to start
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
queue.request_confirmed(id, Ok(to_value(&NH256::from(H256::from(1)))));
|
queue.request_confirmed(id, Ok(ConfirmationResponse::SendTransaction(1.into())));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(handle.join().expect("Thread should finish nicely"), Ok(to_value(&NH256::from(H256::from(1)))));
|
assert_eq!(handle.join().expect("Thread should finish nicely"), Ok(ConfirmationResponse::SendTransaction(1.into())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -49,7 +49,7 @@ use v1::types::{
|
|||||||
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
|
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
|
||||||
};
|
};
|
||||||
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
|
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
|
||||||
use v1::helpers::dispatch::{default_gas_price, dispatch_transaction};
|
use v1::helpers::dispatch::{dispatch_transaction, default_gas_price};
|
||||||
use v1::helpers::block_import::is_major_importing;
|
use v1::helpers::block_import::is_major_importing;
|
||||||
use v1::helpers::auto_args::Trailing;
|
use v1::helpers::auto_args::Trailing;
|
||||||
|
|
||||||
@ -610,7 +610,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
|
|
||||||
let raw_transaction = raw.to_vec();
|
let raw_transaction = raw.to_vec();
|
||||||
match UntrustedRlp::new(&raw_transaction).as_val() {
|
match UntrustedRlp::new(&raw_transaction).as_val() {
|
||||||
Ok(signed_transaction) => dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), signed_transaction),
|
Ok(signed_transaction) => dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), signed_transaction).map(Into::into),
|
||||||
Err(e) => Err(errors::from_rlp_error(e)),
|
Err(e) => Err(errors::from_rlp_error(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ use jsonrpc_core::Error;
|
|||||||
use v1::traits::Personal;
|
use v1::traits::Personal;
|
||||||
use v1::types::{H160 as RpcH160, H256 as RpcH256, TransactionRequest};
|
use v1::types::{H160 as RpcH160, H256 as RpcH256, TransactionRequest};
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
use v1::helpers::dispatch::sign_and_dispatch;
|
use v1::helpers::dispatch::{self, sign_and_dispatch};
|
||||||
|
|
||||||
/// Account management (personal) rpc implementation.
|
/// Account management (personal) rpc implementation.
|
||||||
pub struct PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
pub struct PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||||
@ -92,13 +92,17 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
|
|||||||
|
|
||||||
fn sign_and_send_transaction(&self, request: TransactionRequest, password: String) -> Result<RpcH256, Error> {
|
fn sign_and_send_transaction(&self, request: TransactionRequest, password: String) -> Result<RpcH256, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
let client = take_weak!(self.client);
|
||||||
|
let miner = take_weak!(self.miner);
|
||||||
|
let accounts = take_weak!(self.accounts);
|
||||||
|
|
||||||
|
let request = dispatch::fill_optional_fields(request.into(), &*client, &*miner);
|
||||||
sign_and_dispatch(
|
sign_and_dispatch(
|
||||||
&*take_weak!(self.client),
|
&*client,
|
||||||
&*take_weak!(self.miner),
|
&*miner,
|
||||||
&*take_weak!(self.accounts),
|
&*accounts,
|
||||||
request.into(),
|
request,
|
||||||
Some(password)
|
Some(password)
|
||||||
)
|
).map(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,15 @@
|
|||||||
//! Transactions Confirmations rpc implementation
|
//! Transactions Confirmations rpc implementation
|
||||||
|
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::*;
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethcore::client::MiningBlockChainClient;
|
use ethcore::client::MiningBlockChainClient;
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use v1::traits::Signer;
|
use v1::traits::Signer;
|
||||||
use v1::types::{TransactionModification, ConfirmationRequest, U256};
|
use v1::types::{TransactionModification, ConfirmationRequest, ConfirmationResponse, U256};
|
||||||
use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload};
|
use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload};
|
||||||
use v1::helpers::dispatch::{sign_and_dispatch, sign, decrypt};
|
use v1::helpers::dispatch;
|
||||||
|
|
||||||
/// Transactions confirmation (personal) rpc implementation.
|
/// Transactions confirmation (personal) rpc implementation.
|
||||||
pub struct SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
pub struct SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||||
@ -73,7 +74,7 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
|
|||||||
|
|
||||||
// TODO [ToDr] TransactionModification is redundant for some calls
|
// TODO [ToDr] TransactionModification is redundant for some calls
|
||||||
// might be better to replace it in future
|
// might be better to replace it in future
|
||||||
fn confirm_request(&self, id: U256, modification: TransactionModification, pass: String) -> Result<Value, Error> {
|
fn confirm_request(&self, id: U256, modification: TransactionModification, pass: String) -> Result<ConfirmationResponse, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
let id = id.into();
|
let id = id.into();
|
||||||
@ -83,21 +84,16 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
|
|||||||
let miner = take_weak!(self.miner);
|
let miner = take_weak!(self.miner);
|
||||||
|
|
||||||
signer.peek(&id).map(|confirmation| {
|
signer.peek(&id).map(|confirmation| {
|
||||||
let result = match confirmation.payload {
|
let mut payload = confirmation.payload.clone();
|
||||||
ConfirmationPayload::Transaction(mut request) => {
|
// Modify payload
|
||||||
// apply modification
|
match (&mut payload, modification.gas_price) {
|
||||||
if let Some(gas_price) = modification.gas_price {
|
(&mut ConfirmationPayload::SendTransaction(ref mut request), Some(gas_price)) => {
|
||||||
request.gas_price = gas_price.into();
|
request.gas_price = gas_price.into();
|
||||||
}
|
|
||||||
sign_and_dispatch(&*client, &*miner, &*accounts, request.into(), Some(pass)).map(to_value)
|
|
||||||
},
|
},
|
||||||
ConfirmationPayload::Sign(address, hash) => {
|
_ => {},
|
||||||
sign(&*accounts, address, Some(pass), hash)
|
}
|
||||||
},
|
// Execute
|
||||||
ConfirmationPayload::Decrypt(address, msg) => {
|
let result = dispatch::execute(&*client, &*miner, &*accounts, payload, Some(pass));
|
||||||
decrypt(&*accounts, address, Some(pass), msg)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if let Ok(ref response) = result {
|
if let Ok(ref response) = result {
|
||||||
signer.request_confirmed(id, Ok(response.clone()));
|
signer.request_confirmed(id, Ok(response.clone()));
|
||||||
}
|
}
|
||||||
|
@ -17,24 +17,33 @@
|
|||||||
//! Signing RPC implementation.
|
//! Signing RPC implementation.
|
||||||
|
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
use transient_hashmap::TransientHashMap;
|
||||||
|
use util::{U256, Mutex};
|
||||||
|
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use ethcore::client::MiningBlockChainClient;
|
use ethcore::client::MiningBlockChainClient;
|
||||||
use transient_hashmap::TransientHashMap;
|
|
||||||
use util::{U256, Address, H256, Mutex};
|
|
||||||
|
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::Error;
|
||||||
use v1::helpers::{errors, SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest, SignerService};
|
use v1::helpers::auto_args::Ready;
|
||||||
use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch, sign, decrypt};
|
use v1::helpers::{
|
||||||
|
errors, dispatch,
|
||||||
|
SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationPayload, SignerService
|
||||||
|
};
|
||||||
use v1::traits::{EthSigning, ParitySigning};
|
use v1::traits::{EthSigning, ParitySigning};
|
||||||
use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, U256 as RpcU256, Bytes as RpcBytes};
|
use v1::types::{
|
||||||
|
H160 as RpcH160, H256 as RpcH256, U256 as RpcU256, Bytes as RpcBytes, H520 as RpcH520,
|
||||||
|
Either as RpcEither,
|
||||||
|
TransactionRequest as RpcTransactionRequest,
|
||||||
|
ConfirmationPayload as RpcConfirmationPayload,
|
||||||
|
ConfirmationResponse as RpcConfirmationResponse
|
||||||
|
};
|
||||||
|
|
||||||
const MAX_PENDING_DURATION: u64 = 60 * 60;
|
const MAX_PENDING_DURATION: u64 = 60 * 60;
|
||||||
|
|
||||||
pub enum DispatchResult {
|
pub enum DispatchResult {
|
||||||
Promise(ConfirmationPromise),
|
Promise(ConfirmationPromise),
|
||||||
Value(Value),
|
Value(RpcConfirmationResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of functions that require signing when no trusted signer is used.
|
/// Implementation of functions that require signing when no trusted signer is used.
|
||||||
@ -68,59 +77,41 @@ impl<C, M> SigningQueueClient<C, M> where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_to_queue<WhenUnlocked, Payload>(&self, sender: Address, when_unlocked: WhenUnlocked, payload: Payload)
|
fn handle_dispatch<OnResponse>(&self, res: Result<DispatchResult, Error>, on_response: OnResponse)
|
||||||
-> Result<DispatchResult, Error> where
|
where OnResponse: FnOnce(Result<RpcConfirmationResponse, Error>) + Send + 'static
|
||||||
WhenUnlocked: Fn(&AccountProvider) -> Result<Value, Error>,
|
{
|
||||||
Payload: Fn() -> ConfirmationPayload, {
|
match res {
|
||||||
|
Ok(DispatchResult::Value(result)) => on_response(Ok(result)),
|
||||||
|
Ok(DispatchResult::Promise(promise)) => {
|
||||||
|
promise.wait_for_result(move |result| {
|
||||||
|
on_response(result.unwrap_or_else(|| Err(errors::request_rejected())))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Err(e) => on_response(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_to_queue(&self, payload: ConfirmationPayload) -> Result<DispatchResult, Error> {
|
||||||
|
let client = take_weak!(self.client);
|
||||||
|
let miner = take_weak!(self.miner);
|
||||||
let accounts = take_weak!(self.accounts);
|
let accounts = take_weak!(self.accounts);
|
||||||
|
|
||||||
|
let sender = payload.sender();
|
||||||
if accounts.is_unlocked(sender) {
|
if accounts.is_unlocked(sender) {
|
||||||
return when_unlocked(&accounts).map(DispatchResult::Value);
|
return dispatch::execute(&*client, &*miner, &*accounts, payload, None).map(DispatchResult::Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
take_weak!(self.signer).add_request(payload())
|
take_weak!(self.signer).add_request(payload)
|
||||||
.map(DispatchResult::Promise)
|
.map(DispatchResult::Promise)
|
||||||
.map_err(|_| errors::request_rejected_limit())
|
.map_err(|_| errors::request_rejected_limit())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_dispatch(&self, res: Result<DispatchResult, Error>, ready: Ready) {
|
fn dispatch(&self, payload: RpcConfirmationPayload) -> Result<DispatchResult, Error> {
|
||||||
match res {
|
let client = take_weak!(self.client);
|
||||||
Ok(DispatchResult::Value(v)) => ready.ready(Ok(v)),
|
let miner = take_weak!(self.miner);
|
||||||
Ok(DispatchResult::Promise(promise)) => {
|
|
||||||
promise.wait_for_result(move |result| {
|
|
||||||
ready.ready(result.unwrap_or_else(|| Err(errors::request_rejected())))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
Err(e) => ready.ready(Err(e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dispatch_sign(&self, params: Params) -> Result<DispatchResult, Error> {
|
let payload = dispatch::from_rpc(payload, &*client, &*miner);
|
||||||
from_params::<(RpcH160, RpcH256)>(params).and_then(|(address, msg)| {
|
self.add_to_queue(payload)
|
||||||
let address: Address = address.into();
|
|
||||||
let msg: H256 = msg.into();
|
|
||||||
|
|
||||||
self.add_to_queue(
|
|
||||||
address,
|
|
||||||
|accounts| sign(accounts, address, None, msg.clone()),
|
|
||||||
|| ConfirmationPayload::Sign(address, msg.clone()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dispatch_transaction(&self, params: Params) -> Result<DispatchResult, Error> {
|
|
||||||
from_params::<(TransactionRequest, )>(params).and_then(|(request, )| {
|
|
||||||
let request: TRequest = request.into();
|
|
||||||
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
|
|
||||||
self.add_to_queue(
|
|
||||||
request.from,
|
|
||||||
|accounts| sign_and_dispatch(&*client, &*miner, accounts, request.clone(), None).map(to_value),
|
|
||||||
|| {
|
|
||||||
let request = fill_optional_fields(request.clone(), &*client, &*miner);
|
|
||||||
ConfirmationPayload::Transaction(request)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,62 +119,59 @@ impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
|
|||||||
C: MiningBlockChainClient,
|
C: MiningBlockChainClient,
|
||||||
M: MinerService,
|
M: MinerService,
|
||||||
{
|
{
|
||||||
fn post_sign(&self, params: Params) -> Result<Value, Error> {
|
fn post_sign(&self, address: RpcH160, hash: RpcH256) -> Result<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
self.dispatch_sign(params).map(|result| match result {
|
self.dispatch(RpcConfirmationPayload::Signature((address, hash).into()))
|
||||||
DispatchResult::Value(v) => v,
|
.map(|result| match result {
|
||||||
DispatchResult::Promise(promise) => {
|
DispatchResult::Value(v) => RpcEither::Or(v),
|
||||||
let id = promise.id();
|
DispatchResult::Promise(promise) => {
|
||||||
self.pending.lock().insert(id, promise);
|
let id = promise.id();
|
||||||
to_value(&RpcU256::from(id))
|
self.pending.lock().insert(id, promise);
|
||||||
},
|
RpcEither::Either(id.into())
|
||||||
})
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_transaction(&self, params: Params) -> Result<Value, Error> {
|
fn post_transaction(&self, request: RpcTransactionRequest) -> Result<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
self.dispatch_transaction(params).map(|result| match result {
|
self.dispatch(RpcConfirmationPayload::SendTransaction(request))
|
||||||
DispatchResult::Value(v) => v,
|
.map(|result| match result {
|
||||||
DispatchResult::Promise(promise) => {
|
DispatchResult::Value(v) => RpcEither::Or(v),
|
||||||
let id = promise.id();
|
DispatchResult::Promise(promise) => {
|
||||||
self.pending.lock().insert(id, promise);
|
let id = promise.id();
|
||||||
to_value(&RpcU256::from(id))
|
self.pending.lock().insert(id, promise);
|
||||||
},
|
RpcEither::Either(id.into())
|
||||||
})
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_request(&self, params: Params) -> Result<Value, Error> {
|
fn check_request(&self, id: RpcU256) -> Result<Option<RpcConfirmationResponse>, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
let mut pending = self.pending.lock();
|
let mut pending = self.pending.lock();
|
||||||
from_params::<(RpcU256, )>(params).and_then(|(id, )| {
|
let id: U256 = id.into();
|
||||||
let id: U256 = id.into();
|
let res = match pending.get(&id) {
|
||||||
let res = match pending.get(&id) {
|
Some(ref promise) => match promise.result() {
|
||||||
Some(ref promise) => match promise.result() {
|
ConfirmationResult::Waiting => { return Ok(None); }
|
||||||
ConfirmationResult::Waiting => { return Ok(Value::Null); }
|
ConfirmationResult::Rejected => Err(errors::request_rejected()),
|
||||||
ConfirmationResult::Rejected => Err(errors::request_rejected()),
|
ConfirmationResult::Confirmed(rpc_response) => rpc_response.map(Some),
|
||||||
ConfirmationResult::Confirmed(rpc_response) => rpc_response,
|
},
|
||||||
},
|
_ => { return Err(errors::request_not_found()); }
|
||||||
_ => { return Err(errors::request_not_found()); }
|
};
|
||||||
};
|
pending.remove(&id);
|
||||||
pending.remove(&id);
|
res
|
||||||
res
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt_message(&self, params: Params, ready: Ready) {
|
fn decrypt_message(&self, ready: Ready<RpcBytes>, address: RpcH160, data: RpcBytes) {
|
||||||
let res = self.active()
|
let res = self.active()
|
||||||
.and_then(|_| from_params::<(RpcH160, RpcBytes)>(params))
|
.and_then(|_| self.dispatch(RpcConfirmationPayload::Decrypt((address, data).into())));
|
||||||
.and_then(|(address, msg)| {
|
// TODO [todr] typed handle_dispatch
|
||||||
let address: Address = address.into();
|
self.handle_dispatch(res, |response| {
|
||||||
|
match response {
|
||||||
self.add_to_queue(
|
Ok(RpcConfirmationResponse::Decrypt(data)) => ready.ready(Ok(data)),
|
||||||
address,
|
Err(e) => ready.ready(Err(e)),
|
||||||
|accounts| decrypt(accounts, address, None, msg.clone().into()),
|
e => ready.ready(Err(errors::internal("Unexpected result.", e))),
|
||||||
|| ConfirmationPayload::Decrypt(address, msg.clone().into())
|
}
|
||||||
)
|
});
|
||||||
});
|
|
||||||
|
|
||||||
self.handle_dispatch(res, ready);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,26 +179,36 @@ impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
|
|||||||
C: MiningBlockChainClient,
|
C: MiningBlockChainClient,
|
||||||
M: MinerService,
|
M: MinerService,
|
||||||
{
|
{
|
||||||
fn sign(&self, params: Params, ready: Ready) {
|
fn sign(&self, ready: Ready<RpcH520>, address: RpcH160, hash: RpcH256) {
|
||||||
let res = self.active().and_then(|_| self.dispatch_sign(params));
|
let res = self.active().and_then(|_| self.dispatch(RpcConfirmationPayload::Signature((address, hash).into())));
|
||||||
self.handle_dispatch(res, ready);
|
self.handle_dispatch(res, |response| {
|
||||||
|
match response {
|
||||||
|
Ok(RpcConfirmationResponse::Signature(signature)) => ready.ready(Ok(signature)),
|
||||||
|
Err(e) => ready.ready(Err(e)),
|
||||||
|
e => ready.ready(Err(errors::internal("Unexpected result.", e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_transaction(&self, params: Params, ready: Ready) {
|
fn send_transaction(&self, ready: Ready<RpcH256>, request: RpcTransactionRequest) {
|
||||||
let res = self.active().and_then(|_| self.dispatch_transaction(params));
|
let res = self.active().and_then(|_| self.dispatch(RpcConfirmationPayload::SendTransaction(request)));
|
||||||
self.handle_dispatch(res, ready);
|
self.handle_dispatch(res, |response| {
|
||||||
|
match response {
|
||||||
|
Ok(RpcConfirmationResponse::SendTransaction(hash)) => ready.ready(Ok(hash)),
|
||||||
|
Err(e) => ready.ready(Err(e)),
|
||||||
|
e => ready.ready(Err(errors::internal("Unexpected result.", e))),
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_optional_fields<C, M>(request: TRequest, client: &C, miner: &M) -> FilledRequest
|
fn sign_transaction(&self, ready: Ready<RpcBytes>, request: RpcTransactionRequest) {
|
||||||
where C: MiningBlockChainClient, M: MinerService {
|
let res = self.active().and_then(|_| self.dispatch(RpcConfirmationPayload::SignTransaction(request)));
|
||||||
FilledRequest {
|
self.handle_dispatch(res, |response| {
|
||||||
from: request.from,
|
match response {
|
||||||
to: request.to,
|
Ok(RpcConfirmationResponse::SignTransaction(rlp)) => ready.ready(Ok(rlp)),
|
||||||
nonce: request.nonce,
|
Err(e) => ready.ready(Err(e)),
|
||||||
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
|
e => ready.ready(Err(errors::internal("Unexpected result.", e))),
|
||||||
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
}
|
||||||
value: request.value.unwrap_or_else(|| 0.into()),
|
});
|
||||||
data: request.data.unwrap_or_else(Vec::new),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,19 @@ use ethcore::account_provider::AccountProvider;
|
|||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use ethcore::client::MiningBlockChainClient;
|
use ethcore::client::MiningBlockChainClient;
|
||||||
|
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::Error;
|
||||||
|
use v1::helpers::auto_args::Ready;
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
use v1::helpers::dispatch::{sign_and_dispatch, sign, decrypt};
|
use v1::helpers::dispatch;
|
||||||
use v1::traits::{EthSigning, ParitySigning};
|
use v1::traits::{EthSigning, ParitySigning};
|
||||||
use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, Bytes as RpcBytes};
|
use v1::types::{
|
||||||
|
U256 as RpcU256,
|
||||||
|
H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes,
|
||||||
|
Either as RpcEither,
|
||||||
|
TransactionRequest as RpcTransactionRequest,
|
||||||
|
ConfirmationPayload as RpcConfirmationPayload,
|
||||||
|
ConfirmationResponse as RpcConfirmationResponse,
|
||||||
|
};
|
||||||
|
|
||||||
/// Implementation of functions that require signing when no trusted signer is used.
|
/// Implementation of functions that require signing when no trusted signer is used.
|
||||||
pub struct SigningUnsafeClient<C, M> where
|
pub struct SigningUnsafeClient<C, M> where
|
||||||
@ -58,26 +66,47 @@ impl<C, M> SigningUnsafeClient<C, M> where
|
|||||||
take_weak!(self.client).keep_alive();
|
take_weak!(self.client).keep_alive();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle(&self, payload: RpcConfirmationPayload) -> Result<RpcConfirmationResponse, Error> {
|
||||||
|
try!(self.active());
|
||||||
|
let client = take_weak!(self.client);
|
||||||
|
let miner = take_weak!(self.miner);
|
||||||
|
let accounts = take_weak!(self.accounts);
|
||||||
|
|
||||||
|
let payload = dispatch::from_rpc(payload, &*client, &*miner);
|
||||||
|
dispatch::execute(&*client, &*miner, &*accounts, payload, None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: 'static, M: 'static> EthSigning for SigningUnsafeClient<C, M> where
|
impl<C: 'static, M: 'static> EthSigning for SigningUnsafeClient<C, M> where
|
||||||
C: MiningBlockChainClient,
|
C: MiningBlockChainClient,
|
||||||
M: MinerService,
|
M: MinerService,
|
||||||
{
|
{
|
||||||
fn sign(&self, params: Params, ready: Ready) {
|
fn sign(&self, ready: Ready<RpcH520>, address: RpcH160, hash: RpcH256) {
|
||||||
ready.ready(self.active()
|
let result = match self.handle(RpcConfirmationPayload::Signature((address, hash).into())) {
|
||||||
.and_then(|_| from_params::<(RpcH160, RpcH256)>(params))
|
Ok(RpcConfirmationResponse::Signature(signature)) => Ok(signature),
|
||||||
.and_then(|(address, msg)| {
|
Err(e) => Err(e),
|
||||||
sign(&*take_weak!(self.accounts), address.into(), None, msg.into())
|
e => Err(errors::internal("Unexpected result", e)),
|
||||||
}))
|
};
|
||||||
|
ready.ready(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_transaction(&self, params: Params, ready: Ready) {
|
fn send_transaction(&self, ready: Ready<RpcH256>, request: RpcTransactionRequest) {
|
||||||
ready.ready(self.active()
|
let result = match self.handle(RpcConfirmationPayload::SendTransaction(request)) {
|
||||||
.and_then(|_| from_params::<(TransactionRequest, )>(params))
|
Ok(RpcConfirmationResponse::SendTransaction(hash)) => Ok(hash),
|
||||||
.and_then(|(request, )| {
|
Err(e) => Err(e),
|
||||||
sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), &*take_weak!(self.accounts), request.into(), None).map(to_value)
|
e => Err(errors::internal("Unexpected result", e)),
|
||||||
}))
|
};
|
||||||
|
ready.ready(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_transaction(&self, ready: Ready<RpcBytes>, request: RpcTransactionRequest) {
|
||||||
|
let result = match self.handle(RpcConfirmationPayload::SignTransaction(request)) {
|
||||||
|
Ok(RpcConfirmationResponse::SignTransaction(rlp)) => Ok(rlp),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
e => Err(errors::internal("Unexpected result", e)),
|
||||||
|
};
|
||||||
|
ready.ready(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,25 +114,26 @@ impl<C: 'static, M: 'static> ParitySigning for SigningUnsafeClient<C, M> where
|
|||||||
C: MiningBlockChainClient,
|
C: MiningBlockChainClient,
|
||||||
M: MinerService,
|
M: MinerService,
|
||||||
{
|
{
|
||||||
fn decrypt_message(&self, params: Params, ready: Ready) {
|
fn decrypt_message(&self, ready: Ready<RpcBytes>, address: RpcH160, data: RpcBytes) {
|
||||||
ready.ready(self.active()
|
let result = match self.handle(RpcConfirmationPayload::Decrypt((address, data).into())) {
|
||||||
.and_then(|_| from_params::<(RpcH160, RpcBytes)>(params))
|
Ok(RpcConfirmationResponse::Decrypt(data)) => Ok(data),
|
||||||
.and_then(|(address, ciphertext)| {
|
Err(e) => Err(e),
|
||||||
decrypt(&*take_weak!(self.accounts), address.into(), None, ciphertext.0)
|
e => Err(errors::internal("Unexpected result", e)),
|
||||||
}))
|
};
|
||||||
|
ready.ready(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_sign(&self, _: Params) -> Result<Value, Error> {
|
fn post_sign(&self, _: RpcH160, _: RpcH256) -> Result<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
|
||||||
// We don't support this in non-signer mode.
|
// We don't support this in non-signer mode.
|
||||||
Err(errors::signer_disabled())
|
Err(errors::signer_disabled())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_transaction(&self, _: Params) -> Result<Value, Error> {
|
fn post_transaction(&self, _: RpcTransactionRequest) -> Result<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
|
||||||
// We don't support this in non-signer mode.
|
// We don't support this in non-signer mode.
|
||||||
Err(errors::signer_disabled())
|
Err(errors::signer_disabled())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_request(&self, _: Params) -> Result<Value, Error> {
|
fn check_request(&self, _: RpcU256) -> Result<Option<RpcConfirmationResponse>, Error> {
|
||||||
// We don't support this in non-signer mode.
|
// We don't support this in non-signer mode.
|
||||||
Err(errors::signer_disabled())
|
Err(errors::signer_disabled())
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ use std::str::FromStr;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Instant, Duration};
|
use std::time::{Instant, Duration};
|
||||||
|
use rlp;
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
use util::{Uint, U256, Address, H256, FixedHash, Mutex};
|
use util::{Uint, U256, Address, H256, FixedHash, Mutex};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
@ -761,6 +762,44 @@ fn rpc_eth_send_transaction() {
|
|||||||
|
|
||||||
assert_eq!(tester.io.handle_request_sync(&request), Some(response));
|
assert_eq!(tester.io.handle_request_sync(&request), Some(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_eth_sign_transaction() {
|
||||||
|
let tester = EthTester::default();
|
||||||
|
let address = tester.accounts_provider.new_account("").unwrap();
|
||||||
|
tester.accounts_provider.unlock_account_permanently(address, "".into()).unwrap();
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_signTransaction",
|
||||||
|
"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::one(),
|
||||||
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
|
gas: U256::from(0x76c0),
|
||||||
|
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
|
value: U256::from(0x9184e72au64),
|
||||||
|
data: vec![]
|
||||||
|
};
|
||||||
|
let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
|
||||||
|
let t = t.with_signature(signature, None);
|
||||||
|
let rlp = rlp::encode(&t);
|
||||||
|
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":"0x"#.to_owned() + &rlp.to_hex() + r#"","id":1}"#;
|
||||||
|
|
||||||
|
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
|
||||||
|
|
||||||
|
assert_eq!(tester.io.handle_request_sync(&request), Some(response));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_eth_send_transaction_with_bad_to() {
|
fn rpc_eth_send_transaction_with_bad_to() {
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
@ -839,7 +878,7 @@ fn rpc_eth_send_raw_transaction() {
|
|||||||
let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
|
let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
|
|
||||||
let rlp = ::rlp::encode(&t).to_vec().to_hex();
|
let rlp = rlp::encode(&t).to_vec().to_hex();
|
||||||
|
|
||||||
let req = r#"{
|
let req = r#"{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
@ -71,7 +71,7 @@ fn signer_tester() -> SignerTester {
|
|||||||
fn should_return_list_of_items_to_confirm() {
|
fn should_return_list_of_items_to_confirm() {
|
||||||
// given
|
// given
|
||||||
let tester = signer_tester();
|
let tester = signer_tester();
|
||||||
tester.signer.add_request(ConfirmationPayload::Transaction(FilledTransactionRequest {
|
tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: U256::from(10_000),
|
||||||
@ -80,7 +80,7 @@ fn should_return_list_of_items_to_confirm() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
tester.signer.add_request(ConfirmationPayload::Sign(1.into(), 5.into())).unwrap();
|
tester.signer.add_request(ConfirmationPayload::Signature(1.into(), 5.into())).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#;
|
let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#;
|
||||||
@ -100,7 +100,7 @@ fn should_return_list_of_items_to_confirm() {
|
|||||||
fn should_reject_transaction_from_queue_without_dispatching() {
|
fn should_reject_transaction_from_queue_without_dispatching() {
|
||||||
// given
|
// given
|
||||||
let tester = signer_tester();
|
let tester = signer_tester();
|
||||||
tester.signer.add_request(ConfirmationPayload::Transaction(FilledTransactionRequest {
|
tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: U256::from(10_000),
|
||||||
@ -125,7 +125,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
|||||||
fn should_not_remove_transaction_if_password_is_invalid() {
|
fn should_not_remove_transaction_if_password_is_invalid() {
|
||||||
// given
|
// given
|
||||||
let tester = signer_tester();
|
let tester = signer_tester();
|
||||||
tester.signer.add_request(ConfirmationPayload::Transaction(FilledTransactionRequest {
|
tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: U256::from(10_000),
|
||||||
@ -149,7 +149,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
|||||||
fn should_not_remove_sign_if_password_is_invalid() {
|
fn should_not_remove_sign_if_password_is_invalid() {
|
||||||
// given
|
// given
|
||||||
let tester = signer_tester();
|
let tester = signer_tester();
|
||||||
tester.signer.add_request(ConfirmationPayload::Sign(0.into(), 5.into())).unwrap();
|
tester.signer.add_request(ConfirmationPayload::Signature(0.into(), 5.into())).unwrap();
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -167,7 +167,7 @@ fn should_confirm_transaction_and_dispatch() {
|
|||||||
let tester = signer_tester();
|
let tester = signer_tester();
|
||||||
let address = tester.accounts.new_account("test").unwrap();
|
let address = tester.accounts.new_account("test").unwrap();
|
||||||
let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap();
|
let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap();
|
||||||
tester.signer.add_request(ConfirmationPayload::Transaction(FilledTransactionRequest {
|
tester.signer.add_request(ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
from: address,
|
from: address,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
gas_price: U256::from(10_000),
|
gas_price: U256::from(10_000),
|
||||||
|
@ -16,15 +16,17 @@
|
|||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use jsonrpc_core::{IoHandler, to_value, Success};
|
use rlp;
|
||||||
|
|
||||||
|
use jsonrpc_core::{IoHandler, Success};
|
||||||
use v1::impls::SigningQueueClient;
|
use v1::impls::SigningQueueClient;
|
||||||
use v1::traits::{EthSigning, ParitySigning, Parity};
|
use v1::traits::{EthSigning, ParitySigning, Parity};
|
||||||
use v1::helpers::{SignerService, SigningQueue};
|
use v1::helpers::{SignerService, SigningQueue};
|
||||||
use v1::types::{H256 as RpcH256, H520 as RpcH520, Bytes};
|
use v1::types::ConfirmationResponse;
|
||||||
use v1::tests::helpers::TestMinerService;
|
use v1::tests::helpers::TestMinerService;
|
||||||
use v1::tests::mocked::parity;
|
use v1::tests::mocked::parity;
|
||||||
|
|
||||||
use util::{Address, FixedHash, Uint, U256, H256, H520};
|
use util::{Address, FixedHash, Uint, U256, H256, ToPretty};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethcore::client::TestBlockChainClient;
|
use ethcore::client::TestBlockChainClient;
|
||||||
use ethcore::transaction::{Transaction, Action};
|
use ethcore::transaction::{Transaction, Action};
|
||||||
@ -88,7 +90,7 @@ fn should_add_sign_to_queue() {
|
|||||||
let async_result = tester.io.handle_request(&request).unwrap();
|
let async_result = tester.io.handle_request(&request).unwrap();
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
// respond
|
// respond
|
||||||
tester.signer.request_confirmed(U256::from(1), Ok(to_value(&RpcH520::from(H520::default()))));
|
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(0.into())));
|
||||||
assert!(async_result.on_result(move |res| {
|
assert!(async_result.on_result(move |res| {
|
||||||
assert_eq!(res, response.to_owned());
|
assert_eq!(res, response.to_owned());
|
||||||
}));
|
}));
|
||||||
@ -162,7 +164,7 @@ fn should_check_status_of_request_when_its_resolved() {
|
|||||||
"id": 1
|
"id": 1
|
||||||
}"#;
|
}"#;
|
||||||
tester.io.handle_request_sync(&request).expect("Sent");
|
tester.io.handle_request_sync(&request).expect("Sent");
|
||||||
tester.signer.request_confirmed(U256::from(1), Ok(to_value(&"Hello World!")));
|
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(1.into())));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let request = r#"{
|
let request = r#"{
|
||||||
@ -171,7 +173,7 @@ fn should_check_status_of_request_when_its_resolved() {
|
|||||||
"params": ["0x1"],
|
"params": ["0x1"],
|
||||||
"id": 1
|
"id": 1
|
||||||
}"#;
|
}"#;
|
||||||
let response = r#"{"jsonrpc":"2.0","result":"Hello World!","id":1}"#;
|
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001","id":1}"#;
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned()));
|
assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned()));
|
||||||
@ -228,7 +230,54 @@ fn should_add_transaction_to_queue() {
|
|||||||
let async_result = tester.io.handle_request(&request).unwrap();
|
let async_result = tester.io.handle_request(&request).unwrap();
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
// respond
|
// respond
|
||||||
tester.signer.request_confirmed(U256::from(1), Ok(to_value(&RpcH256::from(H256::default()))));
|
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SendTransaction(0.into())));
|
||||||
|
assert!(async_result.on_result(move |res| {
|
||||||
|
assert_eq!(res, response.to_owned());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_add_sign_transaction_to_the_queue() {
|
||||||
|
// given
|
||||||
|
let tester = eth_signing();
|
||||||
|
let address = tester.accounts.new_account("test").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(tester.signer.requests().len(), 0);
|
||||||
|
|
||||||
|
// when
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_signTransaction",
|
||||||
|
"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::one(),
|
||||||
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
|
gas: U256::from(0x76c0),
|
||||||
|
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
|
value: U256::from(0x9184e72au64),
|
||||||
|
data: vec![]
|
||||||
|
};
|
||||||
|
let signature = tester.accounts.sign(address, Some("test".into()), t.hash(None)).unwrap();
|
||||||
|
let t = t.with_signature(signature, None);
|
||||||
|
let rlp = rlp::encode(&t);
|
||||||
|
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":"0x"#.to_owned() + &rlp.to_hex() + r#"","id":1}"#;
|
||||||
|
|
||||||
|
// then
|
||||||
|
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
|
||||||
|
let async_result = tester.io.handle_request(&request).unwrap();
|
||||||
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
// respond
|
||||||
|
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction(rlp.to_vec().into())));
|
||||||
assert!(async_result.on_result(move |res| {
|
assert!(async_result.on_result(move |res| {
|
||||||
assert_eq!(res, response.to_owned());
|
assert_eq!(res, response.to_owned());
|
||||||
}));
|
}));
|
||||||
@ -325,7 +374,7 @@ fn should_add_decryption_to_the_queue() {
|
|||||||
let async_result = tester.io.handle_request(&request).unwrap();
|
let async_result = tester.io.handle_request(&request).unwrap();
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
// respond
|
// respond
|
||||||
tester.signer.request_confirmed(U256::from(1), Ok(to_value(Bytes(vec![0x1, 0x2]))));
|
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into())));
|
||||||
assert!(async_result.on_result(move |res| {
|
assert!(async_result.on_result(move |res| {
|
||||||
assert_eq!(res, response.to_owned());
|
assert_eq!(res, response.to_owned());
|
||||||
}));
|
}));
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Eth rpc interface.
|
//! Eth rpc interface.
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::Error;
|
||||||
|
|
||||||
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
|
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
|
||||||
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
|
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
|
||||||
|
@ -15,26 +15,27 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Eth rpc interface.
|
//! Eth rpc interface.
|
||||||
use std::sync::Arc;
|
|
||||||
use jsonrpc_core::*;
|
|
||||||
|
|
||||||
/// Signing methods implementation relying on unlocked accounts.
|
use v1::helpers::auto_args::{WrapAsync, Ready};
|
||||||
pub trait EthSigning: Sized + Send + Sync + 'static {
|
use v1::types::{H160, H256, H520, TransactionRequest, Bytes};
|
||||||
/// Signs the data with given address signature.
|
|
||||||
fn sign(&self, _: Params, _: Ready);
|
|
||||||
|
|
||||||
/// Sends transaction; will block for 20s to try to return the
|
build_rpc_trait! {
|
||||||
/// transaction hash.
|
/// Signing methods implementation relying on unlocked accounts.
|
||||||
/// If it cannot yet be signed, it will return a transaction ID for
|
pub trait EthSigning {
|
||||||
/// later use with check_transaction.
|
/// Signs the data with given address signature.
|
||||||
fn send_transaction(&self, _: Params, _: Ready);
|
#[rpc(async, name = "eth_sign")]
|
||||||
|
fn sign(&self, Ready<H520>, H160, H256);
|
||||||
|
|
||||||
/// Should be used to convert object to io delegate.
|
/// Sends transaction; will block waiting for signer to return the
|
||||||
fn to_delegate(self) -> IoDelegate<Self> {
|
/// transaction hash.
|
||||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
/// If Signer is disable it will require the account to be unlocked.
|
||||||
delegate.add_async_method("eth_sign", EthSigning::sign);
|
#[rpc(async, name = "eth_sendTransaction")]
|
||||||
delegate.add_async_method("eth_sendTransaction", EthSigning::send_transaction);
|
fn send_transaction(&self, Ready<H256>, TransactionRequest);
|
||||||
|
|
||||||
delegate
|
/// Signs transactions without dispatching it to the network.
|
||||||
|
/// Returns signed transaction RLP representation.
|
||||||
|
/// It can be later submitted using `eth_sendRawTransaction`.
|
||||||
|
#[rpc(async, name = "eth_signTransaction")]
|
||||||
|
fn sign_transaction(&self, Ready<Bytes>, TransactionRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,38 +15,32 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! ParitySigning rpc interface.
|
//! ParitySigning rpc interface.
|
||||||
use std::sync::Arc;
|
use jsonrpc_core::Error;
|
||||||
use jsonrpc_core::*;
|
|
||||||
|
|
||||||
/// Signing methods implementation relying on unlocked accounts.
|
use v1::helpers::auto_args::{Wrap, WrapAsync, Ready};
|
||||||
pub trait ParitySigning: Sized + Send + Sync + 'static {
|
use v1::types::{U256, H160, H256, Bytes, ConfirmationResponse, TransactionRequest, Either};
|
||||||
/// Posts sign request asynchronously.
|
|
||||||
/// Will return a confirmation ID for later use with check_transaction.
|
|
||||||
fn post_sign(&self, _: Params) -> Result<Value, Error>;
|
|
||||||
|
|
||||||
/// Posts transaction asynchronously.
|
build_rpc_trait! {
|
||||||
/// Will return a transaction ID for later use with check_transaction.
|
/// Signing methods implementation.
|
||||||
fn post_transaction(&self, _: Params) -> Result<Value, Error>;
|
pub trait ParitySigning {
|
||||||
|
/// Posts sign request asynchronously.
|
||||||
|
/// Will return a confirmation ID for later use with check_transaction.
|
||||||
|
#[rpc(name = "parity_postSign")]
|
||||||
|
fn post_sign(&self, H160, H256) -> Result<Either<U256, ConfirmationResponse>, Error>;
|
||||||
|
|
||||||
/// Checks the progress of a previously posted request (transaction/sign).
|
/// Posts transaction asynchronously.
|
||||||
/// Should be given a valid send_transaction ID.
|
/// Will return a transaction ID for later use with check_transaction.
|
||||||
/// Returns the transaction hash, the zero hash (not yet available),
|
#[rpc(name = "parity_postTransaction")]
|
||||||
/// or the signature,
|
fn post_transaction(&self, TransactionRequest) -> Result<Either<U256, ConfirmationResponse>, Error>;
|
||||||
/// or an error.
|
|
||||||
fn check_request(&self, _: Params) -> Result<Value, Error>;
|
|
||||||
|
|
||||||
/// Decrypt some ECIES-encrypted message.
|
/// Checks the progress of a previously posted request (transaction/sign).
|
||||||
/// First parameter is the address with which it is encrypted, second is the ciphertext.
|
/// Should be given a valid send_transaction ID.
|
||||||
fn decrypt_message(&self, _: Params, _: Ready);
|
#[rpc(name = "parity_checkRequest")]
|
||||||
|
fn check_request(&self, U256) -> Result<Option<ConfirmationResponse>, Error>;
|
||||||
|
|
||||||
/// Should be used to convert object to io delegate.
|
/// Decrypt some ECIES-encrypted message.
|
||||||
fn to_delegate(self) -> IoDelegate<Self> {
|
/// First parameter is the address with which it is encrypted, second is the ciphertext.
|
||||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
#[rpc(async, name = "parity_decryptMessage")]
|
||||||
delegate.add_method("parity_postSign", ParitySigning::post_sign);
|
fn decrypt_message(&self, Ready<Bytes>, H160, Bytes);
|
||||||
delegate.add_method("parity_postTransaction", ParitySigning::post_transaction);
|
|
||||||
delegate.add_method("parity_checkRequest", ParitySigning::check_request);
|
|
||||||
delegate.add_async_method("parity_decryptMessage", ParitySigning::decrypt_message);
|
|
||||||
|
|
||||||
delegate
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Parity Signer-related rpc interface.
|
//! Parity Signer-related rpc interface.
|
||||||
use jsonrpc_core::{Value, Error};
|
use jsonrpc_core::Error;
|
||||||
|
|
||||||
use v1::helpers::auto_args::Wrap;
|
use v1::helpers::auto_args::Wrap;
|
||||||
use v1::types::{U256, TransactionModification, ConfirmationRequest};
|
use v1::types::{U256, TransactionModification, ConfirmationRequest, ConfirmationResponse};
|
||||||
|
|
||||||
|
|
||||||
build_rpc_trait! {
|
build_rpc_trait! {
|
||||||
@ -31,7 +31,7 @@ build_rpc_trait! {
|
|||||||
|
|
||||||
/// Confirm specific request.
|
/// Confirm specific request.
|
||||||
#[rpc(name = "signer_confirmRequest")]
|
#[rpc(name = "signer_confirmRequest")]
|
||||||
fn confirm_request(&self, U256, TransactionModification, String) -> Result<Value, Error>;
|
fn confirm_request(&self, U256, TransactionModification, String) -> Result<ConfirmationResponse, Error>;
|
||||||
|
|
||||||
/// Reject the confirmation request.
|
/// Reject the confirmation request.
|
||||||
#[rpc(name = "signer_rejectRequest")]
|
#[rpc(name = "signer_rejectRequest")]
|
||||||
|
@ -16,10 +16,11 @@
|
|||||||
|
|
||||||
//! Types used in Confirmations queue (Trusted Signer)
|
//! Types used in Confirmations queue (Trusted Signer)
|
||||||
|
|
||||||
use v1::types::{U256, TransactionRequest, H160, H256, Bytes};
|
use std::fmt;
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
use v1::types::{U256, TransactionRequest, H160, H256, H520, Bytes};
|
||||||
use v1::helpers;
|
use v1::helpers;
|
||||||
|
|
||||||
|
|
||||||
/// Confirmation waiting in a queue
|
/// Confirmation waiting in a queue
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)]
|
||||||
pub struct ConfirmationRequest {
|
pub struct ConfirmationRequest {
|
||||||
@ -47,6 +48,15 @@ pub struct SignRequest {
|
|||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<(H160, H256)> for SignRequest {
|
||||||
|
fn from(tuple: (H160, H256)) -> Self {
|
||||||
|
SignRequest {
|
||||||
|
address: tuple.0,
|
||||||
|
hash: tuple.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Decrypt request
|
/// Decrypt request
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)]
|
||||||
pub struct DecryptRequest {
|
pub struct DecryptRequest {
|
||||||
@ -56,15 +66,53 @@ pub struct DecryptRequest {
|
|||||||
pub msg: Bytes,
|
pub msg: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<(H160, Bytes)> for DecryptRequest {
|
||||||
|
fn from(tuple: (H160, Bytes)) -> Self {
|
||||||
|
DecryptRequest {
|
||||||
|
address: tuple.0,
|
||||||
|
msg: tuple.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Confirmation response for particular payload
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub enum ConfirmationResponse {
|
||||||
|
/// Transaction Hash
|
||||||
|
SendTransaction(H256),
|
||||||
|
/// Transaction RLP
|
||||||
|
SignTransaction(Bytes),
|
||||||
|
/// Signature
|
||||||
|
Signature(H520),
|
||||||
|
/// Decrypted data
|
||||||
|
Decrypt(Bytes),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for ConfirmationResponse {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
ConfirmationResponse::SendTransaction(ref hash) => hash.serialize(serializer),
|
||||||
|
ConfirmationResponse::SignTransaction(ref rlp) => rlp.serialize(serializer),
|
||||||
|
ConfirmationResponse::Signature(ref signature) => signature.serialize(serializer),
|
||||||
|
ConfirmationResponse::Decrypt(ref data) => data.serialize(serializer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Confirmation payload, i.e. the thing to be confirmed
|
/// Confirmation payload, i.e. the thing to be confirmed
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)]
|
||||||
pub enum ConfirmationPayload {
|
pub enum ConfirmationPayload {
|
||||||
/// Transaction
|
/// Send Transaction
|
||||||
#[serde(rename="transaction")]
|
#[serde(rename="transaction")]
|
||||||
Transaction(TransactionRequest),
|
SendTransaction(TransactionRequest),
|
||||||
|
/// Sign Transaction
|
||||||
|
#[serde(rename="transaction")]
|
||||||
|
SignTransaction(TransactionRequest),
|
||||||
/// Signature
|
/// Signature
|
||||||
#[serde(rename="sign")]
|
#[serde(rename="sign")]
|
||||||
Sign(SignRequest),
|
Signature(SignRequest),
|
||||||
/// Decryption
|
/// Decryption
|
||||||
#[serde(rename="decrypt")]
|
#[serde(rename="decrypt")]
|
||||||
Decrypt(DecryptRequest),
|
Decrypt(DecryptRequest),
|
||||||
@ -73,8 +121,9 @@ pub enum ConfirmationPayload {
|
|||||||
impl From<helpers::ConfirmationPayload> for ConfirmationPayload {
|
impl From<helpers::ConfirmationPayload> for ConfirmationPayload {
|
||||||
fn from(c: helpers::ConfirmationPayload) -> Self {
|
fn from(c: helpers::ConfirmationPayload) -> Self {
|
||||||
match c {
|
match c {
|
||||||
helpers::ConfirmationPayload::Transaction(t) => ConfirmationPayload::Transaction(t.into()),
|
helpers::ConfirmationPayload::SendTransaction(t) => ConfirmationPayload::SendTransaction(t.into()),
|
||||||
helpers::ConfirmationPayload::Sign(address, hash) => ConfirmationPayload::Sign(SignRequest {
|
helpers::ConfirmationPayload::SignTransaction(t) => ConfirmationPayload::SignTransaction(t.into()),
|
||||||
|
helpers::ConfirmationPayload::Signature(address, hash) => ConfirmationPayload::Signature(SignRequest {
|
||||||
address: address.into(),
|
address: address.into(),
|
||||||
hash: hash.into(),
|
hash: hash.into(),
|
||||||
}),
|
}),
|
||||||
@ -94,6 +143,41 @@ pub struct TransactionModification {
|
|||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents two possible return values.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Either<A, B> where
|
||||||
|
A: fmt::Debug + Clone,
|
||||||
|
B: fmt::Debug + Clone,
|
||||||
|
{
|
||||||
|
/// Primary value
|
||||||
|
Either(A),
|
||||||
|
/// Secondary value
|
||||||
|
Or(B),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> From<A> for Either<A, B> where
|
||||||
|
A: fmt::Debug + Clone,
|
||||||
|
B: fmt::Debug + Clone,
|
||||||
|
{
|
||||||
|
fn from(a: A) -> Self {
|
||||||
|
Either::Either(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> Serialize for Either<A, B> where
|
||||||
|
A: Serialize + fmt::Debug + Clone,
|
||||||
|
B: Serialize + fmt::Debug + Clone,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
Either::Either(ref a) => a.serialize(serializer),
|
||||||
|
Either::Or(ref b) => b.serialize(serializer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -107,7 +191,7 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let request = helpers::ConfirmationRequest {
|
let request = helpers::ConfirmationRequest {
|
||||||
id: 15.into(),
|
id: 15.into(),
|
||||||
payload: helpers::ConfirmationPayload::Sign(1.into(), 5.into()),
|
payload: helpers::ConfirmationPayload::Signature(1.into(), 5.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -123,7 +207,7 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let request = helpers::ConfirmationRequest {
|
let request = helpers::ConfirmationRequest {
|
||||||
id: 15.into(),
|
id: 15.into(),
|
||||||
payload: helpers::ConfirmationPayload::Transaction(helpers::FilledTransactionRequest {
|
payload: helpers::ConfirmationPayload::SendTransaction(helpers::FilledTransactionRequest {
|
||||||
from: 0.into(),
|
from: 0.into(),
|
||||||
to: None,
|
to: None,
|
||||||
gas: 15_000.into(),
|
gas: 15_000.into(),
|
||||||
|
@ -38,7 +38,7 @@ pub use self::bytes::Bytes;
|
|||||||
pub use self::block::{RichBlock, Block, BlockTransactions};
|
pub use self::block::{RichBlock, Block, BlockTransactions};
|
||||||
pub use self::block_number::BlockNumber;
|
pub use self::block_number::BlockNumber;
|
||||||
pub use self::call_request::CallRequest;
|
pub use self::call_request::CallRequest;
|
||||||
pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, TransactionModification};
|
pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, ConfirmationResponse, TransactionModification, SignRequest, DecryptRequest, Either};
|
||||||
pub use self::filter::{Filter, FilterChanges};
|
pub use self::filter::{Filter, FilterChanges};
|
||||||
pub use self::hash::{H64, H160, H256, H512, H520, H2048};
|
pub use self::hash::{H64, H160, H256, H512, H520, H2048};
|
||||||
pub use self::index::Index;
|
pub use self::index::Index;
|
||||||
|
Loading…
Reference in New Issue
Block a user