Merge pull request #452 from paritytech/cache_fix
Deployments state cache fix
This commit is contained in:
commit
acb5f1d6bf
|
@ -118,6 +118,8 @@ pub struct Chain {
|
|||
memory_pool: MemoryPoolRef,
|
||||
/// Blocks that have been marked as dead-ends
|
||||
dead_end_blocks: HashSet<H256>,
|
||||
/// Deployments cache
|
||||
deployments: Deployments,
|
||||
/// Is SegWit active?
|
||||
is_segwit_active: bool,
|
||||
}
|
||||
|
@ -150,7 +152,8 @@ impl Chain {
|
|||
.expect("storage with genesis block is required");
|
||||
let best_storage_block = storage.best_block();
|
||||
let best_storage_block_hash = best_storage_block.hash.clone();
|
||||
let is_segwit_active = Deployments::new().segwit(best_storage_block.number, storage.as_block_header_provider(), &consensus);
|
||||
let deployments = Deployments::new();
|
||||
let is_segwit_active = deployments.segwit(best_storage_block.number, storage.as_block_header_provider(), &consensus);
|
||||
|
||||
Chain {
|
||||
genesis_block_hash: genesis_block_hash,
|
||||
|
@ -162,6 +165,7 @@ impl Chain {
|
|||
verifying_transactions: LinkedHashMap::new(),
|
||||
memory_pool: memory_pool,
|
||||
dead_end_blocks: HashSet::new(),
|
||||
deployments: deployments,
|
||||
is_segwit_active: is_segwit_active,
|
||||
}
|
||||
}
|
||||
|
@ -363,7 +367,7 @@ impl Chain {
|
|||
|
||||
// remember new best block hash
|
||||
self.best_storage_block = self.storage.as_store().best_block();
|
||||
self.is_segwit_active = Deployments::new().segwit(self.best_storage_block.number, self.storage.as_block_header_provider(), &self.consensus);
|
||||
self.is_segwit_active = self.deployments.segwit(self.best_storage_block.number, self.storage.as_block_header_provider(), &self.consensus);
|
||||
|
||||
// remove inserted block + handle possible reorganization in headers chain
|
||||
// TODO: mk, not sure if we need both of those params
|
||||
|
@ -399,7 +403,7 @@ impl Chain {
|
|||
|
||||
// remember new best block hash
|
||||
self.best_storage_block = self.storage.best_block();
|
||||
self.is_segwit_active = Deployments::new().segwit(self.best_storage_block.number, self.storage.as_block_header_provider(), &self.consensus);
|
||||
self.is_segwit_active = self.deployments.segwit(self.best_storage_block.number, self.storage.as_block_header_provider(), &self.consensus);
|
||||
|
||||
// remove inserted block + handle possible reorganization in headers chain
|
||||
// TODO: mk, not sure if we need both of those params
|
||||
|
|
|
@ -147,21 +147,18 @@ fn threshold_state(cache: &mut DeploymentStateCache, deployment: Deployment, num
|
|||
}
|
||||
let threshold_state = deployment_state.state;
|
||||
let deployment_iter = ThresholdIterator::new(deployment, headers, number, miner_confirmation_window, rule_change_activation_threshold, threshold_state);
|
||||
let state = match deployment_iter.last() {
|
||||
Some(state) => state,
|
||||
None => DeploymentState {
|
||||
block_number: number,
|
||||
block_hash: hash,
|
||||
state: deployment_state.state,
|
||||
},
|
||||
};
|
||||
let state = deployment_iter.last().expect("iter must have at least one item");
|
||||
let result = state.state;
|
||||
entry.insert(state);
|
||||
result
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
let deployment_iter = ThresholdIterator::new(deployment, headers, miner_confirmation_window - 1, miner_confirmation_window, rule_change_activation_threshold, ThresholdState::Defined);
|
||||
let state = deployment_iter.last().unwrap_or_default();
|
||||
let state = deployment_iter.last().unwrap_or_else(|| DeploymentState {
|
||||
block_number: number,
|
||||
block_hash: hash,
|
||||
state: ThresholdState::Defined,
|
||||
});
|
||||
let result = state.state;
|
||||
entry.insert(state);
|
||||
result
|
||||
|
@ -255,6 +252,7 @@ impl<'a> Iterator for ThresholdIterator<'a> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::collections::HashMap;
|
||||
use chain::BlockHeader;
|
||||
use db::{BlockHeaderProvider, BlockRef};
|
||||
|
@ -268,6 +266,7 @@ mod tests {
|
|||
|
||||
#[derive(Default)]
|
||||
struct DeploymentHeaderProvider {
|
||||
pub request_count: AtomicUsize,
|
||||
pub by_height: Vec<BlockHeader>,
|
||||
pub by_hash: HashMap<H256, usize>,
|
||||
}
|
||||
|
@ -298,6 +297,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn block_header(&self, block_ref: BlockRef) -> Option<BlockHeader> {
|
||||
self.request_count.fetch_add(1, Ordering::Relaxed);
|
||||
match block_ref {
|
||||
BlockRef::Number(height) => self.by_height.get(height as usize).cloned(),
|
||||
BlockRef::Hash(hash) => self.by_hash.get(&hash).and_then(|height| self.by_height.get(*height)).cloned(),
|
||||
|
@ -418,23 +418,33 @@ mod tests {
|
|||
fn test_threshold_state_defined_to_started_to_lockedin() {
|
||||
let (mut cache, mut headers, deployment) = prepare_deployments();
|
||||
let test_cases = vec![
|
||||
(1, make_test_time(1), 0x20000000, ThresholdState::Defined),
|
||||
(1000, make_test_time(10000) - 1, 0x20000001, ThresholdState::Defined),
|
||||
(2000, make_test_time(10000), 0x20000001, ThresholdState::Started),
|
||||
(2050, make_test_time(10010), 0x20000000, ThresholdState::Started),
|
||||
(2950, make_test_time(10020), 0x20000001, ThresholdState::Started),
|
||||
(2999, make_test_time(19999), 0x20000000, ThresholdState::Started),
|
||||
(3000, make_test_time(29999), 0x20000000, ThresholdState::LockedIn),
|
||||
(3999, make_test_time(30001), 0x20000000, ThresholdState::LockedIn),
|
||||
(4000, make_test_time(30002), 0x20000000, ThresholdState::Active),
|
||||
(14333, make_test_time(30003), 0x20000000, ThresholdState::Active),
|
||||
(24000, make_test_time(40000), 0x20000000, ThresholdState::Active),
|
||||
(1, make_test_time(1), 0x20000000, ThresholdState::Defined, false),
|
||||
(1000, make_test_time(10000) - 1, 0x20000001, ThresholdState::Defined, false),
|
||||
(2000, make_test_time(10000), 0x20000001, ThresholdState::Started, false),
|
||||
(2050, make_test_time(10010), 0x20000000, ThresholdState::Started, true),
|
||||
(2950, make_test_time(10020), 0x20000001, ThresholdState::Started, true),
|
||||
(2999, make_test_time(19999), 0x20000000, ThresholdState::Started, true),
|
||||
(3000, make_test_time(29999), 0x20000000, ThresholdState::LockedIn, false),
|
||||
(3999, make_test_time(30001), 0x20000000, ThresholdState::LockedIn, true),
|
||||
(4000, make_test_time(30002), 0x20000000, ThresholdState::Active, false),
|
||||
(14333, make_test_time(30003), 0x20000000, ThresholdState::Active, false),
|
||||
(24000, make_test_time(40000), 0x20000000, ThresholdState::Active, false),
|
||||
];
|
||||
|
||||
for (height, time, version, state) in test_cases {
|
||||
for (height, time, version, state, is_single_request) in test_cases {
|
||||
headers.mine(height, time, version);
|
||||
|
||||
let req_old = headers.request_count.load(Ordering::Relaxed);
|
||||
assert_eq!(threshold_state(&mut cache, deployment, height, &headers, MINER_CONFIRMATION_WINDOW, RULE_CHANGE_ACTIVATION_THRESHOLD), state);
|
||||
let req_new = headers.request_count.load(Ordering::Relaxed);
|
||||
|
||||
// also check that same-period states are read from cache
|
||||
if is_single_request {
|
||||
assert_eq!(req_old + 1, req_new);
|
||||
} else {
|
||||
assert!(req_old < req_new);
|
||||
}
|
||||
|
||||
assert_eq!(threshold_state(&mut DeploymentStateCache::default(), deployment, height, &headers, MINER_CONFIRMATION_WINDOW, RULE_CHANGE_ACTIVATION_THRESHOLD), state);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue