uahf: REQ-7 difficulty adjustment
This commit is contained in:
parent
a769868139
commit
bcdc1e6813
|
@ -3,7 +3,7 @@ use primitives::hash::H256;
|
|||
use primitives::compact::Compact;
|
||||
use chain::{OutPoint, TransactionOutput, IndexedTransaction};
|
||||
use db::{SharedStore, TransactionOutputProvider};
|
||||
use network::Magic;
|
||||
use network::ConsensusParams;
|
||||
use memory_pool::{MemoryPool, OrderingStrategy, Entry};
|
||||
use verification::{work_required, block_reward_satoshi, transaction_sigops};
|
||||
|
||||
|
@ -233,13 +233,13 @@ impl<'a, T> Iterator for FittingTransactionsIterator<'a, T> where T: Iterator<It
|
|||
}
|
||||
|
||||
impl BlockAssembler {
|
||||
pub fn create_new_block(&self, store: &SharedStore, mempool: &MemoryPool, time: u32, network: Magic) -> BlockTemplate {
|
||||
pub fn create_new_block(&self, store: &SharedStore, mempool: &MemoryPool, time: u32, consensus: &ConsensusParams) -> BlockTemplate {
|
||||
// get best block
|
||||
// take it's hash && height
|
||||
let best_block = store.best_block();
|
||||
let previous_header_hash = best_block.hash;
|
||||
let height = best_block.number + 1;
|
||||
let bits = work_required(previous_header_hash.clone(), time, height, store.as_block_header_provider(), network);
|
||||
let bits = work_required(previous_header_hash.clone(), time, height, store.as_block_header_provider(), consensus);
|
||||
let version = BLOCK_VERSION;
|
||||
|
||||
let mut coinbase_value = block_reward_satoshi(height);
|
||||
|
|
|
@ -282,7 +282,7 @@ impl<T, U, V> LocalNode<T, U, V> where T: TaskExecutor, U: Server, V: Client {
|
|||
max_block_sigops: self.consensus.fork.max_block_sigops(height, max_block_size) as u32,
|
||||
};
|
||||
let memory_pool = &*self.memory_pool.read();
|
||||
block_assembler.create_new_block(&self.storage, memory_pool, time::get_time().sec as u32, self.consensus.magic)
|
||||
block_assembler.create_new_block(&self.storage, memory_pool, time::get_time().sec as u32, &self.consensus)
|
||||
}
|
||||
|
||||
/// Install synchronization events listener
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use network::{Magic, ConsensusParams};
|
||||
use network::ConsensusParams;
|
||||
use db::BlockHeaderProvider;
|
||||
use canon::CanonHeader;
|
||||
use error::Error;
|
||||
|
@ -21,7 +21,7 @@ impl<'a> HeaderAcceptor<'a> {
|
|||
deployments: &'a Deployments,
|
||||
) -> Self {
|
||||
HeaderAcceptor {
|
||||
work: HeaderWork::new(header, store, height, consensus.magic),
|
||||
work: HeaderWork::new(header, store, height, consensus),
|
||||
median_timestamp: HeaderMedianTimestamp::new(header, store, height, deployments, consensus),
|
||||
version: HeaderVersion::new(header, height, consensus),
|
||||
}
|
||||
|
@ -67,23 +67,23 @@ pub struct HeaderWork<'a> {
|
|||
header: CanonHeader<'a>,
|
||||
store: &'a BlockHeaderProvider,
|
||||
height: u32,
|
||||
network: Magic,
|
||||
consensus: &'a ConsensusParams,
|
||||
}
|
||||
|
||||
impl<'a> HeaderWork<'a> {
|
||||
fn new(header: CanonHeader<'a>, store: &'a BlockHeaderProvider, height: u32, network: Magic) -> Self {
|
||||
fn new(header: CanonHeader<'a>, store: &'a BlockHeaderProvider, height: u32, consensus: &'a ConsensusParams) -> Self {
|
||||
HeaderWork {
|
||||
header: header,
|
||||
store: store,
|
||||
height: height,
|
||||
network: network,
|
||||
consensus: consensus,
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<(), Error> {
|
||||
let previous_header_hash = self.header.raw.previous_header_hash.clone();
|
||||
let time = self.header.raw.time;
|
||||
let work = work_required(previous_header_hash, time, self.height, self.store, self.network);
|
||||
let work = work_required(previous_header_hash, time, self.height, self.store, self.consensus);
|
||||
if work == self.header.raw.bits {
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
|
@ -2,8 +2,9 @@ use std::cmp;
|
|||
use primitives::compact::Compact;
|
||||
use primitives::hash::H256;
|
||||
use primitives::bigint::U256;
|
||||
use network::Magic;
|
||||
use network::{Magic, ConsensusParams, ConsensusFork};
|
||||
use db::{BlockHeaderProvider, BlockRef};
|
||||
use timestamp::median_timestamp;
|
||||
|
||||
use constants::{
|
||||
DOUBLE_SPACING_SECONDS,
|
||||
|
@ -55,9 +56,10 @@ pub fn retarget_timespan(retarget_timestamp: u32, last_timestamp: u32) -> u32 {
|
|||
}
|
||||
|
||||
/// Returns work required for given header
|
||||
pub fn work_required(parent_hash: H256, time: u32, height: u32, store: &BlockHeaderProvider, network: Magic) -> Compact {
|
||||
pub fn work_required(parent_hash: H256, time: u32, height: u32, store: &BlockHeaderProvider, consensus: &ConsensusParams) -> Compact {
|
||||
let max_bits = consensus.magic.max_bits();
|
||||
if height == 0 {
|
||||
return network.max_bits();
|
||||
return max_bits;
|
||||
}
|
||||
|
||||
let parent_header = store.block_header(parent_hash.clone().into()).expect("self.height != 0; qed");
|
||||
|
@ -73,14 +75,43 @@ pub fn work_required(parent_hash: H256, time: u32, height: u32, store: &BlockHea
|
|||
// bits of last block
|
||||
let last_bits = parent_header.bits;
|
||||
|
||||
return work_required_retarget(network.max_bits(), retarget_timestamp, last_timestamp, last_bits);
|
||||
return work_required_retarget(max_bits, retarget_timestamp, last_timestamp, last_bits);
|
||||
}
|
||||
|
||||
if network == Magic::Testnet {
|
||||
return work_required_testnet(parent_hash, time, height, store, network)
|
||||
if consensus.magic == Magic::Testnet {
|
||||
return work_required_testnet(parent_hash, time, height, store, Magic::Testnet)
|
||||
}
|
||||
|
||||
parent_header.bits
|
||||
match consensus.fork {
|
||||
_ if parent_header.bits == max_bits => parent_header.bits,
|
||||
ConsensusFork::BitcoinCash(fork_height) if height >= fork_height => {
|
||||
// REQ-7 Difficulty adjustement in case of hashrate drop
|
||||
// In case the MTP of the tip of the chain is 12h or more after the MTP 6 block before the tip,
|
||||
// the proof of work target is increased by a quarter, or 25%, which corresponds to a difficulty
|
||||
// reduction of 20%.
|
||||
let ancient_block_ref = (height - 6 - 1).into();
|
||||
let ancient_header = store.block_header(ancient_block_ref)
|
||||
.expect("parent_header.bits != max_bits; difficulty is max_bits for first RETARGETING_INTERVAL height; RETARGETING_INTERVAL > 7; qed");
|
||||
|
||||
let ancient_timestamp = median_timestamp(&ancient_header, store);
|
||||
let parent_timestamp = median_timestamp(&parent_header, store);
|
||||
let timestamp_diff = parent_timestamp.checked_sub(ancient_timestamp).unwrap_or_default();
|
||||
if timestamp_diff < 43_200 {
|
||||
// less than 12h => no difficulty change needed
|
||||
return parent_header.bits;
|
||||
}
|
||||
|
||||
let mut new_bits: U256 = parent_header.bits.into();
|
||||
let max_bits: U256 = max_bits.into();
|
||||
new_bits = new_bits + (new_bits >> 2);
|
||||
if new_bits > max_bits {
|
||||
new_bits = max_bits
|
||||
}
|
||||
|
||||
new_bits.into()
|
||||
},
|
||||
_ => parent_header.bits,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn work_required_testnet(parent_hash: H256, time: u32, height: u32, store: &BlockHeaderProvider, network: Magic) -> Compact {
|
||||
|
|
Loading…
Reference in New Issue