1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use rayon::prelude::{IntoParallelRefIterator, IndexedParallelIterator, ParallelIterator};
use storage::Store;
use network::ConsensusParams;
use error::Error;
use canon::CanonBlock;
use accept_block::BlockAcceptor;
use accept_header::HeaderAcceptor;
use accept_transaction::TransactionAcceptor;
use deployments::BlockDeployments;
use duplex_store::DuplexTransactionOutputProvider;
use VerificationLevel;

pub struct ChainAcceptor<'a> {
	pub block: BlockAcceptor<'a>,
	pub header: HeaderAcceptor<'a>,
	pub transactions: Vec<TransactionAcceptor<'a>>,
}

impl<'a> ChainAcceptor<'a> {
	pub fn new(store: &'a Store, consensus: &'a ConsensusParams, verification_level: VerificationLevel, block: CanonBlock<'a>, height: u32, median_time_past: u32, deployments: &'a BlockDeployments) -> Self {
		trace!(target: "verification", "Block verification {}", block.hash().to_reversed_str());
		let output_store = DuplexTransactionOutputProvider::new(store.as_transaction_output_provider(), block.raw());
		let headers = store.as_block_header_provider();

		ChainAcceptor {
			block: BlockAcceptor::new(store.as_transaction_output_provider(), consensus, block, height, median_time_past, deployments, headers),
			header: HeaderAcceptor::new(headers, consensus, block.header(), height, deployments),
			transactions: block.transactions()
				.into_iter()
				.enumerate()
				.map(|(tx_index, tx)| TransactionAcceptor::new(
						store.as_transaction_meta_provider(),
						output_store,
						consensus,
						tx,
						verification_level,
						block.hash(),
						height,
						block.header.raw.time,
						median_time_past,
						tx_index,
						deployments,
				))
				.collect(),
		}
	}

	pub fn check(&self) -> Result<(), Error> {
		try!(self.block.check());
		try!(self.header.check());
		try!(self.check_transactions());
		Ok(())
	}

	fn check_transactions(&self) -> Result<(), Error> {
		self.transactions.par_iter()
			.enumerate()
			.fold(|| Ok(()), |result, (index, tx)| result.and_then(|_| tx.check().map_err(|err| Error::Transaction(index, err))))
			.reduce(|| Ok(()), |acc, check| acc.and(check))
	}
}