block finality check uses median time past instead of block time after csv is activated (bip113)

This commit is contained in:
debris 2017-05-04 10:32:54 +02:00
parent 349bde9f87
commit f99c369e87
6 changed files with 38 additions and 21 deletions

View File

@ -66,10 +66,6 @@ impl Block {
pub fn hash(&self) -> H256 {
self.block_header.hash()
}
pub fn is_final(&self, height: u32) -> bool {
self.transactions.iter().all(|t| t.is_final_in_block(height, self.block_header.time))
}
}
#[cfg(test)]

View File

@ -1,12 +1,14 @@
use network::{Magic, ConsensusParams};
use db::TransactionOutputProvider;
use db::{TransactionOutputProvider, BlockHeaderProvider};
use script;
use sigops::transaction_sigops;
use work::block_reward_satoshi;
use duplex_store::DuplexTransactionOutputProvider;
use deployments::Deployments;
use canon::CanonBlock;
use constants::MAX_BLOCK_SIGOPS;
use error::{Error, TransactionError};
use timestamp::median_timestamp;
/// Flexible verification of ordered block
pub struct BlockAcceptor<'a> {
@ -17,10 +19,17 @@ pub struct BlockAcceptor<'a> {
}
impl<'a> BlockAcceptor<'a> {
pub fn new(store: &'a TransactionOutputProvider, network: Magic, block: CanonBlock<'a>, height: u32) -> Self {
pub fn new(
store: &'a TransactionOutputProvider,
network: Magic,
block: CanonBlock<'a>,
height: u32,
deployments: &'a Deployments,
headers: &'a BlockHeaderProvider,
) -> Self {
let params = network.consensus_params();
BlockAcceptor {
finality: BlockFinality::new(block, height),
finality: BlockFinality::new(block, height, deployments, headers, &params),
coinbase_script: BlockCoinbaseScript::new(block, &params, height),
coinbase_claim: BlockCoinbaseClaim::new(block, store, height),
sigops: BlockSigops::new(block, store, params, MAX_BLOCK_SIGOPS),
@ -39,18 +48,30 @@ impl<'a> BlockAcceptor<'a> {
pub struct BlockFinality<'a> {
block: CanonBlock<'a>,
height: u32,
csv_active: bool,
headers: &'a BlockHeaderProvider,
}
impl<'a> BlockFinality<'a> {
fn new(block: CanonBlock<'a>, height: u32) -> Self {
fn new(block: CanonBlock<'a>, height: u32, deployments: &'a Deployments, headers: &'a BlockHeaderProvider, params: &ConsensusParams) -> Self {
let csv_active = deployments.csv(height, headers, params);
BlockFinality {
block: block,
height: height,
csv_active: csv_active,
headers: headers,
}
}
fn check(&self) -> Result<(), Error> {
if self.block.is_final(self.height) {
let time_cutoff = if self.csv_active {
median_timestamp(&self.block.header.raw, self.headers)
} else {
self.block.header.raw.time
};
if self.block.transactions.iter().all(|tx| tx.raw.is_final_in_block(self.height, time_cutoff)) {
Ok(())
} else {
Err(Error::NonFinalBlock)

View File

@ -21,7 +21,7 @@ impl<'a> ChainAcceptor<'a> {
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(), network, block, height),
block: BlockAcceptor::new(store.as_transaction_output_provider(), network, block, height, deployments, headers),
header: HeaderAcceptor::new(headers, network, block.header(), height, deployments),
transactions: block.transactions()
.into_iter()

View File

@ -19,12 +19,12 @@ impl<'a> HeaderAcceptor<'a> {
header: CanonHeader<'a>,
height: u32,
deployments: &'a Deployments,
) -> Self {
) -> Self {
let params = network.consensus_params();
HeaderAcceptor {
version: HeaderVersion::new(header, height, params.clone()),
work: HeaderWork::new(header, store, height, network),
median_timestamp: HeaderMedianTimestamp::new(header, store, height, deployments, params),
median_timestamp: HeaderMedianTimestamp::new(header, store, height, deployments, &params),
version: HeaderVersion::new(header, height, params),
}
}
@ -100,7 +100,7 @@ pub struct HeaderMedianTimestamp<'a> {
}
impl<'a> HeaderMedianTimestamp<'a> {
fn new(header: CanonHeader<'a>, store: &'a BlockHeaderProvider, height: u32, deployments: &'a Deployments, params: ConsensusParams) -> Self {
fn new(header: CanonHeader<'a>, store: &'a BlockHeaderProvider, height: u32, deployments: &'a Deployments, params: &ConsensusParams) -> Self {
let active = deployments.csv(height, store, params);
HeaderMedianTimestamp {
header: header,

View File

@ -42,7 +42,7 @@ impl<'a> TransactionAcceptor<'a> {
maturity: TransactionMaturity::new(transaction, meta_store, height),
overspent: TransactionOverspent::new(transaction, output_store),
double_spent: TransactionDoubleSpend::new(transaction, output_store),
eval: TransactionEval::new(transaction, output_store, params, height, time, deployments, headers),
eval: TransactionEval::new(transaction, output_store, &params, height, time, deployments, headers),
}
}
@ -88,7 +88,7 @@ impl<'a> MemoryPoolTransactionAcceptor<'a> {
overspent: TransactionOverspent::new(transaction, output_store),
sigops: TransactionSigops::new(transaction, output_store, params.clone(), MAX_BLOCK_SIGOPS, time),
double_spent: TransactionDoubleSpend::new(transaction, output_store),
eval: TransactionEval::new(transaction, output_store, params, height, time, deployments, headers),
eval: TransactionEval::new(transaction, output_store, &params, height, time, deployments, headers),
}
}
@ -283,7 +283,7 @@ impl<'a> TransactionEval<'a> {
fn new(
transaction: CanonTransaction<'a>,
store: DuplexTransactionOutputProvider<'a>,
params: ConsensusParams,
params: &ConsensusParams,
height: u32,
time: u32,
deployments: &'a Deployments,

View File

@ -62,7 +62,7 @@ impl Deployments {
}
/// Returns true if csv deployment is active
pub fn csv(&self, number: u32, headers: &BlockHeaderProvider, consensus: ConsensusParams) -> bool {
pub fn csv(&self, number: u32, headers: &BlockHeaderProvider, consensus: &ConsensusParams) -> bool {
match consensus.csv_deployment {
Some(csv) => {
let mut cache = self.cache.lock();
@ -74,7 +74,7 @@ impl Deployments {
}
/// Calculates threshold state of given deployment
fn threshold_state(cache: &mut DeploymentStateCache, deployment: Deployment, number: u32, headers: &BlockHeaderProvider, consensus: ConsensusParams) -> ThresholdState {
fn threshold_state(cache: &mut DeploymentStateCache, deployment: Deployment, number: u32, headers: &BlockHeaderProvider, consensus: &ConsensusParams) -> ThresholdState {
if let Some(activation) = deployment.activation {
if activation <= number {
return ThresholdState::Active;
@ -140,12 +140,12 @@ struct ThresholdIterator<'a> {
deployment: Deployment,
block_iterator: BlockIterator<'a>,
headers: &'a BlockHeaderProvider,
consensus: ConsensusParams,
consensus: &'a ConsensusParams,
last_state: ThresholdState,
}
impl<'a> ThresholdIterator<'a> {
fn new(deployment: Deployment, headers: &'a BlockHeaderProvider, to_check: u32, consensus: ConsensusParams, state: ThresholdState) -> Self {
fn new(deployment: Deployment, headers: &'a BlockHeaderProvider, to_check: u32, consensus: &'a ConsensusParams, state: ThresholdState) -> Self {
ThresholdIterator {
deployment: deployment,
block_iterator: BlockIterator::new(to_check, consensus.miner_confirmation_window, headers),