Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

More meaningful errors when sending transaction #1290

Merged
merged 5 commits into from
Jun 16, 2016
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 17 additions & 13 deletions rpc/src/v1/helpers/signing_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ use std::time::{Instant, Duration};
use std::sync::{mpsc, Mutex, RwLock, Arc};
use std::collections::HashMap;
use v1::types::{TransactionRequest, TransactionConfirmation};
use util::{U256, H256};
use util::U256;
use jsonrpc_core;

/// Result that can be returned from JSON RPC.
pub type RpcResult = Result<jsonrpc_core::Value, jsonrpc_core::Error>;

/// Possible events happening in the queue that can be listened to.
#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -59,7 +62,7 @@ pub trait SigningQueue: Send + Sync {

/// Removes a request from the queue.
/// Notifies possible token holders that transaction was confirmed and given hash was assigned.
fn request_confirmed(&self, id: U256, hash: H256) -> Option<TransactionConfirmation>;
fn request_confirmed(&self, id: U256, result: RpcResult) -> Option<TransactionConfirmation>;

/// Returns a request if it is contained in the queue.
fn peek(&self, id: &U256) -> Option<TransactionConfirmation>;
Expand All @@ -75,7 +78,7 @@ enum ConfirmationResult {
/// The transaction has been rejected.
Rejected,
/// The transaction has been confirmed.
Confirmed(H256),
Confirmed(RpcResult),
}

/// Time you need to confirm the transaction in UI.
Expand All @@ -100,7 +103,7 @@ pub struct ConfirmationPromise {

impl ConfirmationToken {
/// Submit solution to all listeners
fn resolve(&self, result: Option<H256>) {
fn resolve(&self, result: Option<RpcResult>) {
let mut res = self.result.lock().unwrap();
*res = result.map_or(ConfirmationResult::Rejected, |h| ConfirmationResult::Confirmed(h));
// Notify listener
Expand All @@ -119,8 +122,8 @@ impl ConfirmationPromise {
/// Blocks current thread and awaits for
/// resolution of the transaction (rejected / confirmed)
/// Returns `None` if transaction was rejected or timeout reached.
/// Returns `Some(hash)` if transaction was confirmed.
pub fn wait_with_timeout(&self) -> Option<H256> {
/// Returns `Some(result)` if transaction was confirmed.
pub fn wait_with_timeout(&self) -> Option<RpcResult> {
let timeout = Duration::from_secs(QUEUE_TIMEOUT_DURATION_SEC);
let deadline = Instant::now() + timeout;

Expand All @@ -137,7 +140,7 @@ impl ConfirmationPromise {
// Check the result
match *res {
ConfirmationResult::Rejected => return None,
ConfirmationResult::Confirmed(h) => return Some(h),
ConfirmationResult::Confirmed(ref h) => return Some(h.clone()),
ConfirmationResult::Waiting => continue,
}
}
Expand Down Expand Up @@ -204,12 +207,12 @@ impl ConfirmationsQueue {

/// Removes transaction from this queue and notifies `ConfirmationPromise` holders about the result.
/// Notifies also a receiver about that event.
fn remove(&self, id: U256, result: Option<H256>) -> Option<TransactionConfirmation> {
fn remove(&self, id: U256, result: Option<RpcResult>) -> Option<TransactionConfirmation> {
let token = self.queue.write().unwrap().remove(&id);

if let Some(token) = token {
// notify receiver about the event
self.notify(result.map_or_else(
self.notify(result.clone().map_or_else(
|| QueueEvent::RequestRejected(id),
|_| QueueEvent::RequestConfirmed(id)
));
Expand Down Expand Up @@ -265,9 +268,9 @@ impl SigningQueue for ConfirmationsQueue {
self.remove(id, None)
}

fn request_confirmed(&self, id: U256, hash: H256) -> Option<TransactionConfirmation> {
fn request_confirmed(&self, id: U256, result: RpcResult) -> Option<TransactionConfirmation> {
debug!(target: "own_tx", "Signer: Transaction confirmed ({:?}).", id);
self.remove(id, Some(hash))
self.remove(id, Some(result))
}

fn requests(&self) -> Vec<TransactionConfirmation> {
Expand All @@ -286,6 +289,7 @@ mod test {
use util::numbers::{U256, H256};
use v1::types::TransactionRequest;
use super::*;
use jsonrpc_core::to_value;

fn request() -> TransactionRequest {
TransactionRequest {
Expand Down Expand Up @@ -317,10 +321,10 @@ mod test {
// Just wait for the other thread to start
thread::sleep(Duration::from_millis(100));
}
queue.request_confirmed(id, H256::from(1));
queue.request_confirmed(id, to_value(&H256::from(1)));

// then
assert_eq!(handle.join().expect("Thread should finish nicely"), H256::from(1));
assert_eq!(handle.join().expect("Thread should finish nicely"), to_value(&H256::from(1)));
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion rpc/src/v1/impls/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
.and_then(|(raw_transaction, )| {
let raw_transaction = raw_transaction.to_vec();
match UntrustedRlp::new(&raw_transaction).as_val() {
Ok(signed_transaction) => to_value(&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),
Err(_) => to_value(&H256::zero()),
}
})
Expand Down
20 changes: 15 additions & 5 deletions rpc/src/v1/impls/eth_signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use util::keys::store::AccountProvider;
use v1::helpers::{SigningQueue, ConfirmationsQueue};
use v1::traits::EthSigning;
use v1::types::TransactionRequest;
use v1::impls::sign_and_dispatch;
use v1::impls::{sign_and_dispatch, error_codes};


/// Implementation of functions that require signing when no trusted signer is used.
Expand All @@ -45,6 +45,7 @@ impl EthSigningQueueClient {
impl EthSigning for EthSigningQueueClient {

fn sign(&self, _params: Params) -> Result<Value, Error> {
warn!("Invoking eth_sign is not yet supported with signer enabled.");
// TODO [ToDr] Implement sign when rest of the signing queue is ready.
rpc_unimplemented!()
}
Expand All @@ -55,7 +56,7 @@ impl EthSigning for EthSigningQueueClient {
let queue = take_weak!(self.queue);
let id = queue.add_request(request);
let result = id.wait_with_timeout();
to_value(&result.unwrap_or_else(H256::new))
result.unwrap_or_else(|| to_value(&H256::new()))
})
}
}
Expand Down Expand Up @@ -93,7 +94,9 @@ impl<C, A, M> EthSigning for EthSigningUnsafeClient<C, A, M> where

fn sign(&self, params: Params) -> Result<Value, Error> {
from_params::<(Address, H256)>(params).and_then(|(addr, msg)| {
to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero()))
take_weak!(self.accounts).sign(&addr, &msg)
.map(|v| to_value(&v))
.unwrap_or_else(|e| Err(account_locked(format!("Error: {:?}", e))))
})
}

Expand All @@ -102,10 +105,17 @@ impl<C, A, M> EthSigning for EthSigningUnsafeClient<C, A, M> where
.and_then(|(request, )| {
let accounts = take_weak!(self.accounts);
match accounts.account_secret(&request.from) {
Ok(secret) => to_value(&sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, secret)),
Err(_) => to_value(&H256::zero())
Ok(secret) => sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, secret),
Err(e) => Err(account_locked(format!("Error: {:?}", e))),
}
})
}
}

fn account_locked(data: String) -> Error {
Error {
code: ErrorCode::ServerError(error_codes::ACCOUNT_LOCKED),
message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(),
data: Some(Value::String(data)),
}
}
Loading