2019-01-07 11:33:07 +01:00
|
|
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
|
|
// This file is part of Parity Ethereum.
|
2018-04-09 16:14:33 +02:00
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
2018-04-09 16:14:33 +02:00
|
|
|
// 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.
|
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
2018-04-09 16:14:33 +02:00
|
|
|
// 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
|
2019-01-07 11:33:07 +01:00
|
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2018-04-09 16:14:33 +02:00
|
|
|
|
|
|
|
//! Private transactions module.
|
|
|
|
|
|
|
|
mod encryptor;
|
2019-02-07 12:39:04 +01:00
|
|
|
mod key_server_keys;
|
2018-04-09 16:14:33 +02:00
|
|
|
mod private_transactions;
|
|
|
|
mod messages;
|
|
|
|
mod error;
|
2019-05-14 11:21:22 +02:00
|
|
|
mod log;
|
2018-04-09 16:14:33 +02:00
|
|
|
|
2019-07-08 23:01:47 +02:00
|
|
|
extern crate account_state;
|
2019-01-04 14:05:46 +01:00
|
|
|
extern crate common_types as types;
|
|
|
|
extern crate ethabi;
|
2018-04-09 16:14:33 +02:00
|
|
|
extern crate ethcore;
|
2019-01-17 16:43:08 +01:00
|
|
|
extern crate ethcore_call_contract as call_contract;
|
2018-04-10 13:56:56 +02:00
|
|
|
extern crate ethcore_io as io;
|
2018-04-09 16:14:33 +02:00
|
|
|
extern crate ethcore_miner;
|
|
|
|
extern crate ethereum_types;
|
|
|
|
extern crate ethjson;
|
2019-01-04 14:05:46 +01:00
|
|
|
extern crate ethkey;
|
2018-04-09 16:14:33 +02:00
|
|
|
extern crate fetch;
|
|
|
|
extern crate futures;
|
2019-06-19 13:54:05 +02:00
|
|
|
extern crate parity_util_mem;
|
2018-04-09 16:14:33 +02:00
|
|
|
extern crate keccak_hash as hash;
|
2019-01-04 14:05:46 +01:00
|
|
|
extern crate parity_bytes as bytes;
|
|
|
|
extern crate parity_crypto as crypto;
|
2018-04-09 16:14:33 +02:00
|
|
|
extern crate parking_lot;
|
2019-02-20 19:09:34 +01:00
|
|
|
extern crate trie_db as trie;
|
2018-07-02 18:50:05 +02:00
|
|
|
extern crate patricia_trie_ethereum as ethtrie;
|
2018-04-09 16:14:33 +02:00
|
|
|
extern crate rlp;
|
2019-05-14 11:21:22 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate serde_derive;
|
|
|
|
extern crate serde;
|
|
|
|
extern crate serde_json;
|
2018-04-09 16:14:33 +02:00
|
|
|
extern crate rustc_hex;
|
2019-07-08 23:01:47 +02:00
|
|
|
extern crate state_db;
|
2019-07-08 18:17:48 +02:00
|
|
|
extern crate trace;
|
2019-01-04 14:05:46 +01:00
|
|
|
extern crate transaction_pool as txpool;
|
|
|
|
extern crate url;
|
2018-04-09 16:14:33 +02:00
|
|
|
#[macro_use]
|
2019-05-14 11:21:22 +02:00
|
|
|
extern crate log as ethlog;
|
2018-04-09 16:14:33 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate ethabi_derive;
|
|
|
|
#[macro_use]
|
|
|
|
extern crate ethabi_contract;
|
2019-03-27 14:46:05 +01:00
|
|
|
extern crate derive_more;
|
2018-04-09 16:14:33 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate rlp_derive;
|
2019-07-16 12:43:47 +02:00
|
|
|
extern crate vm;
|
2018-04-09 16:14:33 +02:00
|
|
|
|
2019-05-14 11:21:22 +02:00
|
|
|
#[cfg(not(time_checked_add))]
|
|
|
|
extern crate time_utils;
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
extern crate rand;
|
|
|
|
#[cfg(test)]
|
2019-01-08 15:07:20 +01:00
|
|
|
extern crate env_logger;
|
2018-04-09 16:14:33 +02:00
|
|
|
|
|
|
|
pub use encryptor::{Encryptor, SecretStoreEncryptor, EncryptorConfig, NoopEncryptor};
|
2019-02-07 12:39:04 +01:00
|
|
|
pub use key_server_keys::{KeyProvider, SecretStoreKeys, StoringKeyProvider};
|
2018-08-29 14:31:04 +02:00
|
|
|
pub use private_transactions::{VerifiedPrivateTransaction, VerificationStore, PrivateTransactionSigningDesc, SigningStore};
|
2018-04-09 16:14:33 +02:00
|
|
|
pub use messages::{PrivateTransaction, SignedPrivateTransaction};
|
2019-03-27 14:46:05 +01:00
|
|
|
pub use error::Error;
|
2019-05-14 11:21:22 +02:00
|
|
|
pub use log::{Logging, TransactionLog, ValidatorLog, PrivateTxStatus, FileLogsSerializer};
|
2018-04-09 16:14:33 +02:00
|
|
|
|
|
|
|
use std::sync::{Arc, Weak};
|
2018-12-06 11:02:15 +01:00
|
|
|
use std::collections::{HashMap, HashSet, BTreeMap};
|
2019-06-03 15:36:21 +02:00
|
|
|
use ethereum_types::{H128, H256, U256, Address, BigEndianHash};
|
2018-04-09 16:14:33 +02:00
|
|
|
use hash::keccak;
|
|
|
|
use rlp::*;
|
2018-08-29 14:31:04 +02:00
|
|
|
use parking_lot::RwLock;
|
2018-04-09 16:14:33 +02:00
|
|
|
use bytes::Bytes;
|
|
|
|
use ethkey::{Signature, recover, public_to_address};
|
|
|
|
use io::IoChannel;
|
|
|
|
use ethcore::executive::{Executive, TransactOptions};
|
|
|
|
use ethcore::executed::{Executed};
|
2019-01-04 14:05:46 +01:00
|
|
|
use types::transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction};
|
2018-04-09 16:14:33 +02:00
|
|
|
use ethcore::{contract_address as ethcore_contract_address};
|
|
|
|
use ethcore::client::{
|
2018-12-19 10:24:14 +01:00
|
|
|
Client, ChainNotify, NewBlocks, ChainMessageType, ClientIoMessage, BlockId,
|
2019-01-17 16:43:08 +01:00
|
|
|
Call, BlockInfo
|
2018-04-09 16:14:33 +02:00
|
|
|
};
|
2018-07-05 17:27:48 +02:00
|
|
|
use ethcore::miner::{self, Miner, MinerService, pool_client::NonceCache};
|
2019-07-08 23:01:47 +02:00
|
|
|
use state_db::StateDB;
|
2019-07-08 18:17:48 +02:00
|
|
|
use account_state::State;
|
|
|
|
use trace::{Tracer, VMTracer};
|
2019-01-17 16:43:08 +01:00
|
|
|
use call_contract::CallContract;
|
2018-04-09 16:14:33 +02:00
|
|
|
use rustc_hex::FromHex;
|
2018-09-13 11:04:39 +02:00
|
|
|
use ethabi::FunctionOutputDecoder;
|
2019-07-16 12:43:47 +02:00
|
|
|
use vm::CreateContractAddress;
|
2018-04-09 16:14:33 +02:00
|
|
|
|
|
|
|
// Source avaiable at https://github.com/parity-contracts/private-tx/blob/master/contracts/PrivateContract.sol
|
|
|
|
const DEFAULT_STUB_CONTRACT: &'static str = include_str!("../res/private.evm");
|
|
|
|
|
2018-09-13 11:04:39 +02:00
|
|
|
use_contract!(private_contract, "res/private.json");
|
2018-04-09 16:14:33 +02:00
|
|
|
|
|
|
|
/// Initialization vector length.
|
|
|
|
const INIT_VEC_LEN: usize = 16;
|
|
|
|
|
2018-07-05 17:27:48 +02:00
|
|
|
/// Size of nonce cache
|
|
|
|
const NONCE_CACHE_SIZE: usize = 128;
|
|
|
|
|
2018-12-03 20:44:36 +01:00
|
|
|
/// Version for the initial private contract wrapper
|
|
|
|
const INITIAL_PRIVATE_CONTRACT_VER: usize = 1;
|
|
|
|
|
|
|
|
/// Version for the private contract notification about private state changes added
|
|
|
|
const PRIVATE_CONTRACT_WITH_NOTIFICATION_VER: usize = 2;
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
/// Configurtion for private transaction provider
|
|
|
|
#[derive(Default, PartialEq, Debug, Clone)]
|
|
|
|
pub struct ProviderConfig {
|
|
|
|
/// Accounts that can be used for validation
|
|
|
|
pub validator_accounts: Vec<Address>,
|
|
|
|
/// Account used for signing public transactions created from private transactions
|
|
|
|
pub signer_account: Option<Address>,
|
2019-05-14 11:21:22 +02:00
|
|
|
/// Path to private tx logs
|
|
|
|
pub logs_path: Option<String>,
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
/// Private transaction execution receipt.
|
|
|
|
pub struct Receipt {
|
|
|
|
/// Private transaction hash.
|
|
|
|
pub hash: H256,
|
2019-02-07 12:39:04 +01:00
|
|
|
/// Contract address.
|
|
|
|
pub contract_address: Address,
|
2018-04-09 16:14:33 +02:00
|
|
|
/// Execution status.
|
|
|
|
pub status_code: u8,
|
|
|
|
}
|
|
|
|
|
2019-02-07 14:34:24 +01:00
|
|
|
/// Payload signing and decrypting capabilities.
|
|
|
|
pub trait Signer: Send + Sync {
|
|
|
|
/// Decrypt payload using private key of given address.
|
|
|
|
fn decrypt(&self, account: Address, shared_mac: &[u8], payload: &[u8]) -> Result<Vec<u8>, Error>;
|
|
|
|
/// Sign given hash using provided account.
|
|
|
|
fn sign(&self, account: Address, hash: ethkey::Message) -> Result<Signature, Error>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Signer implementation that errors on any request.
|
|
|
|
pub struct DummySigner;
|
|
|
|
impl Signer for DummySigner {
|
|
|
|
fn decrypt(&self, _account: Address, _shared_mac: &[u8], _payload: &[u8]) -> Result<Vec<u8>, Error> {
|
|
|
|
Err("Decrypting is not supported.".to_owned())?
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sign(&self, _account: Address, _hash: ethkey::Message) -> Result<Signature, Error> {
|
|
|
|
Err("Signing is not supported.".to_owned())?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Signer implementation using multiple keypairs
|
|
|
|
pub struct KeyPairSigner(pub Vec<ethkey::KeyPair>);
|
|
|
|
impl Signer for KeyPairSigner {
|
|
|
|
fn decrypt(&self, account: Address, shared_mac: &[u8], payload: &[u8]) -> Result<Vec<u8>, Error> {
|
|
|
|
let kp = self.0.iter().find(|k| k.address() == account).ok_or(ethkey::Error::InvalidAddress)?;
|
|
|
|
Ok(ethkey::crypto::ecies::decrypt(kp.secret(), shared_mac, payload)?)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sign(&self, account: Address, hash: ethkey::Message) -> Result<Signature, Error> {
|
|
|
|
let kp = self.0.iter().find(|k| k.address() == account).ok_or(ethkey::Error::InvalidAddress)?;
|
|
|
|
Ok(ethkey::sign(kp.secret(), &hash)?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
/// Manager of private transactions
|
|
|
|
pub struct Provider {
|
|
|
|
encryptor: Box<Encryptor>,
|
|
|
|
validator_accounts: HashSet<Address>,
|
|
|
|
signer_account: Option<Address>,
|
|
|
|
notify: RwLock<Vec<Weak<ChainNotify>>>,
|
2018-08-29 14:31:04 +02:00
|
|
|
transactions_for_signing: RwLock<SigningStore>,
|
|
|
|
transactions_for_verification: VerificationStore,
|
2018-04-09 16:14:33 +02:00
|
|
|
client: Arc<Client>,
|
2018-04-13 17:34:27 +02:00
|
|
|
miner: Arc<Miner>,
|
2019-02-07 14:34:24 +01:00
|
|
|
accounts: Arc<Signer>,
|
2018-04-09 16:14:33 +02:00
|
|
|
channel: IoChannel<ClientIoMessage>,
|
2019-02-07 12:39:04 +01:00
|
|
|
keys_provider: Arc<KeyProvider>,
|
2019-05-14 11:21:22 +02:00
|
|
|
logging: Option<Logging>,
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PrivateExecutionResult<T, V> where T: Tracer, V: VMTracer {
|
|
|
|
code: Option<Bytes>,
|
|
|
|
state: Bytes,
|
2019-02-07 12:39:04 +01:00
|
|
|
contract_address: Address,
|
2018-04-09 16:14:33 +02:00
|
|
|
result: Executed<T::Output, V::Output>,
|
|
|
|
}
|
|
|
|
|
2019-02-07 14:34:24 +01:00
|
|
|
impl Provider {
|
2018-04-09 16:14:33 +02:00
|
|
|
/// Create a new provider.
|
|
|
|
pub fn new(
|
|
|
|
client: Arc<Client>,
|
2018-04-13 17:34:27 +02:00
|
|
|
miner: Arc<Miner>,
|
2019-02-07 14:34:24 +01:00
|
|
|
accounts: Arc<Signer>,
|
2018-04-09 16:14:33 +02:00
|
|
|
encryptor: Box<Encryptor>,
|
|
|
|
config: ProviderConfig,
|
|
|
|
channel: IoChannel<ClientIoMessage>,
|
2019-02-07 12:39:04 +01:00
|
|
|
keys_provider: Arc<KeyProvider>,
|
2018-05-09 08:49:34 +02:00
|
|
|
) -> Self {
|
2019-02-07 12:39:04 +01:00
|
|
|
keys_provider.update_acl_contract();
|
2018-05-09 08:49:34 +02:00
|
|
|
Provider {
|
2018-04-09 16:14:33 +02:00
|
|
|
encryptor,
|
|
|
|
validator_accounts: config.validator_accounts.into_iter().collect(),
|
|
|
|
signer_account: config.signer_account,
|
|
|
|
notify: RwLock::default(),
|
2018-08-29 14:31:04 +02:00
|
|
|
transactions_for_signing: RwLock::default(),
|
|
|
|
transactions_for_verification: VerificationStore::default(),
|
2018-04-09 16:14:33 +02:00
|
|
|
client,
|
2018-04-13 17:34:27 +02:00
|
|
|
miner,
|
2018-04-09 16:14:33 +02:00
|
|
|
accounts,
|
|
|
|
channel,
|
2019-02-07 12:39:04 +01:00
|
|
|
keys_provider,
|
2019-05-14 11:21:22 +02:00
|
|
|
logging: config.logs_path.map(|path| Logging::new(Arc::new(FileLogsSerializer::with_path(path)))),
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO [ToDr] Don't use `ChainNotify` here!
|
|
|
|
// Better to create a separate notification type for this.
|
|
|
|
/// Adds an actor to be notified on certain events
|
|
|
|
pub fn add_notify(&self, target: Arc<ChainNotify>) {
|
|
|
|
self.notify.write().push(Arc::downgrade(&target));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn notify<F>(&self, f: F) where F: Fn(&ChainNotify) {
|
|
|
|
for np in self.notify.read().iter() {
|
|
|
|
if let Some(n) = np.upgrade() {
|
|
|
|
f(&*n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 1. Create private transaction from the signed transaction
|
|
|
|
/// 2. Executes private transaction
|
|
|
|
/// 3. Save it with state returned on prev step to the queue for signing
|
|
|
|
/// 4. Broadcast corresponding message to the chain
|
|
|
|
pub fn create_private_transaction(&self, signed_transaction: SignedTransaction) -> Result<Receipt, Error> {
|
2018-08-29 14:31:04 +02:00
|
|
|
trace!(target: "privatetx", "Creating private transaction from regular transaction: {:?}", signed_transaction);
|
2018-04-09 16:14:33 +02:00
|
|
|
if self.signer_account.is_none() {
|
2018-08-29 14:31:04 +02:00
|
|
|
warn!(target: "privatetx", "Signing account not set");
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(Error::SignerAccountNotSet);
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
let tx_hash = signed_transaction.hash();
|
2019-03-27 14:46:05 +01:00
|
|
|
let contract = Self::contract_address_from_transaction(&signed_transaction).map_err(|_| Error::BadTransactionType)?;
|
2018-12-03 20:44:36 +01:00
|
|
|
let data = signed_transaction.rlp_bytes();
|
|
|
|
let encrypted_transaction = self.encrypt(&contract, &Self::iv_from_transaction(&signed_transaction), &data)?;
|
|
|
|
let private = PrivateTransaction::new(encrypted_transaction, contract);
|
|
|
|
// TODO #9825 [ToDr] Using BlockId::Latest is bad here,
|
|
|
|
// the block may change in the middle of execution
|
|
|
|
// causing really weird stuff to happen.
|
|
|
|
// We should retrieve hash and stick to that. IMHO
|
|
|
|
// best would be to change the API and only allow H256 instead of BlockID
|
|
|
|
// in private-tx to avoid such mistakes.
|
|
|
|
let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest)?;
|
|
|
|
let private_state = self.execute_private_transaction(BlockId::Latest, &signed_transaction)?;
|
|
|
|
trace!(target: "privatetx", "Private transaction created, encrypted transaction: {:?}, private state: {:?}", private, private_state);
|
|
|
|
let contract_validators = self.get_validators(BlockId::Latest, &contract)?;
|
|
|
|
trace!(target: "privatetx", "Required validators: {:?}", contract_validators);
|
|
|
|
let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce);
|
|
|
|
trace!(target: "privatetx", "Hashed effective private state for sender: {:?}", private_state_hash);
|
2019-05-14 11:21:22 +02:00
|
|
|
self.transactions_for_signing.write().add_transaction(private.hash(), signed_transaction, &contract_validators, private_state, contract_nonce)?;
|
2018-12-03 20:44:36 +01:00
|
|
|
self.broadcast_private_transaction(private.hash(), private.rlp_bytes());
|
2019-05-14 11:21:22 +02:00
|
|
|
if let Some(ref logging) = self.logging {
|
|
|
|
logging.private_tx_created(&tx_hash, &contract_validators);
|
|
|
|
}
|
2018-12-03 20:44:36 +01:00
|
|
|
Ok(Receipt {
|
|
|
|
hash: tx_hash,
|
2019-02-07 12:39:04 +01:00
|
|
|
contract_address: contract,
|
2018-12-03 20:44:36 +01:00
|
|
|
status_code: 0,
|
|
|
|
})
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Calculate hash from united private state and contract nonce
|
|
|
|
pub fn calculate_state_hash(&self, state: &Bytes, nonce: U256) -> H256 {
|
|
|
|
let state_hash = keccak(state);
|
2019-06-03 15:36:21 +02:00
|
|
|
let nonce_h256: H256 = BigEndianHash::from_uint(&nonce);
|
2018-04-09 16:14:33 +02:00
|
|
|
let mut state_buf = [0u8; 64];
|
2019-06-03 15:36:21 +02:00
|
|
|
state_buf[..32].clone_from_slice(state_hash.as_bytes());
|
|
|
|
state_buf[32..].clone_from_slice(nonce_h256.as_bytes());
|
2019-07-08 19:21:06 +02:00
|
|
|
keccak(AsRef::<[u8]>::as_ref(&state_buf[..]))
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
2019-02-07 14:34:24 +01:00
|
|
|
fn pool_client<'a>(&'a self, nonce_cache: &'a NonceCache, local_accounts: &'a HashSet<Address>) -> miner::pool_client::PoolClient<'a, Client> {
|
2018-04-13 17:34:27 +02:00
|
|
|
let engine = self.client.engine();
|
|
|
|
miner::pool_client::PoolClient::new(
|
|
|
|
&*self.client,
|
|
|
|
nonce_cache,
|
|
|
|
engine,
|
2019-02-07 14:34:24 +01:00
|
|
|
local_accounts,
|
2019-03-31 10:39:38 +02:00
|
|
|
None, // refuse_service_transactions = true
|
2018-04-13 17:34:27 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
/// Retrieve and verify the first available private transaction for every sender
|
2018-08-29 14:31:04 +02:00
|
|
|
fn process_verification_queue(&self) -> Result<(), Error> {
|
|
|
|
let process_transaction = |transaction: &VerifiedPrivateTransaction| -> Result<_, String> {
|
|
|
|
let private_hash = transaction.private_transaction.hash();
|
|
|
|
match transaction.validator_account {
|
|
|
|
None => {
|
|
|
|
trace!(target: "privatetx", "Propagating transaction further");
|
2018-10-09 22:07:25 +02:00
|
|
|
self.broadcast_private_transaction(private_hash, transaction.private_transaction.rlp_bytes());
|
2018-08-29 14:31:04 +02:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Some(validator_account) => {
|
|
|
|
if !self.validator_accounts.contains(&validator_account) {
|
|
|
|
trace!(target: "privatetx", "Propagating transaction further");
|
2018-10-09 22:07:25 +02:00
|
|
|
self.broadcast_private_transaction(private_hash, transaction.private_transaction.rlp_bytes());
|
2018-08-29 14:31:04 +02:00
|
|
|
return Ok(());
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
2018-12-03 20:44:36 +01:00
|
|
|
let contract = Self::contract_address_from_transaction(&transaction.transaction)
|
|
|
|
.map_err(|_| "Incorrect type of action for the transaction")?;
|
|
|
|
// TODO #9825 [ToDr] Usage of BlockId::Latest
|
|
|
|
let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest);
|
|
|
|
if let Err(e) = contract_nonce {
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(format!("Cannot retrieve contract nonce: {:?}", e).into());
|
2018-12-03 20:44:36 +01:00
|
|
|
}
|
|
|
|
let contract_nonce = contract_nonce.expect("Error was checked before");
|
|
|
|
let private_state = self.execute_private_transaction(BlockId::Latest, &transaction.transaction);
|
|
|
|
if let Err(e) = private_state {
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(format!("Cannot retrieve private state: {:?}", e).into());
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
2018-12-03 20:44:36 +01:00
|
|
|
let private_state = private_state.expect("Error was checked before");
|
|
|
|
let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce);
|
|
|
|
trace!(target: "privatetx", "Hashed effective private state for validator: {:?}", private_state_hash);
|
2019-02-07 14:34:24 +01:00
|
|
|
let signed_state = self.accounts.sign(validator_account, private_state_hash);
|
2018-12-03 20:44:36 +01:00
|
|
|
if let Err(e) = signed_state {
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(format!("Cannot sign the state: {:?}", e).into());
|
2018-12-03 20:44:36 +01:00
|
|
|
}
|
|
|
|
let signed_state = signed_state.expect("Error was checked before");
|
|
|
|
let signed_private_transaction = SignedPrivateTransaction::new(private_hash, signed_state, None);
|
|
|
|
trace!(target: "privatetx", "Sending signature for private transaction: {:?}", signed_private_transaction);
|
|
|
|
self.broadcast_signed_private_transaction(signed_private_transaction.hash(), signed_private_transaction.rlp_bytes());
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-29 14:31:04 +02:00
|
|
|
Ok(())
|
|
|
|
};
|
2019-02-07 14:34:24 +01:00
|
|
|
let nonce_cache = NonceCache::new(NONCE_CACHE_SIZE);
|
|
|
|
let local_accounts = HashSet::new();
|
|
|
|
let ready_transactions = self.transactions_for_verification.drain(self.pool_client(&nonce_cache, &local_accounts));
|
2018-08-29 14:31:04 +02:00
|
|
|
for transaction in ready_transactions {
|
|
|
|
if let Err(e) = process_transaction(&transaction) {
|
|
|
|
warn!(target: "privatetx", "Error: {:?}", e);
|
|
|
|
}
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-08-29 14:31:04 +02:00
|
|
|
/// Add signed private transaction into the store
|
|
|
|
/// Creates corresponding public transaction if last required signature collected and sends it to the chain
|
|
|
|
pub fn process_signature(&self, signed_tx: &SignedPrivateTransaction) -> Result<(), Error> {
|
|
|
|
trace!(target: "privatetx", "Processing signed private transaction");
|
|
|
|
let private_hash = signed_tx.private_transaction_hash();
|
|
|
|
let desc = match self.transactions_for_signing.read().get(&private_hash) {
|
|
|
|
None => {
|
|
|
|
// Not our transaction, broadcast further to peers
|
2018-10-09 22:07:25 +02:00
|
|
|
self.broadcast_signed_private_transaction(signed_tx.hash(), signed_tx.rlp_bytes());
|
2018-08-29 14:31:04 +02:00
|
|
|
return Ok(());
|
|
|
|
},
|
|
|
|
Some(desc) => desc,
|
|
|
|
};
|
|
|
|
let last = self.last_required_signature(&desc, signed_tx.signature())?;
|
2019-05-14 11:21:22 +02:00
|
|
|
let original_tx_hash = desc.original_transaction.hash();
|
2018-08-29 14:31:04 +02:00
|
|
|
|
2019-05-14 11:21:22 +02:00
|
|
|
if last.0 {
|
2018-08-29 14:31:04 +02:00
|
|
|
let mut signatures = desc.received_signatures.clone();
|
|
|
|
signatures.push(signed_tx.signature());
|
|
|
|
let rsv: Vec<Signature> = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect();
|
2018-12-03 20:44:36 +01:00
|
|
|
// Create public transaction
|
2019-03-27 14:46:05 +01:00
|
|
|
let signer_account = self.signer_account.ok_or_else(|| Error::SignerAccountNotSet)?;
|
|
|
|
let state = self.client.state_at(BlockId::Latest).ok_or(Error::StatePruned)?;
|
2019-02-22 15:31:34 +01:00
|
|
|
let nonce = state.nonce(&signer_account)?;
|
2018-08-29 14:31:04 +02:00
|
|
|
let public_tx = self.public_transaction(
|
|
|
|
desc.state.clone(),
|
|
|
|
&desc.original_transaction,
|
|
|
|
&rsv,
|
2019-02-22 15:31:34 +01:00
|
|
|
nonce,
|
2018-08-29 14:31:04 +02:00
|
|
|
desc.original_transaction.gas_price
|
|
|
|
)?;
|
|
|
|
trace!(target: "privatetx", "Last required signature received, public transaction created: {:?}", public_tx);
|
2018-12-03 20:44:36 +01:00
|
|
|
// Sign and add it to the queue
|
2018-08-29 14:31:04 +02:00
|
|
|
let chain_id = desc.original_transaction.chain_id();
|
2019-05-14 11:21:22 +02:00
|
|
|
let public_tx_hash = public_tx.hash(chain_id);
|
|
|
|
let signature = self.accounts.sign(signer_account, public_tx_hash)?;
|
2018-08-29 14:31:04 +02:00
|
|
|
let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?;
|
|
|
|
match self.miner.import_own_transaction(&*self.client, signed.into()) {
|
|
|
|
Ok(_) => trace!(target: "privatetx", "Public transaction added to queue"),
|
|
|
|
Err(err) => {
|
|
|
|
warn!(target: "privatetx", "Failed to add transaction to queue, error: {:?}", err);
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(err.into());
|
2018-08-29 14:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
2018-12-03 20:44:36 +01:00
|
|
|
// Notify about state changes
|
|
|
|
let contract = Self::contract_address_from_transaction(&desc.original_transaction)?;
|
|
|
|
// TODO #9825 Usage of BlockId::Latest
|
|
|
|
if self.get_contract_version(BlockId::Latest, &contract) >= PRIVATE_CONTRACT_WITH_NOTIFICATION_VER {
|
|
|
|
match self.state_changes_notify(BlockId::Latest, &contract, &desc.original_transaction.sender(), desc.original_transaction.hash()) {
|
|
|
|
Ok(_) => trace!(target: "privatetx", "Notification about private state changes sent"),
|
|
|
|
Err(err) => warn!(target: "privatetx", "Failed to send private state changed notification, error: {:?}", err),
|
|
|
|
}
|
|
|
|
}
|
2019-05-14 11:21:22 +02:00
|
|
|
// Store logs
|
|
|
|
if let Some(ref logging) = self.logging {
|
|
|
|
logging.signature_added(&original_tx_hash, &last.1);
|
|
|
|
logging.tx_deployed(&original_tx_hash, &public_tx_hash);
|
|
|
|
}
|
2018-12-03 20:44:36 +01:00
|
|
|
// Remove from store for signing
|
2018-08-29 14:31:04 +02:00
|
|
|
if let Err(err) = self.transactions_for_signing.write().remove(&private_hash) {
|
|
|
|
warn!(target: "privatetx", "Failed to remove transaction from signing store, error: {:?}", err);
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(err);
|
2018-08-29 14:31:04 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-12-03 20:44:36 +01:00
|
|
|
// Add signature to the store
|
2018-08-29 14:31:04 +02:00
|
|
|
match self.transactions_for_signing.write().add_signature(&private_hash, signed_tx.signature()) {
|
2019-05-14 11:21:22 +02:00
|
|
|
Ok(_) => {
|
|
|
|
trace!(target: "privatetx", "Signature stored for private transaction");
|
|
|
|
if let Some(ref logging) = self.logging {
|
|
|
|
logging.signature_added(&original_tx_hash, &last.1);
|
|
|
|
}
|
|
|
|
}
|
2018-08-29 14:31:04 +02:00
|
|
|
Err(err) => {
|
|
|
|
warn!(target: "privatetx", "Failed to add signature to signing store, error: {:?}", err);
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(err);
|
2018-08-29 14:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-12-03 20:44:36 +01:00
|
|
|
fn contract_address_from_transaction(transaction: &SignedTransaction) -> Result<Address, Error> {
|
|
|
|
match transaction.action {
|
|
|
|
Action::Call(contract) => Ok(contract),
|
|
|
|
_ => {
|
|
|
|
warn!(target: "privatetx", "Incorrect type of action for the transaction");
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(Error::BadTransactionType);
|
2018-12-03 20:44:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-14 11:21:22 +02:00
|
|
|
fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result<(bool, Address), Error> {
|
2018-04-09 16:14:33 +02:00
|
|
|
let state_hash = self.calculate_state_hash(&desc.state, desc.contract_nonce);
|
|
|
|
match recover(&sign, &state_hash) {
|
|
|
|
Ok(public) => {
|
|
|
|
let sender = public_to_address(&public);
|
|
|
|
match desc.validators.contains(&sender) {
|
|
|
|
true => {
|
2019-05-14 11:21:22 +02:00
|
|
|
Ok((desc.received_signatures.len() + 1 == desc.validators.len(), sender))
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
false => {
|
2018-08-29 14:31:04 +02:00
|
|
|
warn!(target: "privatetx", "Sender's state doesn't correspond to validator's");
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(Error::StateIncorrect);
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => {
|
2018-08-29 14:31:04 +02:00
|
|
|
warn!(target: "privatetx", "Sender's state doesn't correspond to validator's, error {:?}", err);
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(err.into());
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Broadcast the private transaction message to the chain
|
2018-08-29 14:31:04 +02:00
|
|
|
fn broadcast_private_transaction(&self, transaction_hash: H256, message: Bytes) {
|
|
|
|
self.notify(|notify| notify.broadcast(ChainMessageType::PrivateTransaction(transaction_hash, message.clone())));
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Broadcast signed private transaction message to the chain
|
2018-08-29 14:31:04 +02:00
|
|
|
fn broadcast_signed_private_transaction(&self, transaction_hash: H256, message: Bytes) {
|
|
|
|
self.notify(|notify| notify.broadcast(ChainMessageType::SignedPrivateTransaction(transaction_hash, message.clone())));
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn iv_from_transaction(transaction: &SignedTransaction) -> H128 {
|
|
|
|
let nonce = keccak(&transaction.nonce.rlp_bytes());
|
2019-06-03 15:36:21 +02:00
|
|
|
let (iv, _) = nonce.as_bytes().split_at(INIT_VEC_LEN);
|
2018-04-09 16:14:33 +02:00
|
|
|
H128::from_slice(iv)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn iv_from_address(contract_address: &Address) -> H128 {
|
|
|
|
let address = keccak(&contract_address.rlp_bytes());
|
2019-06-03 15:36:21 +02:00
|
|
|
let (iv, _) = address.as_bytes().split_at(INIT_VEC_LEN);
|
2018-04-09 16:14:33 +02:00
|
|
|
H128::from_slice(iv)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn encrypt(&self, contract_address: &Address, initialisation_vector: &H128, data: &[u8]) -> Result<Bytes, Error> {
|
2018-08-29 14:31:04 +02:00
|
|
|
trace!(target: "privatetx", "Encrypt data using key(address): {:?}", contract_address);
|
2019-02-07 14:34:24 +01:00
|
|
|
Ok(self.encryptor.encrypt(contract_address, initialisation_vector, data)?)
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn decrypt(&self, contract_address: &Address, data: &[u8]) -> Result<Bytes, Error> {
|
2018-08-29 14:31:04 +02:00
|
|
|
trace!(target: "privatetx", "Decrypt data using key(address): {:?}", contract_address);
|
2019-02-07 14:34:24 +01:00
|
|
|
Ok(self.encryptor.decrypt(contract_address, data)?)
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_decrypted_state(&self, address: &Address, block: BlockId) -> Result<Bytes, Error> {
|
2018-09-13 11:04:39 +02:00
|
|
|
let (data, decoder) = private_contract::functions::state::call();
|
|
|
|
let value = self.client.call_contract(block, *address, data)?;
|
2019-03-27 14:46:05 +01:00
|
|
|
let state = decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)))?;
|
2018-04-09 16:14:33 +02:00
|
|
|
self.decrypt(address, &state)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_decrypted_code(&self, address: &Address, block: BlockId) -> Result<Bytes, Error> {
|
2018-09-13 11:04:39 +02:00
|
|
|
let (data, decoder) = private_contract::functions::code::call();
|
|
|
|
let value = self.client.call_contract(block, *address, data)?;
|
2019-03-27 14:46:05 +01:00
|
|
|
let state = decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)))?;
|
2018-09-13 11:04:39 +02:00
|
|
|
self.decrypt(address, &state)
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_contract_nonce(&self, address: &Address, block: BlockId) -> Result<U256, Error> {
|
2018-09-13 11:04:39 +02:00
|
|
|
let (data, decoder) = private_contract::functions::nonce::call();
|
|
|
|
let value = self.client.call_contract(block, *address, data)?;
|
2019-03-27 14:46:05 +01:00
|
|
|
decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)).into())
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn snapshot_to_storage(raw: Bytes) -> HashMap<H256, H256> {
|
|
|
|
let items = raw.len() / 64;
|
|
|
|
(0..items).map(|i| {
|
|
|
|
let offset = i * 64;
|
|
|
|
let key = H256::from_slice(&raw[offset..(offset + 32)]);
|
|
|
|
let value = H256::from_slice(&raw[(offset + 32)..(offset + 64)]);
|
|
|
|
(key, value)
|
|
|
|
}).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn snapshot_from_storage(storage: &HashMap<H256, H256>) -> Bytes {
|
|
|
|
let mut raw = Vec::with_capacity(storage.len() * 64);
|
2018-12-06 11:02:15 +01:00
|
|
|
// Sort the storage to guarantee the order for all parties
|
|
|
|
let sorted_storage: BTreeMap<&H256, &H256> = storage.iter().collect();
|
|
|
|
for (key, value) in sorted_storage {
|
2019-06-03 15:36:21 +02:00
|
|
|
raw.extend_from_slice(key.as_bytes());
|
|
|
|
raw.extend_from_slice(value.as_bytes());
|
2018-04-09 16:14:33 +02:00
|
|
|
};
|
|
|
|
raw
|
|
|
|
}
|
|
|
|
|
2019-07-08 18:17:48 +02:00
|
|
|
fn patch_account_state(&self, contract_address: &Address, block: BlockId, state: &mut State<StateDB>) -> Result<(), Error> {
|
2019-02-07 12:39:04 +01:00
|
|
|
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(())
|
|
|
|
}
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
pub fn execute_private<T, V>(&self, transaction: &SignedTransaction, options: TransactOptions<T, V>, block: BlockId) -> Result<PrivateExecutionResult<T, V>, Error>
|
|
|
|
where
|
|
|
|
T: Tracer,
|
|
|
|
V: VMTracer,
|
|
|
|
{
|
2019-03-27 14:46:05 +01:00
|
|
|
let mut env_info = self.client.env_info(block).ok_or(Error::StatePruned)?;
|
2018-04-09 16:14:33 +02:00
|
|
|
env_info.gas_limit = transaction.gas;
|
|
|
|
|
2019-03-27 14:46:05 +01:00
|
|
|
let mut state = self.client.state_at(block).ok_or(Error::StatePruned)?;
|
2018-12-03 20:44:36 +01:00
|
|
|
// TODO #9825 in case of BlockId::Latest these need to operate on the same state
|
2018-04-09 16:14:33 +02:00
|
|
|
let contract_address = match transaction.action {
|
|
|
|
Action::Call(ref contract_address) => {
|
2019-02-07 12:39:04 +01:00
|
|
|
// Patch current contract state
|
|
|
|
self.patch_account_state(contract_address, block, &mut state)?;
|
2018-04-09 16:14:33 +02:00
|
|
|
Some(*contract_address)
|
|
|
|
},
|
|
|
|
Action::Create => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let engine = self.client.engine();
|
2019-02-07 12:39:04 +01:00
|
|
|
let sender = transaction.sender();
|
|
|
|
let nonce = state.nonce(&sender)?;
|
|
|
|
let contract_address = contract_address.unwrap_or_else(|| {
|
2019-07-16 12:43:47 +02:00
|
|
|
let (new_address, _) = ethcore_contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &nonce, &transaction.data);
|
2019-02-07 12:39:04 +01:00
|
|
|
new_address
|
2018-04-09 16:14:33 +02:00
|
|
|
});
|
2019-02-07 12:39:04 +01:00
|
|
|
// 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)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-23 15:48:01 +02:00
|
|
|
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)?;
|
2019-02-07 12:39:04 +01:00
|
|
|
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))?)
|
2018-04-09 16:14:33 +02:00
|
|
|
};
|
|
|
|
Ok(PrivateExecutionResult {
|
|
|
|
code: encrypted_code,
|
|
|
|
state: encrypted_storage,
|
2019-02-07 12:39:04 +01:00
|
|
|
contract_address: contract_address,
|
2018-04-09 16:14:33 +02:00
|
|
|
result,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_constructor(validators: &[Address], code: Bytes, storage: Bytes) -> Bytes {
|
|
|
|
let constructor_code = DEFAULT_STUB_CONTRACT.from_hex().expect("Default contract code is valid");
|
2018-09-13 11:04:39 +02:00
|
|
|
private_contract::constructor(constructor_code, validators.iter().map(|a| *a).collect::<Vec<Address>>(), code, storage)
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_set_state_call(signatures: &[Signature], storage: Bytes) -> Bytes {
|
2018-09-13 11:04:39 +02:00
|
|
|
private_contract::functions::set_state::encode_input(
|
2018-04-09 16:14:33 +02:00
|
|
|
storage,
|
|
|
|
signatures.iter().map(|s| {
|
|
|
|
let mut v: [u8; 32] = [0; 32];
|
|
|
|
v[31] = s.v();
|
|
|
|
v
|
|
|
|
}).collect::<Vec<[u8; 32]>>(),
|
2019-06-03 15:36:21 +02:00
|
|
|
signatures.iter().map(|s| H256::from_slice(s.r())).collect::<Vec<H256>>(),
|
|
|
|
signatures.iter().map(|s| H256::from_slice(s.s())).collect::<Vec<H256>>(),
|
2018-04-09 16:14:33 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the key from the key server associated with the contract
|
|
|
|
pub fn contract_key_id(&self, contract_address: &Address) -> Result<H256, Error> {
|
2019-02-07 12:39:04 +01:00
|
|
|
Ok(key_server_keys::address_to_key(contract_address))
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Create encrypted public contract deployment transaction.
|
2019-02-07 12:39:04 +01:00
|
|
|
pub fn public_creation_transaction(&self, block: BlockId, source: &SignedTransaction, validators: &[Address], gas_price: U256) -> Result<(Transaction, Address), Error> {
|
2018-04-09 16:14:33 +02:00
|
|
|
if let Action::Call(_) = source.action {
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(Error::BadTransactionType);
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
let sender = source.sender();
|
2019-03-27 14:46:05 +01:00
|
|
|
let state = self.client.state_at(block).ok_or(Error::StatePruned)?;
|
2018-04-09 16:14:33 +02:00
|
|
|
let nonce = state.nonce(&sender)?;
|
|
|
|
let executed = self.execute_private(source, TransactOptions::with_no_tracing(), block)?;
|
2018-11-28 13:14:40 +01:00
|
|
|
let header = self.client.block_header(block)
|
2019-03-27 14:46:05 +01:00
|
|
|
.ok_or(Error::StatePruned)
|
|
|
|
.and_then(|h| h.decode().map_err(|_| Error::StateIncorrect).into())?;
|
2018-11-28 13:14:40 +01:00
|
|
|
let (executed_code, executed_state) = (executed.code.unwrap_or_default(), executed.state);
|
|
|
|
let tx_data = Self::generate_constructor(validators, executed_code.clone(), executed_state.clone());
|
|
|
|
let mut tx = Transaction {
|
2018-04-09 16:14:33 +02:00
|
|
|
nonce: nonce,
|
|
|
|
action: Action::Create,
|
2018-11-28 13:14:40 +01:00
|
|
|
gas: u64::max_value().into(),
|
2018-04-09 16:14:33 +02:00
|
|
|
gas_price: gas_price,
|
|
|
|
value: source.value,
|
2018-11-28 13:14:40 +01:00
|
|
|
data: tx_data,
|
|
|
|
};
|
|
|
|
tx.gas = match self.client.estimate_gas(&tx.clone().fake_sign(sender), &state, &header) {
|
|
|
|
Ok(estimated_gas) => estimated_gas,
|
|
|
|
Err(_) => self.estimate_tx_gas(validators, &executed_code, &executed_state, &[]),
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok((tx, executed.contract_address))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn estimate_tx_gas(&self, validators: &[Address], code: &Bytes, state: &Bytes, signatures: &[Signature]) -> U256 {
|
|
|
|
let default_gas = 650000 +
|
|
|
|
validators.len() as u64 * 30000 +
|
|
|
|
code.len() as u64 * 8000 +
|
|
|
|
signatures.len() as u64 * 50000 +
|
|
|
|
state.len() as u64 * 8000;
|
|
|
|
default_gas.into()
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Create encrypted public contract deployment transaction. Returns updated encrypted state.
|
|
|
|
pub fn execute_private_transaction(&self, block: BlockId, source: &SignedTransaction) -> Result<Bytes, Error> {
|
|
|
|
if let Action::Create = source.action {
|
2019-03-27 14:46:05 +01:00
|
|
|
return Err(Error::BadTransactionType);
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
let result = self.execute_private(source, TransactOptions::with_no_tracing(), block)?;
|
|
|
|
Ok(result.state)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create encrypted public transaction from private transaction.
|
|
|
|
pub fn public_transaction(&self, state: Bytes, source: &SignedTransaction, signatures: &[Signature], nonce: U256, gas_price: U256) -> Result<Transaction, Error> {
|
2018-11-28 13:14:40 +01:00
|
|
|
let gas = self.estimate_tx_gas(&[], &Vec::new(), &state, signatures);
|
2018-04-09 16:14:33 +02:00
|
|
|
Ok(Transaction {
|
|
|
|
nonce: nonce,
|
|
|
|
action: source.action.clone(),
|
|
|
|
gas: gas.into(),
|
|
|
|
gas_price: gas_price,
|
|
|
|
value: 0.into(),
|
|
|
|
data: Self::generate_set_state_call(signatures, state)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Call into private contract.
|
|
|
|
pub fn private_call(&self, block: BlockId, transaction: &SignedTransaction) -> Result<Executed, Error> {
|
|
|
|
let result = self.execute_private(transaction, TransactOptions::with_no_tracing(), block)?;
|
|
|
|
Ok(result.result)
|
|
|
|
}
|
|
|
|
|
2019-05-14 11:21:22 +02:00
|
|
|
/// Retrieves log information about private transaction
|
|
|
|
pub fn private_log(&self, tx_hash: H256) -> Result<TransactionLog, Error> {
|
|
|
|
match self.logging {
|
|
|
|
Some(ref logging) => logging.tx_log(&tx_hash).ok_or(Error::TxNotFoundInLog),
|
|
|
|
None => Err(Error::LoggingPathNotSet),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
/// Returns private validators for a contract.
|
|
|
|
pub fn get_validators(&self, block: BlockId, address: &Address) -> Result<Vec<Address>, Error> {
|
2018-09-13 11:04:39 +02:00
|
|
|
let (data, decoder) = private_contract::functions::get_validators::call();
|
|
|
|
let value = self.client.call_contract(block, *address, data)?;
|
2019-03-27 14:46:05 +01:00
|
|
|
decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)).into())
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
2018-12-03 20:44:36 +01:00
|
|
|
|
|
|
|
fn get_contract_version(&self, block: BlockId, address: &Address) -> usize {
|
|
|
|
let (data, decoder) = private_contract::functions::get_version::call();
|
|
|
|
match self.client.call_contract(block, *address, data)
|
|
|
|
.and_then(|value| decoder.decode(&value).map_err(|e| e.to_string())) {
|
|
|
|
Ok(version) => version.low_u64() as usize,
|
|
|
|
Err(_) => INITIAL_PRIVATE_CONTRACT_VER,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn state_changes_notify(&self, block: BlockId, address: &Address, originator: &Address, transaction_hash: H256) -> Result<(), Error> {
|
|
|
|
let (data, _) = private_contract::functions::notify_changes::call(*originator, transaction_hash.0.to_vec());
|
|
|
|
let _value = self.client.call_contract(block, *address, data)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
2018-05-09 08:49:34 +02:00
|
|
|
pub trait Importer {
|
|
|
|
/// Process received private transaction
|
2018-08-29 14:31:04 +02:00
|
|
|
fn import_private_transaction(&self, _rlp: &[u8]) -> Result<H256, Error>;
|
2018-05-09 08:49:34 +02:00
|
|
|
|
|
|
|
/// Add signed private transaction into the store
|
|
|
|
///
|
|
|
|
/// Creates corresponding public transaction if last required signature collected and sends it to the chain
|
2018-08-29 14:31:04 +02:00
|
|
|
fn import_signed_private_transaction(&self, _rlp: &[u8]) -> Result<H256, Error>;
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO [ToDr] Offload more heavy stuff to the IoService thread.
|
|
|
|
// It seems that a lot of heavy work (verification) is done in this thread anyway
|
|
|
|
// it might actually make sense to decouple it from clientService and just use dedicated thread
|
|
|
|
// for both verification and execution.
|
|
|
|
|
|
|
|
impl Importer for Arc<Provider> {
|
2018-08-29 14:31:04 +02:00
|
|
|
fn import_private_transaction(&self, rlp: &[u8]) -> Result<H256, Error> {
|
|
|
|
trace!(target: "privatetx", "Private transaction received");
|
2018-05-09 08:49:34 +02:00
|
|
|
let private_tx: PrivateTransaction = Rlp::new(rlp).as_val()?;
|
2018-08-29 14:31:04 +02:00
|
|
|
let private_tx_hash = private_tx.hash();
|
|
|
|
let contract = private_tx.contract();
|
2018-05-09 08:49:34 +02:00
|
|
|
let contract_validators = self.get_validators(BlockId::Latest, &contract)?;
|
|
|
|
|
|
|
|
let validation_account = contract_validators
|
|
|
|
.iter()
|
|
|
|
.find(|address| self.validator_accounts.contains(address));
|
|
|
|
|
2018-12-03 20:44:36 +01:00
|
|
|
// Extract the original transaction
|
2018-08-29 14:31:04 +02:00
|
|
|
let encrypted_data = private_tx.encrypted();
|
|
|
|
let transaction_bytes = self.decrypt(&contract, &encrypted_data)?;
|
|
|
|
let original_tx: UnverifiedTransaction = Rlp::new(&transaction_bytes).as_val()?;
|
|
|
|
let nonce_cache = NonceCache::new(NONCE_CACHE_SIZE);
|
2019-02-07 14:34:24 +01:00
|
|
|
let local_accounts = HashSet::new();
|
2018-12-03 20:44:36 +01:00
|
|
|
// Add to the queue for further verification
|
2018-08-29 14:31:04 +02:00
|
|
|
self.transactions_for_verification.add_transaction(
|
|
|
|
original_tx,
|
|
|
|
validation_account.map(|&account| account),
|
|
|
|
private_tx,
|
2019-02-07 14:34:24 +01:00
|
|
|
self.pool_client(&nonce_cache, &local_accounts),
|
2018-08-29 14:31:04 +02:00
|
|
|
)?;
|
|
|
|
let provider = Arc::downgrade(self);
|
|
|
|
let result = self.channel.send(ClientIoMessage::execute(move |_| {
|
|
|
|
if let Some(provider) = provider.upgrade() {
|
|
|
|
if let Err(e) = provider.process_verification_queue() {
|
|
|
|
warn!(target: "privatetx", "Unable to process the queue: {}", e);
|
|
|
|
}
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
2018-08-29 14:31:04 +02:00
|
|
|
}));
|
|
|
|
if let Err(e) = result {
|
|
|
|
warn!(target: "privatetx", "Error sending NewPrivateTransaction message: {:?}", e);
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
2018-08-29 14:31:04 +02:00
|
|
|
Ok(private_tx_hash)
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 14:31:04 +02:00
|
|
|
fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<H256, Error> {
|
2018-05-09 08:49:34 +02:00
|
|
|
let tx: SignedPrivateTransaction = Rlp::new(rlp).as_val()?;
|
2018-08-29 14:31:04 +02:00
|
|
|
trace!(target: "privatetx", "Signature for private transaction received: {:?}", tx);
|
2018-05-09 08:49:34 +02:00
|
|
|
let private_hash = tx.private_transaction_hash();
|
2018-08-29 14:31:04 +02:00
|
|
|
let provider = Arc::downgrade(self);
|
|
|
|
let result = self.channel.send(ClientIoMessage::execute(move |_| {
|
|
|
|
if let Some(provider) = provider.upgrade() {
|
|
|
|
if let Err(e) = provider.process_signature(&tx) {
|
|
|
|
warn!(target: "privatetx", "Unable to process the signature: {}", e);
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-29 14:31:04 +02:00
|
|
|
}));
|
|
|
|
if let Err(e) = result {
|
|
|
|
warn!(target: "privatetx", "Error sending NewSignedPrivateTransaction message: {:?}", e);
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
2018-08-29 14:31:04 +02:00
|
|
|
Ok(private_hash)
|
2018-05-09 08:49:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
impl ChainNotify for Provider {
|
2018-12-19 10:24:14 +01:00
|
|
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
|
|
|
if new_blocks.imported.is_empty() || new_blocks.has_more_blocks_to_import { return }
|
|
|
|
trace!(target: "privatetx", "New blocks imported, try to prune the queue");
|
|
|
|
if let Err(err) = self.process_verification_queue() {
|
|
|
|
warn!(target: "privatetx", "Cannot prune private transactions queue. error: {:?}", err);
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
2019-02-07 12:39:04 +01:00
|
|
|
self.keys_provider.update_acl_contract();
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
}
|