Merge pull request #203 from ethcore/indexed-blocks
Using IndexedBlock-s in sync, verification & db
This commit is contained in:
commit
1e9428a3a5
|
@ -1,5 +1,5 @@
|
|||
use primitives::hash::H256;
|
||||
use super::BlockLocation;
|
||||
use super::{BlockLocation, IndexedBlock};
|
||||
use chain;
|
||||
use error::Error;
|
||||
|
||||
|
@ -46,4 +46,7 @@ pub trait BlockStapler {
|
|||
|
||||
/// insert block in the storage
|
||||
fn insert_block(&self, block: &chain::Block) -> Result<BlockInsertedChain, Error>;
|
||||
|
||||
/// insert pre-processed block in the storage
|
||||
fn insert_indexed_block(&self, block: &IndexedBlock) -> Result<BlockInsertedChain, Error>;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use chain;
|
||||
use primitives::hash::H256;
|
||||
use serialization::Serializable;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IndexedBlock {
|
||||
header: chain::BlockHeader,
|
||||
header_hash: H256,
|
||||
|
@ -28,8 +30,20 @@ impl From<chain::Block> for IndexedBlock {
|
|||
}
|
||||
|
||||
impl IndexedBlock {
|
||||
pub fn transactions_len(&self) -> usize {
|
||||
self.transactions.len()
|
||||
pub fn new(header: chain::BlockHeader, transaction_index: Vec<(H256, chain::Transaction)>) -> Self {
|
||||
let mut block = IndexedBlock {
|
||||
header_hash: header.hash(),
|
||||
header: header,
|
||||
transactions: Vec::with_capacity(transaction_index.len()),
|
||||
transaction_hashes: Vec::with_capacity(transaction_index.len()),
|
||||
};
|
||||
|
||||
for (h256, tx) in transaction_index {
|
||||
block.transactions.push(tx);
|
||||
block.transaction_hashes.push(h256);
|
||||
}
|
||||
|
||||
block
|
||||
}
|
||||
|
||||
pub fn transactions(&self) -> IndexedTransactions {
|
||||
|
@ -39,6 +53,10 @@ impl IndexedBlock {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn transaction_hashes(&self) -> &[H256] {
|
||||
&self.transaction_hashes
|
||||
}
|
||||
|
||||
pub fn header(&self) -> &chain::BlockHeader {
|
||||
&self.header
|
||||
}
|
||||
|
@ -46,6 +64,30 @@ impl IndexedBlock {
|
|||
pub fn hash(&self) -> &H256 {
|
||||
&self.header_hash
|
||||
}
|
||||
|
||||
pub fn transaction_count(&self) -> usize {
|
||||
self.transaction_hashes.len()
|
||||
}
|
||||
|
||||
pub fn to_block(&self) -> chain::Block {
|
||||
chain::Block::new(
|
||||
self.header.clone(),
|
||||
self.transactions.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
// todo: optimize
|
||||
self.to_block().serialized_size()
|
||||
}
|
||||
|
||||
pub fn merkle_root(&self) -> H256 {
|
||||
chain::merkle_root(&self.transaction_hashes)
|
||||
}
|
||||
|
||||
pub fn is_final(&self, height: u32) -> bool {
|
||||
self.transactions.iter().all(|t| t.is_final(height, self.header.time))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IndexedTransactions<'a> {
|
||||
|
|
|
@ -6,7 +6,7 @@ use kvdb::{Database, DatabaseConfig};
|
|||
use byteorder::{LittleEndian, ByteOrder};
|
||||
use primitives::hash::H256;
|
||||
use primitives::bytes::Bytes;
|
||||
use super::{BlockRef, BestBlock, BlockLocation};
|
||||
use super::{BlockRef, BestBlock, BlockLocation, IndexedBlock, IndexedTransactions};
|
||||
use serialization::{serialize, deserialize};
|
||||
use chain;
|
||||
use parking_lot::RwLock;
|
||||
|
@ -168,20 +168,41 @@ impl Storage {
|
|||
})
|
||||
}
|
||||
|
||||
fn block_by_hash(&self, h: &H256) -> Option<IndexedBlock> {
|
||||
|
||||
self.block_header_by_hash(h).map(|header| {
|
||||
let tx_index =
|
||||
self.block_transaction_hashes_by_hash(h)
|
||||
.into_iter()
|
||||
.filter_map(|tx_hash| {
|
||||
self.transaction_bytes(&tx_hash)
|
||||
.map(|tx_bytes| {
|
||||
(
|
||||
tx_hash,
|
||||
deserialize::<_, chain::Transaction>(tx_bytes.as_ref())
|
||||
.expect("Error deserializing transaction, possible db corruption"),
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
IndexedBlock::new(header, tx_index)
|
||||
})
|
||||
}
|
||||
|
||||
/// update transactions metadata in the specified database transaction
|
||||
fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &[chain::Transaction])
|
||||
fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &mut IndexedTransactions)
|
||||
-> Result<(), Error>
|
||||
{
|
||||
if let Some(accepted_tx) = accepted_txs.iter().next() {
|
||||
if let Some((accepted_hash, accepted_tx)) = accepted_txs.next() {
|
||||
context.meta.insert(
|
||||
accepted_tx.hash(),
|
||||
accepted_hash.clone(),
|
||||
TransactionMeta::new_coinbase(number, accepted_tx.outputs.len())
|
||||
);
|
||||
}
|
||||
|
||||
for accepted_tx in accepted_txs.iter().skip(1) {
|
||||
for (accepted_hash, accepted_tx) in accepted_txs {
|
||||
context.meta.insert(
|
||||
accepted_tx.hash(),
|
||||
accepted_hash.clone(),
|
||||
TransactionMeta::new(number, accepted_tx.outputs.len())
|
||||
);
|
||||
|
||||
|
@ -294,8 +315,8 @@ impl Storage {
|
|||
}
|
||||
|
||||
fn canonize_block(&self, context: &mut UpdateContext, at_height: u32, hash: &H256) -> Result<(), Error> {
|
||||
let transactions = self.block_transactions_by_hash(hash);
|
||||
try!(self.update_transactions_meta(context, at_height, &transactions));
|
||||
let block = try!(self.block_by_hash(hash).ok_or(Error::unknown_hash(hash)));
|
||||
try!(self.update_transactions_meta(context, at_height, &mut block.transactions()));
|
||||
|
||||
// only canonical blocks are allowed to wield a number
|
||||
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(at_height), &**hash);
|
||||
|
@ -412,8 +433,12 @@ impl BlockProvider for Storage {
|
|||
|
||||
impl BlockStapler for Storage {
|
||||
|
||||
/// insert pre-processed block in the storage
|
||||
fn insert_block(&self, block: &chain::Block) -> Result<BlockInsertedChain, Error> {
|
||||
self.insert_indexed_block(&block.clone().into())
|
||||
}
|
||||
|
||||
fn insert_indexed_block(&self, block: &IndexedBlock) -> Result<BlockInsertedChain, Error> {
|
||||
// ! lock will be held during the entire insert routine
|
||||
let mut best_block = self.best_block.write();
|
||||
|
||||
|
@ -428,39 +453,38 @@ impl BlockStapler for Storage {
|
|||
|
||||
let mut new_best_number = match best_block.as_ref().map(|b| b.number) {
|
||||
Some(best_number) => {
|
||||
if block.hash() == new_best_hash { best_number + 1 }
|
||||
if block.hash() == &new_best_hash { best_number + 1 }
|
||||
else { best_number }
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let tx_space = block.transactions().len() * 32;
|
||||
let tx_space = block.transaction_count() * 32;
|
||||
let mut tx_refs = Vec::with_capacity(tx_space);
|
||||
for tx in block.transactions() {
|
||||
let tx_hash = tx.hash();
|
||||
tx_refs.extend(&*tx_hash);
|
||||
for (tx_hash, tx) in block.transactions() {
|
||||
tx_refs.extend(&**tx_hash);
|
||||
context.db_transaction.put(
|
||||
Some(COL_TRANSACTIONS),
|
||||
&*tx_hash,
|
||||
&**tx_hash,
|
||||
&serialize(tx),
|
||||
);
|
||||
}
|
||||
context.db_transaction.put(Some(COL_BLOCK_TRANSACTIONS), &*block_hash, &tx_refs);
|
||||
context.db_transaction.put(Some(COL_BLOCK_TRANSACTIONS), &**block_hash, &tx_refs);
|
||||
|
||||
context.db_transaction.put(
|
||||
Some(COL_BLOCK_HEADERS),
|
||||
&*block_hash,
|
||||
&**block_hash,
|
||||
&serialize(block.header())
|
||||
);
|
||||
|
||||
// the block is continuing the main chain
|
||||
let result = if best_block.as_ref().map(|b| b.number) != Some(new_best_number) {
|
||||
try!(self.update_transactions_meta(&mut context, new_best_number, block.transactions()));
|
||||
try!(self.update_transactions_meta(&mut context, new_best_number, &mut block.transactions()));
|
||||
context.db_transaction.write_u32(Some(COL_META), KEY_BEST_BLOCK_NUMBER, new_best_number);
|
||||
|
||||
// updating main chain height reference
|
||||
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(new_best_number), &*block_hash);
|
||||
context.db_transaction.write_u32(Some(COL_BLOCK_NUMBERS), &*block_hash, new_best_number);
|
||||
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(new_best_number), &**block_hash);
|
||||
context.db_transaction.write_u32(Some(COL_BLOCK_NUMBERS), &**block_hash, new_best_number);
|
||||
|
||||
BlockInsertedChain::Main
|
||||
}
|
||||
|
@ -473,10 +497,10 @@ impl BlockStapler for Storage {
|
|||
Ok(Some(mut reorg)) => {
|
||||
// if so, we have new best main chain block
|
||||
new_best_number = reorg.height + 1;
|
||||
new_best_hash = block_hash;
|
||||
new_best_hash = block_hash.clone();
|
||||
|
||||
// and we canonize it also by provisioning transactions
|
||||
try!(self.update_transactions_meta(&mut context, new_best_number, block.transactions()));
|
||||
try!(self.update_transactions_meta(&mut context, new_best_number, &mut block.transactions()));
|
||||
context.db_transaction.write_u32(Some(COL_META), KEY_BEST_BLOCK_NUMBER, new_best_number);
|
||||
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(new_best_number), &*new_best_hash);
|
||||
context.db_transaction.write_u32(Some(COL_BLOCK_NUMBERS), &*new_best_hash, new_best_number);
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
use super::{
|
||||
BlockRef, Store, Error, BestBlock, BlockLocation, BlockInsertedChain, BlockProvider,
|
||||
BlockStapler, TransactionMetaProvider, TransactionProvider, AsTransactionProvider
|
||||
BlockStapler, TransactionMetaProvider, TransactionProvider, AsTransactionProvider,
|
||||
IndexedBlock,
|
||||
};
|
||||
use chain::{self, Block};
|
||||
use primitives::hash::H256;
|
||||
|
@ -111,6 +112,10 @@ impl BlockProvider for TestStorage {
|
|||
}
|
||||
|
||||
impl BlockStapler for TestStorage {
|
||||
/// insert pre-processed block in the storage
|
||||
fn insert_indexed_block(&self, block: &IndexedBlock) -> Result<BlockInsertedChain, Error> {
|
||||
self.insert_block(&block.to_block())
|
||||
}
|
||||
|
||||
fn insert_block(&self, block: &chain::Block) -> Result<BlockInsertedChain, Error> {
|
||||
let hash = block.hash();
|
||||
|
|
|
@ -19,14 +19,15 @@ impl BlocksWriter {
|
|||
}
|
||||
|
||||
pub fn append_block(&mut self, block: chain::Block) -> Result<(), Error> {
|
||||
let indexed_block: db::IndexedBlock = block.into();
|
||||
// TODO: share same verification code with synchronization_client
|
||||
if self.storage.best_block().map_or(false, |bb| bb.hash != block.block_header.previous_header_hash) {
|
||||
if self.storage.best_block().map_or(false, |bb| bb.hash != indexed_block.header().previous_header_hash) {
|
||||
return Err(Error::OutOfOrderBlock);
|
||||
}
|
||||
|
||||
match self.verifier.verify(&block) {
|
||||
match self.verifier.verify(&indexed_block) {
|
||||
Err(err) => Err(Error::Verification(err)),
|
||||
Ok(_chain) => { try!(self.storage.insert_block(&block).map_err(Error::Database)); Ok(()) }
|
||||
Ok(_chain) => { try!(self.storage.insert_indexed_block(&indexed_block).map_err(Error::Database)); Ok(()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn build_compact_block(block: IndexedBlock, prefilled_transactions_indexes:
|
|||
let nonce: u64 = thread_rng().gen();
|
||||
|
||||
let prefilled_transactions_len = prefilled_transactions_indexes.len();
|
||||
let mut short_ids: Vec<ShortTransactionID> = Vec::with_capacity(block.transactions_len() - prefilled_transactions_len);
|
||||
let mut short_ids: Vec<ShortTransactionID> = Vec::with_capacity(block.transaction_count() - prefilled_transactions_len);
|
||||
let mut prefilled_transactions: Vec<PrefilledTransaction> = Vec::with_capacity(prefilled_transactions_len);
|
||||
let mut prefilled_transactions_size: usize = 0;
|
||||
|
||||
|
@ -72,5 +72,5 @@ mod tests {
|
|||
#[test]
|
||||
fn compact_block_is_built_correctly() {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ impl<T, U, V> LocalNode<T, U, V> where T: SynchronizationTaskExecutor + PeersCon
|
|||
trace!(target: "sync", "Got `block` message from peer#{}. Block hash: {}", peer_index, message.block.hash().to_reversed_str());
|
||||
|
||||
// try to process new block
|
||||
self.client.lock().on_peer_block(peer_index, message.block);
|
||||
self.client.lock().on_peer_block(peer_index, message.block.into());
|
||||
}
|
||||
|
||||
pub fn on_peer_headers(&self, peer_index: usize, message: types::Headers) {
|
||||
|
|
|
@ -2,15 +2,15 @@ use std::collections::{HashMap, HashSet, VecDeque};
|
|||
use std::collections::hash_map::Entry;
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use time;
|
||||
use chain::Block;
|
||||
use primitives::hash::H256;
|
||||
use db::IndexedBlock;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Storage for blocks, for which we have no parent yet.
|
||||
/// Blocks from this storage are either moved to verification queue, or removed at all.
|
||||
pub struct OrphanBlocksPool {
|
||||
/// Blocks from requested_hashes, but received out-of-order.
|
||||
orphaned_blocks: HashMap<H256, HashMap<H256, Block>>,
|
||||
orphaned_blocks: HashMap<H256, HashMap<H256, IndexedBlock>>,
|
||||
/// Blocks that we have received without requesting with receiving time.
|
||||
unknown_blocks: LinkedHashMap<H256, f64>,
|
||||
}
|
||||
|
@ -41,15 +41,15 @@ impl OrphanBlocksPool {
|
|||
}
|
||||
|
||||
/// Insert orphaned block, for which we have already requested its parent block
|
||||
pub fn insert_orphaned_block(&mut self, hash: H256, block: Block) {
|
||||
pub fn insert_orphaned_block(&mut self, hash: H256, block: IndexedBlock) {
|
||||
self.orphaned_blocks
|
||||
.entry(block.block_header.previous_header_hash.clone())
|
||||
.entry(block.header().previous_header_hash.clone())
|
||||
.or_insert_with(HashMap::new)
|
||||
.insert(hash, block);
|
||||
}
|
||||
|
||||
/// Insert unknown block, for which we know nothing about its parent block
|
||||
pub fn insert_unknown_block(&mut self, hash: H256, block: Block) {
|
||||
pub fn insert_unknown_block(&mut self, hash: H256, block: IndexedBlock) {
|
||||
let previous_value = self.unknown_blocks.insert(hash.clone(), time::precise_time_s());
|
||||
assert_eq!(previous_value, None);
|
||||
|
||||
|
@ -67,11 +67,11 @@ impl OrphanBlocksPool {
|
|||
}
|
||||
|
||||
/// Remove all blocks, depending on this parent
|
||||
pub fn remove_blocks_for_parent(&mut self, hash: &H256) -> Vec<(H256, Block)> {
|
||||
pub fn remove_blocks_for_parent(&mut self, hash: &H256) -> Vec<(H256, IndexedBlock)> {
|
||||
let mut queue: VecDeque<H256> = VecDeque::new();
|
||||
queue.push_back(hash.clone());
|
||||
|
||||
let mut removed: Vec<(H256, Block)> = Vec::new();
|
||||
let mut removed: Vec<(H256, IndexedBlock)> = Vec::new();
|
||||
while let Some(parent_hash) = queue.pop_front() {
|
||||
if let Entry::Occupied(entry) = self.orphaned_blocks.entry(parent_hash) {
|
||||
let (_, orphaned) = entry.remove_entry();
|
||||
|
@ -86,9 +86,9 @@ impl OrphanBlocksPool {
|
|||
}
|
||||
|
||||
/// Remove blocks with given hashes + all dependent blocks
|
||||
pub fn remove_blocks(&mut self, hashes: &HashSet<H256>) -> Vec<(H256, Block)> {
|
||||
pub fn remove_blocks(&mut self, hashes: &HashSet<H256>) -> Vec<(H256, IndexedBlock)> {
|
||||
// TODO: excess clone
|
||||
let mut removed: Vec<(H256, Block)> = Vec::new();
|
||||
let mut removed: Vec<(H256, IndexedBlock)> = Vec::new();
|
||||
let parent_orphan_keys: Vec<_> = self.orphaned_blocks.keys().cloned().collect();
|
||||
for parent_orphan_key in parent_orphan_keys {
|
||||
if let Entry::Occupied(mut orphan_entry) = self.orphaned_blocks.entry(parent_orphan_key) {
|
||||
|
@ -138,7 +138,7 @@ mod tests {
|
|||
let b1 = test_data::block_h1();
|
||||
let b1_hash = b1.hash();
|
||||
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1);
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1.into());
|
||||
|
||||
assert_eq!(pool.len(), 1);
|
||||
assert!(!pool.contains_unknown_block(&b1_hash));
|
||||
|
@ -151,7 +151,7 @@ mod tests {
|
|||
let b1 = test_data::block_h1();
|
||||
let b1_hash = b1.hash();
|
||||
|
||||
pool.insert_unknown_block(b1_hash.clone(), b1);
|
||||
pool.insert_unknown_block(b1_hash.clone(), b1.into());
|
||||
|
||||
assert_eq!(pool.len(), 1);
|
||||
assert!(pool.contains_unknown_block(&b1_hash));
|
||||
|
@ -166,8 +166,8 @@ mod tests {
|
|||
let b2 = test_data::block_h169();
|
||||
let b2_hash = b2.hash();
|
||||
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1);
|
||||
pool.insert_unknown_block(b2_hash.clone(), b2);
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1.into());
|
||||
pool.insert_unknown_block(b2_hash.clone(), b2.into());
|
||||
|
||||
assert_eq!(pool.len(), 2);
|
||||
assert!(!pool.contains_unknown_block(&b1_hash));
|
||||
|
@ -192,9 +192,9 @@ mod tests {
|
|||
let b3 = test_data::block_h2();
|
||||
let b3_hash = b3.hash();
|
||||
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1);
|
||||
pool.insert_unknown_block(b2_hash.clone(), b2);
|
||||
pool.insert_orphaned_block(b3_hash.clone(), b3);
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1.into());
|
||||
pool.insert_unknown_block(b2_hash.clone(), b2.into());
|
||||
pool.insert_orphaned_block(b3_hash.clone(), b3.into());
|
||||
|
||||
let removed = pool.remove_blocks_for_parent(&test_data::genesis().hash());
|
||||
assert_eq!(removed.len(), 2);
|
||||
|
@ -222,11 +222,11 @@ mod tests {
|
|||
let b5 = test_data::block_h181();
|
||||
let b5_hash = b5.hash();
|
||||
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1);
|
||||
pool.insert_orphaned_block(b2_hash.clone(), b2);
|
||||
pool.insert_orphaned_block(b3_hash.clone(), b3);
|
||||
pool.insert_orphaned_block(b4_hash.clone(), b4);
|
||||
pool.insert_orphaned_block(b5_hash.clone(), b5);
|
||||
pool.insert_orphaned_block(b1_hash.clone(), b1.into());
|
||||
pool.insert_orphaned_block(b2_hash.clone(), b2.into());
|
||||
pool.insert_orphaned_block(b3_hash.clone(), b3.into());
|
||||
pool.insert_orphaned_block(b4_hash.clone(), b4.into());
|
||||
pool.insert_orphaned_block(b5_hash.clone(), b5.into());
|
||||
|
||||
let mut blocks_to_remove: HashSet<H256> = HashSet::new();
|
||||
blocks_to_remove.insert(b1_hash.clone());
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::sync::Arc;
|
|||
use std::collections::VecDeque;
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use parking_lot::RwLock;
|
||||
use chain::{Block, BlockHeader, Transaction};
|
||||
use db;
|
||||
use chain::{BlockHeader, Transaction};
|
||||
use db::{self, IndexedBlock};
|
||||
use best_headers_chain::{BestHeadersChain, Information as BestHeadersInformation};
|
||||
use primitives::bytes::Bytes;
|
||||
use primitives::hash::H256;
|
||||
|
@ -308,11 +308,11 @@ impl Chain {
|
|||
}
|
||||
|
||||
/// Insert new best block to storage
|
||||
pub fn insert_best_block(&mut self, hash: H256, block: &Block) -> Result<BlockInsertionResult, db::Error> {
|
||||
let is_appending_to_main_branch = self.best_storage_block.hash == block.block_header.previous_header_hash;
|
||||
pub fn insert_best_block(&mut self, hash: H256, block: &IndexedBlock) -> Result<BlockInsertionResult, db::Error> {
|
||||
let is_appending_to_main_branch = self.best_storage_block.hash == block.header().previous_header_hash;
|
||||
|
||||
// insert to storage
|
||||
let storage_insertion = try!(self.storage.insert_block(&block));
|
||||
let storage_insertion = try!(self.storage.insert_indexed_block(&block));
|
||||
|
||||
// remember new best block hash
|
||||
self.best_storage_block = self.storage.best_block().expect("Inserted block above");
|
||||
|
@ -327,7 +327,7 @@ impl Chain {
|
|||
|
||||
// all transactions from this block were accepted
|
||||
// => delete accepted transactions from verification queue and from the memory pool
|
||||
let this_block_transactions_hashes = block.transactions.iter().map(|tx| tx.hash());
|
||||
let this_block_transactions_hashes: Vec<H256> = block.transaction_hashes().iter().cloned().collect();
|
||||
for transaction_accepted in this_block_transactions_hashes {
|
||||
self.memory_pool.remove_by_hash(&transaction_accepted);
|
||||
self.verifying_transactions.remove(&transaction_accepted);
|
||||
|
@ -352,7 +352,7 @@ impl Chain {
|
|||
// all transactions from this block were accepted
|
||||
// + all transactions from previous blocks of this fork were accepted
|
||||
// => delete accepted transactions from verification queue and from the memory pool
|
||||
let this_block_transactions_hashes = block.transactions.iter().map(|tx| tx.hash());
|
||||
let this_block_transactions_hashes: Vec<H256> = block.transaction_hashes().iter().cloned().collect();
|
||||
let mut canonized_blocks_hashes: Vec<H256> = Vec::new();
|
||||
let mut new_main_blocks_transactions_hashes: Vec<H256> = Vec::new();
|
||||
while let Some(canonized_block_hash) = reorganization.pop_canonized() {
|
||||
|
@ -360,7 +360,7 @@ impl Chain {
|
|||
new_main_blocks_transactions_hashes.extend(canonized_transactions_hashes);
|
||||
canonized_blocks_hashes.push(canonized_block_hash);
|
||||
}
|
||||
for transaction_accepted in this_block_transactions_hashes.chain(new_main_blocks_transactions_hashes.into_iter()) {
|
||||
for transaction_accepted in this_block_transactions_hashes.into_iter().chain(new_main_blocks_transactions_hashes.into_iter()) {
|
||||
self.memory_pool.remove_by_hash(&transaction_accepted);
|
||||
self.verifying_transactions.remove(&transaction_accepted);
|
||||
}
|
||||
|
@ -784,7 +784,7 @@ mod tests {
|
|||
assert!(chain.information().scheduled == 3 && chain.information().requested == 1
|
||||
&& chain.information().verifying == 1 && chain.information().stored == 1);
|
||||
// insert new best block to the chain
|
||||
chain.insert_best_block(test_data::block_h1().hash(), &test_data::block_h1()).expect("Db error");
|
||||
chain.insert_best_block(test_data::block_h1().hash(), &test_data::block_h1().into()).expect("Db error");
|
||||
assert!(chain.information().scheduled == 3 && chain.information().requested == 1
|
||||
&& chain.information().verifying == 1 && chain.information().stored == 2);
|
||||
assert_eq!(db.best_block().expect("storage with genesis block is required").number, 1);
|
||||
|
@ -799,13 +799,13 @@ mod tests {
|
|||
let block1 = test_data::block_h1();
|
||||
let block1_hash = block1.hash();
|
||||
|
||||
chain.insert_best_block(block1_hash.clone(), &block1).expect("Error inserting new block");
|
||||
chain.insert_best_block(block1_hash.clone(), &block1.into()).expect("Error inserting new block");
|
||||
assert_eq!(chain.block_locator_hashes(), vec![block1_hash.clone(), genesis_hash.clone()]);
|
||||
|
||||
let block2 = test_data::block_h2();
|
||||
let block2_hash = block2.hash();
|
||||
|
||||
chain.insert_best_block(block2_hash.clone(), &block2).expect("Error inserting new block");
|
||||
chain.insert_best_block(block2_hash.clone(), &block2.into()).expect("Error inserting new block");
|
||||
assert_eq!(chain.block_locator_hashes(), vec![block2_hash.clone(), block1_hash.clone(), genesis_hash.clone()]);
|
||||
|
||||
let blocks0 = test_data::build_n_empty_blocks_from_genesis(11, 0);
|
||||
|
@ -878,8 +878,8 @@ mod tests {
|
|||
fn chain_intersect_with_inventory() {
|
||||
let mut chain = Chain::new(Arc::new(db::TestStorage::with_genesis_block()));
|
||||
// append 2 db blocks
|
||||
chain.insert_best_block(test_data::block_h1().hash(), &test_data::block_h1()).expect("Error inserting new block");
|
||||
chain.insert_best_block(test_data::block_h2().hash(), &test_data::block_h2()).expect("Error inserting new block");
|
||||
chain.insert_best_block(test_data::block_h1().hash(), &test_data::block_h1().into()).expect("Error inserting new block");
|
||||
chain.insert_best_block(test_data::block_h2().hash(), &test_data::block_h2().into()).expect("Error inserting new block");
|
||||
|
||||
// prepare blocks
|
||||
let blocks0 = test_data::build_n_empty_blocks_from(9, 0, &test_data::block_h2().block_header);
|
||||
|
@ -992,7 +992,7 @@ mod tests {
|
|||
assert_eq!(chain.information().transactions.transactions_count, 1);
|
||||
|
||||
// when block is inserted to the database => all accepted transactions are removed from mempool && verifying queue
|
||||
chain.insert_best_block(b1.hash(), &b1).expect("block accepted");
|
||||
chain.insert_best_block(b1.hash(), &b1.into()).expect("block accepted");
|
||||
|
||||
assert_eq!(chain.information().transactions.transactions_count, 0);
|
||||
assert!(!chain.forget_verifying_transaction(&tx1_hash));
|
||||
|
@ -1062,15 +1062,15 @@ mod tests {
|
|||
chain.insert_verified_transaction(tx2);
|
||||
|
||||
// no reorg
|
||||
let result = chain.insert_best_block(b1.hash(), &b1).expect("no error");
|
||||
let result = chain.insert_best_block(b1.hash(), &b1.into()).expect("no error");
|
||||
assert_eq!(result.transactions_to_reverify.len(), 0);
|
||||
|
||||
// no reorg
|
||||
let result = chain.insert_best_block(b2.hash(), &b2).expect("no error");
|
||||
let result = chain.insert_best_block(b2.hash(), &b2.into()).expect("no error");
|
||||
assert_eq!(result.transactions_to_reverify.len(), 0);
|
||||
|
||||
// reorg
|
||||
let result = chain.insert_best_block(b3.hash(), &b3).expect("no error");
|
||||
let result = chain.insert_best_block(b3.hash(), &b3.into()).expect("no error");
|
||||
assert_eq!(result.transactions_to_reverify.len(), 2);
|
||||
assert!(result.transactions_to_reverify.iter().any(|&(ref h, _)| h == &tx1_hash));
|
||||
assert!(result.transactions_to_reverify.iter().any(|&(ref h, _)| h == &tx2_hash));
|
||||
|
@ -1114,18 +1114,18 @@ mod tests {
|
|||
chain.insert_verified_transaction(tx4);
|
||||
chain.insert_verified_transaction(tx5);
|
||||
|
||||
assert_eq!(chain.insert_best_block(b0.hash(), &b0).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b0.hash()]));
|
||||
assert_eq!(chain.insert_best_block(b0.hash(), &b0.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b0.hash()]));
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(b1.hash(), &b1).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b1.hash()]));
|
||||
assert_eq!(chain.insert_best_block(b1.hash(), &b1.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b1.hash()]));
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(b2.hash(), &b2).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b2.hash()]));
|
||||
assert_eq!(chain.insert_best_block(b2.hash(), &b2.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b2.hash()]));
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(b3.hash(), &b3).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.insert_best_block(b3.hash(), &b3.clone().into()).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
assert_eq!(chain.insert_best_block(b4.hash(), &b4).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.insert_best_block(b4.hash(), &b4.clone().into()).expect("block accepted"), BlockInsertionResult::default());
|
||||
assert_eq!(chain.information().transactions.transactions_count, 3);
|
||||
// order matters
|
||||
let insert_result = chain.insert_best_block(b5.hash(), &b5).expect("block accepted");
|
||||
let insert_result = chain.insert_best_block(b5.hash(), &b5.clone().into()).expect("block accepted");
|
||||
let transactions_to_reverify_hashes: Vec<_> = insert_result
|
||||
.transactions_to_reverify
|
||||
.into_iter()
|
||||
|
|
|
@ -7,8 +7,8 @@ use futures::{BoxFuture, Future, finished};
|
|||
use futures::stream::Stream;
|
||||
use tokio_core::reactor::{Handle, Interval};
|
||||
use futures_cpupool::CpuPool;
|
||||
use db;
|
||||
use chain::{Block, BlockHeader, Transaction};
|
||||
use db::{self, IndexedBlock};
|
||||
use chain::{BlockHeader, Transaction};
|
||||
use message::types;
|
||||
use message::common::{InventoryVector, InventoryType};
|
||||
use primitives::hash::H256;
|
||||
|
@ -191,7 +191,7 @@ pub trait Client : Send + 'static {
|
|||
fn on_new_transactions_inventory(&mut self, peer_index: usize, transactions_hashes: Vec<H256>);
|
||||
fn on_new_blocks_headers(&mut self, peer_index: usize, blocks_headers: Vec<BlockHeader>);
|
||||
fn on_peer_blocks_notfound(&mut self, peer_index: usize, blocks_hashes: Vec<H256>);
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: Block);
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: IndexedBlock);
|
||||
fn on_peer_transaction(&mut self, peer_index: usize, transaction: Transaction);
|
||||
fn on_peer_filterload(&mut self, peer_index: usize, message: &types::FilterLoad);
|
||||
fn on_peer_filteradd(&mut self, peer_index: usize, message: &types::FilterAdd);
|
||||
|
@ -212,7 +212,7 @@ pub trait ClientCore : VerificationSink {
|
|||
fn on_new_transactions_inventory(&mut self, peer_index: usize, transactions_hashes: Vec<H256>);
|
||||
fn on_new_blocks_headers(&mut self, peer_index: usize, blocks_headers: Vec<BlockHeader>);
|
||||
fn on_peer_blocks_notfound(&mut self, peer_index: usize, blocks_hashes: Vec<H256>);
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: Block) -> Option<VecDeque<(H256, Block)>>;
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: IndexedBlock) -> Option<VecDeque<(H256, IndexedBlock)>>;
|
||||
fn on_peer_transaction(&mut self, peer_index: usize, transaction: Transaction) -> Option<VecDeque<(H256, Transaction)>>;
|
||||
fn on_peer_filterload(&mut self, peer_index: usize, message: &types::FilterLoad);
|
||||
fn on_peer_filteradd(&mut self, peer_index: usize, message: &types::FilterAdd);
|
||||
|
@ -371,8 +371,8 @@ impl<T, U> Client for SynchronizationClient<T, U> where T: TaskExecutor, U: Veri
|
|||
self.core.lock().on_peer_blocks_notfound(peer_index, blocks_hashes);
|
||||
}
|
||||
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: Block) {
|
||||
let blocks_to_verify = { self.core.lock().on_peer_block(peer_index, block) };
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: IndexedBlock) {
|
||||
let blocks_to_verify = self.core.lock().on_peer_block(peer_index, block);
|
||||
|
||||
// verify selected blocks
|
||||
if let Some(mut blocks_to_verify) = blocks_to_verify {
|
||||
|
@ -609,8 +609,8 @@ impl<T> ClientCore for SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
}
|
||||
|
||||
/// Process new block.
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: Block) -> Option<VecDeque<(H256, Block)>> {
|
||||
let block_hash = block.hash();
|
||||
fn on_peer_block(&mut self, peer_index: usize, block: IndexedBlock) -> Option<VecDeque<(H256, IndexedBlock)>> {
|
||||
let block_hash = block.hash().clone();
|
||||
|
||||
// update peers to select next tasks
|
||||
self.peers.on_block_received(peer_index, &block_hash);
|
||||
|
@ -776,7 +776,7 @@ impl<T> ClientCore for SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
|
||||
impl<T> VerificationSink for SynchronizationClientCore<T> where T: TaskExecutor {
|
||||
/// Process successful block verification
|
||||
fn on_block_verification_success(&mut self, block: Block) {
|
||||
fn on_block_verification_success(&mut self, block: IndexedBlock) {
|
||||
let hash = block.hash();
|
||||
// insert block to the storage
|
||||
match {
|
||||
|
@ -1114,9 +1114,9 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
}
|
||||
|
||||
/// Process new peer block
|
||||
fn process_peer_block(&mut self, peer_index: usize, block_hash: H256, block: Block) -> Option<VecDeque<(H256, Block)>> {
|
||||
fn process_peer_block(&mut self, peer_index: usize, block_hash: H256, block: IndexedBlock) -> Option<VecDeque<(H256, IndexedBlock)>> {
|
||||
// prepare list of blocks to verify + make all required changes to the chain
|
||||
let mut result: Option<VecDeque<(H256, Block)>> = None;
|
||||
let mut result: Option<VecDeque<(H256, IndexedBlock)>> = None;
|
||||
let mut chain = self.chain.write();
|
||||
match chain.block_state(&block_hash) {
|
||||
BlockState::Verifying | BlockState::Stored => {
|
||||
|
@ -1125,7 +1125,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
},
|
||||
BlockState::Unknown | BlockState::Scheduled | BlockState::Requested => {
|
||||
// check parent block state
|
||||
match chain.block_state(&block.block_header.previous_header_hash) {
|
||||
match chain.block_state(&block.header().previous_header_hash) {
|
||||
BlockState::Unknown => {
|
||||
if self.state.is_synchronizing() {
|
||||
// when synchronizing, we tend to receive all blocks in-order
|
||||
|
@ -1153,14 +1153,14 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
// remember peer as useful
|
||||
self.peers.useful_peer(peer_index);
|
||||
// schedule verification
|
||||
let mut blocks_to_verify: VecDeque<(H256, Block)> = VecDeque::new();
|
||||
let mut blocks_to_verify: VecDeque<(H256, IndexedBlock)> = VecDeque::new();
|
||||
blocks_to_verify.push_back((block_hash.clone(), block));
|
||||
blocks_to_verify.extend(self.orphaned_blocks_pool.remove_blocks_for_parent(&block_hash));
|
||||
// forget blocks we are going to process
|
||||
let blocks_hashes_to_forget: Vec<_> = blocks_to_verify.iter().map(|t| t.0.clone()).collect();
|
||||
chain.forget_blocks_leave_header(&blocks_hashes_to_forget);
|
||||
// remember that we are verifying these blocks
|
||||
let blocks_headers_to_verify: Vec<_> = blocks_to_verify.iter().map(|&(ref h, ref b)| (h.clone(), b.block_header.clone())).collect();
|
||||
let blocks_headers_to_verify: Vec<_> = blocks_to_verify.iter().map(|&(ref h, ref b)| (h.clone(), b.header().clone())).collect();
|
||||
chain.verify_blocks(blocks_headers_to_verify);
|
||||
// remember that we are verifying block from this peer
|
||||
self.verifying_blocks_by_peer.insert(block_hash.clone(), peer_index);
|
||||
|
@ -1410,7 +1410,7 @@ pub mod tests {
|
|||
assert_eq!(sync.information().peers.active, 1);
|
||||
|
||||
// push unknown block => will be queued as orphan
|
||||
sync.on_peer_block(5, block2);
|
||||
sync.on_peer_block(5, block2.into());
|
||||
assert!(sync.information().state.is_nearly_saturated());
|
||||
assert_eq!(sync.information().orphaned_blocks, 1);
|
||||
assert_eq!(sync.information().chain.scheduled, 0);
|
||||
|
@ -1420,7 +1420,7 @@ pub mod tests {
|
|||
assert_eq!(sync.information().peers.active, 1);
|
||||
|
||||
// push requested block => should be moved to the test storage && orphan should be moved
|
||||
sync.on_peer_block(5, block1);
|
||||
sync.on_peer_block(5, block1.into());
|
||||
assert!(sync.information().state.is_saturated());
|
||||
assert_eq!(sync.information().orphaned_blocks, 0);
|
||||
assert_eq!(sync.information().chain.scheduled, 0);
|
||||
|
@ -1437,7 +1437,7 @@ pub mod tests {
|
|||
let mut sync = sync.lock();
|
||||
|
||||
sync.on_new_blocks_headers(5, vec![test_data::block_h1().block_header.clone(), test_data::block_h2().block_header.clone()]);
|
||||
sync.on_peer_block(5, test_data::block_h169());
|
||||
sync.on_peer_block(5, test_data::block_h169().into());
|
||||
|
||||
// out-of-order block was presented by the peer
|
||||
assert!(sync.information().state.is_synchronizing());
|
||||
|
@ -1485,11 +1485,11 @@ pub mod tests {
|
|||
{
|
||||
let mut sync = sync.lock();
|
||||
// receive block from peer#2
|
||||
sync.on_peer_block(2, block2);
|
||||
sync.on_peer_block(2, block2.into());
|
||||
assert!(sync.information().chain.requested == 2
|
||||
&& sync.information().orphaned_blocks == 1);
|
||||
// receive block from peer#1
|
||||
sync.on_peer_block(1, block1);
|
||||
sync.on_peer_block(1, block1.into());
|
||||
|
||||
assert!(sync.information().chain.requested == 0
|
||||
&& sync.information().orphaned_blocks == 0
|
||||
|
@ -1537,7 +1537,7 @@ pub mod tests {
|
|||
sync.on_new_blocks_headers(1, vec![block.block_header.clone()]);
|
||||
sync.on_new_blocks_headers(2, vec![block.block_header.clone()]);
|
||||
executor.lock().take_tasks();
|
||||
sync.on_peer_block(2, block.clone());
|
||||
sync.on_peer_block(2, block.clone().into());
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
assert_eq!(tasks.len(), 5);
|
||||
|
@ -1570,7 +1570,7 @@ pub mod tests {
|
|||
assert_eq!(chain.information().headers.total, 2);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, b1);
|
||||
sync.on_peer_block(1, b1.into());
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
assert_eq!(tasks, vec![]);
|
||||
|
@ -1581,7 +1581,7 @@ pub mod tests {
|
|||
assert_eq!(chain.information().headers.total, 1);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, b2);
|
||||
sync.on_peer_block(1, b2.into());
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
assert_eq!(tasks, vec![Task::RequestBlocksHeaders(1), Task::RequestMemoryPool(1)]);
|
||||
|
@ -1613,7 +1613,7 @@ pub mod tests {
|
|||
assert_eq!(chain.information().headers.total, 2);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, b2);
|
||||
sync.on_peer_block(1, b2.into());
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
assert_eq!(tasks, vec![]);
|
||||
|
@ -1624,7 +1624,7 @@ pub mod tests {
|
|||
assert_eq!(chain.information().headers.total, 2);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, b1);
|
||||
sync.on_peer_block(1, b1.into());
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
assert_eq!(tasks, vec![Task::RequestBlocksHeaders(1), Task::RequestMemoryPool(1)]);
|
||||
|
@ -1674,35 +1674,35 @@ pub mod tests {
|
|||
Task::RequestBlocks(2, vec![fork2[0].hash(), fork2[1].hash(), fork2[2].hash()]),
|
||||
]);
|
||||
|
||||
sync.on_peer_block(2, fork2[0].clone());
|
||||
sync.on_peer_block(2, fork2[0].clone().into());
|
||||
{
|
||||
let chain = chain.read();
|
||||
assert_eq!(chain.best_storage_block().hash, fork2[0].hash());
|
||||
assert_eq!(chain.best_storage_block().number, 1);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, fork1[0].clone());
|
||||
sync.on_peer_block(1, fork1[0].clone().into());
|
||||
{
|
||||
let chain = chain.read();
|
||||
assert_eq!(chain.best_storage_block().hash, fork2[0].hash());
|
||||
assert_eq!(chain.best_storage_block().number, 1);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, fork1[1].clone());
|
||||
sync.on_peer_block(1, fork1[1].clone().into());
|
||||
{
|
||||
let chain = chain.read();
|
||||
assert_eq!(chain.best_storage_block().hash, fork1[1].hash());
|
||||
assert_eq!(chain.best_storage_block().number, 2);
|
||||
}
|
||||
|
||||
sync.on_peer_block(2, fork2[1].clone());
|
||||
sync.on_peer_block(2, fork2[1].clone().into());
|
||||
{
|
||||
let chain = chain.read();
|
||||
assert_eq!(chain.best_storage_block().hash, fork1[1].hash());
|
||||
assert_eq!(chain.best_storage_block().number, 2);
|
||||
}
|
||||
|
||||
sync.on_peer_block(2, fork2[2].clone());
|
||||
sync.on_peer_block(2, fork2[2].clone().into());
|
||||
{
|
||||
let chain = chain.read();
|
||||
assert_eq!(chain.best_storage_block().hash, fork2[2].hash());
|
||||
|
@ -1740,12 +1740,12 @@ pub mod tests {
|
|||
assert_eq!(chain.information().headers.total, 3);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, common_block.clone());
|
||||
sync.on_peer_block(1, fork1[0].clone());
|
||||
sync.on_peer_block(1, fork1[1].clone());
|
||||
sync.on_peer_block(2, fork2[0].clone());
|
||||
sync.on_peer_block(2, fork2[1].clone());
|
||||
sync.on_peer_block(2, fork2[2].clone());
|
||||
sync.on_peer_block(1, common_block.clone().into());
|
||||
sync.on_peer_block(1, fork1[0].clone().into());
|
||||
sync.on_peer_block(1, fork1[1].clone().into());
|
||||
sync.on_peer_block(2, fork2[0].clone().into());
|
||||
sync.on_peer_block(2, fork2[1].clone().into());
|
||||
sync.on_peer_block(2, fork2[2].clone().into());
|
||||
|
||||
{
|
||||
let chain = chain.read();
|
||||
|
@ -1759,7 +1759,7 @@ pub mod tests {
|
|||
let (_, _, _, chain, sync) = create_sync(None, None);
|
||||
let mut sync = sync.lock();
|
||||
|
||||
sync.on_peer_block(1, test_data::block_h2());
|
||||
sync.on_peer_block(1, test_data::block_h2().into());
|
||||
assert_eq!(sync.information().orphaned_blocks, 1);
|
||||
|
||||
{
|
||||
|
@ -1767,7 +1767,7 @@ pub mod tests {
|
|||
assert_eq!(chain.best_storage_block().number, 0);
|
||||
}
|
||||
|
||||
sync.on_peer_block(1, test_data::block_h1());
|
||||
sync.on_peer_block(1, test_data::block_h1().into());
|
||||
assert_eq!(sync.information().orphaned_blocks, 0);
|
||||
|
||||
{
|
||||
|
@ -1781,7 +1781,7 @@ pub mod tests {
|
|||
let (_, _, executor, _, sync) = create_sync(None, None);
|
||||
let mut sync = sync.lock();
|
||||
|
||||
sync.on_peer_block(1, test_data::block_h2());
|
||||
sync.on_peer_block(1, test_data::block_h2().into());
|
||||
sync.on_new_blocks_inventory(1, vec![test_data::block_h1().hash(), test_data::block_h2().hash()]);
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
|
@ -2051,11 +2051,11 @@ pub mod tests {
|
|||
sync.on_new_blocks_headers(1, vec![b10.block_header.clone(), b11.block_header.clone(), b12.block_header.clone()]);
|
||||
sync.on_new_blocks_headers(2, vec![b10.block_header.clone(), b21.block_header.clone(), b22.block_header.clone()]);
|
||||
|
||||
sync.on_peer_block(1, b10.clone());
|
||||
sync.on_peer_block(1, b11);
|
||||
sync.on_peer_block(1, b12);
|
||||
sync.on_peer_block(1, b10.clone().into());
|
||||
sync.on_peer_block(1, b11.into());
|
||||
sync.on_peer_block(1, b12.into());
|
||||
|
||||
sync.on_peer_block(2, b21.clone());
|
||||
sync.on_peer_block(2, b21.clone().into());
|
||||
|
||||
// should not panic here
|
||||
sync.on_new_blocks_headers(2, vec![b10.block_header.clone(), b21.block_header.clone(),
|
||||
|
@ -2073,8 +2073,8 @@ pub mod tests {
|
|||
|
||||
let mut sync = sync.lock();
|
||||
sync.on_new_blocks_headers(1, vec![b0.block_header.clone(), b1.block_header.clone()]);
|
||||
sync.on_peer_block(1, b0.clone());
|
||||
sync.on_peer_block(1, b1.clone());
|
||||
sync.on_peer_block(1, b0.clone().into());
|
||||
sync.on_peer_block(1, b1.clone().into());
|
||||
|
||||
// we were in synchronization state => block is not relayed
|
||||
{
|
||||
|
@ -2086,7 +2086,7 @@ pub mod tests {
|
|||
]);
|
||||
}
|
||||
|
||||
sync.on_peer_block(2, b2.clone());
|
||||
sync.on_peer_block(2, b2.clone().into());
|
||||
|
||||
// we were in saturated state => block is relayed
|
||||
{
|
||||
|
@ -2096,7 +2096,7 @@ pub mod tests {
|
|||
}
|
||||
|
||||
sync.on_new_blocks_headers(1, vec![b3.block_header.clone()]);
|
||||
sync.on_peer_block(1, b3.clone());
|
||||
sync.on_peer_block(1, b3.clone().into());
|
||||
|
||||
// we were in nearly saturated state => block is relayed
|
||||
{
|
||||
|
@ -2193,7 +2193,7 @@ pub mod tests {
|
|||
// igonore tasks
|
||||
{ executor.lock().take_tasks(); }
|
||||
|
||||
sync.on_peer_block(1, b0.clone());
|
||||
sync.on_peer_block(1, b0.clone().into());
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
let inventory = vec![InventoryVector { inv_type: InventoryType::MessageBlock, hash: b0.hash() }];
|
||||
|
@ -2221,7 +2221,7 @@ pub mod tests {
|
|||
sync.on_peer_connected(3);
|
||||
sync.on_peer_connected(4);
|
||||
|
||||
sync.on_peer_block(1, b1);
|
||||
sync.on_peer_block(1, b1.into());
|
||||
|
||||
{
|
||||
use miner::transaction_fee_rate;
|
||||
|
@ -2260,9 +2260,9 @@ pub mod tests {
|
|||
|
||||
let mut sync = sync.lock();
|
||||
|
||||
sync.on_peer_block(1, test_data::block_h2());
|
||||
sync.on_peer_block(1, test_data::block_h2().into());
|
||||
// should not panic here
|
||||
sync.on_peer_block(2, test_data::block_h2());
|
||||
sync.on_peer_block(2, test_data::block_h2().into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2280,7 +2280,7 @@ pub mod tests {
|
|||
// igonore tasks
|
||||
{ executor.lock().take_tasks(); }
|
||||
|
||||
sync.on_peer_block(1, b0.clone());
|
||||
sync.on_peer_block(1, b0.clone().into());
|
||||
|
||||
let tasks = executor.lock().take_tasks();
|
||||
let inventory = vec![InventoryVector { inv_type: InventoryType::MessageBlock, hash: b0.hash() }];
|
||||
|
|
|
@ -225,7 +225,7 @@ mod tests {
|
|||
let config = ManageUnknownBlocksConfig { removal_time_ms: 1000, max_number: 100 };
|
||||
let mut pool = OrphanBlocksPool::new();
|
||||
let block = test_data::genesis();
|
||||
pool.insert_unknown_block(block.hash(), block);
|
||||
pool.insert_unknown_block(block.hash(), block.into());
|
||||
assert_eq!(manage_unknown_orphaned_blocks(&config, &mut pool), None);
|
||||
assert_eq!(pool.len(), 1);
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ mod tests {
|
|||
let mut pool = OrphanBlocksPool::new();
|
||||
let block = test_data::genesis();
|
||||
let block_hash = block.hash();
|
||||
pool.insert_unknown_block(block_hash.clone(), block);
|
||||
pool.insert_unknown_block(block_hash.clone(), block.into());
|
||||
sleep(Duration::from_millis(1));
|
||||
|
||||
assert_eq!(manage_unknown_orphaned_blocks(&config, &mut pool), Some(vec![block_hash]));
|
||||
|
@ -253,8 +253,8 @@ mod tests {
|
|||
let block1_hash = block1.hash();
|
||||
let block2 = test_data::block_h2();
|
||||
let block2_hash = block2.hash();
|
||||
pool.insert_unknown_block(block1_hash.clone(), block1);
|
||||
pool.insert_unknown_block(block2_hash.clone(), block2);
|
||||
pool.insert_unknown_block(block1_hash.clone(), block1.into());
|
||||
pool.insert_unknown_block(block2_hash.clone(), block2.into());
|
||||
assert_eq!(manage_unknown_orphaned_blocks(&config, &mut pool), Some(vec![block1_hash]));
|
||||
assert_eq!(pool.len(), 1);
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ impl SynchronizationServer {
|
|||
let chain = chain.read();
|
||||
let storage = chain.storage();
|
||||
if let Some(block) = storage.block(db::BlockRef::Hash(block_hash.clone())) {
|
||||
|
||||
|
||||
let requested_len = indexes.len();
|
||||
let transactions_len = block.transactions.len();
|
||||
let mut read_indexes = HashSet::new();
|
||||
|
@ -658,7 +658,7 @@ pub mod tests {
|
|||
#[test]
|
||||
fn server_getblocks_responds_inventory_when_have_unknown_blocks() {
|
||||
let (chain, executor, server) = create_synchronization_server();
|
||||
chain.write().insert_best_block(test_data::block_h1().hash(), &test_data::block_h1()).expect("Db write error");
|
||||
chain.write().insert_best_block(test_data::block_h1().hash(), &test_data::block_h1().into()).expect("Db write error");
|
||||
// when asking for blocks hashes
|
||||
server.serve_getblocks(0, types::GetBlocks {
|
||||
version: 0,
|
||||
|
@ -693,7 +693,7 @@ pub mod tests {
|
|||
#[test]
|
||||
fn server_getheaders_responds_headers_when_have_unknown_blocks() {
|
||||
let (chain, executor, server) = create_synchronization_server();
|
||||
chain.write().insert_best_block(test_data::block_h1().hash(), &test_data::block_h1()).expect("Db write error");
|
||||
chain.write().insert_best_block(test_data::block_h1().hash(), &test_data::block_h1().into()).expect("Db write error");
|
||||
// when asking for blocks hashes
|
||||
let dummy_id = 0;
|
||||
server.serve_getheaders(0, types::GetHeaders {
|
||||
|
|
|
@ -2,16 +2,17 @@ use std::thread;
|
|||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use parking_lot::Mutex;
|
||||
use chain::{Block, Transaction};
|
||||
use chain::Transaction;
|
||||
use network::{Magic, ConsensusParams};
|
||||
use primitives::hash::H256;
|
||||
use verification::{ChainVerifier, Verify as VerificationVerify};
|
||||
use synchronization_chain::ChainRef;
|
||||
use db::IndexedBlock;
|
||||
|
||||
/// Verification events sink
|
||||
pub trait VerificationSink : Send + 'static {
|
||||
/// When block verification has completed successfully.
|
||||
fn on_block_verification_success(&mut self, block: Block);
|
||||
fn on_block_verification_success(&mut self, block: IndexedBlock);
|
||||
/// When block verification has failed.
|
||||
fn on_block_verification_error(&mut self, err: &str, hash: &H256);
|
||||
/// When transaction verification has completed successfully.
|
||||
|
@ -23,7 +24,7 @@ pub trait VerificationSink : Send + 'static {
|
|||
/// Verification thread tasks
|
||||
enum VerificationTask {
|
||||
/// Verify single block
|
||||
VerifyBlock(Block),
|
||||
VerifyBlock(IndexedBlock),
|
||||
/// Verify single transaction
|
||||
VerifyTransaction(Transaction),
|
||||
/// Stop verification thread
|
||||
|
@ -33,7 +34,7 @@ enum VerificationTask {
|
|||
/// Synchronization verifier
|
||||
pub trait Verifier : Send + 'static {
|
||||
/// Verify block
|
||||
fn verify_block(&self, block: Block);
|
||||
fn verify_block(&self, block: IndexedBlock);
|
||||
/// Verify transaction
|
||||
fn verify_transaction(&self, transaction: Transaction);
|
||||
}
|
||||
|
@ -73,7 +74,7 @@ impl AsyncVerifier {
|
|||
match task {
|
||||
VerificationTask::VerifyBlock(block) => {
|
||||
// for changes that are not relying on block#
|
||||
let is_bip16_active_on_block = block.block_header.time >= bip16_time_border;
|
||||
let is_bip16_active_on_block = block.header().time >= bip16_time_border;
|
||||
let force_parameters_change = is_bip16_active_on_block != is_bip16_active;
|
||||
if force_parameters_change {
|
||||
parameters_change_steps = Some(0);
|
||||
|
@ -132,7 +133,7 @@ impl Drop for AsyncVerifier {
|
|||
|
||||
impl Verifier for AsyncVerifier {
|
||||
/// Verify block
|
||||
fn verify_block(&self, block: Block) {
|
||||
fn verify_block(&self, block: IndexedBlock) {
|
||||
self.verification_work_sender
|
||||
.send(VerificationTask::VerifyBlock(block))
|
||||
.expect("Verification thread have the same lifetime as `AsyncVerifier`");
|
||||
|
@ -151,11 +152,12 @@ pub mod tests {
|
|||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use chain::{Block, Transaction};
|
||||
use chain::Transaction;
|
||||
use synchronization_client::SynchronizationClientCore;
|
||||
use synchronization_executor::tests::DummyTaskExecutor;
|
||||
use primitives::hash::H256;
|
||||
use super::{Verifier, VerificationSink};
|
||||
use db::IndexedBlock;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DummyVerifier {
|
||||
|
@ -174,7 +176,7 @@ pub mod tests {
|
|||
}
|
||||
|
||||
impl Verifier for DummyVerifier {
|
||||
fn verify_block(&self, block: Block) {
|
||||
fn verify_block(&self, block: IndexedBlock) {
|
||||
match self.sink {
|
||||
Some(ref sink) => match self.errors.get(&block.hash()) {
|
||||
Some(err) => sink.lock().on_block_verification_error(&err, &block.hash()),
|
||||
|
|
|
@ -57,16 +57,16 @@ impl ChainVerifier {
|
|||
|
||||
/// Returns previous transaction output.
|
||||
/// NOTE: This function expects all previous blocks to be already in database.
|
||||
fn previous_transaction_output(&self, block: &chain::Block, prevout: &chain::OutPoint) -> Option<chain::TransactionOutput> {
|
||||
fn previous_transaction_output(&self, block: &db::IndexedBlock, prevout: &chain::OutPoint) -> Option<chain::TransactionOutput> {
|
||||
self.store.transaction(&prevout.hash)
|
||||
.as_ref()
|
||||
.or_else(|| block.transactions.iter().find(|t| t.hash() == prevout.hash))
|
||||
.or_else(|| block.transactions().find(|&(hash, _)| hash == &prevout.hash).and_then(|(_, tx)| Some(tx)))
|
||||
.and_then(|tx| tx.outputs.iter().nth(prevout.index as usize).cloned())
|
||||
}
|
||||
|
||||
/// Returns number of transaction signature operations.
|
||||
/// NOTE: This function expects all previous blocks to be already in database.
|
||||
fn transaction_sigops(&self, block: &chain::Block, transaction: &chain::Transaction, bip16_active: bool) -> usize {
|
||||
fn transaction_sigops(&self, block: &db::IndexedBlock, transaction: &chain::Transaction, bip16_active: bool) -> usize {
|
||||
let output_sigops: usize = transaction.outputs.iter().map(|output| {
|
||||
let output_script: Script = output.script_pubkey.clone().into();
|
||||
output_script.sigops_count(false)
|
||||
|
@ -93,14 +93,14 @@ impl ChainVerifier {
|
|||
|
||||
/// Returns number of block signature operations.
|
||||
/// NOTE: This function expects all previous blocks to be already in database.
|
||||
fn block_sigops(&self, block: &chain::Block) -> usize {
|
||||
fn block_sigops(&self, block: &db::IndexedBlock) -> usize {
|
||||
// strict pay-to-script-hash signature operations count toward block
|
||||
// signature operations limit is enforced with BIP16
|
||||
let bip16_active = block.block_header.time >= self.network.consensus_params().bip16_time;
|
||||
block.transactions.iter().map(|tx| self.transaction_sigops(block, tx, bip16_active)).sum()
|
||||
let bip16_active = block.header().time >= self.network.consensus_params().bip16_time;
|
||||
block.transactions().map(|(_, tx)| self.transaction_sigops(block, tx, bip16_active)).sum()
|
||||
}
|
||||
|
||||
fn ordered_verify(&self, block: &chain::Block, at_height: u32) -> Result<(), Error> {
|
||||
fn ordered_verify(&self, block: &db::IndexedBlock, at_height: u32) -> Result<(), Error> {
|
||||
if !block.is_final(at_height) {
|
||||
return Err(Error::NonFinalBlock);
|
||||
}
|
||||
|
@ -122,11 +122,15 @@ impl ChainVerifier {
|
|||
}
|
||||
}
|
||||
|
||||
let coinbase_spends = block.transactions()[0].total_spends();
|
||||
let coinbase_spends = block.transactions()
|
||||
.nth(0)
|
||||
.expect("block emptyness should be checked at this point")
|
||||
.1
|
||||
.total_spends();
|
||||
|
||||
// bip30
|
||||
for (tx_index, tx) in block.transactions.iter().enumerate() {
|
||||
if let Some(meta) = self.store.transaction_meta(&tx.hash()) {
|
||||
for (tx_index, (tx_hash, _)) in block.transactions().enumerate() {
|
||||
if let Some(meta) = self.store.transaction_meta(tx_hash) {
|
||||
if !meta.is_fully_spent() && !consensus_params.is_bip30_exception(&block_hash, at_height) {
|
||||
return Err(Error::Transaction(tx_index, TransactionError::UnspentTransactionWithTheSameHash));
|
||||
}
|
||||
|
@ -134,7 +138,7 @@ impl ChainVerifier {
|
|||
}
|
||||
|
||||
let mut total_unspent = 0u64;
|
||||
for (tx_index, tx) in block.transactions().iter().enumerate().skip(1) {
|
||||
for (tx_index, (_, tx)) in block.transactions().enumerate().skip(1) {
|
||||
let mut total_claimed: u64 = 0;
|
||||
for input in &tx.inputs {
|
||||
// Coinbase maturity check
|
||||
|
@ -172,7 +176,7 @@ impl ChainVerifier {
|
|||
}
|
||||
|
||||
fn verify_transaction(&self,
|
||||
block: &chain::Block,
|
||||
block: &db::IndexedBlock,
|
||||
transaction: &chain::Transaction,
|
||||
sequence: usize,
|
||||
) -> Result<(), TransactionError> {
|
||||
|
@ -225,11 +229,11 @@ impl ChainVerifier {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_block(&self, block: &chain::Block) -> VerificationResult {
|
||||
fn verify_block(&self, block: &db::IndexedBlock) -> VerificationResult {
|
||||
let hash = block.hash();
|
||||
|
||||
// There should be at least 1 transaction
|
||||
if block.transactions().is_empty() {
|
||||
if block.transaction_count() == 0 {
|
||||
return Err(Error::Empty);
|
||||
}
|
||||
|
||||
|
@ -244,14 +248,18 @@ impl ChainVerifier {
|
|||
}
|
||||
|
||||
if let Some(median_timestamp) = self.median_timestamp(block) {
|
||||
if median_timestamp >= block.block_header.time {
|
||||
trace!(target: "verification", "median timestamp verification failed, median: {}, current: {}", median_timestamp, block.block_header.time);
|
||||
if median_timestamp >= block.header().time {
|
||||
trace!(
|
||||
target: "verification", "median timestamp verification failed, median: {}, current: {}",
|
||||
median_timestamp,
|
||||
block.header().time
|
||||
);
|
||||
return Err(Error::Timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: serialized_size function is at least suboptimal
|
||||
let size = ::serialization::Serializable::serialized_size(block);
|
||||
let size = block.size();
|
||||
if size > MAX_BLOCK_SIZE {
|
||||
return Err(Error::Size(size))
|
||||
}
|
||||
|
@ -261,20 +269,19 @@ impl ChainVerifier {
|
|||
return Err(Error::MerkleRoot);
|
||||
}
|
||||
|
||||
let first_tx = block.transactions().nth(0).expect("transaction count is checked above to be greater than 0").1;
|
||||
// check first transaction is a coinbase transaction
|
||||
if !block.transactions()[0].is_coinbase() {
|
||||
if !first_tx.is_coinbase() {
|
||||
return Err(Error::Coinbase)
|
||||
}
|
||||
|
||||
// check that coinbase has a valid signature
|
||||
let coinbase = &block.transactions()[0];
|
||||
// is_coinbase() = true above guarantees that there is at least one input
|
||||
let coinbase_script_len = coinbase.inputs[0].script_sig.len();
|
||||
let coinbase_script_len = first_tx.inputs[0].script_sig.len();
|
||||
if coinbase_script_len < 2 || coinbase_script_len > 100 {
|
||||
return Err(Error::CoinbaseSignatureLength(coinbase_script_len));
|
||||
}
|
||||
|
||||
for (idx, transaction) in block.transactions().iter().enumerate() {
|
||||
for (idx, (_, transaction)) in block.transactions().enumerate() {
|
||||
try!(self.verify_transaction(block, transaction, idx).map_err(|e| Error::Transaction(idx, e)))
|
||||
}
|
||||
|
||||
|
@ -294,9 +301,9 @@ impl ChainVerifier {
|
|||
}
|
||||
}
|
||||
|
||||
fn median_timestamp(&self, block: &chain::Block) -> Option<u32> {
|
||||
fn median_timestamp(&self, block: &db::IndexedBlock) -> Option<u32> {
|
||||
let mut timestamps = BTreeSet::new();
|
||||
let mut block_ref = block.block_header.previous_header_hash.clone().into();
|
||||
let mut block_ref = block.header().previous_header_hash.clone().into();
|
||||
// TODO: optimize it, so it does not make 11 redundant queries each time
|
||||
for _ in 0..11 {
|
||||
let previous_header = match self.store.block_header(block_ref) {
|
||||
|
@ -314,12 +321,12 @@ impl ChainVerifier {
|
|||
else { None }
|
||||
}
|
||||
|
||||
fn work_required(&self, block: &chain::Block, height: u32) -> Option<u32> {
|
||||
fn work_required(&self, block: &db::IndexedBlock, height: u32) -> Option<u32> {
|
||||
if height == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let previous_ref = block.block_header.previous_header_hash.clone().into();
|
||||
let previous_ref = block.header().previous_header_hash.clone().into();
|
||||
let previous_header = self.store.block_header(previous_ref).expect("self.height != 0; qed");
|
||||
|
||||
if utils::is_retarget_height(height) {
|
||||
|
@ -342,12 +349,12 @@ impl ChainVerifier {
|
|||
}
|
||||
|
||||
impl Verify for ChainVerifier {
|
||||
fn verify(&self, block: &chain::Block) -> VerificationResult {
|
||||
fn verify(&self, block: &db::IndexedBlock) -> VerificationResult {
|
||||
let result = self.verify_block(block);
|
||||
trace!(
|
||||
target: "verification", "Block {} (transactions: {}) verification finished. Result {:?}",
|
||||
block.hash().to_reversed_str(),
|
||||
block.transactions().len(),
|
||||
block.transaction_count(),
|
||||
result,
|
||||
);
|
||||
result
|
||||
|
@ -357,9 +364,9 @@ impl Verify for ChainVerifier {
|
|||
impl ContinueVerify for ChainVerifier {
|
||||
type State = usize;
|
||||
|
||||
fn continue_verify(&self, block: &chain::Block, state: usize) -> VerificationResult {
|
||||
fn continue_verify(&self, block: &db::IndexedBlock, state: usize) -> VerificationResult {
|
||||
// verify transactions (except coinbase)
|
||||
for (idx, transaction) in block.transactions().iter().enumerate().skip(state - 1) {
|
||||
for (idx, (_, transaction)) in block.transactions().enumerate().skip(state - 1) {
|
||||
try!(self.verify_transaction(block, transaction, idx).map_err(|e| Error::Transaction(idx, e)));
|
||||
}
|
||||
|
||||
|
@ -375,7 +382,7 @@ impl ContinueVerify for ChainVerifier {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use db::{TestStorage, Storage, Store, BlockStapler};
|
||||
use db::{TestStorage, Storage, Store, BlockStapler, IndexedBlock};
|
||||
use network::Magic;
|
||||
use devtools::RandomTempPath;
|
||||
use {script, test_data};
|
||||
|
@ -388,7 +395,7 @@ mod tests {
|
|||
let b2 = test_data::block_h2();
|
||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet);
|
||||
|
||||
assert_eq!(Chain::Orphan, verifier.verify(&b2).unwrap());
|
||||
assert_eq!(Chain::Orphan, verifier.verify(&b2.into()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -396,7 +403,7 @@ mod tests {
|
|||
let storage = TestStorage::with_blocks(&vec![test_data::genesis()]);
|
||||
let b1 = test_data::block_h1();
|
||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet);
|
||||
assert_eq!(Chain::Main, verifier.verify(&b1).unwrap());
|
||||
assert_eq!(Chain::Main, verifier.verify(&b1.into()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -409,7 +416,7 @@ mod tests {
|
|||
);
|
||||
let b1 = test_data::block_h170();
|
||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet);
|
||||
assert_eq!(Chain::Main, verifier.verify(&b1).unwrap());
|
||||
assert_eq!(Chain::Main, verifier.verify(&b1.into()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -426,7 +433,7 @@ mod tests {
|
|||
1,
|
||||
TransactionError::Inconclusive("c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704".into())
|
||||
));
|
||||
assert_eq!(should_be, verifier.verify(&b170));
|
||||
assert_eq!(should_be, verifier.verify(&b170.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -461,7 +468,7 @@ mod tests {
|
|||
TransactionError::Maturity,
|
||||
));
|
||||
|
||||
assert_eq!(expected, verifier.verify(&block));
|
||||
assert_eq!(expected, verifier.verify(&block.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -494,7 +501,7 @@ mod tests {
|
|||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||
|
||||
let expected = Ok(Chain::Main);
|
||||
assert_eq!(expected, verifier.verify(&block));
|
||||
assert_eq!(expected, verifier.verify(&block.into()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -533,7 +540,7 @@ mod tests {
|
|||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||
|
||||
let expected = Ok(Chain::Main);
|
||||
assert_eq!(expected, verifier.verify(&block));
|
||||
assert_eq!(expected, verifier.verify(&block.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -571,7 +578,7 @@ mod tests {
|
|||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||
|
||||
let expected = Err(Error::Transaction(2, TransactionError::Overspend));
|
||||
assert_eq!(expected, verifier.verify(&block));
|
||||
assert_eq!(expected, verifier.verify(&block.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -616,7 +623,7 @@ mod tests {
|
|||
|
||||
let expected = Ok(Chain::Main);
|
||||
|
||||
assert_eq!(expected, verifier.verify(&block))
|
||||
assert_eq!(expected, verifier.verify(&block.into()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -647,7 +654,7 @@ mod tests {
|
|||
builder_tx2 = builder_tx2.push_opcode(script::Opcode::OP_CHECKSIG)
|
||||
}
|
||||
|
||||
let block = test_data::block_builder()
|
||||
let block: IndexedBlock = test_data::block_builder()
|
||||
.transaction().coinbase().build()
|
||||
.transaction()
|
||||
.input()
|
||||
|
@ -662,12 +669,13 @@ mod tests {
|
|||
.build()
|
||||
.build()
|
||||
.merkled_header().parent(genesis.hash()).build()
|
||||
.build();
|
||||
.build()
|
||||
.into();
|
||||
|
||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||
|
||||
let expected = Err(Error::MaximumSigops);
|
||||
assert_eq!(expected, verifier.verify(&block));
|
||||
assert_eq!(expected, verifier.verify(&block.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -682,13 +690,14 @@ mod tests {
|
|||
.build();
|
||||
storage.insert_block(&genesis).unwrap();
|
||||
|
||||
let block = test_data::block_builder()
|
||||
let block: IndexedBlock = test_data::block_builder()
|
||||
.transaction()
|
||||
.coinbase()
|
||||
.output().value(5000000001).build()
|
||||
.build()
|
||||
.merkled_header().parent(genesis.hash()).build()
|
||||
.build();
|
||||
.build()
|
||||
.into();
|
||||
|
||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||
|
||||
|
@ -697,6 +706,6 @@ mod tests {
|
|||
actual: 5000000001
|
||||
});
|
||||
|
||||
assert_eq!(expected, verifier.verify(&block));
|
||||
assert_eq!(expected, verifier.verify(&block.into()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,12 +21,10 @@ extern crate test_data;
|
|||
|
||||
mod chain_verifier;
|
||||
mod compact;
|
||||
mod queue;
|
||||
mod utils;
|
||||
|
||||
pub use primitives::{uint, hash};
|
||||
|
||||
pub use queue::Queue;
|
||||
pub use chain_verifier::ChainVerifier;
|
||||
|
||||
use primitives::hash::H256;
|
||||
|
@ -116,11 +114,11 @@ pub type VerificationResult = Result<Chain, Error>;
|
|||
|
||||
/// Interface for block verification
|
||||
pub trait Verify : Send + Sync {
|
||||
fn verify(&self, block: &chain::Block) -> VerificationResult;
|
||||
fn verify(&self, block: &db::IndexedBlock) -> VerificationResult;
|
||||
}
|
||||
|
||||
/// Trait for verifier that can be interrupted and continue from the specific point
|
||||
pub trait ContinueVerify : Verify + Send + Sync {
|
||||
type State;
|
||||
fn continue_verify(&self, block: &chain::Block, state: Self::State) -> VerificationResult;
|
||||
fn continue_verify(&self, block: &db::IndexedBlock, state: Self::State) -> VerificationResult;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue