From a4de321cc70d89f26f2c7e40af4cc94d36e19847 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 25 Nov 2016 14:54:22 +0300 Subject: [PATCH] median time verfication might be unordered? --- verification/src/chain_verifier.rs | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/verification/src/chain_verifier.rs b/verification/src/chain_verifier.rs index ed7c9f4d..9983bd5a 100644 --- a/verification/src/chain_verifier.rs +++ b/verification/src/chain_verifier.rs @@ -1,6 +1,5 @@ //! Bitcoin chain verifier -use std::cmp; use std::collections::HashSet; use db::{self, BlockRef, BlockLocation}; use super::{Verify, VerificationResult, Chain, Error, TransactionError, ContinueVerify}; @@ -64,13 +63,6 @@ impl ChainVerifier { } } - if let Some(median_timestamp) = self.ordered_median_timestamp(block, at_height) { - if median_timestamp > block.block_header.time { - trace!(target: "verification", "median timestamp verification failed, median: {}, current: {}", median_timestamp, block.block_header.time); - return Err(Error::Timestamp); - } - } - let coinbase_spends = block.transactions()[0].total_spends(); let mut total_unspent = 0u64; @@ -219,6 +211,13 @@ impl ChainVerifier { return Err(Error::Timestamp); } + if let Some(median_timestamp) = self.median_timestamp(block) { + if median_timestamp > block.block_header.time { + trace!(target: "verification", "median timestamp verification failed, median: {}, current: {}", median_timestamp, block.block_header.time); + return Err(Error::Timestamp); + } + } + // todo: serialized_size function is at least suboptimal let size = ::serialization::Serializable::serialized_size(block); if size > MAX_BLOCK_SIZE { @@ -275,24 +274,25 @@ impl ChainVerifier { } } - fn ordered_median_timestamp(&self, block: &chain::Block, height: u32) -> Option { - if height == 0 { - return None; - } - + fn median_timestamp(&self, block: &chain::Block) -> Option { // TODO: make 11 a const - let max = cmp::min(height, 11); let mut timestamps = HashSet::new(); let mut block_ref = block.block_header.previous_header_hash.clone().into(); // TODO: optimize it, so it does not make 11 redundant queries each time - for _ in 0..max { - let previous_header = self.store.block_header(block_ref).expect("block_ref < height; qed"); + for _ in 0..10 { + let previous_header = match self.store.block_header(block_ref) { + Some(h) => h, + None => { break; } + }; timestamps.insert(previous_header.time); block_ref = previous_header.previous_header_hash.into(); } - let timestamps: Vec<_> = timestamps.into_iter().collect(); - Some(timestamps[timestamps.len() / 2]) + if timestamps.len() > 2 { + let timestamps: Vec<_> = timestamps.into_iter().collect(); + Some(timestamps[timestamps.len() / 2]) + } + else { None } } fn work_required(&self, height: u32) -> Option {