diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 764b76588..b8ce09a63 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -23,24 +23,6 @@ use extras::*; use transaction::*; use views::*; -/// Uniquely identifies block. -pub enum BlockId { - /// Block's sha3. - /// Querying by hash is always faster. - Hash(H256), - /// Block number within canon blockchain. - Number(BlockNumber) -} - -/// Uniquely identifies transaction. -pub enum TransactionId { - /// Transaction's sha3. - Hash(H256), - /// Block id and transaction index within this block. - /// Querying by block position is always faster. - Location(BlockId, usize) -} - /// 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`. @@ -129,18 +111,8 @@ pub trait BlockProvider { } /// Get transaction with given transaction hash. - fn transaction(&self, id: TransactionId) -> Option { - match id { - TransactionId::Hash(ref hash) => self.transaction_address(hash), - TransactionId::Location(BlockId::Hash(hash), index) => Some(TransactionAddress { - block_hash: hash, - index: index - }), - TransactionId::Location(BlockId::Number(number), index) => self.block_hash(number).map(|hash| TransactionAddress { - block_hash: hash, - index: index - }) - }.and_then(|address| self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index))) + fn transaction(&self, address: &TransactionAddress) -> Option { + self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)) } /// Get a list of transactions for a given block. diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 3de5c097e..ad102f3e2 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -18,7 +18,7 @@ use util::*; use rocksdb::{Options, DB, DBCompactionStyle}; -use blockchain::{BlockChain, BlockProvider, CacheSize, TransactionId}; +use blockchain::{BlockChain, BlockProvider, CacheSize}; use views::BlockView; use error::*; use header::BlockNumber; @@ -32,8 +32,27 @@ use env_info::LastHashes; use verification::*; use block::*; use transaction::LocalizedTransaction; +use extras::TransactionAddress; pub use blockchain::TreeRoute; +/// Uniquely identifies block. +pub enum BlockId { + /// Block's sha3. + /// Querying by hash is always faster. + Hash(H256), + /// Block number within canon blockchain. + Number(BlockNumber) +} + +/// Uniquely identifies transaction. +pub enum TransactionId { + /// Transaction's sha3. + Hash(H256), + /// Block id and transaction index within this block. + /// Querying by block position is always faster. + Location(BlockId, usize) +} + /// General block status #[derive(Debug, Eq, PartialEq)] pub enum BlockStatus { @@ -70,41 +89,25 @@ impl fmt::Display for BlockChainInfo { /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { - /// Get raw block header data by block header hash. - fn block_header(&self, hash: &H256) -> Option; + /// Get raw block header data by block id. + fn block_header(&self, id: BlockId) -> Option; - /// Get raw block body data by block header hash. + /// Get raw block body data by block id. /// Block body is an RLP list of two items: uncles and transactions. - fn block_body(&self, hash: &H256) -> Option; + fn block_body(&self, id: BlockId) -> Option; /// Get raw block data by block header hash. - fn block(&self, hash: &H256) -> Option; + fn block(&self, id: BlockId) -> Option; /// Get block status by block header hash. - fn block_status(&self, hash: &H256) -> BlockStatus; + fn block_status(&self, id: BlockId) -> BlockStatus; /// Get block total difficulty. - fn block_total_difficulty(&self, hash: &H256) -> Option; + fn block_total_difficulty(&self, id: BlockId) -> Option; /// Get address code. fn code(&self, address: &Address) -> Option; - /// Get raw block header data by block number. - fn block_header_at(&self, n: BlockNumber) -> Option; - - /// Get raw block body data by block number. - /// Block body is an RLP list of two items: uncles and transactions. - fn block_body_at(&self, n: BlockNumber) -> Option; - - /// Get raw block data by block number. - fn block_at(&self, n: BlockNumber) -> Option; - - /// Get block status by block number. - fn block_status_at(&self, n: BlockNumber) -> BlockStatus; - - /// Get block total difficulty. - fn block_total_difficulty_at(&self, n: BlockNumber) -> Option; - /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; @@ -132,7 +135,7 @@ pub trait BlockChainClient : Sync + Send { /// Get the best block header. fn best_block_header(&self) -> Bytes { - self.block_header(&self.chain_info().best_block_hash).unwrap() + self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() } } @@ -332,68 +335,62 @@ impl Client { pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { self.chain.write().unwrap().configure_cache(pref_cache_size, max_cache_size); } + + fn block_hash(&self, id: BlockId) -> Option { + match id { + BlockId::Hash(hash) => Some(hash), + BlockId::Number(number) => self.chain.read().unwrap().block_hash(number) + } + } } impl BlockChainClient for Client { - fn block_header(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block(hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()) + fn block_header(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.chain.read().unwrap().block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) } - fn block_body(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block(hash).map(|bytes| { - let rlp = Rlp::new(&bytes); - let mut body = RlpStream::new(); - body.append_raw(rlp.at(1).as_raw(), 1); - body.append_raw(rlp.at(2).as_raw(), 1); - body.out() + fn block_body(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| { + self.chain.read().unwrap().block(&hash).map(|bytes| { + let rlp = Rlp::new(&bytes); + let mut body = RlpStream::new(); + body.append_raw(rlp.at(1).as_raw(), 1); + body.append_raw(rlp.at(2).as_raw(), 1); + body.out() + }) }) } - fn block(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block(hash) + fn block(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| { + self.chain.read().unwrap().block(&hash) + }) } - fn block_status(&self, hash: &H256) -> BlockStatus { - if self.chain.read().unwrap().is_known(&hash) { - BlockStatus::InChain - } else { - self.block_queue.read().unwrap().block_status(hash) + fn block_status(&self, id: BlockId) -> BlockStatus { + match self.block_hash(id) { + Some(ref hash) if self.chain.read().unwrap().is_known(hash) => BlockStatus::InChain, + Some(hash) => self.block_queue.read().unwrap().block_status(&hash), + None => BlockStatus::Unknown } } - fn block_total_difficulty(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty) + fn block_total_difficulty(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.chain.read().unwrap().block_details(&hash)).map(|d| d.total_difficulty) } fn code(&self, address: &Address) -> Option { self.state().code(address) } - fn block_header_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h)) - } - - fn block_body_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_body(&h)) - } - - fn block_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block(&h)) - } - - fn block_status_at(&self, n: BlockNumber) -> BlockStatus { - match self.chain.read().unwrap().block_hash(n) { - Some(h) => self.block_status(&h), - None => BlockStatus::Unknown - } - } - - fn block_total_difficulty_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_total_difficulty(&h)) - } - fn transaction(&self, id: TransactionId) -> Option { - self.chain.read().unwrap().transaction(id) + match id { + TransactionId::Hash(ref hash) => self.chain.read().unwrap().transaction_address(hash), + TransactionId::Location(id, index) => self.block_hash(id).map(|hash| TransactionAddress { + block_hash: hash, + index: index + }) + }.and_then(|address| self.chain.read().unwrap().transaction(&address)) } fn tree_route(&self, from: &H256, to: &H256) -> Option { @@ -413,7 +410,7 @@ impl BlockChainClient for Client { if self.chain.read().unwrap().is_known(&header.hash()) { return Err(ImportError::AlreadyInChain); } - if self.block_status(&header.parent_hash) == BlockStatus::Unknown { + if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { return Err(ImportError::UnknownParent); } self.block_queue.write().unwrap().import_block(bytes) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 19ab7a389..d9f65adc0 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,7 +23,6 @@ use util::uint::*; use util::sha3::*; use ethcore::client::*; use ethcore::views::*; -use ethcore::blockchain::{BlockId, TransactionId}; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index}; @@ -110,7 +109,7 @@ impl Eth for EthClient { fn block_transaction_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(&hash) { + .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), None => Ok(Value::Null) }) @@ -118,7 +117,7 @@ impl Eth for EthClient { fn block_uncles_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(&hash) { + .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), None => Ok(Value::Null) }) @@ -132,7 +131,7 @@ impl Eth for EthClient { fn block(&self, params: Params) -> Result { from_params::<(H256, bool)>(params) - .and_then(|(hash, include_txs)| match (self.client.block(&hash), self.client.block_total_difficulty(&hash)) { + .and_then(|(hash, include_txs)| match (self.client.block(BlockId::Hash(hash.clone())), self.client.block_total_difficulty(BlockId::Hash(hash))) { (Some(bytes), Some(total_difficulty)) => { let block_view = BlockView::new(&bytes); let view = block_view.header_view(); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 63dc47024..b3dfc71f5 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -33,7 +33,7 @@ use util::*; use std::mem::{replace}; use ethcore::views::{HeaderView}; use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockChainClient, BlockStatus}; +use ethcore::client::{BlockChainClient, BlockStatus, BlockId}; use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::block::Block; @@ -331,7 +331,7 @@ impl ChainSync { self.highest_block = Some(number); } let hash = info.hash(); - match io.chain().block_status(&hash) { + match io.chain().block_status(BlockId::Hash(hash.clone())) { BlockStatus::InChain => { self.have_common_block = true; self.last_imported_block = Some(number); @@ -491,7 +491,7 @@ impl ChainSync { for (rh, rd) in hashes { let h = try!(rh); let d = try!(rd); - match io.chain().block_status(&h) { + match io.chain().block_status(BlockId::Hash(h.clone())) { BlockStatus::InChain => { trace!(target: "sync", "New block hash already in chain {:?}", h); }, @@ -877,7 +877,7 @@ impl ChainSync { // id is a hash let hash: H256 = try!(r.val_at(0)); trace!(target: "sync", "-> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", hash, max_headers, skip, reverse); - match io.chain().block_header(&hash) { + match io.chain().block_header(BlockId::Hash(hash)) { Some(hdr) => From::from(HeaderView::new(&hdr).number()), None => last } @@ -897,7 +897,7 @@ impl ChainSync { let mut data = Bytes::new(); let inc = (skip + 1) as BlockNumber; while number <= last && number > 0 && count < max_count { - if let Some(mut hdr) = io.chain().block_header_at(number) { + if let Some(mut hdr) = io.chain().block_header(BlockId::Number(number)) { data.append(&mut hdr); count += 1; } @@ -929,7 +929,7 @@ impl ChainSync { let mut added = 0usize; let mut data = Bytes::new(); for i in 0..count { - if let Some(mut hdr) = io.chain().block_body(&try!(r.val_at::(i))) { + if let Some(mut hdr) = io.chain().block_body(BlockId::Hash(try!(r.val_at::(i)))) { data.append(&mut hdr); added += 1; } @@ -1060,7 +1060,7 @@ impl ChainSync { let mut rlp_stream = RlpStream::new_list(route.blocks.len()); for block_hash in route.blocks { let mut hash_rlp = RlpStream::new_list(2); - let difficulty = chain.block_total_difficulty(&block_hash).expect("Mallformed block without a difficulty on the chain!"); + let difficulty = chain.block_total_difficulty(BlockId::Hash(block_hash.clone())).expect("Mallformed block without a difficulty on the chain!"); hash_rlp.append(&block_hash); hash_rlp.append(&difficulty); rlp_stream.append_raw(&hash_rlp.out(), 1); @@ -1076,7 +1076,7 @@ impl ChainSync { /// creates latest block rlp for the given client fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes { let mut rlp_stream = RlpStream::new_list(2); - rlp_stream.append_raw(&chain.block(&chain.chain_info().best_block_hash).expect("Creating latest block when there is none"), 1); + rlp_stream.append_raw(&chain.block(BlockId::Hash(chain.chain_info().best_block_hash)).expect("Creating latest block when there is none"), 1); rlp_stream.append(&chain.chain_info().total_difficulty); rlp_stream.out() } @@ -1088,10 +1088,10 @@ impl ChainSync { let latest_hash = chain_info.best_block_hash; let latest_number = chain_info.best_block_number; self.peers.iter().filter(|&(_, peer_info)| - match io.chain().block_status(&peer_info.latest) + match io.chain().block_status(BlockId::Hash(peer_info.latest.clone())) { BlockStatus::InChain => { - let peer_number = HeaderView::new(&io.chain().block_header(&peer_info.latest).unwrap()).number(); + let peer_number = HeaderView::new(&io.chain().block_header(BlockId::Hash(peer_info.latest.clone())).unwrap()).number(); peer_info.latest != latest_hash && latest_number > peer_number && latest_number - peer_number < MAX_PEER_LAG_PROPAGATION }, _ => false @@ -1478,4 +1478,4 @@ mod tests { let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); assert!(result.is_ok()); } -} \ No newline at end of file +}