Trivial journal for private transactions (#10056)
* 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
This commit is contained in:
		
							parent
							
								
									87699f8de0
								
							
						
					
					
						commit
						5a581c1c90
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1050,6 +1050,7 @@ dependencies = [
 | 
			
		||||
 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "time-utils 0.1.0",
 | 
			
		||||
 "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "transaction-pool 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "trie-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
@ -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>;
 | 
			
		||||
 | 
			
		||||
@ -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),
 | 
			
		||||
@ -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),
 | 
			
		||||
@ -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),
 | 
			
		||||
@ -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()
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
@ -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]
 | 
			
		||||
@ -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)]
 | 
			
		||||
@ -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};
 | 
			
		||||
@ -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)]
 | 
			
		||||
@ -177,6 +188,7 @@ pub struct Provider {
 | 
			
		||||
	accounts: Arc<Signer>,
 | 
			
		||||
	channel: IoChannel<ClientIoMessage>,
 | 
			
		||||
	keys_provider: Arc<KeyProvider>,
 | 
			
		||||
	logging: Option<Logging>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
@ -211,6 +223,7 @@ impl Provider {
 | 
			
		||||
			accounts,
 | 
			
		||||
			channel,
 | 
			
		||||
			keys_provider,
 | 
			
		||||
			logging: config.logs_path.map(|path| Logging::new(Arc::new(FileLogsSerializer::with_path(path)))),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
@ -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();
 | 
			
		||||
@ -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"),
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -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");
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										408
									
								
								ethcore/private-tx/src/log.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										408
									
								
								ethcore/private-tx/src/log.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,408 @@
 | 
			
		||||
// 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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! Private transactions logs.
 | 
			
		||||
 | 
			
		||||
use ethereum_types::{H256, Address};
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use std::time::{SystemTime, Duration, Instant};
 | 
			
		||||
use parking_lot::RwLock;
 | 
			
		||||
use serde::ser::{Serializer, SerializeSeq};
 | 
			
		||||
use error::Error;
 | 
			
		||||
 | 
			
		||||
#[cfg(not(time_checked_add))]
 | 
			
		||||
use time_utils::CheckedSystemTime;
 | 
			
		||||
 | 
			
		||||
/// Maximum amount of stored private transaction logs.
 | 
			
		||||
const MAX_JOURNAL_LEN: usize = 1000;
 | 
			
		||||
 | 
			
		||||
/// Maximum period for storing private transaction logs.
 | 
			
		||||
/// Logs older than 20 days will not be processed
 | 
			
		||||
const MAX_STORING_TIME: Duration = Duration::from_secs(60 * 60 * 24 * 20);
 | 
			
		||||
 | 
			
		||||
/// Source of monotonic time for log timestamps
 | 
			
		||||
struct MonoTime {
 | 
			
		||||
	start_time: SystemTime,
 | 
			
		||||
	start_inst: Instant
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl MonoTime {
 | 
			
		||||
	fn new(start: SystemTime) -> Self {
 | 
			
		||||
		Self {
 | 
			
		||||
			start_time: start,
 | 
			
		||||
			start_inst: Instant::now()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn elapsed(&self) -> Duration {
 | 
			
		||||
		self.start_inst.elapsed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn to_system_time(&self) -> SystemTime {
 | 
			
		||||
		self.start_time + self.elapsed()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for MonoTime {
 | 
			
		||||
	fn default() -> Self {
 | 
			
		||||
		MonoTime::new(SystemTime::now())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Current status of the private transaction
 | 
			
		||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
 | 
			
		||||
pub enum PrivateTxStatus {
 | 
			
		||||
	/// Private tx was created but no validation received yet
 | 
			
		||||
	Created,
 | 
			
		||||
	/// Several validators (but not all) validated the transaction
 | 
			
		||||
	Validating,
 | 
			
		||||
	/// All validators has validated the private tx
 | 
			
		||||
	/// Corresponding public tx was created and added into the pool
 | 
			
		||||
	Deployed,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Information about private tx validation
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct ValidatorLog {
 | 
			
		||||
	/// Account of the validator
 | 
			
		||||
	pub account: Address,
 | 
			
		||||
	/// Validation timestamp, None if the transaction is not validated
 | 
			
		||||
	pub validation_timestamp: Option<SystemTime>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
impl PartialEq for ValidatorLog {
 | 
			
		||||
	fn eq(&self, other: &Self) -> bool {
 | 
			
		||||
		self.account == other.account
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Information about the private transaction
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct TransactionLog {
 | 
			
		||||
	/// Original signed transaction hash (used as a source for private tx)
 | 
			
		||||
	pub tx_hash: H256,
 | 
			
		||||
	/// Current status of the private transaction
 | 
			
		||||
	pub status: PrivateTxStatus,
 | 
			
		||||
	/// Creation timestamp
 | 
			
		||||
	pub creation_timestamp: SystemTime,
 | 
			
		||||
	/// List of validations
 | 
			
		||||
	pub validators: Vec<ValidatorLog>,
 | 
			
		||||
	/// Timestamp of the resulting public tx deployment
 | 
			
		||||
	pub deployment_timestamp: Option<SystemTime>,
 | 
			
		||||
	/// Hash of the resulting public tx
 | 
			
		||||
	pub public_tx_hash: Option<H256>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
impl PartialEq for TransactionLog {
 | 
			
		||||
	fn eq(&self, other: &Self) -> bool {
 | 
			
		||||
		self.tx_hash == other.tx_hash &&
 | 
			
		||||
		self.status == other.status &&
 | 
			
		||||
		self.validators == other.validators &&
 | 
			
		||||
		self.public_tx_hash == other.public_tx_hash
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Wrapper other JSON serializer
 | 
			
		||||
pub trait LogsSerializer: Send + Sync + 'static {
 | 
			
		||||
	/// Read logs from the source
 | 
			
		||||
	fn read_logs(&self) -> Result<Vec<TransactionLog>, Error>;
 | 
			
		||||
 | 
			
		||||
	/// Write all logs to the source
 | 
			
		||||
	fn flush_logs(&self, logs: &HashMap<H256, TransactionLog>) -> Result<(), Error>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Logs serializer to the json file
 | 
			
		||||
pub struct FileLogsSerializer {
 | 
			
		||||
	logs_dir: PathBuf,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FileLogsSerializer {
 | 
			
		||||
	pub fn with_path<P: Into<PathBuf>>(logs_dir: P) -> Self {
 | 
			
		||||
		FileLogsSerializer {
 | 
			
		||||
			logs_dir: logs_dir.into(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn open_file(&self, to_create: bool) -> Result<File, Error> {
 | 
			
		||||
		let file_path = self.logs_dir.with_file_name("private_tx.log");
 | 
			
		||||
		if to_create {
 | 
			
		||||
			File::create(&file_path).map_err(From::from)
 | 
			
		||||
		} else {
 | 
			
		||||
			File::open(&file_path).map_err(From::from)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl LogsSerializer for FileLogsSerializer {
 | 
			
		||||
	fn read_logs(&self) -> Result<Vec<TransactionLog>, Error> {
 | 
			
		||||
		let log_file = self.open_file(false)?;
 | 
			
		||||
		match serde_json::from_reader(log_file) {
 | 
			
		||||
			Ok(logs) => Ok(logs),
 | 
			
		||||
			Err(err) => {
 | 
			
		||||
				error!(target: "privatetx", "Cannot deserialize logs from file: {}", err);
 | 
			
		||||
				return Err(format!("Cannot deserialize logs from file: {:?}", err).into());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn flush_logs(&self, logs: &HashMap<H256, TransactionLog>) -> Result<(), Error> {
 | 
			
		||||
		if logs.is_empty() {
 | 
			
		||||
			// Do not create empty file
 | 
			
		||||
			return Ok(());
 | 
			
		||||
		}
 | 
			
		||||
		let log_file = self.open_file(true)?;
 | 
			
		||||
		let mut json = serde_json::Serializer::new(log_file);
 | 
			
		||||
		let mut json_array = json.serialize_seq(Some(logs.len()))?;
 | 
			
		||||
		for v in logs.values() {
 | 
			
		||||
			json_array.serialize_element(v)?;
 | 
			
		||||
		}
 | 
			
		||||
		json_array.end()?;
 | 
			
		||||
		Ok(())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Private transactions logging
 | 
			
		||||
pub struct Logging {
 | 
			
		||||
	logs: RwLock<HashMap<H256, TransactionLog>>,
 | 
			
		||||
	logs_serializer: Arc<LogsSerializer>,
 | 
			
		||||
	mono_time: MonoTime,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Logging {
 | 
			
		||||
	/// Creates the logging object
 | 
			
		||||
	pub fn new(logs_serializer: Arc<LogsSerializer>) -> Self {
 | 
			
		||||
		let mut logging = Logging {
 | 
			
		||||
			logs: RwLock::new(HashMap::new()),
 | 
			
		||||
			logs_serializer,
 | 
			
		||||
			mono_time: MonoTime::default(),
 | 
			
		||||
		};
 | 
			
		||||
		match logging.read_logs() {
 | 
			
		||||
			// Initialize time source by max from current system time and max creation time from already saved logs
 | 
			
		||||
			Ok(initial_time) => logging.mono_time = MonoTime::new(initial_time),
 | 
			
		||||
			Err(err) => warn!(target: "privatetx", "Cannot read logs: {:?}", err),
 | 
			
		||||
		}
 | 
			
		||||
		logging
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Retrieves log for the corresponding tx hash
 | 
			
		||||
	pub fn tx_log(&self, tx_hash: &H256) -> Option<TransactionLog> {
 | 
			
		||||
		self.logs.read().get(&tx_hash).cloned()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Logs the creation of the private transaction
 | 
			
		||||
	pub fn private_tx_created(&self, tx_hash: &H256, validators: &[Address]) {
 | 
			
		||||
		let mut validator_logs = Vec::new();
 | 
			
		||||
		for account in validators {
 | 
			
		||||
			validator_logs.push(ValidatorLog {
 | 
			
		||||
				account: *account,
 | 
			
		||||
				validation_timestamp: None,
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		let mut logs = self.logs.write();
 | 
			
		||||
		if logs.len() > MAX_JOURNAL_LEN {
 | 
			
		||||
			// Remove the oldest log
 | 
			
		||||
			if let Some(tx_hash) = logs.values()
 | 
			
		||||
				.min_by(|x, y| x.creation_timestamp.cmp(&y.creation_timestamp))
 | 
			
		||||
				.map(|oldest| oldest.tx_hash)
 | 
			
		||||
			{
 | 
			
		||||
				logs.remove(&tx_hash);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		logs.insert(*tx_hash, TransactionLog {
 | 
			
		||||
			tx_hash: *tx_hash,
 | 
			
		||||
			status: PrivateTxStatus::Created,
 | 
			
		||||
			creation_timestamp: self.mono_time.to_system_time(),
 | 
			
		||||
			validators: validator_logs,
 | 
			
		||||
			deployment_timestamp: None,
 | 
			
		||||
			public_tx_hash: None,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Logs the validation of the private transaction by one of its validators
 | 
			
		||||
	pub fn signature_added(&self, tx_hash: &H256, validator: &Address) {
 | 
			
		||||
		let mut logs = self.logs.write();
 | 
			
		||||
		if let Some(transaction_log) = logs.get_mut(&tx_hash) {
 | 
			
		||||
			if let Some(ref mut validator_log) = transaction_log.validators.iter_mut().find(|log| log.account == *validator) {
 | 
			
		||||
				transaction_log.status = PrivateTxStatus::Validating;
 | 
			
		||||
				validator_log.validation_timestamp = Some(self.mono_time.to_system_time());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Logs the final deployment of the resulting public transaction
 | 
			
		||||
	pub fn tx_deployed(&self, tx_hash: &H256, public_tx_hash: &H256) {
 | 
			
		||||
		let mut logs = self.logs.write();
 | 
			
		||||
		if let Some(log) = logs.get_mut(&tx_hash) {
 | 
			
		||||
			log.status = PrivateTxStatus::Deployed;
 | 
			
		||||
			log.deployment_timestamp = Some(self.mono_time.to_system_time());
 | 
			
		||||
			log.public_tx_hash = Some(*public_tx_hash);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn read_logs(&self) -> Result<SystemTime, Error> {
 | 
			
		||||
		let mut transaction_logs = self.logs_serializer.read_logs()?;
 | 
			
		||||
		// Drop old logs
 | 
			
		||||
		let earliest_possible = SystemTime::now().checked_sub(MAX_STORING_TIME).ok_or(Error::TimestampOverflow)?;
 | 
			
		||||
		transaction_logs.retain(|tx_log| tx_log.creation_timestamp > earliest_possible);
 | 
			
		||||
		// Sort logs by their creation time in order to find the most recent
 | 
			
		||||
		transaction_logs.sort_by(|a, b| b.creation_timestamp.cmp(&a.creation_timestamp));
 | 
			
		||||
		let initial_timestamp = transaction_logs.first()
 | 
			
		||||
			.map_or(SystemTime::now(), |l| std::cmp::max(SystemTime::now(), l.creation_timestamp));
 | 
			
		||||
		let mut logs = self.logs.write();
 | 
			
		||||
		for log in transaction_logs {
 | 
			
		||||
			logs.insert(log.tx_hash, log);
 | 
			
		||||
		}
 | 
			
		||||
		Ok(initial_timestamp)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn flush_logs(&self) -> Result<(), Error> {
 | 
			
		||||
		let logs = self.logs.read();
 | 
			
		||||
		self.logs_serializer.flush_logs(&logs)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Flush all logs on drop
 | 
			
		||||
impl Drop for Logging {
 | 
			
		||||
	fn drop(&mut self) {
 | 
			
		||||
		if let Err(err) = self.flush_logs() {
 | 
			
		||||
			warn!(target: "privatetx", "Cannot write logs: {:?}", err);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
	use serde_json;
 | 
			
		||||
	use error::Error;
 | 
			
		||||
	use ethereum_types::H256;
 | 
			
		||||
	use std::collections::{HashMap, BTreeMap};
 | 
			
		||||
	use std::sync::Arc;
 | 
			
		||||
	use std::time::{SystemTime, Duration};
 | 
			
		||||
	use types::transaction::Transaction;
 | 
			
		||||
	use parking_lot::RwLock;
 | 
			
		||||
	use super::{TransactionLog, Logging, PrivateTxStatus, LogsSerializer, ValidatorLog};
 | 
			
		||||
 | 
			
		||||
	#[cfg(not(time_checked_add))]
 | 
			
		||||
	use time_utils::CheckedSystemTime;
 | 
			
		||||
 | 
			
		||||
	struct StringLogSerializer {
 | 
			
		||||
		string_log: RwLock<String>,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	impl StringLogSerializer {
 | 
			
		||||
		fn new(source: String) -> Self {
 | 
			
		||||
			StringLogSerializer {
 | 
			
		||||
				string_log: RwLock::new(source),
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fn log(&self) -> String {
 | 
			
		||||
			let log = self.string_log.read();
 | 
			
		||||
			log.clone()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	impl LogsSerializer for StringLogSerializer {
 | 
			
		||||
		fn read_logs(&self) -> Result<Vec<TransactionLog>, Error> {
 | 
			
		||||
			let source = self.string_log.read();
 | 
			
		||||
			if source.is_empty() {
 | 
			
		||||
				return Ok(Vec::new())
 | 
			
		||||
			}
 | 
			
		||||
			let logs = serde_json::from_str(&source).unwrap();
 | 
			
		||||
			Ok(logs)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fn flush_logs(&self, logs: &HashMap<H256, TransactionLog>) -> Result<(), Error> {
 | 
			
		||||
			// Sort logs in order to have the same order
 | 
			
		||||
			let sorted_logs: BTreeMap<&H256, &TransactionLog> = logs.iter().collect();
 | 
			
		||||
			*self.string_log.write() = serde_json::to_string(&sorted_logs.values().collect::<Vec<&&TransactionLog>>())?;
 | 
			
		||||
			Ok(())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn private_log_format() {
 | 
			
		||||
		let s = r#"{
 | 
			
		||||
			"tx_hash":"0x64f648ca7ae7f4138014f860ae56164d8d5732969b1cea54d8be9d144d8aa6f6",
 | 
			
		||||
			"status":"Deployed",
 | 
			
		||||
			"creation_timestamp":{"secs_since_epoch":1557220355,"nanos_since_epoch":196382053},
 | 
			
		||||
			"validators":[{
 | 
			
		||||
				"account":"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1",
 | 
			
		||||
				"validation_timestamp":{"secs_since_epoch":1557220355,"nanos_since_epoch":196382053}
 | 
			
		||||
			}],
 | 
			
		||||
			"deployment_timestamp":{"secs_since_epoch":1557220355,"nanos_since_epoch":196382053},
 | 
			
		||||
			"public_tx_hash":"0x69b9c691ede7993effbcc88911c309af1c82be67b04b3882dd446b808ae146da"
 | 
			
		||||
		}"#;
 | 
			
		||||
 | 
			
		||||
		let _deserialized: TransactionLog = serde_json::from_str(s).unwrap();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn private_log_status() {
 | 
			
		||||
		let logger = Logging::new(Arc::new(StringLogSerializer::new("".into())));
 | 
			
		||||
		let private_tx = Transaction::default();
 | 
			
		||||
		let hash = private_tx.hash(None);
 | 
			
		||||
		logger.private_tx_created(&hash, &vec!["0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1".into()]);
 | 
			
		||||
		logger.signature_added(&hash, &"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1".into());
 | 
			
		||||
		logger.tx_deployed(&hash, &hash);
 | 
			
		||||
		let tx_log = logger.tx_log(&hash).unwrap();
 | 
			
		||||
		assert_eq!(tx_log.status, PrivateTxStatus::Deployed);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn serialization() {
 | 
			
		||||
		let current_timestamp = SystemTime::now();
 | 
			
		||||
		let initial_validator_log = ValidatorLog {
 | 
			
		||||
			account: "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1".into(),
 | 
			
		||||
			validation_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(1)).unwrap()),
 | 
			
		||||
		};
 | 
			
		||||
		let initial_log = TransactionLog {
 | 
			
		||||
			tx_hash: "0x64f648ca7ae7f4138014f860ae56164d8d5732969b1cea54d8be9d144d8aa6f6".into(),
 | 
			
		||||
			status: PrivateTxStatus::Deployed,
 | 
			
		||||
			creation_timestamp: current_timestamp,
 | 
			
		||||
			validators: vec![initial_validator_log],
 | 
			
		||||
			deployment_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(2)).unwrap()),
 | 
			
		||||
			public_tx_hash: Some("0x69b9c691ede7993effbcc88911c309af1c82be67b04b3882dd446b808ae146da".into()),
 | 
			
		||||
		};
 | 
			
		||||
		let serializer = Arc::new(StringLogSerializer::new(serde_json::to_string(&vec![initial_log.clone()]).unwrap()));
 | 
			
		||||
		let logger = Logging::new(serializer.clone());
 | 
			
		||||
		let hash: H256 = "0x63c715e88f7291e66069302f6fcbb4f28a19ef5d7cbd1832d0c01e221c0061c6".into();
 | 
			
		||||
		logger.private_tx_created(&hash, &vec!["0x7ffbe3512782069be388f41be4d8eb350672d3a5".into()]);
 | 
			
		||||
		logger.signature_added(&hash, &"0x7ffbe3512782069be388f41be4d8eb350672d3a5".into());
 | 
			
		||||
		logger.tx_deployed(&hash, &"0xde2209a8635b9cab9eceb67928b217c70ab53f6498e5144492ec01e6f43547d7".into());
 | 
			
		||||
		drop(logger);
 | 
			
		||||
		let added_validator_log = ValidatorLog {
 | 
			
		||||
			account: "0x7ffbe3512782069be388f41be4d8eb350672d3a5".into(),
 | 
			
		||||
			validation_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(7)).unwrap()),
 | 
			
		||||
		};
 | 
			
		||||
		let added_log = TransactionLog {
 | 
			
		||||
			tx_hash: "0x63c715e88f7291e66069302f6fcbb4f28a19ef5d7cbd1832d0c01e221c0061c6".into(),
 | 
			
		||||
			status: PrivateTxStatus::Deployed,
 | 
			
		||||
			creation_timestamp: current_timestamp.checked_add(Duration::from_secs(6)).unwrap(),
 | 
			
		||||
			validators: vec![added_validator_log],
 | 
			
		||||
			deployment_timestamp: Some(current_timestamp.checked_add(Duration::from_secs(8)).unwrap()),
 | 
			
		||||
			public_tx_hash: Some("0xde2209a8635b9cab9eceb67928b217c70ab53f6498e5144492ec01e6f43547d7".into()),
 | 
			
		||||
		};
 | 
			
		||||
		let should_be_final = vec![added_log, initial_log];
 | 
			
		||||
		let deserialized_logs: Vec<TransactionLog> = serde_json::from_str(&serializer.log()).unwrap();
 | 
			
		||||
		assert_eq!(deserialized_logs, should_be_final);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -224,7 +224,7 @@ impl SigningStore {
 | 
			
		||||
		&mut self,
 | 
			
		||||
		private_hash: H256,
 | 
			
		||||
		transaction: SignedTransaction,
 | 
			
		||||
		validators: Vec<Address>,
 | 
			
		||||
		validators: &Vec<Address>,
 | 
			
		||||
		state: Bytes,
 | 
			
		||||
		contract_nonce: U256,
 | 
			
		||||
	) -> Result<(), Error> {
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,7 @@ fn private_contract() {
 | 
			
		||||
	let config = ProviderConfig{
 | 
			
		||||
		validator_accounts: vec![key3.address(), key4.address()],
 | 
			
		||||
		signer_account: None,
 | 
			
		||||
		logs_path: None,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	let io = ethcore_io::IoChannel::disconnected();
 | 
			
		||||
@ -193,6 +194,7 @@ fn call_other_private_contract() {
 | 
			
		||||
	let config = ProviderConfig{
 | 
			
		||||
		validator_accounts: vec![key3.address(), key4.address()],
 | 
			
		||||
		signer_account: None,
 | 
			
		||||
		logs_path: None,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	let io = ethcore_io::IoChannel::disconnected();
 | 
			
		||||
 | 
			
		||||
@ -69,11 +69,13 @@ fn send_private_transaction() {
 | 
			
		||||
	let validator_config = ProviderConfig{
 | 
			
		||||
		validator_accounts: vec![s1.address()],
 | 
			
		||||
		signer_account: None,
 | 
			
		||||
		logs_path: None,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	let signer_config = ProviderConfig{
 | 
			
		||||
		validator_accounts: Vec::new(),
 | 
			
		||||
		signer_account: Some(s0.address()),
 | 
			
		||||
		logs_path: None,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	let private_keys = Arc::new(StoringKeyProvider::default());
 | 
			
		||||
 | 
			
		||||
@ -914,9 +914,11 @@ impl Configuration {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn private_provider_config(&self) -> Result<(ProviderConfig, EncryptorConfig, bool), String> {
 | 
			
		||||
		let dirs = self.directories();
 | 
			
		||||
		let provider_conf = ProviderConfig {
 | 
			
		||||
			validator_accounts: to_addresses(&self.args.arg_private_validators)?,
 | 
			
		||||
			signer_account: self.args.arg_private_signer.clone().and_then(|account| to_address(Some(account)).ok()),
 | 
			
		||||
			logs_path: Some(dirs.base),
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		let encryptor_conf = EncryptorConfig {
 | 
			
		||||
@ -1458,7 +1460,11 @@ mod tests {
 | 
			
		||||
			net_settings: Default::default(),
 | 
			
		||||
			ipfs_conf: Default::default(),
 | 
			
		||||
			secretstore_conf: Default::default(),
 | 
			
		||||
			private_provider_conf: Default::default(),
 | 
			
		||||
			private_provider_conf: ProviderConfig {
 | 
			
		||||
				validator_accounts: Default::default(),
 | 
			
		||||
				signer_account: Default::default(),
 | 
			
		||||
				logs_path: Some(Directories::default().base),
 | 
			
		||||
			},
 | 
			
		||||
			private_encryptor_conf: Default::default(),
 | 
			
		||||
			private_tx_enabled: false,
 | 
			
		||||
			name: "".into(),
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,8 @@ use types::transaction::SignedTransaction;
 | 
			
		||||
 | 
			
		||||
use jsonrpc_core::{Error};
 | 
			
		||||
use v1::types::{Bytes, PrivateTransactionReceipt, TransactionRequest,
 | 
			
		||||
	BlockNumber, PrivateTransactionReceiptAndTransaction, CallRequest, block_number_to_id};
 | 
			
		||||
	BlockNumber, PrivateTransactionReceiptAndTransaction, CallRequest,
 | 
			
		||||
	block_number_to_id, PrivateTransactionLog};
 | 
			
		||||
use v1::traits::Private;
 | 
			
		||||
use v1::metadata::Metadata;
 | 
			
		||||
use v1::helpers::{errors, fake_sign};
 | 
			
		||||
@ -119,4 +120,11 @@ impl Private for PrivateClient {
 | 
			
		||||
		let key = client.contract_key_id(&contract_address).map_err(errors::private_message)?;
 | 
			
		||||
		Ok(key)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn private_log(&self, tx_hash: H256) -> Result<PrivateTransactionLog, Error> {
 | 
			
		||||
		self.unwrap_manager()?
 | 
			
		||||
			.private_log(tx_hash)
 | 
			
		||||
			.map_err(errors::private_message)
 | 
			
		||||
			.map(Into::into)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ use jsonrpc_core::Error;
 | 
			
		||||
use jsonrpc_derive::rpc;
 | 
			
		||||
 | 
			
		||||
use v1::types::{Bytes, PrivateTransactionReceipt, BlockNumber,
 | 
			
		||||
	PrivateTransactionReceiptAndTransaction, CallRequest};
 | 
			
		||||
	PrivateTransactionReceiptAndTransaction, CallRequest, PrivateTransactionLog};
 | 
			
		||||
 | 
			
		||||
/// Private transaction management RPC interface.
 | 
			
		||||
#[rpc]
 | 
			
		||||
@ -44,4 +44,8 @@ pub trait Private {
 | 
			
		||||
	/// Retrieve the id of the key associated with the contract
 | 
			
		||||
	#[rpc(name = "private_contractKey")]
 | 
			
		||||
	fn private_contract_key(&self, H160) -> Result<H256, Error>;
 | 
			
		||||
 | 
			
		||||
	/// Retrieve log information about private transaction
 | 
			
		||||
	#[rpc(name = "private_log")]
 | 
			
		||||
	fn private_log(&self, H256) -> Result<PrivateTransactionLog, Error>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,8 @@ mod histogram;
 | 
			
		||||
mod index;
 | 
			
		||||
mod log;
 | 
			
		||||
mod node_kind;
 | 
			
		||||
mod private_receipt;
 | 
			
		||||
mod private_log;
 | 
			
		||||
mod provenance;
 | 
			
		||||
mod receipt;
 | 
			
		||||
mod rpc_settings;
 | 
			
		||||
@ -43,7 +45,6 @@ mod transaction;
 | 
			
		||||
mod transaction_request;
 | 
			
		||||
mod transaction_condition;
 | 
			
		||||
mod work;
 | 
			
		||||
mod private_receipt;
 | 
			
		||||
mod eip191;
 | 
			
		||||
 | 
			
		||||
pub mod pubsub;
 | 
			
		||||
@ -65,6 +66,8 @@ pub use self::histogram::Histogram;
 | 
			
		||||
pub use self::index::Index;
 | 
			
		||||
pub use self::log::Log;
 | 
			
		||||
pub use self::node_kind::{NodeKind, Availability, Capability};
 | 
			
		||||
pub use self::private_receipt::{PrivateTransactionReceipt, PrivateTransactionReceiptAndTransaction};
 | 
			
		||||
pub use self::private_log::PrivateTransactionLog;
 | 
			
		||||
pub use self::provenance::Origin;
 | 
			
		||||
pub use self::receipt::Receipt;
 | 
			
		||||
pub use self::rpc_settings::RpcSettings;
 | 
			
		||||
@ -79,7 +82,6 @@ pub use self::transaction::{Transaction, RichRawTransaction, LocalTransactionSta
 | 
			
		||||
pub use self::transaction_request::TransactionRequest;
 | 
			
		||||
pub use self::transaction_condition::TransactionCondition;
 | 
			
		||||
pub use self::work::Work;
 | 
			
		||||
pub use self::private_receipt::{PrivateTransactionReceipt, PrivateTransactionReceiptAndTransaction};
 | 
			
		||||
 | 
			
		||||
// TODO [ToDr] Refactor to a proper type Vec of enums?
 | 
			
		||||
/// Expected tracing type.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										93
									
								
								rpc/src/v1/types/private_log.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								rpc/src/v1/types/private_log.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
			
		||||
// 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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use std::time::SystemTime;
 | 
			
		||||
use ethereum_types::{H160, H256};
 | 
			
		||||
use ethcore_private_tx::{TransactionLog as EthTransactionLog, ValidatorLog as EthValidatorLog, PrivateTxStatus as EthStatus};
 | 
			
		||||
 | 
			
		||||
/// Current status of the private transaction
 | 
			
		||||
#[derive(Serialize, Debug)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub enum Status {
 | 
			
		||||
	/// Private tx was created but no validation received yet
 | 
			
		||||
	Created,
 | 
			
		||||
	/// Several validators (but not all) validated the transaction
 | 
			
		||||
	Validating,
 | 
			
		||||
	/// All validators validated the private tx
 | 
			
		||||
	/// Corresponding public tx was created and added into the pool
 | 
			
		||||
	Deployed,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<EthStatus> for Status {
 | 
			
		||||
	fn from(c: EthStatus) -> Self {
 | 
			
		||||
		match c {
 | 
			
		||||
			EthStatus::Created => Status::Created,
 | 
			
		||||
			EthStatus::Validating => Status::Validating,
 | 
			
		||||
			EthStatus::Deployed => Status::Deployed,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Information about private tx validation
 | 
			
		||||
#[derive(Debug, Serialize)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub struct ValidatorLog {
 | 
			
		||||
	/// Account of the validator
 | 
			
		||||
	pub account: H160,
 | 
			
		||||
	/// Validation timestamp, None, if the transaction is not validated yet
 | 
			
		||||
	pub validation_timestamp: Option<u64>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<EthValidatorLog> for ValidatorLog {
 | 
			
		||||
	fn from(r: EthValidatorLog) -> Self {
 | 
			
		||||
		ValidatorLog {
 | 
			
		||||
			account: r.account,
 | 
			
		||||
			validation_timestamp: r.validation_timestamp.map(|t| t.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default().as_secs()),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Information about the private transaction
 | 
			
		||||
#[derive(Debug, Serialize)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub struct PrivateTransactionLog {
 | 
			
		||||
	/// Original signed transaction hash (used as a source for private tx)
 | 
			
		||||
	pub tx_hash: H256,
 | 
			
		||||
	/// Current status of the private transaction
 | 
			
		||||
	pub status: Status,
 | 
			
		||||
	/// Creation timestamp
 | 
			
		||||
	pub creation_timestamp: u64,
 | 
			
		||||
	/// List of validations
 | 
			
		||||
	pub validators: Vec<ValidatorLog>,
 | 
			
		||||
	/// Timestamp of the resulting public tx deployment
 | 
			
		||||
	pub deployment_timestamp: Option<u64>,
 | 
			
		||||
	/// Hash of the resulting public tx
 | 
			
		||||
	pub public_tx_hash: Option<H256>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<EthTransactionLog> for PrivateTransactionLog {
 | 
			
		||||
	fn from(r: EthTransactionLog) -> Self {
 | 
			
		||||
		PrivateTransactionLog {
 | 
			
		||||
			tx_hash: r.tx_hash,
 | 
			
		||||
			status: r.status.into(),
 | 
			
		||||
			creation_timestamp: r.creation_timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default().as_secs(),
 | 
			
		||||
			validators: r.validators.into_iter().map(Into::into).collect(),
 | 
			
		||||
			deployment_timestamp: r.deployment_timestamp.map(|t| t.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default().as_secs()),
 | 
			
		||||
			public_tx_hash: r.public_tx_hash,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user