Owning views of blockchain data (#3982)

* owning views of blockchain data

* port blockchain and client traits to owning views

* fix ethcore tests

* use strong headers and bodies in ethcore_light

* port ethsync to use owning views

* port rpc to owning views

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

View File

@@ -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]