Merge pull request #587 from ethcore/rpc-signing-extend

Rpc transaction signing
This commit is contained in:
Marek Kotewicz
2016-03-11 11:14:17 +01:00
8 changed files with 158 additions and 32 deletions

View File

@@ -28,22 +28,25 @@ use ethcore::views::*;
use ethcore::ethereum::Ethash;
use ethcore::ethereum::denominations::shannon;
use v1::traits::{Eth, EthFilter};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log};
use v1::helpers::{PollFilter, PollManager};
use util::keys::store::AccountProvider;
/// Eth rpc implementation.
pub struct EthClient<C, S> where C: BlockChainClient, S: SyncProvider {
pub struct EthClient<C, S, A> where C: BlockChainClient, S: SyncProvider, A: AccountProvider {
client: Weak<C>,
sync: Weak<S>,
accounts: Weak<A>,
hashrates: RwLock<HashMap<H256, u64>>,
}
impl<C, S> EthClient<C, S> where C: BlockChainClient, S: SyncProvider {
impl<C, S, A> EthClient<C, S, A> where C: BlockChainClient, S: SyncProvider, A: AccountProvider {
/// Creates new EthClient.
pub fn new(client: &Arc<C>, sync: &Arc<S>) -> Self {
pub fn new(client: &Arc<C>, sync: &Arc<S>, accounts: &Arc<A>) -> Self {
EthClient {
client: Arc::downgrade(client),
sync: Arc::downgrade(sync),
accounts: Arc::downgrade(accounts),
hashrates: RwLock::new(HashMap::new()),
}
}
@@ -94,7 +97,7 @@ impl<C, S> EthClient<C, S> where C: BlockChainClient, S: SyncProvider {
}
}
impl<C, S> Eth for EthClient<C, S> where C: BlockChainClient + 'static, S: SyncProvider + 'static {
impl<C, S, A> Eth for EthClient<C, S, A> where C: BlockChainClient + 'static, S: SyncProvider + 'static, A: AccountProvider + 'static {
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)),
@@ -263,6 +266,24 @@ impl<C, S> Eth for EthClient<C, S> where C: BlockChainClient + 'static, S: SyncP
to_value(&true)
})
}
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(TransactionRequest, )>(params)
.and_then(|(transaction_request, )| {
let accounts = take_weak!(self.accounts);
match accounts.account_secret(&transaction_request.from) {
Ok(secret) => {
let sync = take_weak!(self.sync);
let (transaction, _) = transaction_request.to_eth();
let signed_transaction = transaction.sign(&secret);
let hash = signed_transaction.hash();
sync.insert_transaction(signed_transaction);
to_value(&hash)
},
Err(_) => { to_value(&U256::zero()) }
}
})
}
}
/// Eth filter rpc implementation.

View File

@@ -20,30 +20,28 @@ use jsonrpc_core::*;
use v1::traits::Personal;
use util::keys::store::*;
use util::Address;
use std::sync::RwLock;
/// Account management (personal) rpc implementation.
pub struct PersonalClient {
secret_store: Weak<RwLock<SecretStore>>,
accounts: Weak<AccountProvider>,
}
impl PersonalClient {
/// Creates new PersonalClient
pub fn new(store: &Arc<RwLock<SecretStore>>) -> Self {
pub fn new(store: &Arc<AccountProvider>) -> Self {
PersonalClient {
secret_store: Arc::downgrade(store),
accounts: Arc::downgrade(store),
}
}
}
impl Personal for PersonalClient {
fn accounts(&self, _: Params) -> Result<Value, Error> {
let store_wk = take_weak!(self.secret_store);
let store = store_wk.read().unwrap();
let store = take_weak!(self.accounts);
match store.accounts() {
Ok(account_list) => {
Ok(Value::Array(account_list.iter()
.map(|&(account, _)| Value::String(format!("{:?}", account)))
.map(|&account| Value::String(format!("{:?}", account)))
.collect::<Vec<Value>>())
)
}
@@ -54,8 +52,7 @@ impl Personal for PersonalClient {
fn new_account(&self, params: Params) -> Result<Value, Error> {
from_params::<(String, )>(params).and_then(
|(pass, )| {
let store_wk = take_weak!(self.secret_store);
let mut store = store_wk.write().unwrap();
let store = take_weak!(self.accounts);
match store.new_account(&pass) {
Ok(address) => Ok(Value::String(format!("{:?}", address))),
Err(_) => Err(Error::internal_error())
@@ -67,8 +64,7 @@ impl Personal for PersonalClient {
fn unlock_account(&self, params: Params) -> Result<Value, Error> {
from_params::<(Address, String, u64)>(params).and_then(
|(account, account_pass, _)|{
let store_wk = take_weak!(self.secret_store);
let store = store_wk.read().unwrap();
let store = take_weak!(self.accounts);
match store.unlock_account(&account, &account_pass) {
Ok(_) => Ok(Value::Bool(true)),
Err(_) => Ok(Value::Bool(false)),

View File

@@ -15,7 +15,9 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use rustc_serialize::hex::ToHex;
use serde::{Serialize, Serializer};
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error};
use serde::de::Visitor;
use util::common::FromHex;
/// Wrapper structure around vector of bytes.
#[derive(Debug)]
@@ -26,6 +28,7 @@ impl Bytes {
pub fn new(bytes: Vec<u8>) -> Bytes {
Bytes(bytes)
}
pub fn to_vec(self) -> Vec<u8> { let Bytes(x) = self; x }
}
impl Default for Bytes {
@@ -36,7 +39,7 @@ impl Default for Bytes {
}
impl Serialize for Bytes {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
let mut serialized = "0x".to_owned();
serialized.push_str(self.0.to_hex().as_ref());
@@ -44,6 +47,32 @@ impl Serialize for Bytes {
}
}
impl Deserialize for Bytes {
fn deserialize<D>(deserializer: &mut D) -> Result<Bytes, D::Error>
where D: Deserializer {
deserializer.deserialize(BytesVisitor)
}
}
struct BytesVisitor;
impl Visitor for BytesVisitor {
type Value = Bytes;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: Error {
if value.len() >= 2 && &value[0..2] == "0x" {
Ok(Bytes::new(FromHex::from_hex(&value[2..]).unwrap_or_else(|_| vec![])))
} else {
Err(Error::custom("invalid hex"))
}
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: Error {
self.visit_str(value.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -33,3 +33,5 @@ pub use self::log::Log;
pub use self::optionals::OptionalValue;
pub use self::sync::{SyncStatus, SyncInfo};
pub use self::transaction::Transaction;
pub use self::transaction::TransactionRequest;

View File

@@ -17,6 +17,8 @@
use util::numbers::*;
use ethcore::transaction::{LocalizedTransaction, Action};
use v1::types::{Bytes, OptionalValue};
use serde::{Deserializer, Error};
use ethcore;
#[derive(Debug, Default, Serialize)]
pub struct Transaction {
@@ -37,6 +39,35 @@ pub struct Transaction {
pub input: Bytes
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct TransactionRequest {
pub from: Address,
pub to: Option<Address>,
#[serde(rename="gasPrice")]
pub gas_price: Option<U256>,
pub gas: Option<U256>,
pub value: Option<U256>,
pub data: Bytes,
pub nonce: Option<U256>,
}
impl TransactionRequest {
/// maps transaction request to the transaction that can be signed and inserted
pub fn to_eth(self) -> (ethcore::transaction::Transaction, Address) {
(ethcore::transaction::Transaction {
nonce: self.nonce.unwrap_or(U256::zero()),
action: match self.to {
None => ethcore::transaction::Action::Create,
Some(addr) => ethcore::transaction::Action::Call(addr)
},
gas: self.gas.unwrap_or(U256::zero()),
gas_price: self.gas_price.unwrap_or(U256::zero()),
value: self.value.unwrap_or(U256::zero()),
data: self.data.to_vec()
}, self.from)
}
}
impl From<LocalizedTransaction> for Transaction {
fn from(t: LocalizedTransaction) -> Transaction {
Transaction {