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 &
This commit is contained in:
Gav Wood
2016-09-22 14:48:22 +02:00
committed by GitHub
parent 5e0dcd0892
commit 07b5e9a5c7
23 changed files with 122 additions and 29 deletions

View File

@@ -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" }

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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<C, M>(request: TRequest, client: &C, miner: &M) -> FilledRequest
where C: MiningBlockChainClient, M: MinerService {
@@ -168,6 +168,13 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
})
}
fn decrypt_message(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(RpcH160, RpcBytes)>(params).and_then(|(_account, _ciphertext)| {
Err(errors::unimplemented())
})
}
fn check_request(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
let mut pending = self.pending.lock();
@@ -241,6 +248,14 @@ impl<C, M> EthSigning for EthSigningUnsafeClient<C, M> where
}))
}
fn decrypt_message(&self, params: Params) -> Result<Value, Error> {
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<Value, Error> {
// We don't support this in non-signer mode.
Err(errors::signer_disabled())

View File

@@ -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<C, M, S: ?Sized> Ethcore for EthcoreClient<C, M, S> where M: MinerService +
to_value(&H160::from(Brain::new(phrase).generate().unwrap().address()))
)
}
fn encrypt_message(&self, params: Params) -> Result<Value, Error> {
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)))
})
}
}

View File

@@ -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",

View File

@@ -227,6 +227,10 @@ pub trait EthSigning: Sized + Send + Sync + 'static {
/// or an error.
fn check_request(&self, _: Params) -> Result<Value, Error>;
/// 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<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
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
}
}

View File

@@ -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<Value, Error>;
/// 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<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
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
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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};

View File

@@ -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<H160>,
/// Raw transaction data
pub raw: Bytes,
/// Public key of the signer.
#[serde(rename="publicKey")]
pub public_key: Option<H512>,
}
impl From<LocalizedTransaction> for Transaction {
@@ -75,6 +78,7 @@ impl From<LocalizedTransaction> 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<SignedTransaction> 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}"#);
}
}