client.rs 36.2 KiB
Newer Older
// Copyright 2015, 2016 Ethcore (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/>.
Gav Wood's avatar
Gav Wood committed
use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
Marek Kotewicz's avatar
Marek Kotewicz committed
use std::path::{Path};
use std::fmt;
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant};
Gav Wood's avatar
Gav Wood committed
use time::precise_time_ns;
asynchronous rob's avatar
asynchronous rob committed
use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock};
use util::journaldb::{self, JournalDB};
use util::{U256, H256, Address, H2048, Uint};
use util::sha3::*;
asynchronous rob's avatar
asynchronous rob committed
use util::TrieFactory;
use util::kvdb::*;

// other
Tomasz Drwięga's avatar
Tomasz Drwięga committed
use views::{BlockView, HeaderView, BodyView};
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult};
use header::BlockNumber;
use spec::Spec;
use basic_types::Seal;
use engines::Engine;
use service::ClientIoMessage;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
use env_info::LastHashes;
use verification;
use verification::{PreverifiedBlock, Verifier};
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
use block::*;
Marek Kotewicz's avatar
Marek Kotewicz committed
use transaction::{LocalizedTransaction, SignedTransaction, Action};
Marek Kotewicz's avatar
Marek Kotewicz committed
use blockchain::extras::TransactionAddress;
use types::filter::Filter;
use log_entry::LocalizedLogEntry;
use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
Gav Wood's avatar
Gav Wood committed
use client::{
	BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient,
	MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
	ChainNotify
};
use client::Error as ClientError;
Marek Kotewicz's avatar
Marek Kotewicz committed
use env_info::EnvInfo;
use executive::{Executive, Executed, TransactOptions, contract_address};
use receipt::LocalizedReceipt;
Tomasz Drwięga's avatar
Tomasz Drwięga committed
use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase};
use trace;
use trace::FlatTransactionTraces;
use evm::Factory as EvmFactory;
use snapshot::{self, io as snapshot_io};
asynchronous rob's avatar
asynchronous rob committed
use rlp::{View, UntrustedRlp};


// re-export
pub use types::blockchain_info::BlockChainInfo;
pub use types::block_status::BlockStatus;
pub use blockchain::CacheSize as BlockChainCacheSize;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
const MAX_TX_QUEUE_SIZE: usize = 4096;
const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;
Gav Wood's avatar
Gav Wood committed
impl fmt::Display for BlockChainInfo {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "#{}.{}", self.best_block_number, self.best_block_hash)
	}
}

Gav Wood's avatar
Gav Wood committed
/// Report on the status of a client.
#[derive(Default, Clone, Debug, Eq, PartialEq)]
Gav Wood's avatar
Gav Wood committed
pub struct ClientReport {
Gav Wood's avatar
Gav Wood committed
	/// How many blocks have been imported so far.
Gav Wood's avatar
Gav Wood committed
	pub blocks_imported: usize,
Gav Wood's avatar
Gav Wood committed
	/// How many transactions have been applied so far.
Gav Wood's avatar
Gav Wood committed
	pub transactions_applied: usize,
Gav Wood's avatar
Gav Wood committed
	/// How much gas has been processed so far.
Gav Wood's avatar
Gav Wood committed
	pub gas_processed: U256,
Gav Wood's avatar
Gav Wood committed
	/// Memory used by state DB
	pub state_db_mem: usize,
Gav Wood's avatar
Gav Wood committed
}

impl ClientReport {
Gav Wood's avatar
Gav Wood committed
	/// Alter internal reporting to reflect the additional `block` has been processed.
	pub fn accrue_block(&mut self, block: &PreverifiedBlock) {
Gav Wood's avatar
Gav Wood committed
		self.blocks_imported += 1;
		self.transactions_applied += block.transactions.len();
		self.gas_processed = self.gas_processed + block.header.gas_used().clone();
struct SleepState {
	last_activity: Option<Instant>,
	last_autosleep: Option<Instant>,
}

impl SleepState {
	fn new(awake: bool) -> Self {
		SleepState {
			last_activity: match awake { false => None, true => Some(Instant::now()) },
			last_autosleep: match awake { false => Some(Instant::now()), true => None },
		}
	}
}

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
	mode: Mode,
	chain: Arc<BlockChain>,
	tracedb: Arc<TraceDB<BlockChain>>,
	engine: Arc<Engine>,
Tomasz Drwięga's avatar
Tomasz Drwięga committed
	db: Arc<Database>,
Gav Wood's avatar
Gav Wood committed
	state_db: Mutex<Box<JournalDB>>,
	block_queue: BlockQueue,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	report: RwLock<ClientReport>,
Tomusdrw's avatar
Tomusdrw committed
	panic_handler: Arc<PanicHandler>,
	verifier: Box<Verifier>,
	miner: Arc<Miner>,
	sleep_state: Mutex<SleepState>,
	liveness: AtomicBool,
	io_channel: IoChannel<ClientIoMessage>,
	notify: RwLock<Vec<Weak<ChainNotify>>>,
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	queue_transactions: AtomicUsize,
	last_hashes: RwLock<VecDeque<H256>>,
const HISTORY: u64 = 1200;
Gav Wood's avatar
Gav Wood committed
/// Append a path element to the given path and return the string.
Marek Kotewicz's avatar
Marek Kotewicz committed
pub fn append_path<P>(path: P, item: &str) -> String where P: AsRef<Path> {
	let mut p = path.as_ref().to_path_buf();
Gav Wood's avatar
Gav Wood committed
	p.push(item);
	p.to_str().unwrap().to_owned()
}

	/// Create a new client with given spec and DB path and custom verifier.
		config: ClientConfig,
		miner: Arc<Miner>,
		message_channel: IoChannel<ClientIoMessage>,
	) -> Result<Arc<Client>, ClientError> {
Marek Kotewicz's avatar
Marek Kotewicz committed
		let path = path.to_path_buf();
		let gb = spec.genesis_block();
		let mut db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		db_config.cache_size = config.db_cache_size;
		db_config.compaction = config.db_compaction.compaction_profile();
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		db_config.wal = config.db_wal;
Gav Wood's avatar
Gav Wood committed
		let db = Arc::new(try!(Database::open(&db_config, &path.to_str().unwrap()).map_err(ClientError::Database)));
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		let chain = Arc::new(BlockChain::new(config.blockchain, &gb, db.clone()));
		let tracedb = Arc::new(try!(TraceDB::new(config.tracing, db.clone(), chain.clone())));
		let mut state_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE);
		if state_db.is_empty() && try!(spec.ensure_db_good(state_db.as_hashdb_mut())) {
			let mut batch = DBTransaction::new(&db);
			try!(state_db.commit(&mut batch, 0, &spec.genesis_header().hash(), None));
Gav Wood's avatar
Gav Wood committed
			try!(db.write(batch).map_err(ClientError::Database));
		if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.contains(h.state_root())) {
			warn!("State root not found for block #{} ({})", chain.best_block_number(), chain.best_block_hash().hex());
		}

		let engine = spec.engine.clone();
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
		let block_queue = BlockQueue::new(config.queue, engine.clone(), message_channel.clone());
Tomusdrw's avatar
Tomusdrw committed
		let panic_handler = PanicHandler::new_in_arc();
		panic_handler.forward_from(&block_queue);
		let awake = match config.mode { Mode::Dark(..) => false, _ => true };

		let factories = Factories {
			vm: EvmFactory::new(config.vm_type),
			trie: TrieFactory::new(config.trie_spec),
			accountdb: Default::default(),
		};

		let client = Client {
			sleep_state: Mutex::new(SleepState::new(awake)),
Loading full blame...