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:
committed by
Gav Wood
parent
592a3ac623
commit
fe1f542c4f
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user