blockchain.rs 85.8 KiB
Newer Older
// 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/>.

//! Blockchain database.
use std::collections::{HashMap, HashSet};
Marek Kotewicz's avatar
Marek Kotewicz committed
use std::sync::Arc;
Marek Kotewicz's avatar
Marek Kotewicz committed
use std::mem;
use blooms_db;
use heapsize::HeapSizeOf;
use ethereum_types::{H256, Bloom, BloomRef, U256};
use parking_lot::{Mutex, RwLock};
use rlp_compress::{compress, decompress, blocks_swapper};
use header::*;
use transaction::*;
use views::{BlockView, HeaderView};
use log_entry::{LogEntry, LocalizedLogEntry};
use blockchain::best_block::{BestBlock, BestAncientBlock};
use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
use blockchain::extras::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions};
use types::blockchain_info::BlockChainInfo;
use blockchain::update::{ExtrasUpdate, ExtrasInsert};
Marek Kotewicz's avatar
Marek Kotewicz committed
use blockchain::{CacheSize, ImportRoute, Config};
use db::{self, Writable, Readable, CacheUpdatePolicy};
use cache_manager::CacheManager;
use engines::ForkChoice;
use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition};
use rayon::prelude::*;
use ansi_term::Colour;
use kvdb::{DBTransaction, KeyValueDB};
use error::Error;
use std::path::Path;
/// Database backing `BlockChain`.
pub trait BlockChainDB: Send + Sync {
	/// Generic key value store.
	fn key_value(&self) -> &Arc<KeyValueDB>;

	/// Header blooms database.
	fn blooms(&self) -> &blooms_db::Database;

	/// Trace blooms database.
	fn trace_blooms(&self) -> &blooms_db::Database;
}

/// Generic database handler. This trait contains one function `open`. When called, it opens database with a
/// predefined config.
pub trait BlockChainDBHandler: Send + Sync {
	/// Open the predefined key-value database.
	fn open(&self, path: &Path) -> Result<Arc<BlockChainDB>, Error>;
}
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
/// Interface for querying blocks by hash and by number.
pub trait BlockProvider {
	/// Returns true if the given block is known
	/// (though not necessarily a part of the canon chain).
	fn is_known(&self, hash: &H256) -> bool;

	/// Returns true if the given block is known and in the canon chain.
	fn is_canon(&self, hash: &H256) -> bool {
		let is_canon = || Some(hash == &self.block_hash(self.block_number(hash)?)?);
		is_canon().unwrap_or(false)
	}

	/// Get the first block of the best part of the chain.
	/// Return `None` if there is no gap and the first block is the genesis.
	/// Any queries of blocks which precede this one are not guaranteed to
	/// succeed.
	fn first_block(&self) -> Option<H256>;

	/// Get the number of the first block.
	fn first_block_number(&self) -> Option<BlockNumber> {
		self.first_block().map(|b| self.block_number(&b).expect("First block is always set to an existing block or `None`. Existing block always has a number; qed"))
	/// Get the best block of an first block sequence if there is a gap.
	fn best_ancient_block(&self) -> Option<H256>;

	/// Get the number of the first block.
	fn best_ancient_number(&self) -> Option<BlockNumber> {
		self.best_ancient_block().map(|h| self.block_number(&h).expect("Ancient block is always set to an existing block or `None`. Existing block always has a number; qed"))
	}
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Get raw block data
	fn block(&self, hash: &H256) -> Option<encoded::Block>;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed

	/// Get the familial details concerning a block.
	fn block_details(&self, hash: &H256) -> Option<BlockDetails>;

	/// Get the hash of given block's number.
	fn block_hash(&self, index: BlockNumber) -> Option<H256>;

	/// Get the address of transaction with given hash.
	fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress>;

	/// Get receipts of block with given hash.
	fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts>;

Tomasz Drwięga's avatar
Tomasz Drwięga committed
	/// Get the header RLP of a block.
	fn block_header_data(&self, hash: &H256) -> Option<encoded::Header>;
Tomasz Drwięga's avatar
Tomasz Drwięga committed

	/// Get the block body (uncles and transactions).
	fn block_body(&self, hash: &H256) -> Option<encoded::Body>;
Tomasz Drwięga's avatar
Tomasz Drwięga committed

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Get a list of uncles for a given block.
Gav Wood's avatar
Gav Wood committed
	/// Returns None if block does not exist.
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
		self.block_body(hash).map(|body| body.uncles())
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	}

	/// Get a list of uncle hashes for a given block.
	/// Returns None if block does not exist.
	fn uncle_hashes(&self, hash: &H256) -> Option<Vec<H256>> {
		self.block_body(hash).map(|body| body.uncle_hashes())
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	}

	/// Get the number of given block's hash.
	fn block_number(&self, hash: &H256) -> Option<BlockNumber> {
		self.block_header_data(hash).map(|header| header.number())
	/// Get transaction with given transaction hash.
	fn transaction(&self, address: &TransactionAddress) -> Option<LocalizedTransaction> {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		self.block_body(&address.block_hash)
			.and_then(|body| self.block_number(&address.block_hash)
			.and_then(|n| body.view().localized_transaction_at(&address.block_hash, n, address.index)))
Marek Kotewicz's avatar
Marek Kotewicz committed
	/// Get transaction receipt.
	fn transaction_receipt(&self, address: &TransactionAddress) -> Option<Receipt> {
		self.block_receipts(&address.block_hash).and_then(|br| br.receipts.into_iter().nth(address.index))
	}

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Get a list of transactions for a given block.
	/// Returns None if block does not exist.
Marek Kotewicz's avatar
Marek Kotewicz committed
	fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
		self.block_body(hash)
			.and_then(|body| self.block_number(hash)
			.map(|n| body.view().localized_transactions(hash, n)))
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	}

	/// Returns reference to genesis hash.
	fn genesis_hash(&self) -> H256 {
		self.block_hash(0).expect("Genesis hash should always exist")
	}

	/// Returns the header of the genesis block.
	fn genesis_header(&self) -> encoded::Header {
		self.block_header_data(&self.genesis_hash())
			.expect("Genesis header always stored; qed")

	/// Returns numbers of blocks containing given bloom.
	fn blocks_with_bloom<'a, B, I, II>(&self, blooms: II, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>
	where
		BloomRef<'a>: From<B>,
		II: IntoIterator<Item = B, IntoIter = I> + Copy,
		I: Iterator<Item = B>,
		Self: Sized;

	/// Returns logs matching given filter.
	fn logs<F>(&self, blocks: Vec<H256>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
		where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized;
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
enum CacheId {
Tomasz Drwięga's avatar
Tomasz Drwięga committed
	BlockHeader(H256),
	BlockBody(H256),
Marek Kotewicz's avatar
Marek Kotewicz committed
	BlockDetails(H256),
	BlockHashes(BlockNumber),
	TransactionAddresses(H256),
	BlockReceipts(H256),
/// Structure providing fast access to blockchain data.
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
///
Marek Kotewicz's avatar
Marek Kotewicz committed
/// **Does not do input data verification.**
Marek Kotewicz's avatar
Marek Kotewicz committed
pub struct BlockChain {
	// All locks must be captured in the order declared here.
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	best_block: RwLock<BestBlock>,
	// Stores best block of the first uninterrupted sequence of blocks. `None` if there are no gaps.
Loading full blame...