diff --git a/ethcore/private-tx/res/keys_acl.json b/ethcore/private-tx/res/keys_acl.json new file mode 100644 index 000000000..3ec2daf9e --- /dev/null +++ b/ethcore/private-tx/res/keys_acl.json @@ -0,0 +1,43 @@ +[ + { + "constant": true, + "inputs": [ + { + "name":"user", + "type":"address" + } + ], + "name": "availableKeys", + "outputs": [ + { + "name": "", + "type": "bytes32[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant":true, + "inputs": [ + { + "name":"user", + "type":"address" + }, + { + "name":"document", + "type":"bytes32" + } + ], + "name":"checkPermissions", + "outputs": [ + { + "name":"", + "type":"bool" + } + ], + "payable":false, + "type":"function" + } +] diff --git a/ethcore/private-tx/src/encryptor.rs b/ethcore/private-tx/src/encryptor.rs index b19a53d29..2d8b47e63 100644 --- a/ethcore/private-tx/src/encryptor.rs +++ b/ethcore/private-tx/src/encryptor.rs @@ -34,6 +34,7 @@ use bytes::{Bytes, ToPretty}; use error::{Error, ErrorKind}; use url::Url; use super::find_account_password; +use super::key_server_keys::address_to_key; /// Initialization vector length. const INIT_VEC_LEN: usize = 16; @@ -188,11 +189,9 @@ impl SecretStoreEncryptor { } fn sign_contract_address(&self, contract_address: &Address, accounts: &AccountProvider) -> Result { - // key id in SS is H256 && we have H160 here => expand with assitional zeros - let contract_address_extended: H256 = contract_address.into(); let key_server_account = self.config.key_server_account.ok_or_else(|| ErrorKind::KeyServerAccountNotSet)?; let password = find_account_password(&self.config.passwords, accounts, &key_server_account); - Ok(accounts.sign(key_server_account, password, H256::from_slice(&contract_address_extended))?) + Ok(accounts.sign(key_server_account, password, address_to_key(contract_address))?) } } diff --git a/ethcore/private-tx/src/key_server_keys.rs b/ethcore/private-tx/src/key_server_keys.rs new file mode 100644 index 000000000..28d9b3cb9 --- /dev/null +++ b/ethcore/private-tx/src/key_server_keys.rs @@ -0,0 +1,173 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Wrapper around key server responsible for access keys processing. + +use std::sync::Arc; +use parking_lot::RwLock; +use ethereum_types::{H256, Address}; +use call_contract::{CallContract, RegistryInfo}; +use ethcore::client::BlockId; +use ethabi::FunctionOutputDecoder; + +const ACL_CHECKER_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_acl_checker"; + +use_contract!(keys_acl_contract, "res/keys_acl.json"); + +/// Returns the address (of the contract), that corresponds to the key +pub fn key_to_address(key: &H256) -> Address { + Address::from_slice(&key.to_vec()[..10]) +} + +/// Returns the key from the key server associated with the contract +pub fn address_to_key(contract_address: &Address) -> H256 { + // Current solution uses contract address extended with 0 as id + let contract_address_extended: H256 = contract_address.into(); + + H256::from_slice(&contract_address_extended) +} + +/// Trait for keys server keys provider. +pub trait KeyProvider: Send + Sync + 'static { + /// Account, that is used for communication with key server + fn key_server_account(&self) -> Option
; + + /// List of keys available for the account + fn available_keys(&self, block: BlockId, account: &Address) -> Option>; + + /// Update permissioning contract + fn update_acl_contract(&self); +} + +/// Secret Store keys provider +pub struct SecretStoreKeys where C: CallContract + RegistryInfo + Send + Sync + 'static { + client: Arc, + key_server_account: Option
, + keys_acl_contract: RwLock>, +} + +impl SecretStoreKeys where C: CallContract + RegistryInfo + Send + Sync + 'static { + /// Create provider + pub fn new(client: Arc, key_server_account: Option
) -> Self { + SecretStoreKeys { + client, + key_server_account, + keys_acl_contract: RwLock::new(None), + } + } +} + +impl KeyProvider for SecretStoreKeys where C: CallContract + RegistryInfo + Send + Sync + 'static { + fn key_server_account(&self) -> Option
{ + self.key_server_account + } + + fn available_keys(&self, block: BlockId, account: &Address) -> Option> { + match *self.keys_acl_contract.read() { + Some(acl_contract_address) => { + let (data, decoder) = keys_acl_contract::functions::available_keys::call(*account); + if let Ok(value) = self.client.call_contract(block, acl_contract_address, data) { + decoder.decode(&value).ok().map(|key_values| { + key_values.iter().map(key_to_address).collect() + }) + } else { + None + } + } + None => None, + } + } + + fn update_acl_contract(&self) { + let contract_address = self.client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.into(), BlockId::Latest); + if *self.keys_acl_contract.read() != contract_address { + trace!(target: "privatetx", "Configuring for ACL checker contract from address {:?}", + contract_address); + *self.keys_acl_contract.write() = contract_address; + } + } +} + +/// Dummy keys provider. +pub struct StoringKeyProvider { + available_keys: RwLock>>, + key_server_account: Option
, +} + +impl StoringKeyProvider { + /// Store available keys + pub fn set_available_keys(&self, keys: &Vec
) { + *self.available_keys.write() = Some(keys.clone()) + } +} + +impl Default for StoringKeyProvider { + fn default() -> Self { + StoringKeyProvider { + available_keys: RwLock::new(None), + key_server_account: Some(Address::default()), + } + } +} + +impl KeyProvider for StoringKeyProvider { + fn key_server_account(&self) -> Option
{ + self.key_server_account + } + + fn available_keys(&self, _block: BlockId, _account: &Address) -> Option> { + self.available_keys.read().clone() + } + + fn update_acl_contract(&self) {} +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + use ethkey::{Secret, KeyPair}; + use bytes::Bytes; + use super::*; + + struct DummyRegistryClient { + registry_address: Option
, + } + + impl DummyRegistryClient { + pub fn new(registry_address: Option
) -> Self { + DummyRegistryClient { + registry_address + } + } + } + + impl RegistryInfo for DummyRegistryClient { + fn registry_address(&self, _name: String, _block: BlockId) -> Option
{ self.registry_address } + } + + impl CallContract for DummyRegistryClient { + fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result { Ok(vec![]) } + } + + #[test] + fn should_update_acl_contract() { + let key = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000011")).unwrap(); + let client = DummyRegistryClient::new(Some(key.address())); + let keys_data = SecretStoreKeys::new(Arc::new(client), None); + keys_data.update_acl_contract(); + assert_eq!(keys_data.keys_acl_contract.read().unwrap(), key.address()); + } +} \ No newline at end of file diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 3ab39d9e4..cda80fb07 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -21,6 +21,7 @@ #![recursion_limit="256"] mod encryptor; +mod key_server_keys; mod private_transactions; mod messages; mod error; @@ -64,6 +65,7 @@ extern crate rand; extern crate env_logger; pub use encryptor::{Encryptor, SecretStoreEncryptor, EncryptorConfig, NoopEncryptor}; +pub use key_server_keys::{KeyProvider, SecretStoreKeys, StoringKeyProvider}; pub use private_transactions::{VerifiedPrivateTransaction, VerificationStore, PrivateTransactionSigningDesc, SigningStore}; pub use messages::{PrivateTransaction, SignedPrivateTransaction}; pub use error::{Error, ErrorKind}; @@ -87,6 +89,7 @@ use ethcore::client::{ }; use ethcore::account_provider::AccountProvider; use ethcore::miner::{self, Miner, MinerService, pool_client::NonceCache}; +use ethcore::{state, state_db}; use ethcore::trace::{Tracer, VMTracer}; use call_contract::CallContract; use rustc_hex::FromHex; @@ -126,8 +129,8 @@ pub struct ProviderConfig { pub struct Receipt { /// Private transaction hash. pub hash: H256, - /// Created contract address if any. - pub contract_address: Option
, + /// Contract address. + pub contract_address: Address, /// Execution status. pub status_code: u8, } @@ -145,13 +148,14 @@ pub struct Provider { miner: Arc, accounts: Arc, channel: IoChannel, + keys_provider: Arc, } #[derive(Debug)] pub struct PrivateExecutionResult where T: Tracer, V: VMTracer { code: Option, state: Bytes, - contract_address: Option
, + contract_address: Address, result: Executed, } @@ -164,7 +168,9 @@ impl Provider where { encryptor: Box, config: ProviderConfig, channel: IoChannel, + keys_provider: Arc, ) -> Self { + keys_provider.update_acl_contract(); Provider { encryptor, validator_accounts: config.validator_accounts.into_iter().collect(), @@ -177,6 +183,7 @@ impl Provider where { miner, accounts, channel, + keys_provider, } } @@ -227,7 +234,7 @@ impl Provider where { self.broadcast_private_transaction(private.hash(), private.rlp_bytes()); Ok(Receipt { hash: tx_hash, - contract_address: Some(contract), + contract_address: contract, status_code: 0, }) } @@ -484,6 +491,14 @@ impl Provider where { raw } + fn patch_account_state(&self, contract_address: &Address, block: BlockId, state: &mut state::State) -> Result<(), Error> { + let contract_code = Arc::new(self.get_decrypted_code(contract_address, block)?); + let contract_state = self.get_decrypted_state(contract_address, block)?; + trace!(target: "privatetx", "Patching contract at {:?}, code: {:?}, state: {:?}", contract_address, contract_code, contract_state); + state.patch_account(contract_address, contract_code, Self::snapshot_to_storage(contract_state))?; + Ok(()) + } + pub fn execute_private(&self, transaction: &SignedTransaction, options: TransactOptions, block: BlockId) -> Result, Error> where T: Tracer, @@ -496,41 +511,48 @@ impl Provider where { // TODO #9825 in case of BlockId::Latest these need to operate on the same state let contract_address = match transaction.action { Action::Call(ref contract_address) => { - let contract_code = Arc::new(self.get_decrypted_code(contract_address, block)?); - let contract_state = self.get_decrypted_state(contract_address, block)?; - trace!(target: "privatetx", "Patching contract at {:?}, code: {:?}, state: {:?}", contract_address, contract_code, contract_state); - state.patch_account(contract_address, contract_code, Self::snapshot_to_storage(contract_state))?; + // Patch current contract state + self.patch_account_state(contract_address, block, &mut state)?; Some(*contract_address) }, Action::Create => None, }; let engine = self.client.engine(); - let contract_address = contract_address.or({ - let sender = transaction.sender(); - let nonce = state.nonce(&sender)?; + let sender = transaction.sender(); + let nonce = state.nonce(&sender)?; + let contract_address = contract_address.unwrap_or_else(|| { let (new_address, _) = ethcore_contract_address(engine.create_address_scheme(env_info.number), &sender, &nonce, &transaction.data); - Some(new_address) + new_address }); + // Patch other available private contracts' states as well + // TODO: #10133 patch only required for the contract states + if let Some(key_server_account) = self.keys_provider.key_server_account() { + if let Some(available_contracts) = self.keys_provider.available_keys(block, &key_server_account) { + for private_contract in available_contracts { + if private_contract == contract_address { + continue; + } + self.patch_account_state(&private_contract, block, &mut state)?; + } + } + } let machine = engine.machine(); let schedule = machine.schedule(env_info.number); let result = Executive::new(&mut state, &env_info, &machine, &schedule).transact_virtual(transaction, options)?; - let (encrypted_code, encrypted_storage) = match contract_address { - None => bail!(ErrorKind::ContractDoesNotExist), - Some(address) => { - let (code, storage) = state.into_account(&address)?; - trace!(target: "privatetx", "Private contract executed. code: {:?}, state: {:?}, result: {:?}", code, storage, result.output); - let enc_code = match code { - Some(c) => Some(self.encrypt(&address, &Self::iv_from_address(&address), &c)?), - None => None, - }; - (enc_code, self.encrypt(&address, &Self::iv_from_transaction(transaction), &Self::snapshot_from_storage(&storage))?) - }, + let (encrypted_code, encrypted_storage) = { + let (code, storage) = state.into_account(&contract_address)?; + trace!(target: "privatetx", "Private contract executed. code: {:?}, state: {:?}, result: {:?}", code, storage, result.output); + let enc_code = match code { + Some(c) => Some(self.encrypt(&contract_address, &Self::iv_from_address(&contract_address), &c)?), + None => None, + }; + (enc_code, self.encrypt(&contract_address, &Self::iv_from_transaction(transaction), &Self::snapshot_from_storage(&storage))?) }; Ok(PrivateExecutionResult { code: encrypted_code, state: encrypted_storage, - contract_address, + contract_address: contract_address, result, }) } @@ -555,14 +577,11 @@ impl Provider where { /// Returns the key from the key server associated with the contract pub fn contract_key_id(&self, contract_address: &Address) -> Result { - // Current solution uses contract address extended with 0 as id - let contract_address_extended: H256 = contract_address.into(); - - Ok(H256::from_slice(&contract_address_extended)) + Ok(key_server_keys::address_to_key(contract_address)) } /// Create encrypted public contract deployment transaction. - pub fn public_creation_transaction(&self, block: BlockId, source: &SignedTransaction, validators: &[Address], gas_price: U256) -> Result<(Transaction, Option
), Error> { + pub fn public_creation_transaction(&self, block: BlockId, source: &SignedTransaction, validators: &[Address], gas_price: U256) -> Result<(Transaction, Address), Error> { if let Action::Call(_) = source.action { bail!(ErrorKind::BadTransactonType); } @@ -740,5 +759,6 @@ impl ChainNotify for Provider { if let Err(err) = self.process_verification_queue() { warn!(target: "privatetx", "Cannot prune private transactions queue. error: {:?}", err); } + self.keys_provider.update_acl_contract(); } } diff --git a/ethcore/private-tx/tests/private_contract.rs b/ethcore/private-tx/tests/private_contract.rs index b681a0380..0492191b6 100644 --- a/ethcore/private-tx/tests/private_contract.rs +++ b/ethcore/private-tx/tests/private_contract.rs @@ -29,7 +29,7 @@ extern crate rustc_hex; extern crate log; use std::sync::Arc; -use rustc_hex::FromHex; +use rustc_hex::{FromHex, ToHex}; use types::ids::BlockId; use types::transaction::{Transaction, Action}; @@ -42,7 +42,7 @@ use ethcore::test_helpers::{generate_dummy_client, push_block_with_transactions} use ethkey::{Secret, KeyPair, Signature}; use hash::keccak; -use ethcore_private_tx::{NoopEncryptor, Provider, ProviderConfig}; +use ethcore_private_tx::{NoopEncryptor, Provider, ProviderConfig, StoringKeyProvider}; #[test] fn private_contract() { @@ -67,6 +67,7 @@ fn private_contract() { let io = ethcore_io::IoChannel::disconnected(); let miner = Arc::new(Miner::new_for_tests(&::ethcore::spec::Spec::new_test(), None)); + let private_keys = Arc::new(StoringKeyProvider::default()); let pm = Arc::new(Provider::new( client.clone(), miner, @@ -74,6 +75,7 @@ fn private_contract() { Box::new(NoopEncryptor::default()), config, io, + private_keys, )); let (address, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]); @@ -155,3 +157,127 @@ fn private_contract() { let result = pm.private_call(BlockId::Latest, &query_tx).unwrap(); assert_eq!(result.output, "2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()); } + +#[test] +fn call_other_private_contract() { + // This test verifies calls private contract methods from another one + // Two contract will be deployed + // The same contract A: + // contract Test1 { + // bytes32 public x; + // function setX(bytes32 _x) { + // x = _x; + // } + // } + // And the following contract B: + // contract Deployed { + // function setX(uint) {} + // function x() returns (uint) {} + //} + // contract Existing { + // Deployed dc; + // function Existing(address t) { + // dc = Deployed(t); + // } + // function getX() returns (uint) { + // return dc.x(); + // } + // } + //ethcore_logger::init_log(); + + // Create client and provider + let client = generate_dummy_client(0); + let chain_id = client.signing_chain_id(); + let key1 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000011")).unwrap(); + let _key2 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000012")).unwrap(); + let key3 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000013")).unwrap(); + let key4 = KeyPair::from_secret(Secret::from("0000000000000000000000000000000000000000000000000000000000000014")).unwrap(); + let ap = Arc::new(AccountProvider::transient_provider()); + ap.insert_account(key1.secret().clone(), &"".into()).unwrap(); + ap.insert_account(key3.secret().clone(), &"".into()).unwrap(); + ap.insert_account(key4.secret().clone(), &"".into()).unwrap(); + + let config = ProviderConfig{ + validator_accounts: vec![key3.address(), key4.address()], + signer_account: None, + passwords: vec!["".into()], + }; + + let io = ethcore_io::IoChannel::disconnected(); + let miner = Arc::new(Miner::new_for_tests(&::ethcore::spec::Spec::new_test(), None)); + let private_keys = Arc::new(StoringKeyProvider::default()); + let pm = Arc::new(Provider::new( + client.clone(), + miner, + ap.clone(), + Box::new(NoopEncryptor::default()), + config, + io, + private_keys.clone(), + )); + + // Deploy contract A + let (address_a, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &0.into(), &[]); + trace!("Creating private contract A"); + let private_contract_a_test = "6060604052341561000f57600080fd5b60d88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c146046578063bc64b76d14607457600080fd5b3415605057600080fd5b60566098565b60405180826000191660001916815260200191505060405180910390f35b3415607e57600080fd5b6096600480803560001916906020019091905050609e565b005b60005481565b8060008160001916905550505600a165627a7a723058206acbdf4b15ca4c2d43e1b1879b830451a34f1e9d02ff1f2f394d8d857e79d2080029".from_hex().unwrap(); + let mut private_create_tx1 = Transaction::default(); + private_create_tx1.action = Action::Create; + private_create_tx1.data = private_contract_a_test; + private_create_tx1.gas = 200000.into(); + private_create_tx1.nonce = 0.into(); + let private_create_tx_signed = private_create_tx1.sign(&key1.secret(), None); + let validators = vec![key3.address(), key4.address()]; + let (public_tx1, _) = pm.public_creation_transaction(BlockId::Latest, &private_create_tx_signed, &validators, 0.into()).unwrap(); + let public_tx1 = public_tx1.sign(&key1.secret(), chain_id); + trace!("Transaction created. Pushing block"); + push_block_with_transactions(&client, &[public_tx1]); + + // Deploy contract B + let (address_b, _) = contract_address(CreateContractAddress::FromSenderAndNonce, &key1.address(), &1.into(), &[]); + trace!("Creating private contract B"); + // Build constructor data + let mut deploy_data = "6060604052341561000f57600080fd5b6040516020806101c583398101604052808051906020019091905050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505061014a8061007b6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680635197c7aa14610046575b600080fd5b341561005157600080fd5b61005961006f565b6040518082815260200191505060405180910390f35b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c55699c6000604051602001526040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15156100fe57600080fd5b6102c65a03f1151561010f57600080fd5b505050604051805190509050905600a165627a7a723058207f8994e02725b47d76ec73e5c54a338d27b306dd1c830276bff2d75fcd1a5c920029000000000000000000000000".to_string(); + deploy_data.push_str(&address_a.to_vec().to_hex()); + let private_contract_b_test = deploy_data.from_hex().unwrap(); + let mut private_create_tx2 = Transaction::default(); + private_create_tx2.action = Action::Create; + private_create_tx2.data = private_contract_b_test; + private_create_tx2.gas = 200000.into(); + private_create_tx2.nonce = 1.into(); + let private_create_tx_signed = private_create_tx2.sign(&key1.secret(), None); + let (public_tx2, _) = pm.public_creation_transaction(BlockId::Latest, &private_create_tx_signed, &validators, 0.into()).unwrap(); + let public_tx2 = public_tx2.sign(&key1.secret(), chain_id); + trace!("Transaction created. Pushing block"); + push_block_with_transactions(&client, &[public_tx2]); + + // Let provider know, that it has access to both keys for A and B + private_keys.set_available_keys(&vec![address_a, address_b]); + + // Call A.setx(42) + trace!("Modifying private state"); + let mut private_tx = Transaction::default(); + private_tx.action = Action::Call(address_a.clone()); + private_tx.data = "bc64b76d2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); //setX(42) + private_tx.gas = 120000.into(); + private_tx.nonce = 2.into(); + let private_tx = private_tx.sign(&key1.secret(), None); + let private_contract_nonce = pm.get_contract_nonce(&address_b, BlockId::Latest).unwrap(); + let private_state = pm.execute_private_transaction(BlockId::Latest, &private_tx).unwrap(); + let nonced_state_hash = pm.calculate_state_hash(&private_state, private_contract_nonce); + let signatures: Vec<_> = [&key3, &key4].iter().map(|k| + Signature::from(::ethkey::sign(&k.secret(), &nonced_state_hash).unwrap().into_electrum())).collect(); + let public_tx = pm.public_transaction(private_state, &private_tx, &signatures, 2.into(), 0.into()).unwrap(); + let public_tx = public_tx.sign(&key1.secret(), chain_id); + push_block_with_transactions(&client, &[public_tx]); + + // Call B.getX() + trace!("Querying private state"); + let mut query_tx = Transaction::default(); + query_tx.action = Action::Call(address_b.clone()); + query_tx.data = "5197c7aa".from_hex().unwrap(); // getX + query_tx.gas = 50000.into(); + query_tx.nonce = 3.into(); + let query_tx = query_tx.sign(&key1.secret(), chain_id); + let result = pm.private_call(BlockId::Latest, &query_tx).unwrap(); + assert_eq!(&result.output[..], &("2a00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()[..])); +} \ No newline at end of file diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 831d1f0e4..c2137cfc6 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -99,6 +99,7 @@ impl ClientService { account_provider: Arc, encryptor: Box, private_tx_conf: ethcore_private_tx::ProviderConfig, + private_encryptor_conf: ethcore_private_tx::EncryptorConfig, ) -> Result { let io_service = IoService::::start()?; @@ -127,13 +128,18 @@ impl ClientService { }; let snapshot = Arc::new(SnapshotService::new(snapshot_params)?); + let private_keys = Arc::new(ethcore_private_tx::SecretStoreKeys::new( + client.clone(), + private_encryptor_conf.key_server_account, + )); let provider = Arc::new(ethcore_private_tx::Provider::new( - client.clone(), - miner, - account_provider, - encryptor, - private_tx_conf, - io_service.channel(), + client.clone(), + miner, + account_provider, + encryptor, + private_tx_conf, + io_service.channel(), + private_keys, )); let private_tx = Arc::new(PrivateTxService::new(provider)); @@ -314,6 +320,7 @@ mod tests { Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), Default::default(), + Default::default(), ); assert!(service.is_ok()); drop(service.unwrap()); diff --git a/ethcore/sync/src/tests/private.rs b/ethcore/sync/src/tests/private.rs index 10bd7d1f3..221caf77c 100644 --- a/ethcore/sync/src/tests/private.rs +++ b/ethcore/sync/src/tests/private.rs @@ -24,7 +24,7 @@ use ethcore::CreateContractAddress; use types::transaction::{Transaction, Action}; use ethcore::executive::{contract_address}; use ethcore::test_helpers::{push_block_with_transactions}; -use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer, SignedPrivateTransaction}; +use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer, SignedPrivateTransaction, StoringKeyProvider}; use ethcore::account_provider::AccountProvider; use ethkey::{KeyPair}; use tests::helpers::{TestNet, TestIoHandler}; @@ -78,6 +78,8 @@ fn send_private_transaction() { passwords: vec!["".into()], }; + let private_keys = Arc::new(StoringKeyProvider::default()); + let pm0 = Arc::new(Provider::new( client0.clone(), net.peer(0).miner.clone(), @@ -85,6 +87,7 @@ fn send_private_transaction() { Box::new(NoopEncryptor::default()), signer_config, IoChannel::to_handler(Arc::downgrade(&io_handler0)), + private_keys.clone(), )); pm0.add_notify(net.peers[0].clone()); @@ -95,6 +98,7 @@ fn send_private_transaction() { Box::new(NoopEncryptor::default()), validator_config, IoChannel::to_handler(Arc::downgrade(&io_handler1)), + private_keys.clone(), )); pm1.add_notify(net.peers[1].clone()); diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 0f9d081f6..65c43a27c 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -398,6 +398,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), Default::default(), + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; // free up the spec in memory. @@ -589,6 +590,7 @@ fn start_client( Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), Default::default(), + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; drop(spec); diff --git a/parity/run.rs b/parity/run.rs index 805a38c4a..df1437232 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -582,8 +582,9 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: &cmd.dirs.ipc_path(), miner.clone(), account_provider.clone(), - Box::new(SecretStoreEncryptor::new(cmd.private_encryptor_conf, fetch.clone()).map_err(|e| e.to_string())?), + Box::new(SecretStoreEncryptor::new(cmd.private_encryptor_conf.clone(), fetch.clone()).map_err(|e| e.to_string())?), cmd.private_provider_conf, + cmd.private_encryptor_conf, ).map_err(|e| format!("Client service error: {:?}", e))?; let connection_filter_address = spec.params().node_permission_contract; diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 0be4ce15f..e0b8097a2 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -202,6 +202,7 @@ impl SnapshotCommand { Arc::new(AccountProvider::transient_provider()), Box::new(ethcore_private_tx::NoopEncryptor), Default::default(), + Default::default(), ).map_err(|e| format!("Client service error: {:?}", e))?; Ok(service) diff --git a/rpc/src/v1/impls/private.rs b/rpc/src/v1/impls/private.rs index 8744390ba..e9c8c239c 100644 --- a/rpc/src/v1/impls/private.rs +++ b/rpc/src/v1/impls/private.rs @@ -94,7 +94,7 @@ impl Private for PrivateClient { transaction: request, receipt: PrivateTransactionReceipt { transaction_hash: tx_hash.into(), - contract_address: contract_address.map(|address| address.into()), + contract_address: contract_address.into(), status_code: 0, } }) diff --git a/rpc/src/v1/types/private_receipt.rs b/rpc/src/v1/types/private_receipt.rs index a9e1eef01..e6170314f 100644 --- a/rpc/src/v1/types/private_receipt.rs +++ b/rpc/src/v1/types/private_receipt.rs @@ -24,7 +24,7 @@ pub struct PrivateTransactionReceipt { /// Transaction Hash pub transaction_hash: H256, /// Private contract address - pub contract_address: Option, + pub contract_address: H160, /// Status code #[serde(rename = "status")] pub status_code: u8, @@ -34,7 +34,7 @@ impl From for PrivateTransactionReceipt { fn from(r: EthPrivateReceipt) -> Self { PrivateTransactionReceipt { transaction_hash: r.hash.into(), - contract_address: r.contract_address.map(Into::into), + contract_address: r.contract_address.into(), status_code: r.status_code.into(), } }