Merge pull request #3503 from ethcore/signTransaction-format
Correct format of eth_signTransaction
This commit is contained in:
commit
c4f2b71f1b
@ -28,6 +28,7 @@ use jsonrpc_core::Error;
|
|||||||
use v1::helpers::{errors, TransactionRequest, FilledTransactionRequest, ConfirmationPayload};
|
use v1::helpers::{errors, TransactionRequest, FilledTransactionRequest, ConfirmationPayload};
|
||||||
use v1::types::{
|
use v1::types::{
|
||||||
H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes,
|
H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes,
|
||||||
|
RichRawTransaction as RpcRichRawTransaction,
|
||||||
ConfirmationPayload as RpcConfirmationPayload,
|
ConfirmationPayload as RpcConfirmationPayload,
|
||||||
ConfirmationResponse,
|
ConfirmationResponse,
|
||||||
SignRequest as RpcSignRequest,
|
SignRequest as RpcSignRequest,
|
||||||
@ -47,8 +48,7 @@ pub fn execute<C, M>(client: &C, miner: &M, accounts: &AccountProvider, payload:
|
|||||||
},
|
},
|
||||||
ConfirmationPayload::SignTransaction(request) => {
|
ConfirmationPayload::SignTransaction(request) => {
|
||||||
sign_no_dispatch(client, miner, accounts, request, pass)
|
sign_no_dispatch(client, miner, accounts, request, pass)
|
||||||
.map(|tx| rlp::encode(&tx).to_vec())
|
.map(RpcRichRawTransaction::from)
|
||||||
.map(RpcBytes)
|
|
||||||
.map(ConfirmationResponse::SignTransaction)
|
.map(ConfirmationResponse::SignTransaction)
|
||||||
},
|
},
|
||||||
ConfirmationPayload::Signature(address, hash) => {
|
ConfirmationPayload::Signature(address, hash) => {
|
||||||
|
@ -619,6 +619,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn submit_transaction(&self, raw: Bytes) -> Result<RpcH256, Error> {
|
||||||
|
self.send_raw_transaction(raw)
|
||||||
|
}
|
||||||
|
|
||||||
fn call(&self, request: CallRequest, num: Trailing<BlockNumber>) -> Result<Bytes, Error> {
|
fn call(&self, request: CallRequest, num: Trailing<BlockNumber>) -> Result<Bytes, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ use v1::traits::{EthSigning, ParitySigning};
|
|||||||
use v1::types::{
|
use v1::types::{
|
||||||
H160 as RpcH160, H256 as RpcH256, U256 as RpcU256, Bytes as RpcBytes, H520 as RpcH520,
|
H160 as RpcH160, H256 as RpcH256, U256 as RpcU256, Bytes as RpcBytes, H520 as RpcH520,
|
||||||
Either as RpcEither,
|
Either as RpcEither,
|
||||||
|
RichRawTransaction as RpcRichRawTransaction,
|
||||||
TransactionRequest as RpcTransactionRequest,
|
TransactionRequest as RpcTransactionRequest,
|
||||||
ConfirmationPayload as RpcConfirmationPayload,
|
ConfirmationPayload as RpcConfirmationPayload,
|
||||||
ConfirmationResponse as RpcConfirmationResponse
|
ConfirmationResponse as RpcConfirmationResponse
|
||||||
@ -201,11 +202,11 @@ impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_transaction(&self, ready: Ready<RpcBytes>, request: RpcTransactionRequest) {
|
fn sign_transaction(&self, ready: Ready<RpcRichRawTransaction>, request: RpcTransactionRequest) {
|
||||||
let res = self.active().and_then(|_| self.dispatch(RpcConfirmationPayload::SignTransaction(request)));
|
let res = self.active().and_then(|_| self.dispatch(RpcConfirmationPayload::SignTransaction(request)));
|
||||||
self.handle_dispatch(res, |response| {
|
self.handle_dispatch(res, |response| {
|
||||||
match response {
|
match response {
|
||||||
Ok(RpcConfirmationResponse::SignTransaction(rlp)) => ready.ready(Ok(rlp)),
|
Ok(RpcConfirmationResponse::SignTransaction(tx)) => ready.ready(Ok(tx)),
|
||||||
Err(e) => ready.ready(Err(e)),
|
Err(e) => ready.ready(Err(e)),
|
||||||
e => ready.ready(Err(errors::internal("Unexpected result.", e))),
|
e => ready.ready(Err(errors::internal("Unexpected result.", e))),
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ use v1::types::{
|
|||||||
U256 as RpcU256,
|
U256 as RpcU256,
|
||||||
H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes,
|
H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes,
|
||||||
Either as RpcEither,
|
Either as RpcEither,
|
||||||
|
RichRawTransaction as RpcRichRawTransaction,
|
||||||
TransactionRequest as RpcTransactionRequest,
|
TransactionRequest as RpcTransactionRequest,
|
||||||
ConfirmationPayload as RpcConfirmationPayload,
|
ConfirmationPayload as RpcConfirmationPayload,
|
||||||
ConfirmationResponse as RpcConfirmationResponse,
|
ConfirmationResponse as RpcConfirmationResponse,
|
||||||
@ -100,9 +101,9 @@ impl<C: 'static, M: 'static> EthSigning for SigningUnsafeClient<C, M> where
|
|||||||
ready.ready(result);
|
ready.ready(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_transaction(&self, ready: Ready<RpcBytes>, request: RpcTransactionRequest) {
|
fn sign_transaction(&self, ready: Ready<RpcRichRawTransaction>, request: RpcTransactionRequest) {
|
||||||
let result = match self.handle(RpcConfirmationPayload::SignTransaction(request)) {
|
let result = match self.handle(RpcConfirmationPayload::SignTransaction(request)) {
|
||||||
Ok(RpcConfirmationResponse::SignTransaction(rlp)) => Ok(rlp),
|
Ok(RpcConfirmationResponse::SignTransaction(tx)) => Ok(tx),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
e => Err(errors::internal("Unexpected result", e)),
|
e => Err(errors::internal("Unexpected result", e)),
|
||||||
};
|
};
|
||||||
|
@ -18,8 +18,10 @@ 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 rustc_serialize::hex::ToHex;
|
||||||
|
use time::get_time;
|
||||||
use rlp;
|
use rlp;
|
||||||
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;
|
||||||
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionID};
|
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionID};
|
||||||
@ -28,10 +30,10 @@ use ethcore::receipt::LocalizedReceipt;
|
|||||||
use ethcore::transaction::{Transaction, Action};
|
use ethcore::transaction::{Transaction, Action};
|
||||||
use ethcore::miner::{ExternalMiner, MinerService};
|
use ethcore::miner::{ExternalMiner, MinerService};
|
||||||
use ethsync::SyncState;
|
use ethsync::SyncState;
|
||||||
|
|
||||||
|
use jsonrpc_core::IoHandler;
|
||||||
use v1::{Eth, EthClient, EthClientOptions, EthFilter, EthFilterClient, EthSigning, SigningUnsafeClient};
|
use v1::{Eth, EthClient, EthClientOptions, EthFilter, EthFilterClient, EthSigning, SigningUnsafeClient};
|
||||||
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestSnapshotService};
|
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestSnapshotService};
|
||||||
use rustc_serialize::hex::ToHex;
|
|
||||||
use time::get_time;
|
|
||||||
|
|
||||||
fn blockchain_client() -> Arc<TestBlockChainClient> {
|
fn blockchain_client() -> Arc<TestBlockChainClient> {
|
||||||
let client = TestBlockChainClient::new();
|
let client = TestBlockChainClient::new();
|
||||||
@ -798,9 +800,25 @@ fn rpc_eth_sign_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 signature = t.signature();
|
||||||
let rlp = rlp::encode(&t);
|
let rlp = rlp::encode(&t);
|
||||||
|
|
||||||
let response = r#"{"jsonrpc":"2.0","result":"0x"#.to_owned() + &rlp.to_hex() + r#"","id":1}"#;
|
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||||
|
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||||
|
r#""tx":{"# +
|
||||||
|
r#""blockHash":null,"blockNumber":null,"creates":null,"# +
|
||||||
|
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||||
|
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
||||||
|
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
||||||
|
r#""input":"0x","nonce":"0x1","# +
|
||||||
|
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
||||||
|
&format!("\"r\":\"0x{}\",", signature.r().to_hex()) +
|
||||||
|
&format!("\"raw\":\"0x{}\",", rlp.to_hex()) +
|
||||||
|
&format!("\"s\":\"0x{}\",", signature.s().to_hex()) +
|
||||||
|
r#""to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","transactionIndex":null,"# +
|
||||||
|
&format!("\"v\":{},", signature.v()) +
|
||||||
|
r#""value":"0x9184e72a""# +
|
||||||
|
r#"}},"id":1}"#;
|
||||||
|
|
||||||
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
|
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
|
||||||
|
|
||||||
|
@ -268,16 +268,32 @@ fn should_add_sign_transaction_to_the_queue() {
|
|||||||
};
|
};
|
||||||
let signature = tester.accounts.sign(address, Some("test".into()), t.hash(None)).unwrap();
|
let signature = tester.accounts.sign(address, Some("test".into()), t.hash(None)).unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
|
let signature = t.signature();
|
||||||
let rlp = rlp::encode(&t);
|
let rlp = rlp::encode(&t);
|
||||||
|
|
||||||
let response = r#"{"jsonrpc":"2.0","result":"0x"#.to_owned() + &rlp.to_hex() + r#"","id":1}"#;
|
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned() +
|
||||||
|
r#""raw":"0x"# + &rlp.to_hex() + r#"","# +
|
||||||
|
r#""tx":{"# +
|
||||||
|
r#""blockHash":null,"blockNumber":null,"creates":null,"# +
|
||||||
|
&format!("\"from\":\"0x{:?}\",", &address) +
|
||||||
|
r#""gas":"0x76c0","gasPrice":"0x9184e72a000","# +
|
||||||
|
&format!("\"hash\":\"0x{:?}\",", t.hash()) +
|
||||||
|
r#""input":"0x","nonce":"0x1","# +
|
||||||
|
&format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) +
|
||||||
|
&format!("\"r\":\"0x{}\",", signature.r().to_hex()) +
|
||||||
|
&format!("\"raw\":\"0x{}\",", rlp.to_hex()) +
|
||||||
|
&format!("\"s\":\"0x{}\",", signature.s().to_hex()) +
|
||||||
|
r#""to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","transactionIndex":null,"# +
|
||||||
|
&format!("\"v\":{},", signature.v()) +
|
||||||
|
r#""value":"0x9184e72a""# +
|
||||||
|
r#"}},"id":1}"#;
|
||||||
|
|
||||||
// then
|
// then
|
||||||
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
|
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
|
||||||
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(1.into(), Ok(ConfirmationResponse::SignTransaction(rlp.to_vec().into())));
|
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction(t.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());
|
||||||
}));
|
}));
|
||||||
|
@ -102,6 +102,10 @@ build_rpc_trait! {
|
|||||||
#[rpc(name = "eth_sendRawTransaction")]
|
#[rpc(name = "eth_sendRawTransaction")]
|
||||||
fn send_raw_transaction(&self, Bytes) -> Result<H256, Error>;
|
fn send_raw_transaction(&self, Bytes) -> Result<H256, Error>;
|
||||||
|
|
||||||
|
/// Alias of `eth_sendRawTransaction`.
|
||||||
|
#[rpc(name = "eth_submitTransaction")]
|
||||||
|
fn submit_transaction(&self, Bytes) -> Result<H256, Error>;
|
||||||
|
|
||||||
/// Call contract, returning the output data.
|
/// Call contract, returning the output data.
|
||||||
#[rpc(name = "eth_call")]
|
#[rpc(name = "eth_call")]
|
||||||
fn call(&self, CallRequest, Trailing<BlockNumber>) -> Result<Bytes, Error>;
|
fn call(&self, CallRequest, Trailing<BlockNumber>) -> Result<Bytes, Error>;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Eth rpc interface.
|
//! Eth rpc interface.
|
||||||
|
|
||||||
use v1::helpers::auto_args::{WrapAsync, Ready};
|
use v1::helpers::auto_args::{WrapAsync, Ready};
|
||||||
use v1::types::{H160, H256, H520, TransactionRequest, Bytes};
|
use v1::types::{H160, H256, H520, TransactionRequest, RichRawTransaction};
|
||||||
|
|
||||||
build_rpc_trait! {
|
build_rpc_trait! {
|
||||||
/// Signing methods implementation relying on unlocked accounts.
|
/// Signing methods implementation relying on unlocked accounts.
|
||||||
@ -33,9 +33,9 @@ build_rpc_trait! {
|
|||||||
fn send_transaction(&self, Ready<H256>, TransactionRequest);
|
fn send_transaction(&self, Ready<H256>, TransactionRequest);
|
||||||
|
|
||||||
/// Signs transactions without dispatching it to the network.
|
/// Signs transactions without dispatching it to the network.
|
||||||
/// Returns signed transaction RLP representation.
|
/// Returns signed transaction RLP representation and the transaction itself.
|
||||||
/// It can be later submitted using `eth_sendRawTransaction`.
|
/// It can be later submitted using `eth_sendRawTransaction/eth_submitTransaction`.
|
||||||
#[rpc(async, name = "eth_signTransaction")]
|
#[rpc(async, name = "eth_signTransaction")]
|
||||||
fn sign_transaction(&self, Ready<Bytes>, TransactionRequest);
|
fn sign_transaction(&self, Ready<RichRawTransaction>, TransactionRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use v1::types::{U256, TransactionRequest, H160, H256, H520, Bytes};
|
use v1::types::{U256, TransactionRequest, RichRawTransaction, H160, H256, H520, Bytes};
|
||||||
use v1::helpers;
|
use v1::helpers;
|
||||||
|
|
||||||
/// Confirmation waiting in a queue
|
/// Confirmation waiting in a queue
|
||||||
@ -76,12 +76,12 @@ impl From<(H160, Bytes)> for DecryptRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Confirmation response for particular payload
|
/// Confirmation response for particular payload
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum ConfirmationResponse {
|
pub enum ConfirmationResponse {
|
||||||
/// Transaction Hash
|
/// Transaction Hash
|
||||||
SendTransaction(H256),
|
SendTransaction(H256),
|
||||||
/// Transaction RLP
|
/// Transaction RLP
|
||||||
SignTransaction(Bytes),
|
SignTransaction(RichRawTransaction),
|
||||||
/// Signature
|
/// Signature
|
||||||
Signature(H520),
|
Signature(H520),
|
||||||
/// Decrypted data
|
/// Decrypted data
|
||||||
|
@ -44,7 +44,7 @@ pub use self::hash::{H64, H160, H256, H512, H520, H2048};
|
|||||||
pub use self::index::Index;
|
pub use self::index::Index;
|
||||||
pub use self::log::Log;
|
pub use self::log::Log;
|
||||||
pub use self::sync::{SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, PeerEthereumProtocolInfo};
|
pub use self::sync::{SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, PeerEthereumProtocolInfo};
|
||||||
pub use self::transaction::Transaction;
|
pub use self::transaction::{Transaction, RichRawTransaction};
|
||||||
pub use self::transaction_request::TransactionRequest;
|
pub use self::transaction_request::TransactionRequest;
|
||||||
pub use self::receipt::Receipt;
|
pub use self::receipt::Receipt;
|
||||||
pub use self::rpc_settings::RpcSettings;
|
pub use self::rpc_settings::RpcSettings;
|
||||||
|
@ -19,7 +19,7 @@ use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction};
|
|||||||
use v1::types::{Bytes, H160, H256, U256, H512};
|
use v1::types::{Bytes, H160, H256, U256, H512};
|
||||||
|
|
||||||
/// Transaction
|
/// Transaction
|
||||||
#[derive(Debug, Default, Serialize)]
|
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
/// Hash
|
/// Hash
|
||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
@ -62,6 +62,26 @@ pub struct Transaction {
|
|||||||
pub s: H256,
|
pub s: H256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Geth-compatible output for eth_signTransaction method
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
|
||||||
|
pub struct RichRawTransaction {
|
||||||
|
/// Raw transaction RLP
|
||||||
|
pub raw: Bytes,
|
||||||
|
/// Transaction details
|
||||||
|
#[serde(rename="tx")]
|
||||||
|
pub transaction: Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SignedTransaction> for RichRawTransaction {
|
||||||
|
fn from(t: SignedTransaction) -> Self {
|
||||||
|
let tx: Transaction = t.into();
|
||||||
|
RichRawTransaction {
|
||||||
|
raw: tx.raw.clone(),
|
||||||
|
transaction: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<LocalizedTransaction> for Transaction {
|
impl From<LocalizedTransaction> for Transaction {
|
||||||
fn from(t: LocalizedTransaction) -> Transaction {
|
fn from(t: LocalizedTransaction) -> Transaction {
|
||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
|
Loading…
Reference in New Issue
Block a user