Fixing errors returned by sendTransaction* method family (#1665)

This commit is contained in:
Tomasz Drwięga 2016-07-20 12:37:49 +02:00 committed by Gav Wood
parent b007770ba8
commit 9c7395a6be
7 changed files with 51 additions and 36 deletions

View File

@ -83,17 +83,14 @@ impl<C, M> EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: Miner
if accounts.is_unlocked(request.from) { if accounts.is_unlocked(request.from) {
let sender = request.from; let sender = request.from;
return match sign_and_dispatch(&*client, &*miner, request, &*accounts, sender) { return sign_and_dispatch(&*client, &*miner, request, &*accounts, sender);
Ok(hash) => to_value(&hash),
_ => to_value(&RpcH256::default()),
}
} }
let queue = take_weak!(self.queue); let queue = take_weak!(self.queue);
fill_optional_fields(&mut request, &*client, &*miner); fill_optional_fields(&mut request, &*client, &*miner);
let promise = queue.add_request(request); let promise = queue.add_request(request);
f(promise) f(promise)
}) })
} }
} }
@ -110,17 +107,17 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
fn send_transaction(&self, params: Params) -> Result<Value, Error> { fn send_transaction(&self, params: Params) -> Result<Value, Error> {
try!(self.active()); try!(self.active());
self.dispatch(params, |promise: ConfirmationPromise| { self.dispatch(params, |promise| {
promise.wait_with_timeout().unwrap_or_else(|| to_value(&RpcH256::default())) promise.wait_with_timeout().unwrap_or_else(|| to_value(&RpcH256::default()))
}) })
} }
fn post_transaction(&self, params: Params) -> Result<Value, Error> { fn post_transaction(&self, params: Params) -> Result<Value, Error> {
try!(self.active()); try!(self.active());
self.dispatch(params, |promise: ConfirmationPromise| { self.dispatch(params, |promise| {
let ret = to_value(&RpcU256::from(promise.id())); let id = promise.id();
self.pending.lock().insert(promise.id(), promise); self.pending.lock().insert(id, promise);
ret to_value(&RpcU256::from(id))
}) })
} }
@ -192,11 +189,8 @@ impl<C, M> EthSigning for EthSigningUnsafeClient<C, M> where
.and_then(|(request, )| { .and_then(|(request, )| {
let request: TRequest = request.into(); let request: TRequest = request.into();
let sender = request.from; let sender = request.from;
match sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, &*take_weak!(self.accounts), sender) { sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, &*take_weak!(self.accounts), sender)
Ok(hash) => to_value(&hash), })
_ => to_value(&RpcH256::default()),
}
})
} }
fn post_transaction(&self, _: Params) -> Result<Value, Error> { fn post_transaction(&self, _: Params) -> Result<Value, Error> {

View File

@ -73,6 +73,7 @@ mod error_codes {
pub const UNKNOWN_ERROR: i64 = -32009; pub const UNKNOWN_ERROR: i64 = -32009;
pub const TRANSACTION_ERROR: i64 = -32010; pub const TRANSACTION_ERROR: i64 = -32010;
pub const ACCOUNT_LOCKED: i64 = -32020; pub const ACCOUNT_LOCKED: i64 = -32020;
pub const PASSWORD_INVALID: i64 = -32021;
pub const SIGNER_DISABLED: i64 = -32030; pub const SIGNER_DISABLED: i64 = -32030;
} }
@ -109,7 +110,7 @@ fn unlock_sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionReq
let signed_transaction = { let signed_transaction = {
let t = prepare_transaction(client, miner, request); let t = prepare_transaction(client, miner, request);
let hash = t.hash(); let hash = t.hash();
let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(signing_error)); let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(password_error));
t.with_signature(signature) t.with_signature(signature)
}; };
@ -147,6 +148,14 @@ fn signing_error(error: AccountError) -> Error {
} }
} }
fn password_error(error: AccountError) -> Error {
Error {
code: ErrorCode::ServerError(error_codes::PASSWORD_INVALID),
message: "Account password is invalid or account does not exist.".into(),
data: Some(Value::String(format!("{:?}", error))),
}
}
fn transaction_error(error: EthcoreError) -> Error { fn transaction_error(error: EthcoreError) -> Error {
use ethcore::error::TransactionError::*; use ethcore::error::TransactionError::*;

View File

@ -18,7 +18,7 @@
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use jsonrpc_core::*; use jsonrpc_core::*;
use v1::traits::Personal; use v1::traits::Personal;
use v1::types::{H160 as RpcH160, H256 as RpcH256, TransactionRequest}; use v1::types::{H160 as RpcH160, TransactionRequest};
use v1::impls::unlock_sign_and_dispatch; use v1::impls::unlock_sign_and_dispatch;
use v1::helpers::{TransactionRequest as TRequest}; use v1::helpers::{TransactionRequest as TRequest};
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
@ -101,10 +101,7 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
let sender = request.from; let sender = request.from;
let accounts = take_weak!(self.accounts); let accounts = take_weak!(self.accounts);
match unlock_sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, &*accounts, sender, password) { unlock_sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, &*accounts, sender, password)
Ok(hash) => Ok(hash), })
_ => to_value(&RpcH256::default()),
}
})
} }
} }

View File

@ -70,7 +70,7 @@ impl<C: 'static, M: 'static> PersonalSigner for SignerClient<C, M> where C: Mini
let queue = take_weak!(self.queue); let queue = take_weak!(self.queue);
let client = take_weak!(self.client); let client = take_weak!(self.client);
let miner = take_weak!(self.miner); let miner = take_weak!(self.miner);
queue.peek(&id).and_then(|confirmation| { queue.peek(&id).map(|confirmation| {
let mut request = confirmation.transaction; let mut request = confirmation.transaction;
// apply modification // apply modification
if let Some(gas_price) = modification.gas_price { if let Some(gas_price) = modification.gas_price {
@ -78,18 +78,12 @@ impl<C: 'static, M: 'static> PersonalSigner for SignerClient<C, M> where C: Mini
} }
let sender = request.from; let sender = request.from;
let result = unlock_sign_and_dispatch(&*client, &*miner, request, &*accounts, sender, pass);
match unlock_sign_and_dispatch(&*client, &*miner, request, &*accounts, sender, pass) { if let Ok(ref hash) = result {
Ok(hash) => { queue.request_confirmed(id, Ok(hash.clone()));
queue.request_confirmed(id, Ok(hash.clone()));
Some(to_value(&hash))
},
_ => None
} }
}) result
.unwrap_or_else(|| { }).unwrap_or_else(|| Err(Error::invalid_params()))
to_value(&false)
})
} }
) )
} }

View File

@ -609,6 +609,27 @@ fn rpc_eth_send_transaction() {
assert_eq!(tester.io.handle_request(&request), Some(response)); assert_eq!(tester.io.handle_request(&request), Some(response));
} }
#[test]
fn rpc_eth_send_transaction_error() {
let tester = EthTester::default();
let address = tester.accounts_provider.new_account("").unwrap();
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_sendTransaction",
"params": [{
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a"
}],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32020,"message":"Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.","data":"NotUnlocked"},"id":1}"#;
assert_eq!(tester.io.handle_request(&request), Some(response.into()));
}
#[test] #[test]
fn rpc_eth_send_raw_transaction() { fn rpc_eth_send_raw_transaction() {
let tester = EthTester::default(); let tester = EthTester::default();

View File

@ -135,7 +135,7 @@ fn sign_and_send_transaction_with_invalid_password() {
"id": 1 "id": 1
}"#; }"#;
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000","id":1}"#; let response = r#"{"jsonrpc":"2.0","error":{"code":-32021,"message":"Account password is invalid or account does not exist.","data":"SStore(InvalidPassword)"},"id":1}"#;
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response.into())); assert_eq!(tester.io.handle_request(request.as_ref()), Some(response.into()));
} }

View File

@ -132,7 +132,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
// when // when
let request = r#"{"jsonrpc":"2.0","method":"personal_confirmTransaction","params":["0x01",{},"xxx"],"id":1}"#; let request = r#"{"jsonrpc":"2.0","method":"personal_confirmTransaction","params":["0x01",{},"xxx"],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; let response = r#"{"jsonrpc":"2.0","error":{"code":-32021,"message":"Account password is invalid or account does not exist.","data":"SStore(InvalidAccount)"},"id":1}"#;
// then // then
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned())); assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));