storing block receitps in db, client logs method implementation
This commit is contained in:
parent
b01652f3e7
commit
5826a34ebb
@ -50,7 +50,9 @@ pub struct CacheSize {
|
|||||||
/// Logs cache size.
|
/// Logs cache size.
|
||||||
pub block_logs: usize,
|
pub block_logs: usize,
|
||||||
/// Blooms cache size.
|
/// Blooms cache size.
|
||||||
pub blocks_blooms: usize
|
pub blocks_blooms: usize,
|
||||||
|
/// Block receipts size.
|
||||||
|
pub block_receipts: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BloomIndexer {
|
struct BloomIndexer {
|
||||||
@ -147,6 +149,9 @@ pub trait BlockProvider {
|
|||||||
/// Get the address of transaction with given hash.
|
/// Get the address of transaction with given hash.
|
||||||
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress>;
|
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress>;
|
||||||
|
|
||||||
|
/// Get receipts of block with given hash.
|
||||||
|
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts>;
|
||||||
|
|
||||||
/// Get the partial-header of a block.
|
/// Get the partial-header of a block.
|
||||||
fn block_header(&self, hash: &H256) -> Option<Header> {
|
fn block_header(&self, hash: &H256) -> Option<Header> {
|
||||||
self.block(hash).map(|bytes| BlockView::new(&bytes).header())
|
self.block(hash).map(|bytes| BlockView::new(&bytes).header())
|
||||||
@ -223,6 +228,7 @@ pub struct BlockChain {
|
|||||||
transaction_addresses: RwLock<HashMap<H256, TransactionAddress>>,
|
transaction_addresses: RwLock<HashMap<H256, TransactionAddress>>,
|
||||||
block_logs: RwLock<HashMap<H256, BlockLogBlooms>>,
|
block_logs: RwLock<HashMap<H256, BlockLogBlooms>>,
|
||||||
blocks_blooms: RwLock<HashMap<H256, BlocksBlooms>>,
|
blocks_blooms: RwLock<HashMap<H256, BlocksBlooms>>,
|
||||||
|
block_receipts: RwLock<HashMap<H256, BlockReceipts>>,
|
||||||
|
|
||||||
extras_db: DB,
|
extras_db: DB,
|
||||||
blocks_db: DB,
|
blocks_db: DB,
|
||||||
@ -287,6 +293,11 @@ impl BlockProvider for BlockChain {
|
|||||||
self.query_extras(hash, &self.transaction_addresses)
|
self.query_extras(hash, &self.transaction_addresses)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get receipts of block with given hash.
|
||||||
|
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
|
||||||
|
self.query_extras(hash, &self.block_receipts)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns numbers of blocks containing given bloom.
|
/// Returns numbers of blocks containing given bloom.
|
||||||
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber> {
|
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber> {
|
||||||
let filter = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels());
|
let filter = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels());
|
||||||
@ -348,6 +359,7 @@ impl BlockChain {
|
|||||||
transaction_addresses: RwLock::new(HashMap::new()),
|
transaction_addresses: RwLock::new(HashMap::new()),
|
||||||
block_logs: RwLock::new(HashMap::new()),
|
block_logs: RwLock::new(HashMap::new()),
|
||||||
blocks_blooms: RwLock::new(HashMap::new()),
|
blocks_blooms: RwLock::new(HashMap::new()),
|
||||||
|
block_receipts: RwLock::new(HashMap::new()),
|
||||||
extras_db: extras_db,
|
extras_db: extras_db,
|
||||||
blocks_db: blocks_db,
|
blocks_db: blocks_db,
|
||||||
cache_man: RwLock::new(cache_man),
|
cache_man: RwLock::new(cache_man),
|
||||||
@ -504,7 +516,7 @@ impl BlockChain {
|
|||||||
/// Inserts the block into backing cache database.
|
/// Inserts the block into backing cache database.
|
||||||
/// Expects the block to be valid and already verified.
|
/// Expects the block to be valid and already verified.
|
||||||
/// If the block is already known, does nothing.
|
/// If the block is already known, does nothing.
|
||||||
pub fn insert_block(&self, bytes: &[u8], receipts: &[Receipt]) {
|
pub fn insert_block(&self, bytes: &[u8], receipts: Vec<Receipt>) {
|
||||||
// create views onto rlp
|
// create views onto rlp
|
||||||
let block = BlockView::new(bytes);
|
let block = BlockView::new(bytes);
|
||||||
let header = block.header_view();
|
let header = block.header_view();
|
||||||
@ -546,8 +558,7 @@ impl BlockChain {
|
|||||||
|
|
||||||
/// Transforms block into WriteBatch that may be written into database
|
/// Transforms block into WriteBatch that may be written into database
|
||||||
/// Additionally, if it's new best block it returns new best block object.
|
/// Additionally, if it's new best block it returns new best block object.
|
||||||
//fn block_to_extras_insert_batch(&self, bytes: &[u8], _receipts: &[Receipt]) -> (WriteBatch, Option<BestBlock>, BlockDetails) {
|
fn block_to_extras_update(&self, bytes: &[u8], receipts: Vec<Receipt>) -> ExtrasUpdate {
|
||||||
fn block_to_extras_update(&self, bytes: &[u8], _receipts: &[Receipt]) -> ExtrasUpdate {
|
|
||||||
// create views onto rlp
|
// create views onto rlp
|
||||||
let block = BlockView::new(bytes);
|
let block = BlockView::new(bytes);
|
||||||
let header = block.header_view();
|
let header = block.header_view();
|
||||||
@ -585,11 +596,8 @@ impl BlockChain {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// save blooms (is it really required?). maybe store receipt whole instead?
|
// update block receipts
|
||||||
//let blooms: Vec<H2048> = receipts.iter().map(|r| r.log_bloom.clone()).collect();
|
batch.put_extras(&hash, &BlockReceipts::new(receipts));
|
||||||
//batch.put_extras(&hash, &BlockLogBlooms {
|
|
||||||
//blooms: blooms
|
|
||||||
//});
|
|
||||||
|
|
||||||
// if it's not new best block, just return
|
// if it's not new best block, just return
|
||||||
if !is_new_best {
|
if !is_new_best {
|
||||||
@ -741,7 +749,8 @@ impl BlockChain {
|
|||||||
block_details: self.block_details.read().unwrap().heap_size_of_children(),
|
block_details: self.block_details.read().unwrap().heap_size_of_children(),
|
||||||
transaction_addresses: self.transaction_addresses.read().unwrap().heap_size_of_children(),
|
transaction_addresses: self.transaction_addresses.read().unwrap().heap_size_of_children(),
|
||||||
block_logs: self.block_logs.read().unwrap().heap_size_of_children(),
|
block_logs: self.block_logs.read().unwrap().heap_size_of_children(),
|
||||||
blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children()
|
blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children(),
|
||||||
|
block_receipts: self.block_receipts.read().unwrap().heap_size_of_children()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,6 +782,7 @@ impl BlockChain {
|
|||||||
let mut transaction_addresses = self.transaction_addresses.write().unwrap();
|
let mut transaction_addresses = self.transaction_addresses.write().unwrap();
|
||||||
let mut block_logs = self.block_logs.write().unwrap();
|
let mut block_logs = self.block_logs.write().unwrap();
|
||||||
let mut blocks_blooms = self.blocks_blooms.write().unwrap();
|
let mut blocks_blooms = self.blocks_blooms.write().unwrap();
|
||||||
|
let mut block_receipts = self.block_receipts.write().unwrap();
|
||||||
|
|
||||||
for id in cache_man.cache_usage.pop_back().unwrap().into_iter() {
|
for id in cache_man.cache_usage.pop_back().unwrap().into_iter() {
|
||||||
cache_man.in_use.remove(&id);
|
cache_man.in_use.remove(&id);
|
||||||
@ -782,6 +792,7 @@ impl BlockChain {
|
|||||||
CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); },
|
CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); },
|
||||||
CacheID::Extras(ExtrasIndex::BlockLogBlooms, h) => { block_logs.remove(&h); },
|
CacheID::Extras(ExtrasIndex::BlockLogBlooms, h) => { block_logs.remove(&h); },
|
||||||
CacheID::Extras(ExtrasIndex::BlocksBlooms, h) => { blocks_blooms.remove(&h); },
|
CacheID::Extras(ExtrasIndex::BlocksBlooms, h) => { blocks_blooms.remove(&h); },
|
||||||
|
CacheID::Extras(ExtrasIndex::BlockReceipts, h) => { block_receipts.remove(&h); },
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -823,7 +834,7 @@ mod tests {
|
|||||||
|
|
||||||
let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap();
|
let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap();
|
||||||
|
|
||||||
bc.insert_block(&first, &[]);
|
bc.insert_block(&first, vec![]);
|
||||||
|
|
||||||
let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap();
|
let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap();
|
||||||
|
|
||||||
@ -856,10 +867,10 @@ mod tests {
|
|||||||
|
|
||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let bc = BlockChain::new(&genesis, temp.as_path());
|
let bc = BlockChain::new(&genesis, temp.as_path());
|
||||||
bc.insert_block(&b1, &[]);
|
bc.insert_block(&b1, vec![]);
|
||||||
bc.insert_block(&b2, &[]);
|
bc.insert_block(&b2, vec![]);
|
||||||
bc.insert_block(&b3a, &[]);
|
bc.insert_block(&b3a, vec![]);
|
||||||
bc.insert_block(&b3b, &[]);
|
bc.insert_block(&b3b, vec![]);
|
||||||
|
|
||||||
assert_eq!(bc.best_block_hash(), best_block_hash);
|
assert_eq!(bc.best_block_hash(), best_block_hash);
|
||||||
assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0);
|
assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0);
|
||||||
@ -936,7 +947,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let bc = BlockChain::new(&genesis, temp.as_path());
|
let bc = BlockChain::new(&genesis, temp.as_path());
|
||||||
assert_eq!(bc.best_block_hash(), genesis_hash);
|
assert_eq!(bc.best_block_hash(), genesis_hash);
|
||||||
bc.insert_block(&b1, &[]);
|
bc.insert_block(&b1, vec![]);
|
||||||
assert_eq!(bc.best_block_hash(), b1_hash);
|
assert_eq!(bc.best_block_hash(), b1_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,7 +1006,7 @@ mod tests {
|
|||||||
|
|
||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let bc = BlockChain::new(&genesis, temp.as_path());
|
let bc = BlockChain::new(&genesis, temp.as_path());
|
||||||
bc.insert_block(&b1, &[]);
|
bc.insert_block(&b1, vec![]);
|
||||||
|
|
||||||
let transactions = bc.transactions(&b1_hash).unwrap();
|
let transactions = bc.transactions(&b1_hash).unwrap();
|
||||||
assert_eq!(transactions.len(), 7);
|
assert_eq!(transactions.len(), 7);
|
||||||
@ -1026,13 +1037,13 @@ mod tests {
|
|||||||
assert_eq!(blocks_b1, vec![]);
|
assert_eq!(blocks_b1, vec![]);
|
||||||
assert_eq!(blocks_b2, vec![]);
|
assert_eq!(blocks_b2, vec![]);
|
||||||
|
|
||||||
bc.insert_block(&b1, &[]);
|
bc.insert_block(&b1, vec![]);
|
||||||
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3);
|
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3);
|
||||||
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3);
|
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3);
|
||||||
assert_eq!(blocks_b1, vec![1]);
|
assert_eq!(blocks_b1, vec![1]);
|
||||||
assert_eq!(blocks_b2, vec![]);
|
assert_eq!(blocks_b2, vec![]);
|
||||||
|
|
||||||
bc.insert_block(&b2, &[]);
|
bc.insert_block(&b2, vec![]);
|
||||||
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3);
|
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3);
|
||||||
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3);
|
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3);
|
||||||
assert_eq!(blocks_b1, vec![1]);
|
assert_eq!(blocks_b1, vec![1]);
|
||||||
|
@ -33,7 +33,9 @@ use env_info::LastHashes;
|
|||||||
use verification::*;
|
use verification::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use transaction::LocalizedTransaction;
|
use transaction::LocalizedTransaction;
|
||||||
use extras::TransactionAddress;
|
use extras::{TransactionAddress, BlockReceipts};
|
||||||
|
use filter::Filter;
|
||||||
|
use log_entry::LocalizedLogEntry;
|
||||||
pub use blockchain::TreeRoute;
|
pub use blockchain::TreeRoute;
|
||||||
|
|
||||||
/// Uniquely identifies block.
|
/// Uniquely identifies block.
|
||||||
@ -147,6 +149,9 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
|
|
||||||
/// Returns numbers of blocks containing given bloom.
|
/// Returns numbers of blocks containing given bloom.
|
||||||
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>>;
|
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>>;
|
||||||
|
|
||||||
|
/// Returns logs matching given filter.
|
||||||
|
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug, Eq, PartialEq)]
|
#[derive(Default, Clone, Debug, Eq, PartialEq)]
|
||||||
@ -307,7 +312,7 @@ impl Client {
|
|||||||
|
|
||||||
good_blocks.push(header.hash().clone());
|
good_blocks.push(header.hash().clone());
|
||||||
|
|
||||||
self.chain.write().unwrap().insert_block(&block.bytes, result.block().receipts()); //TODO: err here?
|
self.chain.write().unwrap().insert_block(&block.bytes, result.block().receipts().clone()); //TODO: err here?
|
||||||
let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None };
|
let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None };
|
||||||
match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) {
|
match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
@ -474,6 +479,50 @@ impl BlockChainClient for Client {
|
|||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||||
|
let mut blocks = filter.bloom_possibilities().iter()
|
||||||
|
.map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone()))
|
||||||
|
.filter_map(|m| m)
|
||||||
|
.flat_map(|m| m)
|
||||||
|
// remove duplicate elements
|
||||||
|
.collect::<HashSet<u64>>()
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<u64>>();
|
||||||
|
|
||||||
|
blocks.sort();
|
||||||
|
|
||||||
|
blocks.into_iter()
|
||||||
|
.map(|number| self.chain.read().unwrap().block_hash(number).map(|hash| (number, hash)))
|
||||||
|
.filter_map(|m| m)
|
||||||
|
.map(|(number, hash)| self.chain.read().unwrap().block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
||||||
|
.filter_map(|m| m)
|
||||||
|
.map(|(number, hash, receipts)| {
|
||||||
|
let mut log_index = 0;
|
||||||
|
receipts.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, receipt)| {
|
||||||
|
log_index += receipt.logs.len();
|
||||||
|
receipt.logs.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|tuple| filter.matches(&tuple.1))
|
||||||
|
.map(|(i, log)| LocalizedLogEntry {
|
||||||
|
entry: log,
|
||||||
|
block_hash: hash.clone(),
|
||||||
|
block_number: number as usize,
|
||||||
|
transaction_hash: H256::new(),
|
||||||
|
transaction_index: index,
|
||||||
|
log_index: log_index
|
||||||
|
})
|
||||||
|
.collect::<Vec<LocalizedLogEntry>>()
|
||||||
|
})
|
||||||
|
.flat_map(|m| m)
|
||||||
|
.collect::<Vec<LocalizedLogEntry>>()
|
||||||
|
|
||||||
|
})
|
||||||
|
.flat_map(|m| m)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MayPanic for Client {
|
impl MayPanic for Client {
|
||||||
|
@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
//! Blockchain DB extras.
|
//! Blockchain DB extras.
|
||||||
|
|
||||||
|
use rocksdb::{DB, Writable};
|
||||||
use util::*;
|
use util::*;
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use rocksdb::{DB, Writable};
|
use receipt::Receipt;
|
||||||
|
|
||||||
/// Represents index of extra data in database
|
/// Represents index of extra data in database
|
||||||
#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
|
#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
|
||||||
@ -32,7 +33,9 @@ pub enum ExtrasIndex {
|
|||||||
/// Block log blooms index
|
/// Block log blooms index
|
||||||
BlockLogBlooms = 3,
|
BlockLogBlooms = 3,
|
||||||
/// Block blooms index
|
/// Block blooms index
|
||||||
BlocksBlooms = 4
|
BlocksBlooms = 4,
|
||||||
|
/// Block receipts index
|
||||||
|
BlockReceipts
|
||||||
}
|
}
|
||||||
|
|
||||||
/// trait used to write Extras data to db
|
/// trait used to write Extras data to db
|
||||||
@ -307,3 +310,43 @@ impl Encodable for TransactionAddress {
|
|||||||
s.append(&self.index);
|
s.append(&self.index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Contains all block receipts.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BlockReceipts {
|
||||||
|
pub receipts: Vec<Receipt>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockReceipts {
|
||||||
|
pub fn new(receipts: Vec<Receipt>) -> Self {
|
||||||
|
BlockReceipts {
|
||||||
|
receipts: receipts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for BlockReceipts {
|
||||||
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
|
Ok(BlockReceipts {
|
||||||
|
receipts: try!(Decodable::decode(decoder))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for BlockReceipts {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
s.append(&self.receipts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeapSizeOf for BlockReceipts {
|
||||||
|
fn heap_size_of_children(&self) -> usize {
|
||||||
|
self.receipts.heap_size_of_children()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExtrasIndexable for BlockReceipts {
|
||||||
|
fn extras_index() -> ExtrasIndex {
|
||||||
|
ExtrasIndex::BlockReceipts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,26 +17,27 @@
|
|||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use util::sha3::*;
|
use util::sha3::*;
|
||||||
use client::BlockId;
|
use client::BlockId;
|
||||||
|
use log_entry::LogEntry;
|
||||||
|
|
||||||
/// Blockchain log filter data.
|
/// Blockchain log filter data.
|
||||||
pub struct Filter {
|
pub struct Filter {
|
||||||
/// Blockchain will be searched from this block.
|
/// Blockchain will be searched from this block.
|
||||||
from_block: BlockId,
|
pub from_block: BlockId,
|
||||||
|
|
||||||
/// Till this block.
|
/// Till this block.
|
||||||
to_block: BlockId,
|
pub to_block: BlockId,
|
||||||
|
|
||||||
/// Search addresses.
|
/// Search addresses.
|
||||||
///
|
///
|
||||||
/// If None, match all.
|
/// If None, match all.
|
||||||
/// If specified, log must be produced by one of these addresses.
|
/// If specified, log must be produced by one of these addresses.
|
||||||
address: Option<Vec<Address>>,
|
pub address: Option<Vec<Address>>,
|
||||||
|
|
||||||
/// Search topics.
|
/// Search topics.
|
||||||
///
|
///
|
||||||
/// If None, match all.
|
/// If None, match all.
|
||||||
/// If specified, log must contain one of these topics.
|
/// If specified, log must contain one of these topics.
|
||||||
topics: [Option<Vec<H256>>; 4]
|
pub topics: [Option<Vec<H256>>; 4]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filter {
|
impl Filter {
|
||||||
@ -63,6 +64,23 @@ impl Filter {
|
|||||||
}).flat_map(|m| m).collect()
|
}).flat_map(|m| m).collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if given log entry matches filter.
|
||||||
|
pub fn matches(&self, log: &LogEntry) -> bool {
|
||||||
|
let matches = match self.address {
|
||||||
|
Some(ref addresses) if !addresses.is_empty() => addresses.iter().fold(false, |res, address| {
|
||||||
|
res || &log.address == address
|
||||||
|
}),
|
||||||
|
_ => true
|
||||||
|
};
|
||||||
|
|
||||||
|
matches && self.topics.iter().enumerate().fold(true, |res, (i, topic)| match *topic {
|
||||||
|
Some(ref topics) if !topics.is_empty() => res && topics.iter().fold(false, | acc, topic | {
|
||||||
|
acc || log.topics.get(i) == Some(topic)
|
||||||
|
}),
|
||||||
|
_ => res,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -71,6 +89,7 @@ mod tests {
|
|||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use client::BlockId;
|
use client::BlockId;
|
||||||
|
use log_entry::LogEntry;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bloom_possibilities_none() {
|
fn test_bloom_possibilities_none() {
|
||||||
@ -149,4 +168,49 @@ mod tests {
|
|||||||
assert_eq!(possibilities[0], H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
assert_eq!(possibilities[0], H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_filter_matches() {
|
||||||
|
let filter = Filter {
|
||||||
|
from_block: BlockId::Earliest,
|
||||||
|
to_block: BlockId::Latest,
|
||||||
|
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
|
||||||
|
topics: [
|
||||||
|
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
|
||||||
|
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap()]),
|
||||||
|
None, None
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let entry0 = LogEntry {
|
||||||
|
address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
|
||||||
|
topics: vec![
|
||||||
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(),
|
||||||
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap(),
|
||||||
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(),
|
||||||
|
],
|
||||||
|
data: vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let entry1 = LogEntry {
|
||||||
|
address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5e").unwrap(),
|
||||||
|
topics: vec![
|
||||||
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(),
|
||||||
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap(),
|
||||||
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(),
|
||||||
|
],
|
||||||
|
data: vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let entry2 = LogEntry {
|
||||||
|
address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
|
||||||
|
topics: vec![
|
||||||
|
H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(),
|
||||||
|
],
|
||||||
|
data: vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(filter.matches(&entry0), true);
|
||||||
|
assert_eq!(filter.matches(&entry1), false);
|
||||||
|
assert_eq!(filter.matches(&entry2), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,24 @@ impl Encodable for LogEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Decodable for LogEntry {
|
||||||
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
|
let d = decoder.as_rlp();
|
||||||
|
let entry = LogEntry {
|
||||||
|
address: try!(d.val_at(0)),
|
||||||
|
topics: try!(d.val_at(1)),
|
||||||
|
data: try!(d.val_at(2)),
|
||||||
|
};
|
||||||
|
Ok(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeapSizeOf for LogEntry {
|
||||||
|
fn heap_size_of_children(&self) -> usize {
|
||||||
|
self.topics.heap_size_of_children() + self.data.heap_size_of_children()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LogEntry {
|
impl LogEntry {
|
||||||
/// Calculates the bloom of this log entry.
|
/// Calculates the bloom of this log entry.
|
||||||
pub fn bloom(&self) -> LogBloom {
|
pub fn bloom(&self) -> LogBloom {
|
||||||
|
@ -55,6 +55,24 @@ impl Encodable for Receipt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Decodable for Receipt {
|
||||||
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
|
let d = decoder.as_rlp();
|
||||||
|
let receipt = Receipt {
|
||||||
|
state_root: try!(d.val_at(0)),
|
||||||
|
gas_used: try!(d.val_at(1)),
|
||||||
|
log_bloom: try!(d.val_at(2)),
|
||||||
|
logs: try!(d.val_at(3)),
|
||||||
|
};
|
||||||
|
Ok(receipt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeapSizeOf for Receipt {
|
||||||
|
fn heap_size_of_children(&self) -> usize {
|
||||||
|
self.logs.heap_size_of_children()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic() {
|
fn test_basic() {
|
||||||
|
@ -224,7 +224,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult<BlockCh
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path());
|
let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path());
|
||||||
for block_order in 1..block_number {
|
for block_order in 1..block_number {
|
||||||
bc.insert_block(&create_unverifiable_block(block_order, bc.best_block_hash()), &[]);
|
bc.insert_block(&create_unverifiable_block(block_order, bc.best_block_hash()), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuardedTempResult::<BlockChain> {
|
GuardedTempResult::<BlockChain> {
|
||||||
@ -237,7 +237,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes
|
|||||||
let temp = RandomTempPath::new();
|
let temp = RandomTempPath::new();
|
||||||
let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path());
|
let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path());
|
||||||
for block_order in 1..block_number {
|
for block_order in 1..block_number {
|
||||||
bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), &[]);
|
bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuardedTempResult::<BlockChain> {
|
GuardedTempResult::<BlockChain> {
|
||||||
|
@ -306,6 +306,10 @@ mod tests {
|
|||||||
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec<BlockNumber> {
|
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec<BlockNumber> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn block_receipts(&self, _hash: &H256) -> Option<BlockReceipts> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> {
|
fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> {
|
||||||
|
Loading…
Reference in New Issue
Block a user