diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index f8e9de3f4..723d89b80 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -39,8 +39,18 @@ impl Block { pub fn is_good(b: &[u8]) -> bool { UntrustedRlp::new(b).as_val::().is_ok() } + + /// Get the RLP-encoding of the block without the seal. + pub fn rlp_bytes(&self, seal: Seal) -> Bytes { + let mut block_rlp = RlpStream::new_list(3); + self.header.stream_rlp(&mut block_rlp, seal); + block_rlp.append(&self.transactions); + block_rlp.append(&self.uncles); + block_rlp.out() + } } + impl Decodable for Block { fn decode(decoder: &D) -> Result where D: Decoder { if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() { @@ -140,9 +150,12 @@ impl ExecutedBlock { /// Trait for a object that is a `ExecutedBlock`. pub trait IsBlock { - /// Get the block associated with this object. + /// Get the `ExecutedBlock` associated with this object. fn block(&self) -> &ExecutedBlock; + /// Get the base `Block` object associated with this. + fn base(&self) -> &Block { &self.block().base } + /// Get the header associated with this object's block. fn header(&self) -> &Header { &self.block().base.header } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 2b1286ef4..344add17b 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -44,6 +44,7 @@ use error::{ImportError, ExecutionError, BlockError, ImportResult}; use header::BlockNumber; use state::State; use spec::Spec; +use basic_types::Seal; use engine::Engine; use views::HeaderView; use service::ClientIoMessage; @@ -462,8 +463,10 @@ impl Client { /// Otherwise, this can fail (but may not) if the DB prunes state. pub fn state_at(&self, id: BlockID) -> Option { // fast path for latest state. - if let BlockID::Latest = id.clone() { - return Some(self.state()) + match id.clone() { + BlockID::Pending => return self.miner.pending_state().or_else(|| Some(self.state())), + BlockID::Latest => return Some(self.state()), + _ => {}, } let block_number = match self.block_number(id.clone()) { @@ -556,7 +559,7 @@ impl Client { BlockID::Number(number) => Some(number), BlockID::Hash(ref hash) => self.chain.block_number(hash), BlockID::Earliest => Some(0), - BlockID::Latest => Some(self.chain.best_block_number()) + BlockID::Latest | BlockID::Pending => Some(self.chain.best_block_number()), } } @@ -565,7 +568,7 @@ impl Client { BlockID::Hash(hash) => Some(hash), BlockID::Number(number) => chain.block_hash(number), BlockID::Earliest => chain.block_hash(0), - BlockID::Latest => Some(chain.best_block_hash()) + BlockID::Latest | BlockID::Pending => Some(chain.best_block_hash()), } } @@ -683,6 +686,11 @@ impl BlockChainClient for Client { } fn block(&self, id: BlockID) -> Option { + if let &BlockID::Pending = &id { + if let Some(block) = self.miner.pending_block() { + return Some(block.rlp_bytes(Seal::Without)); + } + } Self::block_hash(&self.chain, id).and_then(|hash| { self.chain.block(&hash) }) @@ -697,6 +705,11 @@ impl BlockChainClient for Client { } fn block_total_difficulty(&self, id: BlockID) -> Option { + if let &BlockID::Pending = &id { + if let Some(block) = self.miner.pending_block() { + return Some(*block.header.difficulty() + self.block_total_difficulty(BlockID::Latest).expect("blocks in chain have details; qed")); + } + } Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block_details(&hash)).map(|d| d.total_difficulty) } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index ab5fbee25..e0280b388 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -241,7 +241,7 @@ impl TestBlockChainClient { BlockID::Hash(hash) => Some(hash), BlockID::Number(n) => self.numbers.read().get(&(n as usize)).cloned(), BlockID::Earliest => self.numbers.read().get(&0).cloned(), - BlockID::Latest => self.numbers.read().get(&(self.numbers.read().len() - 1)).cloned() + BlockID::Latest | BlockID::Pending => self.numbers.read().get(&(self.numbers.read().len() - 1)).cloned() } } } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index c49397c4e..b3f2765e2 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -22,8 +22,9 @@ use util::*; use util::using_queue::{UsingQueue, GetAction}; use account_provider::AccountProvider; use views::{BlockView, HeaderView}; +use state::State; use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics}; -use block::{ClosedBlock, IsBlock}; +use block::{ClosedBlock, IsBlock, Block}; use error::*; use transaction::SignedTransaction; use receipt::Receipt; @@ -226,6 +227,16 @@ impl Miner { self.options.force_sealing || !self.options.new_work_notify.is_empty() } + /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. + pub fn pending_state(&self) -> Option { + self.sealing_work.lock().peek_last_ref().map(|b| b.block().fields().state.clone()) + } + + /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. + pub fn pending_block(&self) -> Option { + self.sealing_work.lock().peek_last_ref().map(|b| b.base().clone()) + } + /// Prepares new block for sealing including top transactions from queue. #[cfg_attr(feature="dev", allow(match_same_arms))] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] diff --git a/ethcore/src/types/ids.rs b/ethcore/src/types/ids.rs index c08ab4116..7fcd0fd19 100644 --- a/ethcore/src/types/ids.rs +++ b/ethcore/src/types/ids.rs @@ -33,7 +33,9 @@ pub enum BlockID { /// Earliest block (genesis). Earliest, /// Latest mined block. - Latest + Latest, + /// Pending block. + Pending, } /// Uniquely identifies transaction. diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index e2d150c66..302d099d5 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -28,7 +28,7 @@ pub enum BlockNumber { /// Earliest block (genesis) Earliest, /// Pending block (being mined) - Pending + Pending, } impl Deserialize for BlockNumber { @@ -63,8 +63,8 @@ impl Into for BlockNumber { match self { BlockNumber::Num(n) => BlockID::Number(n), BlockNumber::Earliest => BlockID::Earliest, - // TODO: change this once blockid support pendingst, - BlockNumber::Pending | BlockNumber::Latest => BlockID::Latest, + BlockNumber::Latest => BlockID::Latest, + BlockNumber::Pending => BlockID::Pending, } } } @@ -87,7 +87,7 @@ mod tests { assert_eq!(BlockID::Number(100), BlockNumber::Num(100).into()); assert_eq!(BlockID::Earliest, BlockNumber::Earliest.into()); assert_eq!(BlockID::Latest, BlockNumber::Latest.into()); - assert_eq!(BlockID::Latest, BlockNumber::Pending.into()); + assert_eq!(BlockID::Pending, BlockNumber::Pending.into()); } }