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 {
|
pub fn hash(&self) -> H256 {
|
||||||
self.block_header.hash()
|
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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use network::{Magic, ConsensusParams};
|
use network::{Magic, ConsensusParams};
|
||||||
use db::TransactionOutputProvider;
|
use db::{TransactionOutputProvider, BlockHeaderProvider};
|
||||||
use script;
|
use script;
|
||||||
use sigops::transaction_sigops;
|
use sigops::transaction_sigops;
|
||||||
use work::block_reward_satoshi;
|
use work::block_reward_satoshi;
|
||||||
use duplex_store::DuplexTransactionOutputProvider;
|
use duplex_store::DuplexTransactionOutputProvider;
|
||||||
|
use deployments::Deployments;
|
||||||
use canon::CanonBlock;
|
use canon::CanonBlock;
|
||||||
use constants::MAX_BLOCK_SIGOPS;
|
use constants::MAX_BLOCK_SIGOPS;
|
||||||
use error::{Error, TransactionError};
|
use error::{Error, TransactionError};
|
||||||
|
use timestamp::median_timestamp;
|
||||||
|
|
||||||
/// Flexible verification of ordered block
|
/// Flexible verification of ordered block
|
||||||
pub struct BlockAcceptor<'a> {
|
pub struct BlockAcceptor<'a> {
|
||||||
|
@ -17,10 +19,17 @@ pub struct BlockAcceptor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> 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();
|
let params = network.consensus_params();
|
||||||
BlockAcceptor {
|
BlockAcceptor {
|
||||||
finality: BlockFinality::new(block, height),
|
finality: BlockFinality::new(block, height, deployments, headers, ¶ms),
|
||||||
coinbase_script: BlockCoinbaseScript::new(block, ¶ms, height),
|
coinbase_script: BlockCoinbaseScript::new(block, ¶ms, height),
|
||||||
coinbase_claim: BlockCoinbaseClaim::new(block, store, height),
|
coinbase_claim: BlockCoinbaseClaim::new(block, store, height),
|
||||||
sigops: BlockSigops::new(block, store, params, MAX_BLOCK_SIGOPS),
|
sigops: BlockSigops::new(block, store, params, MAX_BLOCK_SIGOPS),
|
||||||
|
@ -39,18 +48,30 @@ impl<'a> BlockAcceptor<'a> {
|
||||||
pub struct BlockFinality<'a> {
|
pub struct BlockFinality<'a> {
|
||||||
block: CanonBlock<'a>,
|
block: CanonBlock<'a>,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
csv_active: bool,
|
||||||
|
headers: &'a BlockHeaderProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BlockFinality<'a> {
|
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 {
|
BlockFinality {
|
||||||
block: block,
|
block: block,
|
||||||
height: height,
|
height: height,
|
||||||
|
csv_active: csv_active,
|
||||||
|
headers: headers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(&self) -> Result<(), Error> {
|
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(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::NonFinalBlock)
|
Err(Error::NonFinalBlock)
|
||||||
|
|
|
@ -21,7 +21,7 @@ impl<'a> ChainAcceptor<'a> {
|
||||||
let output_store = DuplexTransactionOutputProvider::new(store.as_transaction_output_provider(), block.raw());
|
let output_store = DuplexTransactionOutputProvider::new(store.as_transaction_output_provider(), block.raw());
|
||||||
let headers = store.as_block_header_provider();
|
let headers = store.as_block_header_provider();
|
||||||
ChainAcceptor {
|
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),
|
header: HeaderAcceptor::new(headers, network, block.header(), height, deployments),
|
||||||
transactions: block.transactions()
|
transactions: block.transactions()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -19,12 +19,12 @@ impl<'a> HeaderAcceptor<'a> {
|
||||||
header: CanonHeader<'a>,
|
header: CanonHeader<'a>,
|
||||||
height: u32,
|
height: u32,
|
||||||
deployments: &'a Deployments,
|
deployments: &'a Deployments,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let params = network.consensus_params();
|
let params = network.consensus_params();
|
||||||
HeaderAcceptor {
|
HeaderAcceptor {
|
||||||
version: HeaderVersion::new(header, height, params.clone()),
|
|
||||||
work: HeaderWork::new(header, store, height, network),
|
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> {
|
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);
|
let active = deployments.csv(height, store, params);
|
||||||
HeaderMedianTimestamp {
|
HeaderMedianTimestamp {
|
||||||
header: header,
|
header: header,
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl<'a> TransactionAcceptor<'a> {
|
||||||
maturity: TransactionMaturity::new(transaction, meta_store, height),
|
maturity: TransactionMaturity::new(transaction, meta_store, height),
|
||||||
overspent: TransactionOverspent::new(transaction, output_store),
|
overspent: TransactionOverspent::new(transaction, output_store),
|
||||||
double_spent: TransactionDoubleSpend::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),
|
overspent: TransactionOverspent::new(transaction, output_store),
|
||||||
sigops: TransactionSigops::new(transaction, output_store, params.clone(), MAX_BLOCK_SIGOPS, time),
|
sigops: TransactionSigops::new(transaction, output_store, params.clone(), MAX_BLOCK_SIGOPS, time),
|
||||||
double_spent: TransactionDoubleSpend::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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ impl<'a> TransactionEval<'a> {
|
||||||
fn new(
|
fn new(
|
||||||
transaction: CanonTransaction<'a>,
|
transaction: CanonTransaction<'a>,
|
||||||
store: DuplexTransactionOutputProvider<'a>,
|
store: DuplexTransactionOutputProvider<'a>,
|
||||||
params: ConsensusParams,
|
params: &ConsensusParams,
|
||||||
height: u32,
|
height: u32,
|
||||||
time: u32,
|
time: u32,
|
||||||
deployments: &'a Deployments,
|
deployments: &'a Deployments,
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl Deployments {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if csv deployment is active
|
/// 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 {
|
match consensus.csv_deployment {
|
||||||
Some(csv) => {
|
Some(csv) => {
|
||||||
let mut cache = self.cache.lock();
|
let mut cache = self.cache.lock();
|
||||||
|
@ -74,7 +74,7 @@ impl Deployments {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates threshold state of given deployment
|
/// 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 let Some(activation) = deployment.activation {
|
||||||
if activation <= number {
|
if activation <= number {
|
||||||
return ThresholdState::Active;
|
return ThresholdState::Active;
|
||||||
|
@ -140,12 +140,12 @@ struct ThresholdIterator<'a> {
|
||||||
deployment: Deployment,
|
deployment: Deployment,
|
||||||
block_iterator: BlockIterator<'a>,
|
block_iterator: BlockIterator<'a>,
|
||||||
headers: &'a BlockHeaderProvider,
|
headers: &'a BlockHeaderProvider,
|
||||||
consensus: ConsensusParams,
|
consensus: &'a ConsensusParams,
|
||||||
last_state: ThresholdState,
|
last_state: ThresholdState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ThresholdIterator<'a> {
|
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 {
|
ThresholdIterator {
|
||||||
deployment: deployment,
|
deployment: deployment,
|
||||||
block_iterator: BlockIterator::new(to_check, consensus.miner_confirmation_window, headers),
|
block_iterator: BlockIterator::new(to_check, consensus.miner_confirmation_window, headers),
|
||||||
|
|
Loading…
Reference in New Issue