From 07b5e9a5c7315116fb05bd5d81997f8b2d1b2ab2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 22 Sep 2016 14:48:22 +0200 Subject: [PATCH] Encryption, decryption and public key RPCs. (#1946) * Fix up pending receipts details. * Add support for additional params and registry over RPC. * Fix tests. * Add test, additional fix. Fixes #1932. * Fix up tests. * Fix test. * Fix test. * Remove unused use. * Add encryption, decryption and public-key RPCs. * Remove & --- Cargo.lock | 1 + ethcore/src/account_provider.rs | 20 ++++++++++++++++++++ ethcore/src/client/traits.rs | 7 +++++-- ethcore/src/types/transaction.rs | 9 +++++++-- ethcrypto/src/lib.rs | 12 ++++++++++++ ethkey/Cargo.toml | 2 +- ethstore/src/account/safe_account.rs | 7 ++++++- ethstore/src/error.rs | 9 +++++++++ ethstore/src/ethstore.rs | 5 +++++ ethstore/src/secret_store.rs | 13 ++----------- rpc/Cargo.toml | 1 + rpc/src/lib.rs | 1 + rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/impls/eth_filter.rs | 2 +- rpc/src/v1/impls/eth_signing.rs | 17 ++++++++++++++++- rpc/src/v1/impls/ethcore.rs | 11 ++++++++++- rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/traits/eth.rs | 5 +++++ rpc/src/v1/traits/ethcore.rs | 5 +++++ rpc/src/v1/types/block.rs | 2 +- rpc/src/v1/types/hash.rs | 7 ++++--- rpc/src/v1/types/mod.rs.in | 2 +- rpc/src/v1/types/transaction.rs | 9 +++++++-- 23 files changed, 122 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b373f2f2..8e1e4e3f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -458,6 +458,7 @@ dependencies = [ "ethcore-io 1.4.0", "ethcore-ipc 1.4.0", "ethcore-util 1.4.0", + "ethcrypto 0.1.0", "ethjson 0.1.0", "ethkey 0.2.0", "ethstore 0.1.0", diff --git a/ethcore/src/account_provider.rs b/ethcore/src/account_provider.rs index c2379d09e..851d015ba 100644 --- a/ethcore/src/account_provider.rs +++ b/ethcore/src/account_provider.rs @@ -322,6 +322,26 @@ impl AccountProvider { Ok(signature) } + /// Decrypts a message. Account must be unlocked. + pub fn decrypt(&self, account: Address, shared_mac: &[u8], message: &[u8]) -> Result, Error> { + let data = { + let mut unlocked = self.unlocked.lock(); + let data = try!(unlocked.get(&account).ok_or(Error::NotUnlocked)).clone(); + if let Unlock::Temp = data.unlock { + unlocked.remove(&account).expect("data exists: so key must exist: qed"); + } + if let Unlock::Timed((ref start, ref duration)) = data.unlock { + if start.elapsed() > Duration::from_millis(*duration as u64) { + unlocked.remove(&account).expect("data exists: so key must exist: qed"); + return Err(Error::NotUnlocked); + } + } + data + }; + + Ok(try!(self.sstore.decrypt(&account, &data.password, shared_mac, message))) + } + /// Unlocks an account, signs the message, and locks it again. pub fn sign_with_password(&self, account: Address, password: String, message: Message) -> Result { let signature = try!(self.sstore.sign(&account, &password, &message)); diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 271e95785..45f7322fd 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -215,8 +215,11 @@ pub trait BlockChainClient : Sync + Send { /// Extended client interface used for mining pub trait MiningBlockChainClient : BlockChainClient { /// Returns OpenBlock prepared for closing. - fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) - -> OpenBlock; + fn prepare_open_block(&self, + author: Address, + gas_range_target: (U256, U256), + extra_data: Bytes + ) -> OpenBlock; /// Returns EvmFactory. fn vm_factory(&self) -> &EvmFactory; diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index f7e582f11..386b85f7e 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -21,7 +21,7 @@ use std::cell::*; use rlp::*; use util::sha3::Hashable; use util::{H256, Address, U256, Bytes}; -use ethkey::{Signature, sign, Secret, recover, public_to_address, Error as EthkeyError}; +use ethkey::{Signature, sign, Secret, Public, recover, public_to_address, Error as EthkeyError}; use error::*; use evm::Schedule; use header::BlockNumber; @@ -305,13 +305,18 @@ impl SignedTransaction { match sender { Some(s) => Ok(s), None => { - let s = public_to_address(&try!(recover(&self.signature(), &self.unsigned.hash()))); + let s = public_to_address(&try!(self.public_key())); self.sender.set(Some(s)); Ok(s) } } } + /// Returns the public key of the sender. + pub fn public_key(&self) -> Result { + Ok(try!(recover(&self.signature(), &self.unsigned.hash()))) + } + /// Do basic validation, checking for valid signature and minimum gas, // TODO: consider use in block validation. #[cfg(test)] diff --git a/ethcrypto/src/lib.rs b/ethcrypto/src/lib.rs index 680718d12..7a1aba48c 100644 --- a/ethcrypto/src/lib.rs +++ b/ethcrypto/src/lib.rs @@ -22,6 +22,7 @@ extern crate crypto as rcrypto; extern crate secp256k1; extern crate ethkey; +use std::fmt; use tiny_keccak::Keccak; use rcrypto::pbkdf2::pbkdf2; use rcrypto::scrypt::{scrypt, ScryptParams}; @@ -39,6 +40,17 @@ pub enum Error { InvalidMessage, } +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let s = match *self { + Error::Secp(ref err) => err.to_string(), + Error::InvalidMessage => "Invalid message".into(), + }; + + write!(f, "{}", s) + } +} + impl From for Error { fn from(e: SecpError) -> Self { Error::Secp(e) diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index 8e95d8519..319a38b20 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ethkey" version = "0.2.0" -authors = ["debris "] +authors = ["Ethcore "] [dependencies] rand = "0.3.14" diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 56e8494f7..38069a718 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -16,7 +16,7 @@ use ethkey::{KeyPair, sign, Address, Secret, Signature, Message}; use {json, Error, crypto}; -use crypto::Keccak256; +use crypto::{Keccak256}; use random::Random; use account::{Version, Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf}; @@ -170,6 +170,11 @@ impl SafeAccount { sign(&secret, message).map_err(From::from) } + pub fn decrypt(&self, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { + let secret = try!(self.crypto.secret(password)); + crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) + } + pub fn change_password(&self, old_password: &str, new_password: &str, iterations: u32) -> Result { let secret = try!(self.crypto.secret(old_password)); let result = SafeAccount { diff --git a/ethstore/src/error.rs b/ethstore/src/error.rs index a5d3de745..cee689b24 100644 --- a/ethstore/src/error.rs +++ b/ethstore/src/error.rs @@ -17,6 +17,7 @@ use std::fmt; use std::io::Error as IoError; use ethkey::Error as EthKeyError; +use crypto::Error as EthCryptoError; #[derive(Debug)] pub enum Error { @@ -28,6 +29,7 @@ pub enum Error { InvalidKeyFile(String), CreationFailed, EthKey(EthKeyError), + EthCrypto(EthCryptoError), Custom(String), } @@ -42,6 +44,7 @@ impl fmt::Display for Error { Error::InvalidKeyFile(ref reason) => format!("Invalid key file: {}", reason), Error::CreationFailed => "Account creation failed".into(), Error::EthKey(ref err) => err.to_string(), + Error::EthCrypto(ref err) => err.to_string(), Error::Custom(ref s) => s.clone(), }; @@ -60,3 +63,9 @@ impl From for Error { Error::EthKey(err) } } + +impl From for Error { + fn from(err: EthCryptoError) -> Self { + Error::EthCrypto(err) + } +} diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 29f4c757c..8de988b9a 100644 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -144,6 +144,11 @@ impl SecretStore for EthStore { account.sign(password, message) } + fn decrypt(&self, account: &Address, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { + let account = try!(self.get(account)); + account.decrypt(password, shared_mac, message) + } + fn uuid(&self, address: &Address) -> Result { let account = try!(self.get(address)); Ok(account.id.into()) diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs index 90ed79fb5..aa79cb8b6 100644 --- a/ethstore/src/secret_store.rs +++ b/ethstore/src/secret_store.rs @@ -20,33 +20,24 @@ use json::UUID; pub trait SecretStore: Send + Sync { fn insert_account(&self, secret: Secret, password: &str) -> Result; - fn import_presale(&self, json: &[u8], password: &str) -> Result; - fn import_wallet(&self, json: &[u8], password: &str) -> Result; - - fn accounts(&self) -> Result, Error>; - fn change_password(&self, account: &Address, old_password: &str, new_password: &str) -> Result<(), Error>; - fn remove_account(&self, account: &Address, password: &str) -> Result<(), Error>; fn sign(&self, account: &Address, password: &str, message: &Message) -> Result; + fn decrypt(&self, account: &Address, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error>; + fn accounts(&self) -> Result, Error>; fn uuid(&self, account: &Address) -> Result; - fn name(&self, account: &Address) -> Result; - fn meta(&self, account: &Address) -> Result; fn set_name(&self, address: &Address, name: String) -> Result<(), Error>; - fn set_meta(&self, address: &Address, meta: String) -> Result<(), Error>; fn local_path(&self) -> String; - fn list_geth_accounts(&self, testnet: bool) -> Vec
; - fn import_geth_accounts(&self, desired: Vec
, testnet: bool) -> Result, Error>; } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 440e41fc9..c3f9cddbd 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -17,6 +17,7 @@ jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.gi ethcore-io = { path = "../util/io" } ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } +ethcrypto = { path = "../ethcrypto" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } ethash = { path = "../ethash" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 978b6f239..7f2f11400 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -28,6 +28,7 @@ extern crate jsonrpc_http_server; extern crate ethcore_io as io; extern crate ethcore; extern crate ethkey; +extern crate ethcrypto as crypto; extern crate ethstore; extern crate ethsync; extern crate transient_hashmap; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 3799dd925..cffbe87e5 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -45,7 +45,7 @@ use v1::traits::Eth; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256}; use v1::helpers::{CallRequest as CRequest, errors, limit_logs}; use v1::helpers::dispatch::{default_gas_price, dispatch_transaction}; -use v1::helpers::params::{expect_no_params, params_len, from_params_default_second, from_params_default_third}; +use v1::helpers::params::{expect_no_params, from_params_default_second, from_params_default_third}; /// Eth RPC options pub struct EthClientOptions { diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 4301daae0..369f474d7 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -26,7 +26,7 @@ use util::Mutex; use v1::traits::EthFilter; use v1::types::{BlockNumber, Index, Filter, Log, H256 as RpcH256, U256 as RpcU256}; use v1::helpers::{PollFilter, PollManager, limit_logs}; -use v1::helpers::params::{expect_no_params, params_len}; +use v1::helpers::params::{expect_no_params}; use v1::impls::eth::pending_logs; /// Eth filter rpc implementation. diff --git a/rpc/src/v1/impls/eth_signing.rs b/rpc/src/v1/impls/eth_signing.rs index 9ae243de4..9290a9425 100644 --- a/rpc/src/v1/impls/eth_signing.rs +++ b/rpc/src/v1/impls/eth_signing.rs @@ -26,7 +26,7 @@ use ethcore::account_provider::AccountProvider; use v1::helpers::{errors, SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest, SignerService}; use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch}; use v1::traits::EthSigning; -use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U256 as RpcU256}; +use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U256 as RpcU256, Bytes as RpcBytes}; fn fill_optional_fields(request: TRequest, client: &C, miner: &M) -> FilledRequest where C: MiningBlockChainClient, M: MinerService { @@ -168,6 +168,13 @@ impl EthSigning for EthSigningQueueClient }) } + fn decrypt_message(&self, params: Params) -> Result { + try!(self.active()); + from_params::<(RpcH160, RpcBytes)>(params).and_then(|(_account, _ciphertext)| { + Err(errors::unimplemented()) + }) + } + fn check_request(&self, params: Params) -> Result { try!(self.active()); let mut pending = self.pending.lock(); @@ -241,6 +248,14 @@ impl EthSigning for EthSigningUnsafeClient where })) } + fn decrypt_message(&self, params: Params) -> Result { + try!(self.active()); + from_params::<(RpcH160, RpcBytes)>(params).and_then(|(address, ciphertext)| { + let s = try!(take_weak!(self.accounts).decrypt(address.into(), &[0; 0], &ciphertext.0).map_err(|_| Error::internal_error())); + Ok(to_value(RpcBytes::from(s))) + }) + } + fn post_sign(&self, _: Params) -> Result { // We don't support this in non-signer mode. Err(errors::signer_disabled()) diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index 6ff7cff26..b9f8c4bf5 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -21,6 +21,7 @@ use std::collections::{BTreeMap}; use util::{RotatingLogger, Address}; use util::misc::version_data; +use crypto::ecies; use ethkey::{Brain, Generator}; use ethstore::random_phrase; use ethsync::{SyncProvider, ManageNetwork}; @@ -29,7 +30,7 @@ use ethcore::client::{MiningBlockChainClient}; use jsonrpc_core::*; use v1::traits::Ethcore; -use v1::types::{Bytes, U256, H160, Peers}; +use v1::types::{Bytes, U256, H160, H512, Peers}; use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::params::expect_no_params; @@ -217,4 +218,12 @@ impl Ethcore for EthcoreClient where M: MinerService + to_value(&H160::from(Brain::new(phrase).generate().unwrap().address())) ) } + + fn encrypt_message(&self, params: Params) -> Result { + try!(self.active()); + from_params::<(H512, Bytes)>(params).and_then(|(key, phrase)| { + let s = try!(ecies::encrypt(&key.into(), &[0; 0], &phrase.0).map_err(|_| Error::internal_error())); + Ok(to_value(&Bytes::from(s))) + }) + } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 630d55491..eb3fbaf6e 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -457,7 +457,7 @@ fn rpc_eth_pending_transaction_by_hash() { tester.miner.pending_transactions.lock().insert(H256::zero(), tx); } - let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0xa"},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0xa"},"id":1}"#; let request = r#"{ "jsonrpc": "2.0", "method": "eth_getTransactionByHash", diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 610591f1f..744d3b83a 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -227,6 +227,10 @@ pub trait EthSigning: Sized + Send + Sync + 'static { /// or an error. fn check_request(&self, _: Params) -> Result; + /// Decrypt some ECIES-encrypted message. + /// First parameter is the address with which it is encrypted, second is the ciphertext. + fn decrypt_message(&self, _: Params) -> Result; + /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { let mut delegate = IoDelegate::new(Arc::new(self)); @@ -235,6 +239,7 @@ pub trait EthSigning: Sized + Send + Sync + 'static { delegate.add_method("eth_postSign", EthSigning::post_sign); delegate.add_method("eth_postTransaction", EthSigning::post_transaction); delegate.add_method("eth_checkRequest", EthSigning::check_request); + delegate.add_method("ethcore_decryptMessage", EthSigning::decrypt_message); delegate } } diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index efd838297..90661129b 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -76,6 +76,10 @@ pub trait Ethcore: Sized + Send + Sync + 'static { /// Returns the value of the registrar for this network. fn registry_address(&self, _: Params) -> Result; + /// Encrypt some data with a public key under ECIES. + /// First parameter is the 512-byte destination public key, second is the message. + fn encrypt_message(&self, _: Params) -> Result; + /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { let mut delegate = IoDelegate::new(Arc::new(self)); @@ -98,6 +102,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static { delegate.add_method("ethcore_generateSecretPhrase", Ethcore::generate_secret_phrase); delegate.add_method("ethcore_phraseToAddress", Ethcore::phrase_to_address); delegate.add_method("ethcore_registryAddress", Ethcore::registry_address); + delegate.add_method("ethcore_encryptMessage", Ethcore::encrypt_message); delegate } diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 21459d026..70f39ba73 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -103,7 +103,7 @@ mod tests { fn test_serialize_block_transactions() { let t = BlockTransactions::Full(vec![Transaction::default()]); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x"}]"#); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null}]"#); let t = BlockTransactions::Hashes(vec![H256::default().into()]); let serialized = serde_json::to_string(&t).unwrap(); diff --git a/rpc/src/v1/types/hash.rs b/rpc/src/v1/types/hash.rs index 47c529235..3080aa031 100644 --- a/rpc/src/v1/types/hash.rs +++ b/rpc/src/v1/types/hash.rs @@ -20,7 +20,7 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use serde; use rustc_serialize::hex::{ToHex, FromHex}; -use util::{H64 as Eth64, H256 as EthH256, H520 as EthH520, H2048 as Eth2048, H160 as Eth160}; +use util::{H64 as Eth64, H160 as Eth160, H256 as Eth256, H520 as Eth520, H512 as Eth512, H2048 as Eth2048}; macro_rules! impl_hash { ($name: ident, $other: ident, $size: expr) => { @@ -144,6 +144,7 @@ macro_rules! impl_hash { impl_hash!(H64, Eth64, 8); impl_hash!(H160, Eth160, 20); -impl_hash!(H256, EthH256, 32); -impl_hash!(H520, EthH520, 65); +impl_hash!(H256, Eth256, 32); +impl_hash!(H512, Eth512, 64); +impl_hash!(H520, Eth520, 65); impl_hash!(H2048, Eth2048, 256); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 312e93818..e4fd613aa 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -37,7 +37,7 @@ pub use self::block_number::BlockNumber; pub use self::call_request::CallRequest; pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, TransactionModification}; pub use self::filter::Filter; -pub use self::hash::{H64, H160, H256, H520, H2048}; +pub use self::hash::{H64, H160, H256, H512, H520, H2048}; pub use self::index::Index; pub use self::log::Log; pub use self::sync::{SyncStatus, SyncInfo, Peers}; diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index d4697aff2..6aa9ee899 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -16,7 +16,7 @@ use ethcore::contract_address; use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction}; -use v1::types::{Bytes, H160, H256, U256}; +use v1::types::{Bytes, H160, H256, U256, H512}; /// Transaction #[derive(Debug, Default, Serialize)] @@ -51,6 +51,9 @@ pub struct Transaction { pub creates: Option, /// Raw transaction data pub raw: Bytes, + /// Public key of the signer. + #[serde(rename="publicKey")] + pub public_key: Option, } impl From for Transaction { @@ -75,6 +78,7 @@ impl From for Transaction { Action::Call(_) => None, }, raw: ::rlp::encode(&t.signed).to_vec().into(), + public_key: t.public_key().ok().map(Into::into), } } } @@ -101,6 +105,7 @@ impl From for Transaction { Action::Call(_) => None, }, raw: ::rlp::encode(&t).to_vec().into(), + public_key: t.public_key().ok().map(Into::into), } } } @@ -114,7 +119,7 @@ mod tests { fn test_transaction_serialize() { let t = Transaction::default(); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x"}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null}"#); } }