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]
|
||||
|
||||
Reference in New Issue
Block a user