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

Trivial journal for private transactions #10056

Merged
merged 23 commits into from
May 14, 2019
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
eee735d
Journal for private txs added
grbIzl Dec 7, 2018
552e130
Tests after adding logging to private tx fixed
grbIzl Dec 11, 2018
81dc28f
Logs getter and tests added
grbIzl Dec 11, 2018
4836339
Time and amount limit for logs added
grbIzl Dec 11, 2018
cd66d06
RPC method for log retrieving added
grbIzl Dec 12, 2018
488624e
Correct path name and time validation implemented
grbIzl Dec 12, 2018
22c7aff
References for parameters added, redundant cloning reworked
grbIzl Feb 6, 2019
7ffcdb0
References for parameters added, redundant cloning reworked
grbIzl Feb 6, 2019
3e26764
Work with json moved to the separate struct
grbIzl Feb 6, 2019
d2f8da9
Serialization test added
grbIzl Feb 8, 2019
841548d
Fixed build after the merge with head
grbIzl Feb 8, 2019
d00ca5c
Documentation for methods fixed, redundant field removed
grbIzl Mar 28, 2019
23f279c
Fixed error usages
grbIzl Mar 28, 2019
9cff57e
Timestamp trait implemented for std struct
grbIzl Apr 4, 2019
3b22ab8
Commented code removed
grbIzl Apr 10, 2019
6c535a0
Remove timestamp source, rework serialization test
grbIzl May 6, 2019
91b62e4
u64 replaced with SystemTime
grbIzl May 7, 2019
f94905b
Path made mandatory for logging
grbIzl May 7, 2019
541f5d2
Source of monotonic time added
grbIzl May 7, 2019
ad25432
into_system_time method renamed
grbIzl May 8, 2019
9a274ef
Initialize time source by max from current system time and max creati…
grbIzl May 8, 2019
d261c52
Redundant conversions removed, code a little bit reworked according t…
grbIzl May 10, 2019
a67dab5
One more redundant conversion removed, rpc call simplified
grbIzl May 13, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_else(|| Error::TxNotFoundInLog.into()),
grbIzl marked this conversation as resolved.
Show resolved Hide resolved
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