block finality check uses median time past instead of block time after csv is activated (bip113)
This commit is contained in:
parent
349bde9f87
commit
f99c369e87
|
@ -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)]
|
||||
|
|
|
@ -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, ¶ms),
|
||||
coinbase_script: BlockCoinbaseScript::new(block, ¶ms, 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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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, ¶ms),
|
||||
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,
|
||||
|
|
|
@ -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, ¶ms, 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, ¶ms, 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,
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue