Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Trivial journal for private transactions (#10056)
Browse files Browse the repository at this point in the history
* Journal for private txs added

* Tests after adding logging to private tx fixed

* Logs getter and tests added

* Time and amount limit for logs added

* RPC method for log retrieving added

* Correct path name and time validation implemented

* References for parameters added, redundant cloning reworked

* References for parameters added, redundant cloning reworked

* Work with json moved to the separate struct

* Serialization test added

* Fixed build after the merge with head

* Documentation for methods fixed, redundant field removed

* Fixed error usages

* Timestamp trait implemented for std struct

* Commented code removed

* Remove timestamp source, rework serialization test

* u64 replaced with SystemTime

* Path made mandatory for logging

* Source of monotonic time added

* into_system_time method renamed

* Initialize time source by max from current system time and max creation time from already saved logs

* Redundant conversions removed, code a little bit reworked according to review comments

* One more redundant conversion removed, rpc call simplified
  • Loading branch information
grbIzl authored and ltfschoen committed May 15, 2019
1 parent e6e5f82 commit 8bf3492
Show file tree
Hide file tree
Showing 13 changed files with 596 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ethcore/private-tx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
time-utils = { path = "../../util/time-utils" }
tiny-keccak = "1.4"
transaction-pool = "2.0"
url = "1"
Expand Down
20 changes: 20 additions & 0 deletions ethcore/private-tx/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use ethkey::Error as KeyError;
use ethkey::crypto::Error as CryptoError;
use txpool::VerifiedTransaction;
use private_transactions::VerifiedPrivateTransaction;
use serde_json::{Error as SerdeError};

type TxPoolError = txpool::Error<<VerifiedPrivateTransaction as VerifiedTransaction>::Hash>;

Expand All @@ -45,6 +46,9 @@ pub enum Error {
/// Crypto error.
#[display(fmt = "Crypto Error {}", _0)]
Crypto(CryptoError),
/// Serialization error.
#[display(fmt = "Serialization Error {}", _0)]
Json(SerdeError),
/// Encryption error.
#[display(fmt = "Encryption error. ({})", _0)]
Encrypt(String),
Expand Down Expand Up @@ -99,6 +103,15 @@ pub enum Error {
/// Key server URL is not set.
#[display(fmt = "Key server URL is not set.")]
KeyServerNotSet,
/// Transaction not found in logs.
#[display(fmt = "Private transaction not found in logs.")]
TxNotFoundInLog,
/// Path for logging not set.
#[display(fmt = "Path for logging not set.")]
LoggingPathNotSet,
/// Timestamp overflow error.
#[display(fmt = "Timestamp overflow error.")]
TimestampOverflow,
/// VM execution error.
#[display(fmt = "VM execution error {}", _0)]
Execution(ExecutionError),
Expand All @@ -123,6 +136,7 @@ impl error::Error for Error {
Error::Decoder(e) => Some(e),
Error::Trie(e) => Some(e),
Error::TxPool(e) => Some(e),
Error::Json(e) => Some(e),
Error::Crypto(e) => Some(e),
Error::Execution(e) => Some(e),
Error::Key(e) => Some(e),
Expand Down Expand Up @@ -187,6 +201,12 @@ impl From<TxPoolError> for Error {
}
}

impl From<SerdeError> for Error {
fn from(err: SerdeError) -> Self {
Error::Json(err).into()
}
}

impl From<EthcoreError> for Error {
fn from(err: EthcoreError) -> Self {
Error::Ethcore(err).into()
Expand Down
54 changes: 43 additions & 11 deletions ethcore/private-tx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ mod key_server_keys;
mod private_transactions;
mod messages;
mod error;
mod log;

extern crate common_types as types;
extern crate ethabi;
Expand All @@ -45,11 +46,15 @@ extern crate parking_lot;
extern crate trie_db as trie;
extern crate patricia_trie_ethereum as ethtrie;
extern crate rlp;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate rustc_hex;
extern crate transaction_pool as txpool;
extern crate url;
#[macro_use]
extern crate log;
extern crate log as ethlog;
#[macro_use]
extern crate ethabi_derive;
#[macro_use]
Expand All @@ -58,6 +63,9 @@ extern crate derive_more;
#[macro_use]
extern crate rlp_derive;

#[cfg(not(time_checked_add))]
extern crate time_utils;

#[cfg(test)]
extern crate rand;
#[cfg(test)]
Expand All @@ -68,6 +76,7 @@ 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;
pub use log::{Logging, TransactionLog, ValidatorLog, PrivateTxStatus, FileLogsSerializer};

use std::sync::{Arc, Weak};
use std::collections::{HashMap, HashSet, BTreeMap};
Expand Down Expand Up @@ -117,6 +126,8 @@ pub struct ProviderConfig {
pub validator_accounts: Vec<Address>,
/// Account used for signing public transactions created from private transactions
pub signer_account: Option<Address>,
/// Path to private tx logs
pub logs_path: Option<String>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -177,6 +188,7 @@ pub struct Provider {
accounts: Arc<Signer>,
channel: IoChannel<ClientIoMessage>,
keys_provider: Arc<KeyProvider>,
logging: Option<Logging>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -211,6 +223,7 @@ impl Provider {
accounts,
channel,
keys_provider,
logging: config.logs_path.map(|path| Logging::new(Arc::new(FileLogsSerializer::with_path(path)))),
}
}

Expand Down Expand Up @@ -257,8 +270,11 @@ impl Provider {
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);
self.transactions_for_signing.write().add_transaction(private.hash(), signed_transaction, contract_validators, private_state, contract_nonce)?;
self.transactions_for_signing.write().add_transaction(private.hash(), signed_transaction, &contract_validators, private_state, contract_nonce)?;
self.broadcast_private_transaction(private.hash(), private.rlp_bytes());
if let Some(ref logging) = self.logging {
logging.private_tx_created(&tx_hash, &contract_validators);
}
Ok(Receipt {
hash: tx_hash,
contract_address: contract,
Expand Down Expand Up @@ -354,8 +370,9 @@ impl Provider {
Some(desc) => desc,
};
let last = self.last_required_signature(&desc, signed_tx.signature())?;
let original_tx_hash = desc.original_transaction.hash();

if last {
if last.0 {
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();
Expand All @@ -373,8 +390,8 @@ impl Provider {
trace!(target: "privatetx", "Last required signature received, public transaction created: {:?}", public_tx);
// Sign and add it to the queue
let chain_id = desc.original_transaction.chain_id();
let hash = public_tx.hash(chain_id);
let signature = self.accounts.sign(signer_account, hash)?;
let public_tx_hash = public_tx.hash(chain_id);
let signature = self.accounts.sign(signer_account, public_tx_hash)?;
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"),
Expand All @@ -392,6 +409,11 @@ impl Provider {
Err(err) => warn!(target: "privatetx", "Failed to send private state changed notification, error: {:?}", err),
}
}
// 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);
}
// Remove from store for signing
if let Err(err) = self.transactions_for_signing.write().remove(&private_hash) {
warn!(target: "privatetx", "Failed to remove transaction from signing store, error: {:?}", err);
Expand All @@ -400,7 +422,12 @@ impl Provider {
} else {
// Add signature to the store
match self.transactions_for_signing.write().add_signature(&private_hash, signed_tx.signature()) {
Ok(_) => trace!(target: "privatetx", "Signature stored for private transaction"),
Ok(_) => {
trace!(target: "privatetx", "Signature stored for private transaction");
if let Some(ref logging) = self.logging {
logging.signature_added(&original_tx_hash, &last.1);
}
}
Err(err) => {
warn!(target: "privatetx", "Failed to add signature to signing store, error: {:?}", err);
return Err(err);
Expand All @@ -420,17 +447,14 @@ impl Provider {
}
}

fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result<bool, Error> {
if desc.received_signatures.contains(&sign) {
return Ok(false);
}
fn last_required_signature(&self, desc: &PrivateTransactionSigningDesc, sign: Signature) -> Result<(bool, Address), Error> {
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 => {
Ok(desc.received_signatures.len() + 1 == desc.validators.len())
Ok((desc.received_signatures.len() + 1 == desc.validators.len(), sender))
}
false => {
warn!(target: "privatetx", "Sender's state doesn't correspond to validator's");
Expand Down Expand Up @@ -674,6 +698,14 @@ impl Provider {
Ok(result.result)
}

/// 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),
}
}

/// Returns private validators for a contract.
pub fn get_validators(&self, block: BlockId, address: &Address) -> Result<Vec<Address>, Error> {
let (data, decoder) = private_contract::functions::get_validators::call();
Expand Down
Loading

0 comments on commit 8bf3492

Please sign in to comment.