From 7dce803e6bb6cc308897926e0947f3b81813ea76 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Mon, 15 May 2023 23:25:44 +0200 Subject: [PATCH 1/5] migration to bitcoin 0.30 Signed-off-by: Vincenzo Palazzo --- Cargo.lock | 66 +++++++++++++++++++++++++++++++---- chain/src/block.rs | 2 +- chain/src/block/cache.rs | 31 ++++++++-------- chain/src/filter.rs | 2 +- common/Cargo.toml | 3 +- common/src/block.rs | 10 ++---- common/src/block/filter.rs | 4 +-- common/src/block/store.rs | 20 +++++++---- common/src/block/tree.rs | 30 +++++++++------- common/src/collections.rs | 2 +- common/src/lib.rs | 3 +- common/src/network.rs | 15 ++++---- p2p/src/fsm.rs | 21 +++++------ p2p/src/fsm/cbfmgr.rs | 6 ++-- p2p/src/fsm/cbfmgr/rescan.rs | 8 ++--- p2p/src/fsm/fees.rs | 2 +- p2p/src/fsm/output.rs | 3 +- test/src/block.rs | 53 +++++++++++++--------------- test/src/block/cache/model.rs | 9 +++-- 19 files changed, 175 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6dd32815..d252ba44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,16 +102,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" dependencies = [ "bech32", - "bitcoin_hashes", - "secp256k1", + "bitcoin_hashes 0.11.0", + "secp256k1 0.24.1", ] +[[package]] +name = "bitcoin" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b36f4c848f6bd9ff208128f08751135846cc23ae57d66ab10a22efff1c675f3c" +dependencies = [ + "bech32", + "bitcoin-private", + "bitcoin_hashes 0.12.0", + "hex_lit", + "secp256k1 0.27.0", +] + +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + [[package]] name = "bitcoin_hashes" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -156,7 +184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a4b7b647ac3591f204635a704dcbf23b74f0b2be60dd23c9b2aa63caac4eb19" dependencies = [ "aes-ctr", - "bitcoin", + "bitcoin 0.29.2", "hidapi", ] @@ -254,6 +282,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + [[package]] name = "hidapi" version = "1.4.2" @@ -374,8 +408,7 @@ dependencies = [ name = "nakamoto-common" version = "0.4.0" dependencies = [ - "bitcoin", - "bitcoin_hashes", + "bitcoin 0.30.0", "fastrand", "log", "microserde", @@ -661,9 +694,19 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff55dc09d460954e9ef2fa8a7ced735a964be9981fd50e870b2b3b0705e14964" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.11.0", "rand", - "secp256k1-sys", + "secp256k1-sys 0.6.1", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "bitcoin_hashes 0.12.0", + "secp256k1-sys 0.8.1", ] [[package]] @@ -675,6 +718,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "signal-hook" version = "0.3.14" diff --git a/chain/src/block.rs b/chain/src/block.rs index 279ebc14..0f4de162 100644 --- a/chain/src/block.rs +++ b/chain/src/block.rs @@ -2,7 +2,7 @@ pub mod cache; pub mod store; -pub use nakamoto_common::bitcoin::blockdata::block::{Block, BlockHeader}; +pub use nakamoto_common::bitcoin::blockdata::block::{Block, Header as BlockHeader}; pub use nakamoto_common::bitcoin::blockdata::transaction::Transaction; pub use nakamoto_common::bitcoin::hash_types::BlockHash; pub use nakamoto_common::block::tree::*; diff --git a/chain/src/block/cache.rs b/chain/src/block/cache.rs index 8312782a..61a2621c 100644 --- a/chain/src/block/cache.rs +++ b/chain/src/block/cache.rs @@ -11,15 +11,14 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::ops::ControlFlow; +use common::block::Target; use nakamoto_common as common; use nakamoto_common::bitcoin; -use nakamoto_common::bitcoin::blockdata::block::BlockHeader; +use nakamoto_common::bitcoin::blockdata::block::Header as BlockHeader; use nakamoto_common::bitcoin::consensus::params::Params; use nakamoto_common::bitcoin::hash_types::BlockHash; use nakamoto_common::bitcoin::network::constants::Network; -use nakamoto_common::bitcoin::util::BitArray; -use nakamoto_common::bitcoin::util::uint::Uint256; use nakamoto_common::block::tree::{self, BlockReader, BlockTree, Branch, Error, ImportResult}; use nakamoto_common::block::{ self, @@ -76,7 +75,7 @@ pub struct BlockCache { checkpoints: BTreeMap, params: Params, /// Total cumulative work on the active chain. - chainwork: Uint256, + chainwork: Work, store: S, } @@ -240,17 +239,17 @@ impl> BlockCache { // // We do this because it's cheap to verify and prevents flooding attacks. let target = header.target(); - match header.validate_pow(&target) { + match header.validate_pow(target) { Ok(_) => { - let limit = self.params.pow_limit; + let limit = self.params.pow_limit.to_target(); if target > limit { return Err(Error::InvalidBlockTarget(target, limit)); } } - Err(bitcoin::util::Error::BlockBadProofOfWork) => { + Err(bitcoin::error::Error::BlockBadProofOfWork) => { return Err(Error::InvalidBlockPoW); } - Err(bitcoin::util::Error::BlockBadTarget) => unreachable! { + Err(bitcoin::error::Error::BlockBadTarget) => unreachable! { // The only way to get a 'bad target' error is to pass a different target // than the one specified in the header. }, @@ -288,7 +287,9 @@ impl> BlockCache { let mut best_branch = None; let mut best_hash = tip.hash(); - let mut best_work = Uint256::zero(); + // FIXME: this need to be a Work by network? or the min is equal for + // every network? + let mut best_work = Work::MAINNET_MIN; for branch in candidates.iter() { // Total work included in this branch. @@ -455,11 +456,11 @@ impl> BlockCache { let target = BlockHeader::u256_from_compact_target(compact_target); - match header.validate_pow(&target) { - Err(bitcoin::util::Error::BlockBadProofOfWork) => { + match header.validate_pow(target) { + Err(bitcoin::error::Error::BlockBadProofOfWork) => { return Err(Error::InvalidBlockPoW); } - Err(bitcoin::util::Error::BlockBadTarget) => { + Err(bitcoin::error::Error::BlockBadTarget) => { return Err(Error::InvalidBlockTarget(header.target(), target)); } Err(_) => unreachable!(), @@ -497,10 +498,10 @@ impl> BlockCache { let pow_limit_bits = block::pow_limit_bits(¶ms.network); for (height, header) in self.iter().rev() { - if header.bits != pow_limit_bits + if header.bits.to_consensus() != pow_limit_bits || height % self.params.difficulty_adjustment_interval() == 0 { - return header.bits; + return header.bits.to_consensus(); } } pow_limit_bits @@ -682,7 +683,7 @@ impl> BlockReader for BlockCache { } /// Get the "chainwork", ie. the total accumulated proof-of-work of the active chain. - fn chain_work(&self) -> Uint256 { + fn chain_work(&self) -> Work { self.chainwork } diff --git a/chain/src/filter.rs b/chain/src/filter.rs index 7d85adab..75d9b97d 100644 --- a/chain/src/filter.rs +++ b/chain/src/filter.rs @@ -2,4 +2,4 @@ pub mod cache; pub mod store; -pub use nakamoto_common::bitcoin::util::bip158::BlockFilter; +pub use nakamoto_common::bitcoin::bip158::BlockFilter; diff --git a/common/Cargo.toml b/common/Cargo.toml index 2a9fe19e..ed3d9241 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -11,8 +11,7 @@ edition = "2021" [dependencies] nakamoto-net = { version = "0.4.0", path = "../net" } -bitcoin = "0.29.2" -bitcoin_hashes = "0.11.0" +bitcoin = { version = "0.30.0" } thiserror = "1.0" fastrand = "1.3.5" nonempty = "0.7" diff --git a/common/src/block.rs b/common/src/block.rs index 8fcf5100..72393a63 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -7,15 +7,10 @@ pub mod store; pub mod time; pub mod tree; -pub use bitcoin::blockdata::block::{Block, BlockHeader}; +pub use bitcoin::blockdata::block::{Block, Header as BlockHeader}; pub use bitcoin::blockdata::transaction::Transaction; pub use bitcoin::hash_types::BlockHash; - -/// Difficulty target of a block. -pub type Target = bitcoin::util::uint::Uint256; - -/// Block work. -pub type Work = bitcoin::util::uint::Uint256; +pub use bitcoin::pow::{Target, Work}; /// Compact difficulty bits (target) of a block. pub type Bits = u32; @@ -62,5 +57,6 @@ pub fn pow_limit_bits(network: &bitcoin::Network) -> Bits { bitcoin::Network::Testnet => 0x1d00ffff, bitcoin::Network::Regtest => 0x207fffff, bitcoin::Network::Signet => 0x1e0377ae, + _ => unreachable!(), } } diff --git a/common/src/block/filter.rs b/common/src/block/filter.rs index 2451ee29..e6b0f768 100644 --- a/common/src/block/filter.rs +++ b/common/src/block/filter.rs @@ -3,13 +3,13 @@ use std::ops::RangeInclusive; -use bitcoin_hashes::Hash; use thiserror::Error; +pub use bitcoin::bip158::BlockFilter; pub use bitcoin::hash_types::{FilterHash, FilterHeader}; -pub use bitcoin::util::bip158::BlockFilter; use super::Height; +use crate::bitcoin_hashes::Hash; use crate::block::store::{self, Genesis}; use crate::network::Network; diff --git a/common/src/block/store.rs b/common/src/block/store.rs index ea755699..7b71e58d 100644 --- a/common/src/block/store.rs +++ b/common/src/block/store.rs @@ -1,11 +1,14 @@ //! Block header storage. #![allow(clippy::len_without_is_empty)] +use std::borrow::Borrow; + use crate::block::Height; -use bitcoin::blockdata::block::BlockHeader; +use bitcoin::bip158::BlockFilter; +use bitcoin::block::Header; use bitcoin::consensus::encode; use bitcoin::hash_types::FilterHash; -use bitcoin::util::bip158::BlockFilter; +use bitcoin::{OutPoint, Script, ScriptBuf}; use thiserror::Error; use crate::network::Network; @@ -35,7 +38,7 @@ pub trait Genesis { } /// Genesis implementation for `bitcoin`'s header. -impl Genesis for BlockHeader { +impl Genesis for Header { fn genesis(network: Network) -> Self { network.genesis() } @@ -47,9 +50,12 @@ impl Genesis for FilterHash { use bitcoin::hashes::Hash; let genesis = network.genesis_block(); - let filter = BlockFilter::new_script_filter(&genesis, |_| { - panic!("{}: genesis block should have no inputs", source!()) - }) + let filter = BlockFilter::new_script_filter( + &genesis, + |_| -> Result { + panic!("{}: genesis block should have no inputs", source!()) + }, + ) .unwrap(); FilterHash::hash(&filter.content) @@ -61,7 +67,7 @@ impl Genesis for BlockFilter { fn genesis(network: Network) -> Self { let genesis = network.genesis_block(); - BlockFilter::new_script_filter(&genesis, |_| { + BlockFilter::new_script_filter(&genesis, |_| -> Result { panic!("{}: genesis block should have no inputs", source!()) }) .unwrap() diff --git a/common/src/block/tree.rs b/common/src/block/tree.rs index 41058914..80d2219e 100644 --- a/common/src/block/tree.rs +++ b/common/src/block/tree.rs @@ -2,10 +2,10 @@ #![warn(missing_docs)] use std::collections::BTreeMap; -use bitcoin::blockdata::block::BlockHeader; +use bitcoin::block::Header as BlockHeader; use bitcoin::consensus::params::Params; use bitcoin::hash_types::BlockHash; -use bitcoin::util::uint::Uint256; +use bitcoin::CompactTarget; use thiserror::Error; @@ -102,7 +102,8 @@ pub struct Branch<'a, H: Header>(pub &'a [H]); impl<'a, H: Header> Branch<'a, H> { /// Compute the total proof-of-work carried by this branch. pub fn work(&self) -> Work { - let mut work = Work::default(); + // FIXME: this should be by network + let mut work = Work::MAINNET_MIN; for header in self.0.iter() { work = work + header.work(); } @@ -145,7 +146,7 @@ pub trait BlockReader { Box::new(self.iter().map(|(_, h)| h)) } /// Get the "chainwork", ie. the total accumulated proof-of-work of the active chain. - fn chain_work(&self) -> Uint256; + fn chain_work(&self) -> Work; /// Iterate over the longest chain, starting from genesis, including heights. fn iter<'a>(&'a self) -> Box + 'a>; /// Iterate over a range of blocks. @@ -206,7 +207,7 @@ pub trait BlockReader { // Only adjust on set intervals. Otherwise return current target. // Since the height is 0-indexed, we add `1` to check it against the interval. if (last_height + 1) % params.difficulty_adjustment_interval() != 0 { - return BlockHeader::compact_target_from_u256(&last_target); + return last_target.to_compact_lossy().to_consensus(); } let last_adjustment_height = @@ -217,7 +218,7 @@ pub trait BlockReader { let last_adjustment_time = last_adjustment_block.time; if params.no_pow_retargeting { - return last_adjustment_block.bits; + return last_adjustment_block.bits.to_consensus(); } let actual_timespan = last_time - last_adjustment_time; @@ -229,16 +230,21 @@ pub trait BlockReader { adjusted_timespan = params.pow_target_timespan as BlockTime * 4; } - let mut target = last_target; + // FIXME: from now till the end it is a mess! + let mut target = last_target.to_compact_lossy().to_consensus(); - target = target.mul_u32(adjusted_timespan); - target = target / Target::from_u64(params.pow_target_timespan).unwrap(); + target = target * adjusted_timespan; + target = target / (params.pow_target_timespan as u32); // Ensure a difficulty floor. - if target > params.pow_limit { - target = params.pow_limit; + if Target::from(CompactTarget::from_consensus(target)).to_work() > params.pow_limit { + target = params + .pow_limit + .to_target() + .to_compact_lossy() + .to_consensus(); } - BlockHeader::compact_target_from_u256(&target) + target } } diff --git a/common/src/collections.rs b/common/src/collections.rs index 766262bb..6e1c12e7 100644 --- a/common/src/collections.rs +++ b/common/src/collections.rs @@ -1,5 +1,5 @@ //! Collections used in `nakamoto`. -use bitcoin_hashes::siphash24::Hash; +use bitcoin::hashes::siphash24::Hash; use std::ops::{Deref, DerefMut}; use crate::nonempty::NonEmpty; diff --git a/common/src/lib.rs b/common/src/lib.rs index fff261ca..36af265e 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -7,7 +7,8 @@ pub mod network; pub mod p2p; pub use bitcoin; -pub use bitcoin_hashes; +// re-aliasing to bitcoin_hashes for retro-compatibility +pub use bitcoin::hashes as bitcoin_hashes; pub use nakamoto_net as net; pub use nonempty; diff --git a/common/src/network.rs b/common/src/network.rs index b77dd9cd..196b2e6e 100644 --- a/common/src/network.rs +++ b/common/src/network.rs @@ -1,13 +1,13 @@ //! Bitcoin peer network. Eg. *Mainnet*. use std::str::FromStr; -use bitcoin::blockdata::block::{Block, BlockHeader}; +use bitcoin::blockdata::block::{Block, Header}; use bitcoin::consensus::params::Params; use bitcoin::hash_types::BlockHash; use bitcoin::hashes::hex::FromHex; use bitcoin::network::constants::ServiceFlags; -use bitcoin_hashes::sha256d; +use bitcoin::hashes::sha256d; use crate::block::Height; @@ -86,6 +86,7 @@ impl From for Network { bitcoin::Network::Testnet => Self::Testnet, bitcoin::Network::Signet => Self::Signet, bitcoin::Network::Regtest => Self::Regtest, + _ => unreachable!(), } } } @@ -114,7 +115,7 @@ impl Network { .iter() .cloned() .map(|(height, hash)| { - let hash = BlockHash::from_hex(hash).unwrap(); + let hash = BlockHash::from_str(hash).unwrap(); (height, hash) }); @@ -169,7 +170,7 @@ impl Network { /// /// assert_eq!(network.genesis_hash(), genesis.block_hash()); /// ``` - pub fn genesis(&self) -> BlockHeader { + pub fn genesis(&self) -> Header { self.genesis_block().header } @@ -183,7 +184,7 @@ impl Network { /// Get the hash of the genesis block of this network. pub fn genesis_hash(&self) -> BlockHash { use crate::block::genesis; - use bitcoin_hashes::Hash; + use bitcoin::hashes::Hash; let hash = match self { Self::Mainnet => genesis::MAINNET, @@ -191,7 +192,7 @@ impl Network { Self::Regtest => genesis::REGTEST, Self::Signet => genesis::SIGNET, }; - BlockHash::from_hash( + BlockHash::from_raw_hash( sha256d::Hash::from_slice(hash) .expect("the genesis hash has the right number of bytes"), ) @@ -204,6 +205,6 @@ impl Network { /// Get the network magic number for this network. pub fn magic(&self) -> u32 { - bitcoin::Network::from(*self).magic() + u32::from_le_bytes(bitcoin::Network::from(*self).magic().to_bytes()) } } diff --git a/p2p/src/fsm.rs b/p2p/src/fsm.rs index eb8af178..2a572003 100644 --- a/p2p/src/fsm.rs +++ b/p2p/src/fsm.rs @@ -45,7 +45,6 @@ use std::net; use std::ops::{Bound, RangeInclusive}; use std::sync::Arc; -use nakamoto_common::bitcoin::blockdata::block::BlockHeader; use nakamoto_common::bitcoin::consensus::encode; use nakamoto_common::bitcoin::consensus::params::Params; use nakamoto_common::bitcoin::network::constants::ServiceFlags; @@ -53,14 +52,13 @@ use nakamoto_common::bitcoin::network::message::{NetworkMessage, RawNetworkMessa use nakamoto_common::bitcoin::network::message_blockdata::{GetHeadersMessage, Inventory}; use nakamoto_common::bitcoin::network::message_filter::GetCFilters; use nakamoto_common::bitcoin::network::message_network::VersionMessage; -use nakamoto_common::bitcoin::network::Address; -use nakamoto_common::bitcoin::util::uint::Uint256; -use nakamoto_common::bitcoin::{Script, Txid}; +use nakamoto_common::bitcoin::network::{Address, Magic}; +use nakamoto_common::bitcoin::{ScriptBuf, Txid}; use nakamoto_common::block::filter::Filters; use nakamoto_common::block::time::AdjustedClock; use nakamoto_common::block::time::{LocalDuration, LocalTime}; use nakamoto_common::block::tree::{self, BlockReader, BlockTree, ImportResult}; -use nakamoto_common::block::{BlockHash, Height}; +use nakamoto_common::block::{BlockHash, BlockHeader, Height, Work}; use nakamoto_common::block::{BlockTime, Transaction}; use nakamoto_common::network; use nakamoto_common::nonempty::NonEmpty; @@ -233,7 +231,7 @@ pub enum Command { /// Get connected peers. GetPeers(ServiceFlags, chan::Sender>), /// Get the tip of the active chain. - GetTip(chan::Sender<(Height, BlockHeader, Uint256)>), + GetTip(chan::Sender<(Height, BlockHeader, Work)>), /// Get a block from the active chain. RequestBlock(BlockHash), /// Get block filters. @@ -248,12 +246,12 @@ pub enum Command { /// Stop scanning at this height. If unbounded, don't stop scanning. to: Bound, /// Scripts to match on. - watch: Vec