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:
parent
592a3ac623
commit
fe1f542c4f
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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]
|
||||
|
273
ethcore/src/types/encoded.rs
Normal file
273
ethcore/src/types/encoded.rs
Normal 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() }
|
||||
}
|
@ -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;
|
||||
|
@ -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> {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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."); }
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user