Owning views of blockchain data (#3982)

* owning views of blockchain data

* port blockchain and client traits to owning views

* fix ethcore tests

* use strong headers and bodies in ethcore_light

* port ethsync to use owning views

* port rpc to owning views

* port parity informant and blockchain export
This commit is contained in:
Robert Habermeier 2016-12-28 13:44:51 +01:00 committed by Gav Wood
parent 592a3ac623
commit fe1f542c4f
22 changed files with 493 additions and 212 deletions

View File

@ -26,6 +26,7 @@ use ethcore::block_status::BlockStatus;
use ethcore::verification::queue::{HeaderQueue, QueueInfo};
use ethcore::transaction::{SignedTransaction, PendingTransaction};
use ethcore::blockchain_info::BlockChainInfo;
use ethcore::encoded;
use io::IoChannel;
use util::hash::{H256, H256FastMap};
@ -90,11 +91,11 @@ impl Provider for Client {
None
}
fn block_header(&self, _id: BlockId) -> Option<Bytes> {
fn block_header(&self, _id: BlockId) -> Option<encoded::Header> {
None
}
fn block_body(&self, _id: BlockId) -> Option<Bytes> {
fn block_body(&self, _id: BlockId) -> Option<encoded::Body> {
None
}
@ -110,7 +111,7 @@ impl Provider for Client {
Vec::new()
}
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
None
}

View File

@ -706,7 +706,7 @@ impl LightProtocol {
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
for header in response {
stream.append_raw(&header, 1);
stream.append_raw(&header.into_inner(), 1);
}
stream.out()
@ -757,7 +757,7 @@ impl LightProtocol {
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::Bodies, req.block_hashes.len())?;
let response = self.provider.block_bodies(req);
let response_len = response.iter().filter(|x| &x[..] != &::rlp::EMPTY_LIST_RLP).count();
let response_len = response.iter().filter(|x| x.is_some()).count();
let actual_cost = self.flow_params.compute_cost(request::Kind::Bodies, response_len);
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
@ -768,7 +768,10 @@ impl LightProtocol {
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
for body in response {
stream.append_raw(&body, 1);
match body {
Some(body) => stream.append_raw(&body.into_inner(), 1),
None => stream.append_empty_data(),
};
}
stream.out()

View File

@ -21,6 +21,7 @@ use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
use ethcore::ids::BlockId;
use ethcore::transaction::PendingTransaction;
use ethcore::encoded;
use network::{PeerId, NodeId};
use net::buffer_flow::FlowParams;
@ -94,11 +95,11 @@ impl Provider for TestProvider {
None
}
fn block_header(&self, id: BlockId) -> Option<Bytes> {
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
self.0.client.block_header(id)
}
fn block_body(&self, id: BlockId) -> Option<Bytes> {
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
self.0.client.block_body(id)
}
@ -122,7 +123,7 @@ impl Provider for TestProvider {
req.account_key.iter().chain(req.account_key.iter()).cloned().collect()
}
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
None
}
@ -273,7 +274,7 @@ fn get_block_headers() {
response_stream.append(&req_id).append(&new_buf).begin_list(10);
for header in headers {
response_stream.append_raw(&header, 1);
response_stream.append_raw(&header.into_inner(), 1);
}
response_stream.out()
@ -320,7 +321,7 @@ fn get_block_bodies() {
response_stream.append(&req_id).append(&new_buf).begin_list(10);
for body in bodies {
response_stream.append_raw(&body, 1);
response_stream.append_raw(&body.into_inner(), 1);
}
response_stream.out()

View File

@ -21,6 +21,7 @@ use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
use ethcore::transaction::PendingTransaction;
use ethcore::ids::BlockId;
use ethcore::encoded;
use util::{Bytes, H256};
@ -52,9 +53,8 @@ pub trait Provider: Send + Sync {
///
/// The returned vector may have any length in the range [0, `max`], but the
/// results within must adhere to the `skip` and `reverse` parameters.
fn block_headers(&self, req: request::Headers) -> Vec<Bytes> {
fn block_headers(&self, req: request::Headers) -> Vec<encoded::Header> {
use request::HashOrNumber;
use ethcore::views::HeaderView;
if req.max == 0 { return Vec::new() }
@ -67,9 +67,9 @@ pub trait Provider: Send + Sync {
return Vec::new();
}
Some(header) => {
let num = HeaderView::new(&header).number();
let num = header.number();
let canon_hash = self.block_header(BlockId::Number(num))
.map(|h| HeaderView::new(&h).hash());
.map(|h| h.hash());
if req.max == 1 || canon_hash != Some(hash) {
// Non-canonical header or single header requested.
@ -92,19 +92,18 @@ pub trait Provider: Send + Sync {
}
/// Get a block header by id.
fn block_header(&self, id: BlockId) -> Option<Bytes>;
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
/// Provide as many as possible of the requested blocks (minus the headers) encoded
/// in RLP format.
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes> {
fn block_bodies(&self, req: request::Bodies) -> Vec<Option<encoded::Body>> {
req.block_hashes.into_iter()
.map(|hash| self.block_body(BlockId::Hash(hash)))
.map(|body| body.unwrap_or_else(|| ::rlp::EMPTY_LIST_RLP.to_vec()))
.collect()
}
/// Get a block body by id.
fn block_body(&self, id: BlockId) -> Option<Bytes>;
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
/// Provide the receipts as many as possible of the requested blocks.
/// Returns a vector of RLP-encoded lists of receipts.
@ -169,7 +168,7 @@ pub trait Provider: Send + Sync {
None => rlp::EMPTY_LIST_RLP.to_vec(),
Some((header, proof)) => {
let mut stream = RlpStream::new_list(2);
stream.append_raw(&header, 1).begin_list(proof.len());
stream.append_raw(&header.into_inner(), 1).begin_list(proof.len());
for node in proof {
stream.append_raw(&node, 1);
@ -184,7 +183,7 @@ pub trait Provider: Send + Sync {
/// Provide a header proof from a given Canonical Hash Trie as well as the
/// corresponding header. The first element is the block header and the
/// second is a merkle proof of the CHT.
fn header_proof(&self, req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)>;
fn header_proof(&self, req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)>;
/// Provide pending transactions.
fn ready_transactions(&self) -> Vec<PendingTransaction>;
@ -204,11 +203,11 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
Some(self.pruning_info().earliest_state)
}
fn block_header(&self, id: BlockId) -> Option<Bytes> {
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
BlockChainClient::block_header(self, id)
}
fn block_body(&self, id: BlockId) -> Option<Bytes> {
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
BlockChainClient::block_body(self, id)
}
@ -227,7 +226,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
self.code_by_hash(req.account_key, BlockId::Hash(req.block_hash))
}
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
None
}

View File

@ -35,6 +35,7 @@ use blockchain::{CacheSize, ImportRoute, Config};
use db::{self, Writable, Readable, CacheUpdatePolicy};
use cache_manager::CacheManager;
use engines::Engine;
use encoded;
const LOG_BLOOMS_LEVELS: usize = 3;
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
@ -64,7 +65,7 @@ pub trait BlockProvider {
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"))
}
/// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes>;
fn block(&self, hash: &H256) -> Option<encoded::Block>;
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails>;
@ -80,25 +81,25 @@ pub trait BlockProvider {
/// Get the partial-header of a block.
fn block_header(&self, hash: &H256) -> Option<Header> {
self.block_header_data(hash).map(|header| decode(&header))
self.block_header_data(hash).map(|header| header.decode())
}
/// Get the header RLP of a block.
fn block_header_data(&self, hash: &H256) -> Option<Bytes>;
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header>;
/// Get the block body (uncles and transactions).
fn block_body(&self, hash: &H256) -> Option<Bytes>;
fn block_body(&self, hash: &H256) -> Option<encoded::Body>;
/// Get a list of uncles for a given block.
/// Returns None if block does not exist.
fn uncles(&self, hash: &H256) -> Option<Vec<Header>> {
self.block_body(hash).map(|bytes| BodyView::new(&bytes).uncles())
self.block_body(hash).map(|body| body.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_body(hash).map(|bytes| BodyView::new(&bytes).uncle_hashes())
self.block_body(hash).map(|body| body.uncle_hashes())
}
/// Get the number of given block's hash.
@ -109,8 +110,8 @@ pub trait BlockProvider {
/// Get transaction with given transaction hash.
fn transaction(&self, address: &TransactionAddress) -> Option<LocalizedTransaction> {
self.block_body(&address.block_hash)
.and_then(|bytes| self.block_number(&address.block_hash)
.and_then(|n| BodyView::new(&bytes).localized_transaction_at(&address.block_hash, n, address.index)))
.and_then(|body| self.block_number(&address.block_hash)
.and_then(|n| body.view().localized_transaction_at(&address.block_hash, n, address.index)))
}
/// Get transaction receipt.
@ -122,8 +123,8 @@ pub trait BlockProvider {
/// Returns None if block does not exist.
fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
self.block_body(hash)
.and_then(|bytes| self.block_number(hash)
.map(|n| BodyView::new(&bytes).localized_transactions(hash, n)))
.and_then(|body| self.block_number(hash)
.map(|n| body.view().localized_transactions(hash, n)))
}
/// Returns reference to genesis hash.
@ -224,27 +225,27 @@ impl BlockProvider for BlockChain {
}
/// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes> {
fn block(&self, hash: &H256) -> Option<encoded::Block> {
match (self.block_header_data(hash), self.block_body(hash)) {
(Some(header), Some(body)) => {
let mut block = RlpStream::new_list(3);
let body_rlp = Rlp::new(&body);
block.append_raw(&header, 1);
let body_rlp = body.rlp();
block.append_raw(header.rlp().as_raw(), 1);
block.append_raw(body_rlp.at(0).as_raw(), 1);
block.append_raw(body_rlp.at(1).as_raw(), 1);
Some(block.out())
Some(encoded::Block::new(block.out()))
},
_ => None,
}
}
/// Get block header data
fn block_header_data(&self, hash: &H256) -> Option<Bytes> {
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header> {
// Check cache first
{
let read = self.block_headers.read();
if let Some(v) = read.get(hash) {
return Some(v.clone());
return Some(encoded::Header::new(v.clone()));
}
}
@ -252,7 +253,9 @@ impl BlockProvider for BlockChain {
{
let best_block = self.best_block.read();
if &best_block.hash == hash {
return Some(Rlp::new(&best_block.block).at(0).as_raw().to_vec());
return Some(encoded::Header::new(
Rlp::new(&best_block.block).at(0).as_raw().to_vec()
))
}
}
@ -265,7 +268,7 @@ impl BlockProvider for BlockChain {
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
let mut write = self.block_headers.write();
write.insert(hash.clone(), bytes.clone());
Some(bytes)
Some(encoded::Header::new(bytes))
},
None => None
};
@ -275,12 +278,12 @@ impl BlockProvider for BlockChain {
}
/// Get block body data
fn block_body(&self, hash: &H256) -> Option<Bytes> {
fn block_body(&self, hash: &H256) -> Option<encoded::Body> {
// Check cache first
{
let read = self.block_bodies.read();
if let Some(v) = read.get(hash) {
return Some(v.clone());
return Some(encoded::Body::new(v.clone()));
}
}
@ -288,7 +291,7 @@ impl BlockProvider for BlockChain {
{
let best_block = self.best_block.read();
if &best_block.hash == hash {
return Some(Self::block_to_body(&best_block.block));
return Some(encoded::Body::new(Self::block_to_body(&best_block.block)));
}
}
@ -301,7 +304,7 @@ impl BlockProvider for BlockChain {
let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec();
let mut write = self.block_bodies.write();
write.insert(hash.clone(), bytes.clone());
Some(bytes)
Some(encoded::Body::new(bytes))
},
None => None
};
@ -358,7 +361,7 @@ impl BlockProvider for BlockChain {
let mut logs = blocks.into_iter()
.filter_map(|number| self.block_hash(number).map(|hash| (number, hash)))
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, BodyView::new(b).transaction_hashes())))
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes())))
.flat_map(|(number, hash, mut receipts, mut hashes)| {
if receipts.len() != hashes.len() {
warn!("Block {} ({}) has different number of receipts ({}) to transactions ({}). Database corrupt?", number, hash, receipts.len(), hashes.len());
@ -484,7 +487,7 @@ impl BlockChain {
// Fetch best block details
let best_block_number = bc.block_number(&best_block_hash).unwrap();
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
let best_block_rlp = bc.block(&best_block_hash).unwrap();
let best_block_rlp = bc.block(&best_block_hash).unwrap().into_inner();
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.to_vec());
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
@ -578,7 +581,7 @@ impl BlockChain {
batch.put(db::COL_EXTRA, b"best", &hash);
let best_block_total_difficulty = self.block_details(&hash).unwrap().total_difficulty;
let best_block_rlp = self.block(&hash).unwrap();
let best_block_rlp = self.block(&hash).unwrap().into_inner();
let mut best_block = self.best_block.write();
*best_block = BestBlock {
@ -862,7 +865,7 @@ impl BlockChain {
let number = header.number();
let parent_hash = header.parent_hash();
let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash));
let is_new_best = self.engine.is_new_best_block(self.best_block_total_difficulty(), HeaderView::new(&self.best_block_header()), &parent_details, header);
let is_new_best = self.engine.is_new_best_block(self.best_block_total_difficulty(), self.best_block_header().view(), &parent_details, header);
BlockInfo {
hash: hash,
@ -1108,8 +1111,8 @@ impl BlockChain {
BlockLocation::BranchBecomingCanonChain(ref data) => {
let addresses = data.enacted.iter()
.flat_map(|hash| {
let bytes = self.block_body(hash).expect("Enacted block must be in database.");
let hashes = BodyView::new(&bytes).transaction_hashes();
let body = self.block_body(hash).expect("Enacted block must be in database.");
let hashes = body.transaction_hashes();
hashes.into_iter()
.enumerate()
.map(|(i, tx_hash)| (tx_hash, Some(TransactionAddress {
@ -1129,8 +1132,8 @@ impl BlockChain {
});
let retracted = data.retracted.iter().flat_map(|hash| {
let bytes = self.block_body(hash).expect("Retracted block must be in database.");
let hashes = BodyView::new(&bytes).transaction_hashes();
let body = self.block_body(hash).expect("Retracted block must be in database.");
let hashes = body.transaction_hashes();
hashes.into_iter().map(|hash| (hash, None)).collect::<HashMap<H256, Option<TransactionAddress>>>()
});
@ -1179,7 +1182,7 @@ impl BlockChain {
let mut blooms: Vec<bc::Bloom> = data.enacted.iter()
.map(|hash| self.block_header_data(hash).unwrap())
.map(|bytes| HeaderView::new(&bytes).log_bloom())
.map(|h| h.log_bloom())
.map(Bloom::from)
.map(Into::into)
.collect();
@ -1212,9 +1215,10 @@ impl BlockChain {
}
/// Get best block header
pub fn best_block_header(&self) -> Bytes {
pub fn best_block_header(&self) -> encoded::Header {
let block = self.best_block.read();
BlockView::new(&block.block).header_view().rlp().as_raw().to_vec()
let raw = BlockView::new(&block.block).header_view().rlp().as_raw().to_vec();
encoded::Header::new(raw)
}
/// Get current cache size.
@ -1329,7 +1333,7 @@ mod tests {
}
fn new_chain(genesis: &[u8], db: Arc<Database>) -> BlockChain {
BlockChain::new(Config::default(), genesis, db, Spec::new_null().engine)
BlockChain::new(Config::default(), genesis, db, Spec::new_null().engine)
}
#[test]

View File

@ -32,7 +32,7 @@ use util::kvdb::*;
// other
use io::*;
use views::{HeaderView, BodyView, BlockView};
use views::BlockView;
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
use header::BlockNumber;
use state::{State, CleanupMode};
@ -67,10 +67,11 @@ use evm::{Factory as EvmFactory, Schedule};
use miner::{Miner, MinerService};
use snapshot::{self, io as snapshot_io};
use factory::Factories;
use rlp::{decode, View, UntrustedRlp};
use rlp::{View, UntrustedRlp};
use state_db::StateDB;
use rand::OsRng;
use client::registry::Registry;
use encoded;
// re-export
pub use types::blockchain_info::BlockChainInfo;
@ -303,17 +304,16 @@ impl Client {
/// The env info as of the best block.
fn latest_env_info(&self) -> EnvInfo {
let header_data = self.best_block_header();
let view = HeaderView::new(&header_data);
let header = self.best_block_header();
EnvInfo {
number: view.number(),
author: view.author(),
timestamp: view.timestamp(),
difficulty: view.difficulty(),
last_hashes: self.build_last_hashes(view.hash()),
number: header.number(),
author: header.author(),
timestamp: header.timestamp(),
difficulty: header.difficulty(),
last_hashes: self.build_last_hashes(header.hash()),
gas_used: U256::default(),
gas_limit: view.gas_limit(),
gas_limit: header.gas_limit(),
}
}
@ -642,8 +642,7 @@ impl Client {
return None;
}
let root = HeaderView::new(&header).state_root();
let root = header.state_root();
State::from_existing(db, root, self.engine.account_start_nonce(), self.factories.clone()).ok()
})
}
@ -666,7 +665,6 @@ impl Client {
/// Get a copy of the best block's state.
pub fn state(&self) -> State {
let header = self.best_block_header();
let header = HeaderView::new(&header);
State::from_existing(
self.state_db.lock().boxed_clone_canon(&header.hash()),
header.state_root(),
@ -843,13 +841,12 @@ impl snapshot::DatabaseRestore for Client {
impl BlockChainClient for Client {
fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result<Executed, CallError> {
let header = self.block_header(block).ok_or(CallError::StatePruned)?;
let view = HeaderView::new(&header);
let last_hashes = self.build_last_hashes(view.parent_hash());
let last_hashes = self.build_last_hashes(header.parent_hash());
let env_info = EnvInfo {
number: view.number(),
author: view.author(),
timestamp: view.timestamp(),
difficulty: view.difficulty(),
number: header.number(),
author: header.author(),
timestamp: header.timestamp(),
difficulty: header.difficulty(),
last_hashes: last_hashes,
gas_used: U256::zero(),
gas_limit: U256::max_value(),
@ -879,26 +876,25 @@ impl BlockChainClient for Client {
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
let header_data = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
let body_data = self.block_body(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
let header = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
let body = self.block_body(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
let mut state = self.state_at_beginning(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
let txs = BodyView::new(&body_data).transactions();
let txs = body.transactions();
if address.index >= txs.len() {
return Err(CallError::TransactionNotFound);
}
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
let view = HeaderView::new(&header_data);
let last_hashes = self.build_last_hashes(view.hash());
let last_hashes = self.build_last_hashes(header.hash());
let mut env_info = EnvInfo {
number: view.number(),
author: view.author(),
timestamp: view.timestamp(),
difficulty: view.difficulty(),
number: header.number(),
author: header.author(),
timestamp: header.timestamp(),
difficulty: header.difficulty(),
last_hashes: last_hashes,
gas_used: U256::default(),
gas_limit: view.gas_limit(),
gas_limit: header.gas_limit(),
};
for t in txs.iter().take(address.index) {
match Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, Default::default()) {
@ -959,11 +955,11 @@ impl BlockChainClient for Client {
}
}
fn best_block_header(&self) -> Bytes {
fn best_block_header(&self) -> encoded::Header {
self.chain.read().best_block_header()
}
fn block_header(&self, id: BlockId) -> Option<Bytes> {
fn block_header(&self, id: BlockId) -> Option<::encoded::Header> {
let chain = self.chain.read();
Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash))
}
@ -977,15 +973,15 @@ impl BlockChainClient for Client {
}
}
fn block_body(&self, id: BlockId) -> Option<Bytes> {
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
let chain = self.chain.read();
Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash))
}
fn block(&self, id: BlockId) -> Option<Bytes> {
fn block(&self, id: BlockId) -> Option<encoded::Block> {
if let BlockId::Pending = id {
if let Some(block) = self.miner.pending_block() {
return Some(block.rlp_bytes(Seal::Without));
return Some(encoded::Block::new(block.rlp_bytes(Seal::Without)));
}
}
let chain = self.chain.read();
@ -1128,9 +1124,10 @@ impl BlockChainClient for Client {
self.transaction_address(id).map(|addr| addr.block_hash)
}
fn uncle(&self, id: UncleId) -> Option<Bytes> {
fn uncle(&self, id: UncleId) -> Option<encoded::Header> {
let index = id.position;
self.block_body(id.block).and_then(|body| BodyView::new(&body).uncle_rlp_at(index))
self.block_body(id.block).and_then(|body| body.view().uncle_rlp_at(index))
.map(encoded::Header::new)
}
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
@ -1138,8 +1135,8 @@ impl BlockChainClient for Client {
self.transaction_address(id)
.and_then(|address| chain.block_number(&address.block_hash).and_then(|block_number| {
let t = chain.block_body(&address.block_hash)
.and_then(|block| {
BodyView::new(&block).localized_transaction_at(&address.block_hash, block_number, address.index)
.and_then(|body| {
body.view().localized_transaction_at(&address.block_hash, block_number, address.index)
});
let tx_and_sender = t.and_then(|tx| tx.sender().ok().map(|sender| (tx, sender)));
@ -1360,13 +1357,12 @@ impl BlockChainClient for Client {
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
self.block_header(id)
.map(|block| decode(&block))
.map(|header| self.engine.extra_info(&header))
.map(|header| self.engine.extra_info(&header.decode()))
}
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
self.uncle(id)
.map(|header| self.engine.extra_info(&decode(&header)))
.map(|header| self.engine.extra_info(&header.decode()))
}
fn pruning_info(&self) -> PruningInfo {

View File

@ -39,7 +39,6 @@ use miner::{Miner, MinerService, TransactionImportResult};
use spec::Spec;
use types::mode::Mode;
use types::pruning_info::PruningInfo;
use views::BlockView;
use verification::queue::QueueInfo;
use block::{OpenBlock, SealedBlock};
@ -47,6 +46,7 @@ use executive::Executed;
use error::CallError;
use trace::LocalizedTrace;
use state_db::StateDB;
use encoded;
/// Test client.
pub struct TestBlockChainClient {
@ -263,7 +263,7 @@ impl TestBlockChainClient {
/// Make a bad block by setting invalid extra data.
pub fn corrupt_block(&self, n: BlockNumber) {
let hash = self.block_hash(BlockId::Number(n)).unwrap();
let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap());
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode();
header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec());
let mut rlp = RlpStream::new_list(3);
rlp.append(&header);
@ -275,7 +275,7 @@ impl TestBlockChainClient {
/// Make a bad block by setting invalid parent hash.
pub fn corrupt_block_parent(&self, n: BlockNumber) {
let hash = self.block_hash(BlockId::Number(n)).unwrap();
let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap());
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode();
header.set_parent_hash(H256::from(42));
let mut rlp = RlpStream::new_list(3);
rlp.append(&header);
@ -458,7 +458,7 @@ impl BlockChainClient for TestBlockChainClient {
None // Simple default.
}
fn uncle(&self, _id: UncleId) -> Option<Bytes> {
fn uncle(&self, _id: UncleId) -> Option<encoded::Header> {
None // Simple default.
}
@ -487,34 +487,39 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!();
}
fn best_block_header(&self) -> Bytes {
self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).expect("Best block always have header.")
fn best_block_header(&self) -> encoded::Header {
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
.expect("Best block always has header.")
}
fn block_header(&self, id: BlockId) -> Option<Bytes> {
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
self.block_hash(id)
.and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
.map(encoded::Header::new)
}
fn block_number(&self, _id: BlockId) -> Option<BlockNumber> {
unimplemented!()
}
fn block_body(&self, id: BlockId) -> Option<Bytes> {
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| {
let mut stream = RlpStream::new_list(2);
stream.append_raw(Rlp::new(r).at(1).as_raw(), 1);
stream.append_raw(Rlp::new(r).at(2).as_raw(), 1);
stream.out()
encoded::Body::new(stream.out())
}))
}
fn block(&self, id: BlockId) -> Option<Bytes> {
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).cloned())
fn block(&self, id: BlockId) -> Option<encoded::Block> {
self.block_hash(id)
.and_then(|hash| self.blocks.read().get(&hash).cloned())
.map(encoded::Block::new)
}
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
self.block(id)
.map(|block| BlockView::new(&block).header())
.map(|block| block.view().header())
.map(|header| self.spec.engine.extra_info(&header))
}

View File

@ -24,7 +24,6 @@ use header::{BlockNumber};
use transaction::{LocalizedTransaction, SignedTransaction, PendingTransaction};
use log_entry::LocalizedLogEntry;
use filter::Filter;
use views::{BlockView};
use error::{ImportResult, CallError};
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
@ -40,6 +39,7 @@ use types::blockchain_info::BlockChainInfo;
use types::block_status::BlockStatus;
use types::mode::Mode;
use types::pruning_info::PruningInfo;
use encoded;
#[ipc(client_ident="RemoteClient")]
/// Blockchain database client. Owns and manages a blockchain and a block queue.
@ -50,17 +50,17 @@ pub trait BlockChainClient : Sync + Send {
fn keep_alive(&self) {}
/// Get raw block header data by block id.
fn block_header(&self, id: BlockId) -> Option<Bytes>;
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
/// Look up the block number for the given block ID.
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
/// Get raw block body data by block id.
/// Block body is an RLP list of two items: uncles and transactions.
fn block_body(&self, id: BlockId) -> Option<Bytes>;
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
/// Get raw block data by block header hash.
fn block(&self, id: BlockId) -> Option<Bytes>;
fn block(&self, id: BlockId) -> Option<encoded::Block>;
/// Get block status by block header hash.
fn block_status(&self, id: BlockId) -> BlockStatus;
@ -136,7 +136,7 @@ pub trait BlockChainClient : Sync + Send {
fn transaction_block(&self, id: TransactionId) -> Option<H256>;
/// Get uncle with given id.
fn uncle(&self, id: UncleId) -> Option<Bytes>;
fn uncle(&self, id: UncleId) -> Option<encoded::Header>;
/// Get transaction receipt with given hash.
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt>;
@ -173,7 +173,7 @@ pub trait BlockChainClient : Sync + Send {
fn additional_params(&self) -> BTreeMap<String, String>;
/// Get the best block header.
fn best_block_header(&self) -> Bytes;
fn best_block_header(&self) -> encoded::Header;
/// Returns numbers of blocks containing given bloom.
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>>;
@ -220,8 +220,7 @@ pub trait BlockChainClient : Sync + Send {
let mut corpus = Vec::new();
while corpus.is_empty() {
for _ in 0..sample_size {
let block_bytes = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
let block = BlockView::new(&block_bytes);
let block = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
let header = block.header_view();
if header.number() == 0 {
return corpus;

View File

@ -20,8 +20,6 @@ use std::time::{Instant, Duration};
use util::*;
use util::using_queue::{UsingQueue, GetAction};
use account_provider::{AccountProvider, Error as AccountError};
use views::{BlockView, HeaderView};
use header::Header;
use state::{State, CleanupMode};
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockId, CallAnalytics, TransactionId};
use client::TransactionImportResult;
@ -536,7 +534,7 @@ impl Miner {
}
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {
let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit();
let gas_limit = chain.best_block_header().gas_limit();
let mut queue = self.transaction_queue.lock();
queue.set_gas_limit(gas_limit);
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
@ -598,7 +596,7 @@ impl Miner {
let schedule = chain.latest_schedule();
let gas_required = |tx: &SignedTransaction| tx.gas_required(&schedule).into();
let best_block_header: Header = ::rlp::decode(&chain.best_block_header());
let best_block_header = chain.best_block_header().decode();
transactions.into_iter()
.map(|tx| {
if chain.transaction_block(TransactionId::Hash(tx.hash())).is_some() {
@ -1127,7 +1125,6 @@ impl MinerService for Miner {
.map(|hash| {
let block = chain.block(BlockId::Hash(*hash))
.expect("Client is sending message after commit to db and inserting to chain; the block is available; qed");
let block = BlockView::new(&block);
let txs = block.transactions();
// populate sender
for tx in &txs {

View File

@ -190,8 +190,7 @@ impl<'a> BlockChunker<'a> {
.and_then(|b| self.chain.block_receipts(&self.current_hash).map(|r| (b, r)))
.ok_or(Error::BlockNotFound(self.current_hash))?;
let view = BlockView::new(&block);
let abridged_rlp = AbridgedBlock::from_block_view(&view).into_inner();
let abridged_rlp = AbridgedBlock::from_block_view(&block.view()).into_inner();
let pair = {
let mut pair_stream = RlpStream::new_list(2);
@ -213,7 +212,7 @@ impl<'a> BlockChunker<'a> {
self.rlps.push_front(pair);
last = self.current_hash;
self.current_hash = view.header_view().parent_hash();
self.current_hash = block.header_view().parent_hash();
}
if loaded_size != 0 {

View File

@ -20,7 +20,6 @@ use util::Mutex;
use client::{BlockChainClient, Client, ChainNotify};
use ids::BlockId;
use service::ClientIoMessage;
use views::HeaderView;
use io::IoChannel;
use util::{H256, Bytes};
@ -43,7 +42,7 @@ impl<F> Oracle for StandardOracle<F>
where F: Send + Sync + Fn() -> bool
{
fn to_number(&self, hash: H256) -> Option<u64> {
self.client.block_header(BlockId::Hash(hash)).map(|h| HeaderView::new(&h).number())
self.client.block_header(BlockId::Hash(hash)).map(|h| h.number())
}
fn is_major_importing(&self) -> bool {

View File

@ -24,7 +24,7 @@ use types::filter::Filter;
use util::*;
use devtools::*;
use miner::Miner;
use rlp::{Rlp, View};
use rlp::View;
use spec::Spec;
use views::BlockView;
use util::stats::Histogram;
@ -103,7 +103,7 @@ fn imports_good_block() {
client.import_verified_blocks();
let block = client.block_header(BlockId::Number(1)).unwrap();
assert!(!block.is_empty());
assert!(!block.into_inner().is_empty());
}
#[test]
@ -128,7 +128,7 @@ fn query_none_block() {
fn query_bad_block() {
let client_result = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]);
let client = client_result.reference();
let bad_block:Option<Bytes> = client.block_header(BlockId::Number(1));
let bad_block: Option<_> = client.block_header(BlockId::Number(1));
assert!(bad_block.is_none());
}
@ -180,7 +180,7 @@ fn returns_block_body() {
let client = client_result.reference();
let block = BlockView::new(&dummy_block);
let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap();
let body = Rlp::new(&body);
let body = body.rlp();
assert_eq!(body.item_count(), 2);
assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]);
assert_eq!(body.at(1).as_raw()[..], block.rlp().at(2).as_raw()[..]);
@ -192,7 +192,7 @@ fn imports_block_sequence() {
let client = client_result.reference();
let block = client.block_header(BlockId::Number(5)).unwrap();
assert!(!block.is_empty());
assert!(!block.into_inner().is_empty());
}
#[test]

View File

@ -0,0 +1,273 @@
// Copyright 2015, 2016 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/>.
//! Lazily-decoded owning views of RLP-encoded blockchain objects.
//! These views are meant to contain _trusted_ data -- without encoding
//! errors or inconsistencies.
//!
//! In general these views are useful when only a few fields of an object
//! are relevant. In these cases it's more efficient to decode the object piecemeal.
//! When the entirety of the object is needed, it's better to upgrade it to a fully
//! decoded object where parts like the hash can be saved.
use block::Block as FullBlock;
use header::{BlockNumber, Header as FullHeader};
use transaction::SignedTransaction;
use views;
use util::{Address, Hashable, H256, H2048, U256};
use rlp::{Rlp, View};
/// Owning header view.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Header(Vec<u8>);
impl Header {
/// Create a new owning header view.
/// Expects the data to be an RLP-encoded header -- any other case will likely lead to
/// panics further down the line.
pub fn new(encoded: Vec<u8>) -> Self { Header(encoded) }
/// Upgrade this encoded view to a fully owned `Header` object.
pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0) }
/// Get a borrowed header view onto the data.
#[inline]
pub fn view(&self) -> views::HeaderView { views::HeaderView::new(&self.0) }
/// Get the rlp of the header.
#[inline]
pub fn rlp(&self) -> Rlp { Rlp::new(&self.0) }
/// Consume the view and return the raw bytes.
pub fn into_inner(self) -> Vec<u8> { self.0 }
}
// forwarders to borrowed view.
impl Header {
/// Returns the header hash.
pub fn hash(&self) -> H256 { self.sha3() }
/// Returns the parent hash.
pub fn parent_hash(&self) -> H256 { self.view().parent_hash() }
/// Returns the uncles hash.
pub fn uncles_hash(&self) -> H256 { self.view().uncles_hash() }
/// Returns the author.
pub fn author(&self) -> Address { self.view().author() }
/// Returns the state root.
pub fn state_root(&self) -> H256 { self.view().state_root() }
/// Returns the transaction trie root.
pub fn transactions_root(&self) -> H256 { self.view().transactions_root() }
/// Returns the receipts trie root
pub fn receipts_root(&self) -> H256 { self.view().receipts_root() }
/// Returns the block log bloom
pub fn log_bloom(&self) -> H2048 { self.view().log_bloom() }
/// Difficulty of this block
pub fn difficulty(&self) -> U256 { self.view().difficulty() }
/// Number of this block.
pub fn number(&self) -> BlockNumber { self.view().number() }
/// Time this block was produced.
pub fn timestamp(&self) -> u64 { self.view().timestamp() }
/// Gas limit of this block.
pub fn gas_limit(&self) -> U256 { self.view().gas_limit() }
/// Total gas used in this block.
pub fn gas_used(&self) -> U256 { self.view().gas_used() }
/// Block extra data.
pub fn extra_data(&self) -> Vec<u8> { self.view().extra_data() }
/// Engine-specific seal fields.
pub fn seal(&self) -> Vec<Vec<u8>> { self.view().seal() }
}
impl Hashable for Header {
fn sha3(&self) -> H256 {
self.0.sha3()
}
}
/// Owning block body view.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Body(Vec<u8>);
impl Body {
/// Create a new owning block body view. The raw bytes passed in must be an rlp-encoded block
/// body.
pub fn new(raw: Vec<u8>) -> Self { Body(raw) }
/// Get a borrowed view of the data within.
#[inline]
pub fn view(&self) -> views::BodyView { views::BodyView::new(&self.0) }
/// Fully decode this block body.
pub fn decode(&self) -> (Vec<SignedTransaction>, Vec<FullHeader>) {
(self.view().transactions(), self.view().uncles())
}
/// Get the RLP of this block body.
#[inline]
pub fn rlp(&self) -> Rlp {
Rlp::new(&self.0)
}
/// Consume the view and return the raw bytes.
pub fn into_inner(self) -> Vec<u8> { self.0 }
}
// forwarders to borrowed view.
impl Body {
/// Get a vector of all transactions.
pub fn transactions(&self) -> Vec<SignedTransaction> { self.view().transactions() }
/// Number of transactions in the block.
pub fn transactions_count(&self) -> usize { self.view().transactions_count() }
/// A view over each transaction in the block.
pub fn transaction_views(&self) -> Vec<views::TransactionView> { self.view().transaction_views() }
/// The hash of each transaction in the block.
pub fn transaction_hashes(&self) -> Vec<H256> { self.view().transaction_hashes() }
/// Decode uncle headers.
pub fn uncles(&self) -> Vec<FullHeader> { self.view().uncles() }
/// Number of uncles.
pub fn uncles_count(&self) -> usize { self.view().uncles_count() }
/// Borrowed view over each uncle.
pub fn uncle_views(&self) -> Vec<views::HeaderView> { self.view().uncle_views() }
/// Hash of each uncle.
pub fn uncle_hashes(&self) -> Vec<H256> { self.view().uncle_hashes() }
}
/// Owning block view.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)]
pub struct Block(Vec<u8>);
impl Block {
/// Create a new owning block view. The raw bytes passed in must be an rlp-encoded block.
pub fn new(raw: Vec<u8>) -> Self { Block(raw) }
/// Get a borrowed view of the whole block.
#[inline]
pub fn view(&self) -> views::BlockView { views::BlockView::new(&self.0) }
/// Get a borrowed view of the block header.
#[inline]
pub fn header_view(&self) -> views::HeaderView { self.view().header_view() }
/// Decode to a full block.
pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0) }
/// Get the rlp of this block.
#[inline]
pub fn rlp(&self) -> Rlp {
Rlp::new(&self.0)
}
/// Consume the view and return the raw bytes.
pub fn into_inner(self) -> Vec<u8> { self.0 }
}
// forwarders to borrowed header view.
impl Block {
/// Returns the header hash.
pub fn hash(&self) -> H256 { self.header_view().sha3() }
/// Returns the parent hash.
pub fn parent_hash(&self) -> H256 { self.header_view().parent_hash() }
/// Returns the uncles hash.
pub fn uncles_hash(&self) -> H256 { self.header_view().uncles_hash() }
/// Returns the author.
pub fn author(&self) -> Address { self.header_view().author() }
/// Returns the state root.
pub fn state_root(&self) -> H256 { self.header_view().state_root() }
/// Returns the transaction trie root.
pub fn transactions_root(&self) -> H256 { self.header_view().transactions_root() }
/// Returns the receipts trie root
pub fn receipts_root(&self) -> H256 { self.header_view().receipts_root() }
/// Returns the block log bloom
pub fn log_bloom(&self) -> H2048 { self.header_view().log_bloom() }
/// Difficulty of this block
pub fn difficulty(&self) -> U256 { self.header_view().difficulty() }
/// Number of this block.
pub fn number(&self) -> BlockNumber { self.header_view().number() }
/// Time this block was produced.
pub fn timestamp(&self) -> u64 { self.header_view().timestamp() }
/// Gas limit of this block.
pub fn gas_limit(&self) -> U256 { self.header_view().gas_limit() }
/// Total gas used in this block.
pub fn gas_used(&self) -> U256 { self.header_view().gas_used() }
/// Block extra data.
pub fn extra_data(&self) -> Vec<u8> { self.header_view().extra_data() }
/// Engine-specific seal fields.
pub fn seal(&self) -> Vec<Vec<u8>> { self.header_view().seal() }
}
// forwarders to body view.
impl Block {
/// Get a vector of all transactions.
pub fn transactions(&self) -> Vec<SignedTransaction> { self.view().transactions() }
/// Number of transactions in the block.
pub fn transactions_count(&self) -> usize { self.view().transactions_count() }
/// A view over each transaction in the block.
pub fn transaction_views(&self) -> Vec<views::TransactionView> { self.view().transaction_views() }
/// The hash of each transaction in the block.
pub fn transaction_hashes(&self) -> Vec<H256> { self.view().transaction_hashes() }
/// Decode uncle headers.
pub fn uncles(&self) -> Vec<FullHeader> { self.view().uncles() }
/// Number of uncles.
pub fn uncles_count(&self) -> usize { self.view().uncles_count() }
/// Borrowed view over each uncle.
pub fn uncle_views(&self) -> Vec<views::HeaderView> { self.view().uncle_views() }
/// Hash of each uncle.
pub fn uncle_hashes(&self) -> Vec<H256> { self.view().uncle_hashes() }
}

View File

@ -35,4 +35,5 @@ pub mod restoration_status;
pub mod snapshot_manifest;
pub mod mode;
pub mod pruning_info;
pub mod security_level;
pub mod security_level;
pub mod encoded;

View File

@ -117,7 +117,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
excluded.insert(details.parent.clone());
let b = bc.block(&hash)
.expect("parent already known to be stored; qed");
excluded.extend(BlockView::new(&b).uncle_hashes());
excluded.extend(b.uncle_hashes());
hash = details.parent;
}
None => break
@ -264,6 +264,7 @@ mod tests {
use types::log_entry::{LogEntry, LocalizedLogEntry};
use rlp::View;
use time::get_time;
use encoded;
fn check_ok(result: Result<(), Error>) {
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
@ -322,16 +323,20 @@ mod tests {
}
/// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes> {
self.blocks.get(hash).cloned()
fn block(&self, hash: &H256) -> Option<encoded::Block> {
self.blocks.get(hash).cloned().map(encoded::Block::new)
}
fn block_header_data(&self, hash: &H256) -> Option<Bytes> {
self.block(hash).map(|b| BlockView::new(&b).header_rlp().as_raw().to_vec())
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header> {
self.block(hash)
.map(|b| b.header_view().rlp().as_raw().to_vec())
.map(encoded::Header::new)
}
fn block_body(&self, hash: &H256) -> Option<Bytes> {
self.block(hash).map(|b| BlockChain::block_to_body(&b))
fn block_body(&self, hash: &H256) -> Option<encoded::Body> {
self.block(hash)
.map(|b| BlockChain::block_to_body(&b.into_inner()))
.map(encoded::Body::new)
}
fn best_ancient_block(&self) -> Option<H256> {

View File

@ -94,7 +94,7 @@ impl<'a> BlockView<'a> {
}
/// Return List of transactions in given block.
pub fn transaction_views(&self) -> Vec<TransactionView> {
pub fn transaction_views(&self) -> Vec<TransactionView<'a>> {
self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect()
}
@ -132,7 +132,7 @@ impl<'a> BlockView<'a> {
}
/// Return List of transactions in given block.
pub fn uncle_views(&self) -> Vec<HeaderView> {
pub fn uncle_views(&self) -> Vec<HeaderView<'a>> {
self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect()
}

View File

@ -71,7 +71,7 @@ impl<'a> BodyView<'a> {
}
/// Return List of transactions in given block.
pub fn transaction_views(&self) -> Vec<TransactionView> {
pub fn transaction_views(&self) -> Vec<TransactionView<'a>> {
self.rlp.at(0).iter().map(TransactionView::new_from_rlp).collect()
}
@ -106,7 +106,7 @@ impl<'a> BodyView<'a> {
}
/// Return List of transactions in given block.
pub fn uncle_views(&self) -> Vec<HeaderView> {
pub fn uncle_views(&self) -> Vec<HeaderView<'a>> {
self.rlp.at(1).iter().map(HeaderView::new_from_rlp).collect()
}

View File

@ -186,16 +186,16 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
// prepare client config
let mut client_config = to_client_config(
&cmd.cache_config,
Mode::Active,
tracing,
fat_db,
cmd.compaction,
cmd.wal,
cmd.vm_type,
"".into(),
algorithm,
cmd.pruning_history,
&cmd.cache_config,
Mode::Active,
tracing,
fat_db,
cmd.compaction,
cmd.wal,
cmd.vm_type,
"".into(),
algorithm,
cmd.pruning_history,
cmd.check_seal
);
@ -390,7 +390,7 @@ fn execute_export(cmd: ExportBlockchain) -> Result<(), String> {
if i % 10000 == 0 {
info!("#{}", i);
}
let b = client.block(BlockId::Number(i)).ok_or("Error exporting incomplete chain")?;
let b = client.block(BlockId::Number(i)).ok_or("Error exporting incomplete chain")?.into_inner();
match format {
DataFormat::Binary => { out.write(&b).expect("Couldn't write to stream."); }
DataFormat::Hex => { out.write_fmt(format_args!("{}", b.pretty())).expect("Couldn't write to stream."); }

View File

@ -27,11 +27,11 @@ use ethsync::{SyncProvider, ManageNetwork};
use util::{Uint, RwLock, Mutex, H256, Colour, Bytes};
use ethcore::client::*;
use ethcore::service::ClientIoMessage;
use ethcore::views::BlockView;
use ethcore::snapshot::service::Service as SnapshotService;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};
use number_prefix::{binary_prefix, Standalone, Prefixed};
use ethcore_rpc::is_major_importing;
use rlp::View;
pub struct Informant {
report: RwLock<Option<ClientReport>>,
@ -186,21 +186,19 @@ impl ChainNotify for Informant {
let txs_imported = imported.iter()
.take(imported.len().saturating_sub(if ripe { 1 } else { 0 }))
.filter_map(|h| self.client.block(BlockId::Hash(*h)))
.map(|b| BlockView::new(&b).transactions_count())
.map(|b| b.transactions_count())
.sum();
if ripe {
if let Some(block) = imported.last().and_then(|h| self.client.block(BlockId::Hash(*h))) {
let view = BlockView::new(&block);
let header = view.header();
let tx_count = view.transactions_count();
let size = block.len();
let header_view = block.header_view();
let size = block.rlp().as_raw().len();
let (skipped, skipped_txs) = (self.skipped.load(AtomicOrdering::Relaxed) + imported.len() - 1, self.skipped_txs.load(AtomicOrdering::Relaxed) + txs_imported);
info!(target: "import", "Imported {} {} ({} txs, {} Mgas, {} ms, {} KiB){}",
Colour::White.bold().paint(format!("#{}", header.number())),
Colour::White.bold().paint(format!("{}", header.hash())),
Colour::Yellow.bold().paint(format!("{}", tx_count)),
Colour::Yellow.bold().paint(format!("{:.2}", header.gas_used().low_u64() as f32 / 1000000f32)),
Colour::White.bold().paint(format!("#{}", header_view.number())),
Colour::White.bold().paint(format!("{}", header_view.hash())),
Colour::Yellow.bold().paint(format!("{}", block.transactions_count())),
Colour::Yellow.bold().paint(format!("{:.2}", header_view.gas_used().low_u64() as f32 / 1000000f32)),
Colour::Purple.bold().paint(format!("{:.2}", duration as f32 / 1000000f32)),
Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)),
if skipped > 0 {

View File

@ -36,7 +36,6 @@ use ethcore::account_provider::AccountProvider;
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId};
use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber};
use ethcore::block::IsBlock;
use ethcore::views::*;
use ethcore::ethereum::Ethash;
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, PendingTransaction, Action};
use ethcore::log_entry::LogEntry;
@ -122,13 +121,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
fn block(&self, id: BlockId, include_txs: bool) -> Result<Option<RichBlock>, Error> {
let client = take_weak!(self.client);
match (client.block(id.clone()), client.block_total_difficulty(id)) {
(Some(bytes), Some(total_difficulty)) => {
let block_view = BlockView::new(&bytes);
let view = block_view.header_view();
let block = RichBlock {
(Some(block), Some(total_difficulty)) => {
let view = block.header_view();
Ok(Some(RichBlock {
block: Block {
hash: Some(view.sha3().into()),
size: Some(bytes.len().into()),
size: Some(block.rlp().as_raw().len().into()),
parent_hash: view.parent_hash().into(),
uncles_hash: view.uncles_hash().into(),
author: view.author().into(),
@ -144,16 +142,15 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
difficulty: view.difficulty().into(),
total_difficulty: total_difficulty.into(),
seal_fields: view.seal().into_iter().map(|f| rlp::decode(&f)).map(Bytes::new).collect(),
uncles: block_view.uncle_hashes().into_iter().map(Into::into).collect(),
uncles: block.uncle_hashes().into_iter().map(Into::into).collect(),
transactions: match include_txs {
true => BlockTransactions::Full(block_view.localized_transactions().into_iter().map(Into::into).collect()),
false => BlockTransactions::Hashes(block_view.transaction_hashes().into_iter().map(Into::into).collect()),
true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(Into::into).collect()),
false => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()),
},
extra_data: Bytes::new(view.extra_data()),
},
extra_info: client.block_extra_info(id.clone()).expect(EXTRA_INFO_PROOF),
};
Ok(Some(block))
}))
},
_ => Ok(None)
}
@ -169,7 +166,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
fn uncle(&self, id: UncleId) -> Result<Option<RichBlock>, Error> {
let client = take_weak!(self.client);
let uncle: BlockHeader = match client.uncle(id) {
Some(rlp) => rlp::decode(&rlp),
Some(hdr) => hdr.decode(),
None => { return Ok(None); }
};
let parent_difficulty = match client.block_total_difficulty(BlockId::Hash(uncle.parent_hash().clone())) {
@ -419,7 +416,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
self.active()?;
Ok(
take_weak!(self.client).block(BlockId::Hash(hash.into()))
.map(|bytes| BlockView::new(&bytes).transactions_count().into())
.map(|block| block.transactions_count().into())
)
}
@ -432,7 +429,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
)),
_ => Ok(
take_weak!(self.client).block(num.into())
.map(|bytes| BlockView::new(&bytes).transactions_count().into())
.map(|block| block.transactions_count().into())
)
}
}
@ -442,7 +439,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
Ok(
take_weak!(self.client).block(BlockId::Hash(hash.into()))
.map(|bytes| BlockView::new(&bytes).uncles_count().into())
.map(|block| block.uncles_count().into())
)
}
@ -453,7 +450,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
BlockNumber::Pending => Ok(Some(0.into())),
_ => Ok(
take_weak!(self.client).block(num.into())
.map(|bytes| BlockView::new(&bytes).uncles_count().into())
.map(|block| block.uncles_count().into())
),
}
}

View File

@ -17,7 +17,7 @@
use util::*;
use rlp::*;
use network::NetworkError;
use ethcore::header::{ Header as BlockHeader};
use ethcore::header::Header as BlockHeader;
known_heap_size!(0, HeaderId);
@ -511,7 +511,9 @@ mod test {
let client = TestBlockChainClient::new();
let nblocks = 200;
client.add_blocks(nblocks, EachBlockWith::Nothing);
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
let blocks: Vec<_> = (0..nblocks)
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner())
.collect();
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
@ -564,7 +566,9 @@ mod test {
let client = TestBlockChainClient::new();
let nblocks = 200;
client.add_blocks(nblocks, EachBlockWith::Nothing);
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
let blocks: Vec<_> = (0..nblocks)
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner())
.collect();
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
@ -586,7 +590,9 @@ mod test {
let client = TestBlockChainClient::new();
let nblocks = 200;
client.add_blocks(nblocks, EachBlockWith::Nothing);
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
let blocks: Vec<_> = (0..nblocks)
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap().into_inner())
.collect();
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();

View File

@ -92,7 +92,6 @@
use util::*;
use rlp::*;
use network::*;
use ethcore::views::{HeaderView};
use ethcore::header::{BlockNumber, Header as BlockHeader};
use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo};
use ethcore::error::*;
@ -1493,14 +1492,15 @@ impl ChainSync {
trace!(target: "sync", "{} -> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", peer_id, hash, max_headers, skip, reverse);
match io.chain().block_header(BlockId::Hash(hash)) {
Some(hdr) => {
let number = From::from(HeaderView::new(&hdr).number());
debug_assert_eq!(HeaderView::new(&hdr).sha3(), hash);
let number = hdr.number().into();
debug_assert_eq!(hdr.sha3(), hash);
if max_headers == 1 || io.chain().block_hash(BlockId::Number(number)) != Some(hash) {
// Non canonical header or single header requested
// TODO: handle single-step reverse hashchains of non-canon hashes
trace!(target:"sync", "Returning single header: {:?}", hash);
let mut rlp = RlpStream::new_list(1);
rlp.append_raw(&hdr, 1);
rlp.append_raw(&hdr.into_inner(), 1);
return Ok(Some((BLOCK_HEADERS_PACKET, rlp)));
}
number
@ -1528,8 +1528,8 @@ impl ChainSync {
trace!(target: "sync", "{}: Returning cached fork header", peer_id);
data.extend_from_slice(hdr);
count += 1;
} else if let Some(mut hdr) = io.chain().block_header(BlockId::Number(number)) {
data.append(&mut hdr);
} else if let Some(hdr) = io.chain().block_header(BlockId::Number(number)) {
data.append(&mut hdr.into_inner());
count += 1;
} else {
// No required block.
@ -1562,8 +1562,8 @@ 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(BlockId::Hash(r.val_at::<H256>(i)?)) {
data.append(&mut hdr);
if let Some(body) = io.chain().block_body(BlockId::Hash(r.val_at::<H256>(i)?)) {
data.append(&mut body.into_inner());
added += 1;
}
}
@ -1585,8 +1585,8 @@ impl ChainSync {
let mut added = 0usize;
let mut data = Vec::new();
for i in 0..count {
if let Some(hdr) = io.chain().state_data(&r.val_at::<H256>(i)?) {
data.push(hdr);
if let Some(node) = io.chain().state_data(&r.val_at::<H256>(i)?) {
data.push(node);
added += 1;
}
}
@ -1819,8 +1819,8 @@ impl ChainSync {
let mut rlp_stream = RlpStream::new_list(blocks.len());
for block_hash in blocks {
let mut hash_rlp = RlpStream::new_list(2);
let number = HeaderView::new(&chain.block_header(BlockId::Hash(block_hash.clone()))
.expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.")).number();
let number = chain.block_header(BlockId::Hash(block_hash.clone()))
.expect("chain.tree_route and chain.find_uncles only return hahses of blocks that are in the blockchain. qed.").number();
hash_rlp.append(&block_hash);
hash_rlp.append(&number);
rlp_stream.append_raw(hash_rlp.as_raw(), 1);
@ -1844,7 +1844,8 @@ impl ChainSync {
/// creates latest block rlp for the given client
fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes {
ChainSync::create_block_rlp(
&chain.block(BlockId::Hash(chain.chain_info().best_block_hash)).expect("Best block always exists"),
&chain.block(BlockId::Hash(chain.chain_info().best_block_hash))
.expect("Best block always exists").into_inner(),
chain.chain_info().total_difficulty
)
}
@ -1852,7 +1853,7 @@ impl ChainSync {
/// creates given hash block rlp for the given client
fn create_new_block_rlp(chain: &BlockChainClient, hash: &H256) -> Bytes {
ChainSync::create_block_rlp(
&chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed"),
&chain.block(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed").into_inner(),
chain.block_total_difficulty(BlockId::Hash(hash.clone())).expect("Block has just been sealed; qed.")
)
}
@ -1915,8 +1916,7 @@ impl ChainSync {
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize {
trace!(target: "sync", "Sending NewHashes to {:?}", peers);
let mut sent = 0;
let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(chain_info.best_block_hash.clone()))
.expect("Best block always exists")).parent_hash();
let last_parent = &io.chain().best_block_header().parent_hash();
for peer_id in peers {
sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) {
Some(rlp) => {
@ -2099,7 +2099,6 @@ mod tests {
use super::*;
use ::SyncConfig;
use super::{PeerInfo, PeerAsking};
use ethcore::views::BlockView;
use ethcore::header::*;
use ethcore::client::*;
use ethcore::miner::MinerService;
@ -2253,7 +2252,8 @@ mod tests {
let mut client = TestBlockChainClient::new();
client.add_blocks(100, EachBlockWith::Nothing);
let blocks: Vec<_> = (0 .. 100).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect();
let blocks: Vec<_> = (0 .. 100)
.map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).map(|b| b.into_inner()).unwrap()).collect();
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
@ -2444,7 +2444,7 @@ mod tests {
let mut client = TestBlockChainClient::new();
client.add_blocks(2, EachBlockWith::Uncle);
let queue = RwLock::new(VecDeque::new());
let block = client.block(BlockId::Latest).unwrap();
let block = client.block(BlockId::Latest).unwrap().into_inner();
let mut sync = ChainSync::new(SyncConfig::default(), &client);
sync.peers.insert(0,
PeerInfo {
@ -2722,9 +2722,8 @@ mod tests {
// Add some balance to clients and reset nonces
for h in &[good_blocks[0], retracted_blocks[0]] {
let block = client.block(BlockId::Hash(*h)).unwrap();
let view = BlockView::new(&block);
client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000));
client.set_nonce(view.transactions()[0].sender().unwrap(), U256::from(0));
client.set_balance(block.transactions()[0].sender().unwrap(), U256::from(1_000_000_000));
client.set_nonce(block.transactions()[0].sender().unwrap(), U256::from(0));
}
@ -2741,8 +2740,7 @@ mod tests {
// We need to update nonce status (because we say that the block has been imported)
for h in &[good_blocks[0]] {
let block = client.block(BlockId::Hash(*h)).unwrap();
let view = BlockView::new(&block);
client.set_nonce(view.transactions()[0].sender().unwrap(), U256::from(1));
client.set_nonce(block.transactions()[0].sender().unwrap(), U256::from(1));
}
{
let queue = RwLock::new(VecDeque::new());