blockchain.rs 51.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/>.

//! Blockchain database.
Marek Kotewicz's avatar
Marek Kotewicz committed
use rocksdb::{DB, WriteBatch, Writable};
use header::*;
Marek Kotewicz's avatar
Marek Kotewicz committed
use extras::*;
use transaction::*;
Marek Kotewicz's avatar
Marek Kotewicz committed
use views::*;
use chainfilter::{ChainFilter, BloomIndex, FilterDataSource};

const BLOOM_INDEX_SIZE: usize = 16;
const BLOOM_LEVELS: u8 = 3;
Marek Kotewicz's avatar
Marek Kotewicz committed

/// Represents a tree route between `from` block and `to` block:
pub struct TreeRoute {
	/// A vector of hashes of all blocks, ordered from `from` to `to`.
	pub blocks: Vec<H256>,
	/// Best common ancestor of these blocks.
	pub ancestor: H256,
	/// An index where best common ancestor would be.
	pub index: usize
}

/// Represents blockchain's in-memory cache size in bytes.
#[derive(Debug)]
pub struct CacheSize {
	/// Blocks cache size.
	pub blocks: usize,
	/// BlockDetails cache size.
	pub block_details: usize,
	/// Transaction addresses cache size.
	pub transaction_addresses: usize,
	/// Logs cache size.
	pub block_logs: usize,
	/// Blooms cache size.
	pub blocks_blooms: usize
}

struct BloomIndexer {
	index_size: usize,
	levels: u8
}

impl BloomIndexer {
	fn new(index_size: usize, levels: u8) -> Self {
		BloomIndexer {
			index_size: index_size,
			levels: levels
		}
	}

	/// Calculates bloom's position in database.
	fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation {
		use std::{mem, ptr};
		
		let hash = unsafe {
			let mut hash: H256 = mem::zeroed();
			ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8);
			hash[8] = bloom_index.level;
			hash.reverse();
			hash
		};

		BlocksBloomLocation {
			hash: hash,
			index: bloom_index.index % self.index_size
		}
	}

	fn index_size(&self) -> usize {
		self.index_size
	}

	fn levels(&self) -> u8 {
		self.levels
	}
}

/// Blockchain update info.
struct ExtrasUpdate {
	/// Block hash.
	hash: H256,
	/// DB update batch.
	batch: WriteBatch,
	/// Inserted block familial details.
	details: BlockDetails,
	/// New best block (if it has changed).
	new_best: Option<BestBlock>,
	/// Changed blocks bloom location hashes.
	bloom_hashes: HashSet<H256>
}

Gav Wood's avatar
Gav Wood committed
impl CacheSize {
	/// Total amount used by the cache.
	fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms }
}

Marek Kotewicz's avatar
Marek Kotewicz committed
/// Information about best block gathered together
struct BestBlock {
	pub hash: H256,
	pub total_difficulty: U256
}

impl BestBlock {
	fn new() -> BestBlock {
		BestBlock {
			hash: H256::new(),
			total_difficulty: U256::from(0)
		}
	}
}

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;

	/// Get raw block data
	fn block(&self, hash: &H256) -> Option<Bytes>;

	/// 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>;

Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
	/// Get the partial-header of a block.
	fn block_header(&self, hash: &H256) -> Option<Header> {
		self.block(hash).map(|bytes| BlockView::new(&bytes).header())
	}

	/// Get a list of uncles for a given block.
	/// Returns None if block deos not exist.
	fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
		self.block(hash).map(|bytes| BlockView::new(&bytes).uncles())
	}

	/// 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(hash).map(|bytes| BlockView::new(&bytes).uncle_hashes())
	}

	/// Get the number of given block's hash.
	fn block_number(&self, hash: &H256) -> Option<BlockNumber> {
		self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number())
	}

	/// Get transaction with given transaction hash.
	fn transaction(&self, address: &TransactionAddress) -> Option<LocalizedTransaction> {
		self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(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>> {
		self.block(hash).map(|bytes| BlockView::new(&bytes).localized_transactions())
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) -> Header {
		self.block_header(&self.genesis_hash()).unwrap()
	}

	/// Returns numbers of blocks containing given bloom.
	fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>;
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
Gav Wood's avatar
Gav Wood committed
enum CacheID {
	Block(H256),
	Extras(ExtrasIndex, H256),
Loading full blame...