verificatino uses indexed blokcs
This commit is contained in:
parent
6fee34ad66
commit
67e64a5391
|
@ -1,5 +1,6 @@
|
||||||
use chain;
|
use chain;
|
||||||
use primitives::hash::H256;
|
use primitives::hash::H256;
|
||||||
|
use serialization::Serializable;
|
||||||
|
|
||||||
pub struct IndexedBlock {
|
pub struct IndexedBlock {
|
||||||
header: chain::BlockHeader,
|
header: chain::BlockHeader,
|
||||||
|
@ -73,6 +74,19 @@ impl IndexedBlock {
|
||||||
self.transactions.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> {
|
pub struct IndexedTransactions<'a> {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
//! Bitcoin chain verifier
|
//! Bitcoin chain verifier
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use db::{self, BlockRef, BlockLocation};
|
use db::{self, BlockRef, BlockLocation, IndexedBlock};
|
||||||
use network::Magic;
|
use network::Magic;
|
||||||
use super::{Verify, VerificationResult, Chain, Error, TransactionError, ContinueVerify};
|
use super::{Verify, VerificationResult, Chain, Error, TransactionError, ContinueVerify};
|
||||||
use {chain, utils};
|
use {chain, utils};
|
||||||
|
use primitives::H256;
|
||||||
|
|
||||||
const BLOCK_MAX_FUTURE: i64 = 2 * 60 * 60; // 2 hours
|
const BLOCK_MAX_FUTURE: i64 = 2 * 60 * 60; // 2 hours
|
||||||
const COINBASE_MATURITY: u32 = 100; // 2 hours
|
const COINBASE_MATURITY: u32 = 100; // 2 hours
|
||||||
|
@ -56,7 +57,7 @@ impl ChainVerifier {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if !block.is_final(at_height) {
|
||||||
return Err(Error::NonFinalBlock);
|
return Err(Error::NonFinalBlock);
|
||||||
}
|
}
|
||||||
|
@ -73,11 +74,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
|
// bip30
|
||||||
for (tx_index, tx) in block.transactions.iter().enumerate() {
|
for (tx_index, (tx_hash, tx)) in block.transactions().enumerate() {
|
||||||
if let Some(meta) = self.store.transaction_meta(&tx.hash()) {
|
if let Some(meta) = self.store.transaction_meta(tx_hash) {
|
||||||
if !meta.is_fully_spent() && !consensus_params.is_bip30_exception(&block_hash, at_height) {
|
if !meta.is_fully_spent() && !consensus_params.is_bip30_exception(&block_hash, at_height) {
|
||||||
return Err(Error::Transaction(tx_index, TransactionError::UnspentTransactionWithTheSameHash));
|
return Err(Error::Transaction(tx_index, TransactionError::UnspentTransactionWithTheSameHash));
|
||||||
}
|
}
|
||||||
|
@ -85,7 +90,7 @@ impl ChainVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut total_unspent = 0u64;
|
let mut total_unspent = 0u64;
|
||||||
for (tx_index, tx) in block.transactions().iter().enumerate().skip(1) {
|
for (tx_index, (tx_hash, tx)) in block.transactions().enumerate().skip(1) {
|
||||||
|
|
||||||
let mut total_claimed: u64 = 0;
|
let mut total_claimed: u64 = 0;
|
||||||
|
|
||||||
|
@ -106,7 +111,13 @@ impl ChainVerifier {
|
||||||
|
|
||||||
self.store.transaction(&input.previous_output.hash)
|
self.store.transaction(&input.previous_output.hash)
|
||||||
// todo: optimize block decomposition vec<transaction> -> hashmap<h256, transaction>
|
// todo: optimize block decomposition vec<transaction> -> hashmap<h256, transaction>
|
||||||
.or(block.transactions().iter().find(|tx| !tx.is_coinbase() && tx.hash() == input.previous_output.hash).cloned())
|
.or(
|
||||||
|
block.transactions()
|
||||||
|
.skip(1)
|
||||||
|
.find(|&(hash, tx)| hash == &input.previous_output.hash)
|
||||||
|
.and_then(|(_, tx)| Some(tx))
|
||||||
|
.cloned()
|
||||||
|
)
|
||||||
.ok_or(
|
.ok_or(
|
||||||
Error::Transaction(tx_index, TransactionError::UnknownReference(input.previous_output.hash.clone()))
|
Error::Transaction(tx_index, TransactionError::UnknownReference(input.previous_output.hash.clone()))
|
||||||
)
|
)
|
||||||
|
@ -140,7 +151,8 @@ impl ChainVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_transaction(&self,
|
fn verify_transaction(&self,
|
||||||
block: &chain::Block,
|
block: &db::IndexedBlock,
|
||||||
|
hash: &H256,
|
||||||
transaction: &chain::Transaction,
|
transaction: &chain::Transaction,
|
||||||
sequence: usize,
|
sequence: usize,
|
||||||
) -> Result<usize, TransactionError> {
|
) -> Result<usize, TransactionError> {
|
||||||
|
@ -170,7 +182,10 @@ impl ChainVerifier {
|
||||||
let store_parent_transaction = self.store.transaction(&input.previous_output.hash);
|
let store_parent_transaction = self.store.transaction(&input.previous_output.hash);
|
||||||
let parent_transaction = store_parent_transaction
|
let parent_transaction = store_parent_transaction
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.or_else(|| block.transactions.iter().find(|t| t.hash() == input.previous_output.hash))
|
.or_else(
|
||||||
|
|| block.transactions().find(|&(hash, tx)| hash == &input.previous_output.hash)
|
||||||
|
.and_then(|(hash, tx)| Some(tx))
|
||||||
|
)
|
||||||
.ok_or_else(|| TransactionError::Inconclusive(input.previous_output.hash.clone()))?;
|
.ok_or_else(|| TransactionError::Inconclusive(input.previous_output.hash.clone()))?;
|
||||||
|
|
||||||
if parent_transaction.outputs.len() <= input.previous_output.index as usize {
|
if parent_transaction.outputs.len() <= input.previous_output.index as usize {
|
||||||
|
@ -212,11 +227,11 @@ impl ChainVerifier {
|
||||||
Ok(sigops)
|
Ok(sigops)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block(&self, block: &chain::Block) -> VerificationResult {
|
fn verify_block(&self, block: &db::IndexedBlock) -> VerificationResult {
|
||||||
let hash = block.hash();
|
let hash = block.hash();
|
||||||
|
|
||||||
// There should be at least 1 transaction
|
// There should be at least 1 transaction
|
||||||
if block.transactions().is_empty() {
|
if block.transaction_count() == 0 {
|
||||||
return Err(Error::Empty);
|
return Err(Error::Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,14 +246,18 @@ impl ChainVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(median_timestamp) = self.median_timestamp(block) {
|
if let Some(median_timestamp) = self.median_timestamp(block) {
|
||||||
if median_timestamp >= block.block_header.time {
|
if median_timestamp >= block.header().time {
|
||||||
trace!(target: "verification", "median timestamp verification failed, median: {}, current: {}", median_timestamp, block.block_header.time);
|
trace!(
|
||||||
|
target: "verification", "median timestamp verification failed, median: {}, current: {}",
|
||||||
|
median_timestamp,
|
||||||
|
block.header().time
|
||||||
|
);
|
||||||
return Err(Error::Timestamp);
|
return Err(Error::Timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: serialized_size function is at least suboptimal
|
// todo: serialized_size function is at least suboptimal
|
||||||
let size = ::serialization::Serializable::serialized_size(block);
|
let size = block.size();
|
||||||
if size > MAX_BLOCK_SIZE {
|
if size > MAX_BLOCK_SIZE {
|
||||||
return Err(Error::Size(size))
|
return Err(Error::Size(size))
|
||||||
}
|
}
|
||||||
|
@ -248,25 +267,25 @@ impl ChainVerifier {
|
||||||
return Err(Error::MerkleRoot);
|
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
|
// check first transaction is a coinbase transaction
|
||||||
if !block.transactions()[0].is_coinbase() {
|
if !first_tx.is_coinbase() {
|
||||||
return Err(Error::Coinbase)
|
return Err(Error::Coinbase)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that coinbase has a valid signature
|
// check that coinbase has a valid signature
|
||||||
let coinbase = &block.transactions()[0];
|
|
||||||
// is_coinbase() = true above guarantees that there is at least one input
|
// 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 {
|
if coinbase_script_len < 2 || coinbase_script_len > 100 {
|
||||||
return Err(Error::CoinbaseSignatureLength(coinbase_script_len));
|
return Err(Error::CoinbaseSignatureLength(coinbase_script_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction verification including number of signature operations checking
|
// transaction verification including number of signature operations checking
|
||||||
let mut block_sigops = 0;
|
let mut block_sigops = 0;
|
||||||
for (idx, transaction) in block.transactions().iter().enumerate() {
|
for (idx, (tx_hash, transaction)) in block.transactions().enumerate() {
|
||||||
block_sigops += try!(
|
block_sigops += try!(
|
||||||
self.verify_transaction(
|
self.verify_transaction(
|
||||||
block,
|
block,
|
||||||
|
tx_hash,
|
||||||
transaction,
|
transaction,
|
||||||
idx,
|
idx,
|
||||||
).map_err(|e| Error::Transaction(idx, e))
|
).map_err(|e| Error::Transaction(idx, e))
|
||||||
|
@ -293,9 +312,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 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
|
// TODO: optimize it, so it does not make 11 redundant queries each time
|
||||||
for _ in 0..11 {
|
for _ in 0..11 {
|
||||||
let previous_header = match self.store.block_header(block_ref) {
|
let previous_header = match self.store.block_header(block_ref) {
|
||||||
|
@ -313,12 +332,12 @@ impl ChainVerifier {
|
||||||
else { None }
|
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 {
|
if height == 0 {
|
||||||
return None;
|
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");
|
let previous_header = self.store.block_header(previous_ref).expect("self.height != 0; qed");
|
||||||
|
|
||||||
if utils::is_retarget_height(height) {
|
if utils::is_retarget_height(height) {
|
||||||
|
@ -341,12 +360,12 @@ impl ChainVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Verify for 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);
|
let result = self.verify_block(block);
|
||||||
trace!(
|
trace!(
|
||||||
target: "verification", "Block {} (transactions: {}) verification finished. Result {:?}",
|
target: "verification", "Block {} (transactions: {}) verification finished. Result {:?}",
|
||||||
block.hash().to_reversed_str(),
|
block.hash().to_reversed_str(),
|
||||||
block.transactions().len(),
|
block.transaction_count(),
|
||||||
result,
|
result,
|
||||||
);
|
);
|
||||||
result
|
result
|
||||||
|
@ -356,10 +375,10 @@ impl Verify for ChainVerifier {
|
||||||
impl ContinueVerify for ChainVerifier {
|
impl ContinueVerify for ChainVerifier {
|
||||||
type State = usize;
|
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)
|
// verify transactions (except coinbase)
|
||||||
for (idx, transaction) in block.transactions().iter().enumerate().skip(state - 1) {
|
for (idx, (tx_hash, transaction)) in block.transactions().enumerate().skip(state - 1) {
|
||||||
try!(self.verify_transaction(block, transaction, idx).map_err(|e| Error::Transaction(idx, e)));
|
try!(self.verify_transaction(block, tx_hash, transaction, idx).map_err(|e| Error::Transaction(idx, e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let _parent = match self.store.block(BlockRef::Hash(block.header().previous_header_hash.clone())) {
|
let _parent = match self.store.block(BlockRef::Hash(block.header().previous_header_hash.clone())) {
|
||||||
|
@ -374,7 +393,7 @@ impl ContinueVerify for ChainVerifier {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use db::{TestStorage, Storage, Store, BlockStapler};
|
use db::{TestStorage, Storage, Store, BlockStapler, IndexedBlock};
|
||||||
use network::Magic;
|
use network::Magic;
|
||||||
use devtools::RandomTempPath;
|
use devtools::RandomTempPath;
|
||||||
use {script, test_data};
|
use {script, test_data};
|
||||||
|
@ -387,7 +406,7 @@ mod tests {
|
||||||
let b2 = test_data::block_h2();
|
let b2 = test_data::block_h2();
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet);
|
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]
|
#[test]
|
||||||
|
@ -395,7 +414,7 @@ mod tests {
|
||||||
let storage = TestStorage::with_blocks(&vec![test_data::genesis()]);
|
let storage = TestStorage::with_blocks(&vec![test_data::genesis()]);
|
||||||
let b1 = test_data::block_h1();
|
let b1 = test_data::block_h1();
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet);
|
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]
|
#[test]
|
||||||
|
@ -408,7 +427,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
let b1 = test_data::block_h170();
|
let b1 = test_data::block_h170();
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet);
|
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]
|
#[test]
|
||||||
|
@ -425,7 +444,7 @@ mod tests {
|
||||||
1,
|
1,
|
||||||
TransactionError::Inconclusive("c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704".into())
|
TransactionError::Inconclusive("c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704".into())
|
||||||
));
|
));
|
||||||
assert_eq!(should_be, verifier.verify(&b170));
|
assert_eq!(should_be, verifier.verify(&b170.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -460,7 +479,7 @@ mod tests {
|
||||||
TransactionError::Maturity,
|
TransactionError::Maturity,
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(expected, verifier.verify(&block));
|
assert_eq!(expected, verifier.verify(&block.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -493,7 +512,7 @@ mod tests {
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||||
|
|
||||||
let expected = Ok(Chain::Main);
|
let expected = Ok(Chain::Main);
|
||||||
assert_eq!(expected, verifier.verify(&block));
|
assert_eq!(expected, verifier.verify(&block.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -532,7 +551,7 @@ mod tests {
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||||
|
|
||||||
let expected = Ok(Chain::Main);
|
let expected = Ok(Chain::Main);
|
||||||
assert_eq!(expected, verifier.verify(&block));
|
assert_eq!(expected, verifier.verify(&block.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -570,7 +589,7 @@ mod tests {
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||||
|
|
||||||
let expected = Err(Error::Transaction(2, TransactionError::Overspend));
|
let expected = Err(Error::Transaction(2, TransactionError::Overspend));
|
||||||
assert_eq!(expected, verifier.verify(&block));
|
assert_eq!(expected, verifier.verify(&block.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -615,7 +634,7 @@ mod tests {
|
||||||
|
|
||||||
let expected = Ok(Chain::Main);
|
let expected = Ok(Chain::Main);
|
||||||
|
|
||||||
assert_eq!(expected, verifier.verify(&block))
|
assert_eq!(expected, verifier.verify(&block.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -646,7 +665,7 @@ mod tests {
|
||||||
builder_tx2 = builder_tx2.push_opcode(script::Opcode::OP_CHECKSIG)
|
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().coinbase().build()
|
||||||
.transaction()
|
.transaction()
|
||||||
.input()
|
.input()
|
||||||
|
@ -661,12 +680,13 @@ mod tests {
|
||||||
.build()
|
.build()
|
||||||
.build()
|
.build()
|
||||||
.merkled_header().parent(genesis.hash()).build()
|
.merkled_header().parent(genesis.hash()).build()
|
||||||
.build();
|
.build()
|
||||||
|
.into();
|
||||||
|
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||||
|
|
||||||
let expected = Err(Error::MaximumSigops);
|
let expected = Err(Error::MaximumSigops);
|
||||||
assert_eq!(expected, verifier.verify(&block));
|
assert_eq!(expected, verifier.verify(&block.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -681,13 +701,14 @@ mod tests {
|
||||||
.build();
|
.build();
|
||||||
storage.insert_block(&genesis).unwrap();
|
storage.insert_block(&genesis).unwrap();
|
||||||
|
|
||||||
let block = test_data::block_builder()
|
let block: IndexedBlock = test_data::block_builder()
|
||||||
.transaction()
|
.transaction()
|
||||||
.coinbase()
|
.coinbase()
|
||||||
.output().value(5000000001).build()
|
.output().value(5000000001).build()
|
||||||
.build()
|
.build()
|
||||||
.merkled_header().parent(genesis.hash()).build()
|
.merkled_header().parent(genesis.hash()).build()
|
||||||
.build();
|
.build()
|
||||||
|
.into();
|
||||||
|
|
||||||
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
let verifier = ChainVerifier::new(Arc::new(storage), Magic::Testnet).pow_skip().signatures_skip();
|
||||||
|
|
||||||
|
@ -696,6 +717,6 @@ mod tests {
|
||||||
actual: 5000000001
|
actual: 5000000001
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(expected, verifier.verify(&block));
|
assert_eq!(expected, verifier.verify(&block.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,11 @@ extern crate test_data;
|
||||||
|
|
||||||
mod chain_verifier;
|
mod chain_verifier;
|
||||||
mod compact;
|
mod compact;
|
||||||
mod queue;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod lookup;
|
||||||
|
|
||||||
pub use primitives::{uint, hash};
|
pub use primitives::{uint, hash};
|
||||||
|
|
||||||
pub use queue::Queue;
|
|
||||||
pub use chain_verifier::ChainVerifier;
|
pub use chain_verifier::ChainVerifier;
|
||||||
|
|
||||||
use primitives::hash::H256;
|
use primitives::hash::H256;
|
||||||
|
@ -116,11 +115,11 @@ pub type VerificationResult = Result<Chain, Error>;
|
||||||
|
|
||||||
/// Interface for block verification
|
/// Interface for block verification
|
||||||
pub trait Verify : Send + Sync {
|
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
|
/// Trait for verifier that can be interrupted and continue from the specific point
|
||||||
pub trait ContinueVerify : Verify + Send + Sync {
|
pub trait ContinueVerify : Verify + Send + Sync {
|
||||||
type State;
|
type State;
|
||||||
fn continue_verify(&self, block: &chain::Block, state: Self::State) -> VerificationResult;
|
fn continue_verify(&self, block: &db::IndexedBlock, state: Self::State) -> VerificationResult;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
use db;
|
||||||
|
use chain;
|
||||||
|
use primitives::H256;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
struct BlockTransactionLookup<'a, 'b> {
|
||||||
|
store: &'a db::Store,
|
||||||
|
block: &'b db::IndexedBlock,
|
||||||
|
cache: HashMap<H256, chain::Transaction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> BlockTransactionLookup<'a, 'b> {
|
||||||
|
fn new(store: &'a db::Store, block: &'b db::IndexedBlock) -> BlockTransactionLookup<'a, 'b> {
|
||||||
|
BlockTransactionLookup { store: store, block: block, cache: HashMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find(&mut self, hash: &H256) -> Option<(&H256, &chain::Transaction)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue