Fix "pending" parameter on RPC block requests (#1602)

* Initial commit.

* Pending blocks work.

* Address grumbles.

* Fix up for new API.
This commit is contained in:
Gav Wood 2016-07-14 15:24:12 +02:00 committed by Arkadiy Paronyan
parent 2b193f00d4
commit 598833d1ea
6 changed files with 51 additions and 12 deletions

View File

@ -39,8 +39,18 @@ impl Block {
pub fn is_good(b: &[u8]) -> bool {
UntrustedRlp::new(b).as_val::<Block>().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<D>(decoder: &D) -> Result<Self, DecoderError> 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 }

View File

@ -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<State> {
// 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<Bytes> {
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<U256> {
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)
}

View File

@ -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()
}
}
}

View File

@ -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<State> {
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<Block> {
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))]

View File

@ -33,7 +33,9 @@ pub enum BlockID {
/// Earliest block (genesis).
Earliest,
/// Latest mined block.
Latest
Latest,
/// Pending block.
Pending,
}
/// Uniquely identifies transaction.

View File

@ -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<BlockID> 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());
}
}