diff --git a/logs/src/lib.rs b/logs/src/lib.rs index 217bb472..c30c2779 100644 --- a/logs/src/lib.rs +++ b/logs/src/lib.rs @@ -48,7 +48,7 @@ impl LogFormatter for DateAndColorLogFormatter { pub fn init(filters: &str, formatter: T) where T: LogFormatter { let mut builder = LogBuilder::new(); let filters = match env::var("RUST_LOG") { - Ok(env_filters) => format!("{},{}", env_filters, filters), + Ok(env_filters) => format!("{},{}", filters, env_filters), Err(_) => filters.into(), }; diff --git a/network/src/consensus.rs b/network/src/consensus.rs index 5ff676e2..9dd0268c 100644 --- a/network/src/consensus.rs +++ b/network/src/consensus.rs @@ -1,9 +1,6 @@ use hash::H256; use {Network, Magic, Deployment}; -/// First block of BitcoinCash fork. -const BITCOIN_CASH_FORK_BLOCK: u32 = 478559; // https://blockchair.com/bitcoin-cash/block/478559 - #[derive(Debug, Clone)] /// Parameters that influence chain consensus. pub struct ConsensusParams { @@ -38,10 +35,9 @@ pub struct ConsensusParams { pub struct BitcoinCashConsensusParams { /// Initial BCH hard fork height. pub height: u32, - /// Time when difficulty adjustment hardfork becomes active (~Nov 13 2017). + /// Time when difficulty adjustment hardfork becomes active. /// https://reviews.bitcoinabc.org/D601 - // TODO: change to height after activation - pub difficulty_adjustion_time: u32, + pub difficulty_adjustion_height: u32, } #[derive(Debug, Clone)] @@ -227,11 +223,21 @@ impl ConsensusFork { } } -impl Default for BitcoinCashConsensusParams { - fn default() -> Self { - BitcoinCashConsensusParams { - height: BITCOIN_CASH_FORK_BLOCK, - difficulty_adjustion_time: 1510600000, +impl BitcoinCashConsensusParams { + pub fn new(network: Network) -> Self { + match network { + Network::Mainnet | Network::Other(_) => BitcoinCashConsensusParams { + height: 478559, + difficulty_adjustion_height: 504031, + }, + Network::Testnet => BitcoinCashConsensusParams { + height: 1155876, + difficulty_adjustion_height: 1188697, + }, + Network::Regtest | Network::Unitest => BitcoinCashConsensusParams { + height: 0, + difficulty_adjustion_height: 0, + }, } } } @@ -239,7 +245,7 @@ impl Default for BitcoinCashConsensusParams { #[cfg(test)] mod tests { use super::super::Network; - use super::{ConsensusParams, ConsensusFork}; + use super::{ConsensusParams, ConsensusFork, BitcoinCashConsensusParams}; #[test] fn test_consensus_params_bip34_height() { @@ -279,7 +285,7 @@ mod tests { #[test] fn test_consensus_fork_min_block_size() { assert_eq!(ConsensusFork::NoFork.min_block_size(0), 0); - let fork = ConsensusFork::BitcoinCash(Default::default()); + let fork = ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(Network::Mainnet)); assert_eq!(fork.min_block_size(0), 0); assert_eq!(fork.min_block_size(fork.activation_height()), 1_000_001); } @@ -287,13 +293,13 @@ mod tests { #[test] fn test_consensus_fork_max_transaction_size() { assert_eq!(ConsensusFork::NoFork.max_transaction_size(), 1_000_000); - assert_eq!(ConsensusFork::BitcoinCash(Default::default()).max_transaction_size(), 1_000_000); + assert_eq!(ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(Network::Mainnet)).max_transaction_size(), 1_000_000); } #[test] fn test_consensus_fork_max_block_sigops() { assert_eq!(ConsensusFork::NoFork.max_block_sigops(0, 1_000_000), 20_000); - let fork = ConsensusFork::BitcoinCash(Default::default()); + let fork = ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(Network::Mainnet)); assert_eq!(fork.max_block_sigops(0, 1_000_000), 20_000); assert_eq!(fork.max_block_sigops(fork.activation_height(), 2_000_000), 40_000); assert_eq!(fork.max_block_sigops(fork.activation_height() + 100, 3_000_000), 60_000); diff --git a/p2p/src/io/handshake.rs b/p2p/src/io/handshake.rs index 21a50ab4..5fe750b2 100644 --- a/p2p/src/io/handshake.rs +++ b/p2p/src/io/handshake.rs @@ -211,7 +211,7 @@ mod tests { use tokio_io::{AsyncRead, AsyncWrite}; use bytes::Bytes; use ser::Stream; - use network::{Network, ConsensusFork}; + use network::{Network, ConsensusFork, BitcoinCashConsensusParams}; use message::{Message, Error}; use message::types::Verack; use message::types::version::{Version, V0, V106, V70001}; @@ -389,7 +389,7 @@ mod tests { #[test] fn test_fails_to_accept_other_fork_node() { let magic1 = Network::Mainnet.magic(&ConsensusFork::NoFork); - let magic2 = Network::Mainnet.magic(&ConsensusFork::BitcoinCash(Default::default())); + let magic2 = Network::Mainnet.magic(&ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(Network::Mainnet))); let version = 70012; let local_version = local_version(); let remote_version = remote_version(); diff --git a/pbtc/config.rs b/pbtc/config.rs index e15594a2..32c55bf6 100644 --- a/pbtc/config.rs +++ b/pbtc/config.rs @@ -2,7 +2,7 @@ use std::net; use clap; use db; use message::Services; -use network::{Network, ConsensusParams, ConsensusFork}; +use network::{Network, ConsensusParams, ConsensusFork, BitcoinCashConsensusParams}; use p2p::InternetProtocol; use seednodes::{mainnet_seednodes, testnet_seednodes, bitcoin_cash_seednodes, bitcoin_cash_testnet_seednodes}; use rpc_apis::ApiSet; @@ -57,7 +57,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result { (true, true) => return Err("Only one testnet option can be used".into()), }; - let consensus_fork = parse_consensus_fork(&db, &matches)?; + let consensus_fork = parse_consensus_fork(network, &db, &matches)?; let consensus = ConsensusParams::new(network, consensus_fork); let (in_connections, out_connections) = match network { @@ -167,7 +167,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result { Ok(config) } -fn parse_consensus_fork(db: &db::SharedStore, matches: &clap::ArgMatches) -> Result { +fn parse_consensus_fork(network: Network, db: &db::SharedStore, matches: &clap::ArgMatches) -> Result { let old_consensus_fork = db.consensus_fork()?; let new_consensus_fork = match (matches.is_present("segwit"), matches.is_present("bitcoin-cash")) { (false, false) => match &old_consensus_fork { @@ -188,7 +188,7 @@ fn parse_consensus_fork(db: &db::SharedStore, matches: &clap::ArgMatches) -> Res Ok(match new_consensus_fork { "segwit" => ConsensusFork::NoFork, - "bitcoin-cash" => ConsensusFork::BitcoinCash(Default::default()), + "bitcoin-cash" => ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(network)), _ => unreachable!("hardcoded above"), }) } diff --git a/sync/src/synchronization_client_core.rs b/sync/src/synchronization_client_core.rs index b6d31adb..ba7429d0 100644 --- a/sync/src/synchronization_client_core.rs +++ b/sync/src/synchronization_client_core.rs @@ -880,7 +880,8 @@ impl SynchronizationClientCore where T: TaskExecutor { for (header_index, header) in headers.iter().enumerate() { // check that this header is direct child of previous header if &header.raw.previous_header_hash != last_known_hash { - self.peers.misbehaving(peer_index, &format!("Neighbour headers in `headers` message are unlinked: Prev: {}, PrevLink: {}, Curr: {}", last_known_hash.to_reversed_str(), header.raw.previous_header_hash.to_reversed_str(), header.hash.to_reversed_str())); + self.peers.misbehaving(peer_index, &format!("Neighbour headers in `headers` message are unlinked: Prev: {}, PrevLink: {}, Curr: {}", + last_known_hash.to_reversed_str(), header.raw.previous_header_hash.to_reversed_str(), header.hash.to_reversed_str())); return BlocksHeadersVerificationResult::Skip; } @@ -893,8 +894,10 @@ impl SynchronizationClientCore where T: TaskExecutor { self.peers.misbehaving(peer_index, &format!("Provided dead-end block {:?}", header.hash.to_reversed_str())); return BlocksHeadersVerificationResult::Skip; }, - _ => { - trace!(target: "sync", "Ignoring {} headers from peer#{} - known header in the middle", headers.len(), peer_index); + block_state => { + trace!(target: "sync", "Ignoring {} headers from peer#{} - known ({:?}) header {} at the {}/{} ({}...{})", + headers.len(), peer_index, block_state, header.hash.to_reversed_str(), header_index, headers.len(), + headers[0].hash.to_reversed_str(), headers[headers.len() - 1].hash.to_reversed_str()); self.peers_tasks.useful_peer(peer_index); return BlocksHeadersVerificationResult::Skip; }, diff --git a/verification/src/accept_transaction.rs b/verification/src/accept_transaction.rs index c2fc48bc..49fbd2ea 100644 --- a/verification/src/accept_transaction.rs +++ b/verification/src/accept_transaction.rs @@ -470,7 +470,7 @@ impl<'a> TransactionPrematureWitness<'a> { #[cfg(test)] mod tests { use chain::{IndexedTransaction, Transaction, TransactionOutput}; - use network::{Network, ConsensusParams, ConsensusFork}; + use network::{Network, ConsensusParams, ConsensusFork, BitcoinCashConsensusParams}; use script::Builder; use canon::CanonTransaction; use error::TransactionError; @@ -492,7 +492,7 @@ mod tests { assert_eq!(transaction.raw.outputs[0].script_pubkey.len(), 46 + 2); - let consensus = ConsensusParams::new(Network::Mainnet, ConsensusFork::BitcoinCash(Default::default())); + let consensus = ConsensusParams::new(Network::Mainnet, ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(Network::Mainnet))); let checker = TransactionReturnReplayProtection::new(CanonTransaction::new(&transaction), &consensus, consensus.fork.activation_height()); assert_eq!(checker.check(), Err(TransactionError::ReturnReplayProtection)); let checker = TransactionReturnReplayProtection::new(CanonTransaction::new(&transaction), &consensus, consensus.fork.activation_height() - 1); diff --git a/verification/src/work_bch.rs b/verification/src/work_bch.rs index d3e43849..7bbb557e 100644 --- a/verification/src/work_bch.rs +++ b/verification/src/work_bch.rs @@ -14,8 +14,8 @@ use constants::{ /// Returns work required for given header for the post-HF Bitcoin Cash block pub fn work_required_bitcoin_cash(parent_header: IndexedBlockHeader, time: u32, height: u32, store: &BlockHeaderProvider, consensus: &ConsensusParams, fork: &BitcoinCashConsensusParams, max_bits: Compact) -> Compact { // special processing of Bitcoin Cash difficulty adjustment hardfork (Nov 2017), where difficulty is adjusted after each block - let parent_timestamp = median_timestamp_inclusive(parent_header.hash.clone(), store); - if parent_timestamp >= fork.difficulty_adjustion_time { + // `height` is the height of the new block => comparison is shifted by one + if height.saturating_sub(1) >= fork.difficulty_adjustion_height { return work_required_bitcoin_cash_adjusted(parent_header, time, height, store, consensus); } @@ -40,6 +40,7 @@ pub fn work_required_bitcoin_cash(parent_header: IndexedBlockHeader, time: u32, .expect("parent_header.bits != max_bits; difficulty is max_bits for first RETARGETING_INTERVAL height; RETARGETING_INTERVAL > 7; qed"); let ancient_timestamp = median_timestamp_inclusive(ancient_header.hash(), store); + let parent_timestamp = median_timestamp_inclusive(parent_header.hash.clone(), 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 @@ -215,7 +216,7 @@ mod tests { let main_consensus = ConsensusParams::new(Network::Mainnet, ConsensusFork::NoFork); let uahf_consensus = ConsensusParams::new(Network::Mainnet, ConsensusFork::BitcoinCash(BitcoinCashConsensusParams { height: 1000, - difficulty_adjustion_time: 0xffffffff, + difficulty_adjustion_height: 0xffffffff, })); let mut header_provider = MemoryBlockHeaderProvider::default(); header_provider.insert(BlockHeader { @@ -267,7 +268,7 @@ mod tests { fn bitcoin_cash_adjusted_difficulty() { let uahf_consensus = ConsensusParams::new(Network::Mainnet, ConsensusFork::BitcoinCash(BitcoinCashConsensusParams { height: 1000, - difficulty_adjustion_time: 0xffffffff, + difficulty_adjustion_height: 0xffffffff, }));