Merge rust-bitcoin/rust-bitcoin#2945: Support Testnet4 Network

2424b654d5 feat: rust-bitcoin supports testnet4 (BinChengZhao)
afa91a2030 Introduce TestnetVersion enum with only TestnetV3 (BinChengZhao)

Pull request description:

  Fixed: https://github.com/rust-bitcoin/rust-bitcoin/issues/2749

  1. Adjust `Network` to support `Testnet4`. (Based on https://github.com/rust-bitcoin/rust-bitcoin/issues/2749#issuecomment-2152366608 as an implementation idea.)

  2. Handle conflicting procedure macros and declaration macros, since the original macros can't handle the new `Network::Testnet(TestnetVersion)` structure properly, and make internal implementations compatible with previous versions (e.g., `testnet` for `Testnet3`, `testnet4` for `Testnet4`, to minimize user-side effects).

  3. add `Testnet4` related Params, Block.

  4. optimize compatibility test cases.

  5. Regarding `fn: genesis_block`, calling `bitcoin_genesis_tx` with any Network type internally gets a reasonable `merkle_root`, but not `Testnet4`. (By comparison, I confirmed that the built-in transaction data provided is correct, and combined with the fixed `merkle_root` of `Testnet4` the correct block hash can be computed, which is not possible if the transaction data is incorrect.) **I'd appreciate it if some developer could guide me on what the problem is, and I'll work on it.**

  Of course, all these changes are based on https://github.com/rust-bitcoin/rust-bitcoin/issues/2749 , and the consensus of the discussion, if you have any comments, please leave a message, I will actively improve, and promote the support of `Testnet4`.

ACKs for top commit:
  tcharding:
    ACK 2424b654d5
  apoelstra:
    ACK 2424b654d5 successfully ran local tests

Tree-SHA512: a501f0a320460afdad2eb12ef6ff315b6357b7779dfe7c7028ea090da567019c947599006a06b3834265db1481129752f015629ef72fea6f862d01323ce9d024
This commit is contained in:
merge-script 2024-10-07 17:15:04 +00:00
commit 31f1a12aaf
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
9 changed files with 277 additions and 109 deletions

View File

@ -194,7 +194,7 @@ impl fmt::Display for AddressInner {
pub enum KnownHrp { pub enum KnownHrp {
/// The main Bitcoin network. /// The main Bitcoin network.
Mainnet, Mainnet,
/// The test networks, testnet and signet. /// The test networks, testnet (testnet3), testnet4, and signet.
Testnets, Testnets,
/// The regtest network. /// The regtest network.
Regtest, Regtest,
@ -207,7 +207,7 @@ impl KnownHrp {
match network { match network {
Bitcoin => Self::Mainnet, Bitcoin => Self::Mainnet,
Testnet | Signet => Self::Testnets, Testnet(_) | Signet => Self::Testnets,
Regtest => Self::Regtest, Regtest => Self::Regtest,
} }
} }
@ -708,11 +708,11 @@ impl Address<NetworkUnchecked> {
/// network a simple comparison is not enough anymore. Instead this function can be used. /// network a simple comparison is not enough anymore. Instead this function can be used.
/// ///
/// ```rust /// ```rust
/// use bitcoin::{Address, Network}; /// use bitcoin::{Address, Network, TestnetVersion};
/// use bitcoin::address::NetworkUnchecked; /// use bitcoin::address::NetworkUnchecked;
/// ///
/// let address: Address<NetworkUnchecked> = "2N83imGV3gPwBzKJQvWJ7cRUY2SpUyU6A5e".parse().unwrap(); /// let address: Address<NetworkUnchecked> = "2N83imGV3gPwBzKJQvWJ7cRUY2SpUyU6A5e".parse().unwrap();
/// assert!(address.is_valid_for_network(Network::Testnet)); /// assert!(address.is_valid_for_network(Network::Testnet(TestnetVersion::V3)));
/// assert!(address.is_valid_for_network(Network::Regtest)); /// assert!(address.is_valid_for_network(Network::Regtest));
/// assert!(address.is_valid_for_network(Network::Signet)); /// assert!(address.is_valid_for_network(Network::Signet));
/// ///
@ -720,7 +720,7 @@ impl Address<NetworkUnchecked> {
/// ///
/// let address: Address<NetworkUnchecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap(); /// let address: Address<NetworkUnchecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap();
/// assert!(address.is_valid_for_network(Network::Bitcoin)); /// assert!(address.is_valid_for_network(Network::Bitcoin));
/// assert_eq!(address.is_valid_for_network(Network::Testnet), false); /// assert_eq!(address.is_valid_for_network(Network::Testnet(TestnetVersion::V4)), false);
/// ``` /// ```
pub fn is_valid_for_network(&self, n: Network) -> bool { pub fn is_valid_for_network(&self, n: Network) -> bool {
use AddressInner::*; use AddressInner::*;
@ -888,8 +888,8 @@ mod tests {
use hex_lit::hex; use hex_lit::hex;
use super::*; use super::*;
use crate::network::params;
use crate::network::Network::{Bitcoin, Testnet}; use crate::network::Network::{Bitcoin, Testnet};
use crate::network::{params, TestnetVersion};
use crate::script::ScriptBufExt as _; use crate::script::ScriptBufExt as _;
fn roundtrips(addr: &Address, network: Network) { fn roundtrips(addr: &Address, network: Network) {
@ -942,7 +942,7 @@ mod tests {
let addr = Address::p2pkh(key, NetworkKind::Test); let addr = Address::p2pkh(key, NetworkKind::Test);
assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC"); assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC");
assert_eq!(addr.address_type(), Some(AddressType::P2pkh)); assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
roundtrips(&addr, Testnet); roundtrips(&addr, Testnet(TestnetVersion::V3));
} }
#[test] #[test]
@ -965,7 +965,7 @@ mod tests {
let addr = Address::p2sh(&script, NetworkKind::Test).unwrap(); let addr = Address::p2sh(&script, NetworkKind::Test).unwrap();
assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr"); assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr");
assert_eq!(addr.address_type(), Some(AddressType::P2sh)); assert_eq!(addr.address_type(), Some(AddressType::P2sh));
roundtrips(&addr, Testnet); roundtrips(&addr, Testnet(TestnetVersion::V3));
} }
#[test] #[test]
@ -1282,7 +1282,7 @@ mod tests {
let address = address_string let address = address_string
.parse::<Address<_>>() .parse::<Address<_>>()
.expect("address") .expect("address")
.require_network(Network::Testnet) .require_network(Network::Testnet(TestnetVersion::V3))
.expect("testnet"); .expect("testnet");
let pubkey_string = "04e96e22004e3db93530de27ccddfdf1463975d2138ac018fc3e7ba1a2e5e0aad8e424d0b55e2436eb1d0dcd5cb2b8bcc6d53412c22f358de57803a6a655fbbd04"; let pubkey_string = "04e96e22004e3db93530de27ccddfdf1463975d2138ac018fc3e7ba1a2e5e0aad8e424d0b55e2436eb1d0dcd5cb2b8bcc6d53412c22f358de57803a6a655fbbd04";

View File

@ -477,7 +477,7 @@ mod tests {
use super::*; use super::*;
use crate::consensus::encode::{deserialize, serialize}; use crate::consensus::encode::{deserialize, serialize};
use crate::Network; use crate::{Network, TestnetVersion};
#[test] #[test]
fn test_coinbase_and_bip34() { fn test_coinbase_and_bip34() {
@ -546,7 +546,7 @@ mod tests {
// Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b // Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b
#[test] #[test]
fn segwit_block_test() { fn segwit_block_test() {
let params = Params::new(Network::Testnet); let params = Params::new(Network::Testnet(TestnetVersion::V3));
let segwit_block = include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw").to_vec(); let segwit_block = include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw").to_vec();
let decode: Result<Block, _> = deserialize(&segwit_block); let decode: Result<Block, _> = deserialize(&segwit_block);

View File

@ -17,7 +17,7 @@ use crate::opcodes::all::*;
use crate::pow::CompactTarget; use crate::pow::CompactTarget;
use crate::transaction::{self, OutPoint, Transaction, TxIn, TxOut}; use crate::transaction::{self, OutPoint, Transaction, TxIn, TxOut};
use crate::witness::Witness; use crate::witness::Witness;
use crate::{script, Amount, BlockHash, Sequence}; use crate::{script, Amount, BlockHash, Sequence, TestnetVersion};
/// How many seconds between blocks we expect on average. /// How many seconds between blocks we expect on average.
pub const TARGET_BLOCK_SPACING: u32 = 600; pub const TARGET_BLOCK_SPACING: u32 = 600;
@ -72,8 +72,11 @@ const GENESIS_OUTPUT_PK: [u8; 65] = [
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f
]; ];
#[rustfmt::skip]
const TESTNET4_GENESIS_OUTPUT_PK: [u8; 33] = [0x00; 33];
/// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block. /// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block.
fn bitcoin_genesis_tx() -> Transaction { fn bitcoin_genesis_tx(params: &Params) -> Transaction {
// Base // Base
let mut ret = Transaction { let mut ret = Transaction {
version: transaction::Version::ONE, version: transaction::Version::ONE,
@ -82,12 +85,28 @@ fn bitcoin_genesis_tx() -> Transaction {
output: vec![], output: vec![],
}; };
// Inputs let (in_script, out_script) = {
let in_script = script::Builder::new() match params.network {
Network::Testnet(TestnetVersion::V4) => (
script::Builder::new()
.push_int_unchecked(486604799)
.push_int_non_minimal(4)
.push_slice(b"03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e")
.into_script(),
script::Builder::new().push_slice(TESTNET4_GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script(),
),
_ => (
script::Builder::new()
.push_int_unchecked(486604799) .push_int_unchecked(486604799)
.push_int_non_minimal(4) .push_int_non_minimal(4)
.push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks") .push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
.into_script(); .into_script(),
script::Builder::new().push_slice(GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script(),
),
}
};
ret.input.push(TxIn { ret.input.push(TxIn {
previous_output: OutPoint::COINBASE_PREVOUT, previous_output: OutPoint::COINBASE_PREVOUT,
script_sig: in_script, script_sig: in_script,
@ -95,9 +114,6 @@ fn bitcoin_genesis_tx() -> Transaction {
witness: Witness::default(), witness: Witness::default(),
}); });
// Outputs
let out_script =
script::Builder::new().push_slice(GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script();
ret.output.push(TxOut { value: Amount::from_sat(50 * 100_000_000), script_pubkey: out_script }); ret.output.push(TxOut { value: Amount::from_sat(50 * 100_000_000), script_pubkey: out_script });
// end // end
@ -106,10 +122,12 @@ fn bitcoin_genesis_tx() -> Transaction {
/// Constructs and returns the genesis block. /// Constructs and returns the genesis block.
pub fn genesis_block(params: impl AsRef<Params>) -> Block { pub fn genesis_block(params: impl AsRef<Params>) -> Block {
let txdata = vec![bitcoin_genesis_tx()]; let params = params.as_ref();
let txdata = vec![bitcoin_genesis_tx(params)];
let hash: sha256d::Hash = txdata[0].compute_txid().into(); let hash: sha256d::Hash = txdata[0].compute_txid().into();
let merkle_root = hash.into(); let merkle_root: crate::TxMerkleNode = hash.into();
match params.as_ref().network {
match params.network {
Network::Bitcoin => Block { Network::Bitcoin => Block {
header: block::Header { header: block::Header {
version: block::Version::ONE, version: block::Version::ONE,
@ -121,7 +139,7 @@ pub fn genesis_block(params: impl AsRef<Params>) -> Block {
}, },
txdata, txdata,
}, },
Network::Testnet => Block { Network::Testnet(TestnetVersion::V3) => Block {
header: block::Header { header: block::Header {
version: block::Version::ONE, version: block::Version::ONE,
prev_blockhash: BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, prev_blockhash: BlockHash::GENESIS_PREVIOUS_BLOCK_HASH,
@ -132,6 +150,17 @@ pub fn genesis_block(params: impl AsRef<Params>) -> Block {
}, },
txdata, txdata,
}, },
Network::Testnet(TestnetVersion::V4) => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: BlockHash::GENESIS_PREVIOUS_BLOCK_HASH,
merkle_root,
time: 1714777860,
bits: CompactTarget::from_consensus(0x1d00ffff),
nonce: 393743547,
},
txdata,
},
Network::Signet => Block { Network::Signet => Block {
header: block::Header { header: block::Header {
version: block::Version::ONE, version: block::Version::ONE,
@ -170,11 +199,22 @@ impl ChainHash {
111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131,
101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0,
]); ]);
/// `ChainHash` for testnet bitcoin. /// `ChainHash` for testnet3 bitcoin.
#[deprecated(since = "0.33.0", note = "Use TESTNET3 instead")]
pub const TESTNET: Self = Self([ pub const TESTNET: Self = Self([
67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151, 67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151,
32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0, 32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0,
]); ]);
/// `ChainHash` for testnet3 bitcoin.
pub const TESTNET3: Self = Self([
67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151,
32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0,
]);
/// `ChainHash` for testnet4 bitcoin.
pub const TESTNET4: Self = Self([
67, 240, 139, 218, 176, 80, 227, 91, 86, 124, 134, 75, 145, 244, 127, 80, 174, 114, 90,
226, 222, 83, 188, 251, 186, 242, 132, 218, 0, 0, 0, 0,
]);
/// `ChainHash` for signet bitcoin. /// `ChainHash` for signet bitcoin.
pub const SIGNET: Self = Self([ pub const SIGNET: Self = Self([
246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249, 246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249,
@ -191,9 +231,13 @@ impl ChainHash {
/// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash) /// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash)
/// for specification. /// for specification.
pub fn using_genesis_block(params: impl AsRef<Params>) -> Self { pub fn using_genesis_block(params: impl AsRef<Params>) -> Self {
let network = params.as_ref().network; match params.as_ref().network {
let hashes = [Self::BITCOIN, Self::TESTNET, Self::SIGNET, Self::REGTEST]; Network::Bitcoin => Self::BITCOIN,
hashes[network as usize] Network::Testnet(TestnetVersion::V3) => Self::TESTNET3,
Network::Testnet(TestnetVersion::V4) => Self::TESTNET4,
Network::Signet => Self::SIGNET,
Network::Regtest => Self::REGTEST,
}
} }
/// Returns the hash of the `network` genesis block for use as a chain hash. /// Returns the hash of the `network` genesis block for use as a chain hash.
@ -201,8 +245,13 @@ impl ChainHash {
/// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash) /// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash)
/// for specification. /// for specification.
pub const fn using_genesis_block_const(network: Network) -> Self { pub const fn using_genesis_block_const(network: Network) -> Self {
let hashes = [Self::BITCOIN, Self::TESTNET, Self::SIGNET, Self::REGTEST]; match network {
hashes[network as usize] Network::Bitcoin => Self::BITCOIN,
Network::Testnet(TestnetVersion::V3) => Self::TESTNET3,
Network::Testnet(TestnetVersion::V4) => Self::TESTNET4,
Network::Signet => Self::SIGNET,
Network::Regtest => Self::REGTEST,
}
} }
/// Converts genesis block hash into `ChainHash`. /// Converts genesis block hash into `ChainHash`.
@ -222,7 +271,7 @@ mod test {
#[test] #[test]
fn bitcoin_genesis_first_transaction() { fn bitcoin_genesis_first_transaction() {
let gen = bitcoin_genesis_tx(); let gen = bitcoin_genesis_tx(&Params::MAINNET);
assert_eq!(gen.version, transaction::Version::ONE); assert_eq!(gen.version, transaction::Version::ONE);
assert_eq!(gen.input.len(), 1); assert_eq!(gen.input.len(), 1);
@ -278,7 +327,7 @@ mod test {
#[test] #[test]
fn testnet_genesis_full_block() { fn testnet_genesis_full_block() {
let gen = genesis_block(&params::TESTNET); let gen = genesis_block(&params::TESTNET3);
assert_eq!(gen.header.version, block::Version::ONE); assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH); assert_eq!(gen.header.prev_blockhash, BlockHash::GENESIS_PREVIOUS_BLOCK_HASH);
assert_eq!( assert_eq!(
@ -332,7 +381,8 @@ mod test {
#[allow(unreachable_patterns)] // This is specifically trying to catch later added variants. #[allow(unreachable_patterns)] // This is specifically trying to catch later added variants.
match network { match network {
Network::Bitcoin => {}, Network::Bitcoin => {},
Network::Testnet => {}, Network::Testnet(TestnetVersion::V3) => {},
Network::Testnet(TestnetVersion::V4) => {},
Network::Signet => {}, Network::Signet => {},
Network::Regtest => {}, Network::Regtest => {},
_ => panic!("update ChainHash::using_genesis_block and chain_hash_genesis_block with new variants"), _ => panic!("update ChainHash::using_genesis_block and chain_hash_genesis_block with new variants"),
@ -352,7 +402,8 @@ mod test {
chain_hash_genesis_block! { chain_hash_genesis_block! {
mainnet_chain_hash_genesis_block, Network::Bitcoin; mainnet_chain_hash_genesis_block, Network::Bitcoin;
testnet_chain_hash_genesis_block, Network::Testnet; testnet_chain_hash_genesis_block, Network::Testnet(TestnetVersion::V3);
testnet4_chain_hash_genesis_block, Network::Testnet(TestnetVersion::V4);
signet_chain_hash_genesis_block, Network::Signet; signet_chain_hash_genesis_block, Network::Signet;
regtest_chain_hash_genesis_block, Network::Regtest; regtest_chain_hash_genesis_block, Network::Regtest;
} }

View File

@ -202,12 +202,12 @@ mod primitive {
} }
} }
// Sizes up to 73 to support all pubkey and signature sizes // Sizes up to 76 to support all pubkey and signature sizes
from_array! { from_array! {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 71, 72, 73, 74, 75, 76
} }
/// Owned, growable counterpart to `PushBytes`. /// Owned, growable counterpart to `PushBytes`.

View File

@ -135,7 +135,7 @@ pub use crate::{
crypto::key::{self, PrivateKey, PubkeyHash, PublicKey, CompressedPublicKey, WPubkeyHash, XOnlyPublicKey}, crypto::key::{self, PrivateKey, PubkeyHash, PublicKey, CompressedPublicKey, WPubkeyHash, XOnlyPublicKey},
crypto::sighash::{self, LegacySighash, SegwitV0Sighash, TapSighash, TapSighashTag}, crypto::sighash::{self, LegacySighash, SegwitV0Sighash, TapSighash, TapSighashTag},
merkle_tree::{MerkleBlock, TxMerkleNode, WitnessMerkleNode}, merkle_tree::{MerkleBlock, TxMerkleNode, WitnessMerkleNode},
network::{Network, NetworkKind}, network::{Network, NetworkKind, TestnetVersion},
network::params::{self, Params}, network::params::{self, Params},
pow::{CompactTarget, Target, Work}, pow::{CompactTarget, Target, Work},
psbt::Psbt, psbt::Psbt,

View File

@ -25,7 +25,7 @@ use core::str::FromStr;
use internals::write_err; use internals::write_err;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use crate::constants::ChainHash; use crate::constants::ChainHash;
use crate::p2p::Magic; use crate::p2p::Magic;
@ -57,27 +57,72 @@ impl From<Network> for NetworkKind {
match n { match n {
Bitcoin => NetworkKind::Main, Bitcoin => NetworkKind::Main,
Testnet | Signet | Regtest => NetworkKind::Test, Testnet(_) | Signet | Regtest => NetworkKind::Test,
} }
} }
} }
/// The testnet version to act on.
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
#[non_exhaustive]
pub enum TestnetVersion {
/// Testnet version 3.
V3,
/// Testnet version 4.
V4,
}
/// The cryptocurrency network to act on. /// The cryptocurrency network to act on.
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)] #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[non_exhaustive] #[non_exhaustive]
pub enum Network { pub enum Network {
/// Mainnet Bitcoin. /// Mainnet Bitcoin.
Bitcoin, Bitcoin,
/// Bitcoin's testnet network. /// Bitcoin's testnet network.
Testnet, Testnet(TestnetVersion),
/// Bitcoin's signet network. /// Bitcoin's signet network.
Signet, Signet,
/// Bitcoin's regtest network. /// Bitcoin's regtest network.
Regtest, Regtest,
} }
#[cfg(feature = "serde")]
impl Serialize for Network {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_display_str())
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Network {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct NetworkVisitor;
impl<'de> Visitor<'de> for NetworkVisitor {
type Value = Network;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid network identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Network, E>
where
E: serde::de::Error,
{
Network::from_str(value).map_err(E::custom)
}
}
deserializer.deserialize_str(NetworkVisitor)
}
}
impl Network { impl Network {
/// Creates a `Network` from the magic bytes. /// Creates a `Network` from the magic bytes.
/// ///
@ -118,7 +163,9 @@ impl Network {
pub fn to_core_arg(self) -> &'static str { pub fn to_core_arg(self) -> &'static str {
match self { match self {
Network::Bitcoin => "main", Network::Bitcoin => "main",
Network::Testnet => "test", // For user-side compatibility, testnet3 is retained as test
Network::Testnet(TestnetVersion::V3) => "test",
Network::Testnet(TestnetVersion::V4) => "testnet4",
Network::Signet => "signet", Network::Signet => "signet",
Network::Regtest => "regtest", Network::Regtest => "regtest",
} }
@ -138,7 +185,8 @@ impl Network {
let network = match core_arg { let network = match core_arg {
"main" => Bitcoin, "main" => Bitcoin,
"test" => Testnet, "test" => Testnet(TestnetVersion::V3),
"testnet4" => Testnet(TestnetVersion::V4),
"signet" => Signet, "signet" => Signet,
"regtest" => Regtest, "regtest" => Regtest,
_ => return Err(ParseNetworkError(core_arg.to_owned())), _ => return Err(ParseNetworkError(core_arg.to_owned())),
@ -175,13 +223,25 @@ impl Network {
/// Returns the associated network parameters. /// Returns the associated network parameters.
pub const fn params(self) -> &'static Params { pub const fn params(self) -> &'static Params {
const PARAMS: [Params; 4] = [ match self {
Params::new(Network::Bitcoin), Network::Bitcoin => &Params::BITCOIN,
Params::new(Network::Testnet), Network::Testnet(TestnetVersion::V3) => &Params::TESTNET3,
Params::new(Network::Signet), Network::Testnet(TestnetVersion::V4) => &Params::TESTNET4,
Params::new(Network::Regtest), Network::Signet => &Params::SIGNET,
]; Network::Regtest => &Params::REGTEST,
&PARAMS[self as usize] }
}
/// Returns a string representation of the `Network` enum variant.
/// This is useful for displaying the network type as a string.
const fn as_display_str(self) -> &'static str {
match self {
Network::Bitcoin => "bitcoin",
Network::Testnet(TestnetVersion::V3) => "testnet",
Network::Testnet(TestnetVersion::V4) => "testnet4",
Network::Signet => "signet",
Network::Regtest => "regtest",
}
} }
} }
@ -212,7 +272,7 @@ pub mod as_core_arg {
Network::from_core_arg(s).map_err(|_| { Network::from_core_arg(s).map_err(|_| {
E::invalid_value( E::invalid_value(
serde::de::Unexpected::Str(s), serde::de::Unexpected::Str(s),
&"bitcoin network encoded as a string (either main, test, signet or regtest)", &"bitcoin network encoded as a string (either main, test, testnet4, signet or regtest)",
) )
}) })
} }
@ -220,7 +280,7 @@ pub mod as_core_arg {
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
write!( write!(
formatter, formatter,
"bitcoin network encoded as a string (either main, test, signet or regtest)" "bitcoin network encoded as a string (either main, test, testnet4, signet or regtest)"
) )
} }
} }
@ -250,30 +310,21 @@ impl FromStr for Network {
#[inline] #[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
use Network::*; match s {
"bitcoin" => Ok(Network::Bitcoin),
let network = match s { // For user-side compatibility, testnet3 is retained as testnet
"bitcoin" => Bitcoin, "testnet" => Ok(Network::Testnet(TestnetVersion::V3)),
"testnet" => Testnet, "testnet4" => Ok(Network::Testnet(TestnetVersion::V4)),
"signet" => Signet, "signet" => Ok(Network::Signet),
"regtest" => Regtest, "regtest" => Ok(Network::Regtest),
_ => return Err(ParseNetworkError(s.to_owned())), _ => Err(ParseNetworkError(s.to_owned())),
}; }
Ok(network)
} }
} }
impl fmt::Display for Network { impl fmt::Display for Network {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use Network::*; write!(f, "{}", self.as_display_str())
let s = match *self {
Bitcoin => "bitcoin",
Testnet => "testnet",
Signet => "signet",
Regtest => "regtest",
};
write!(f, "{}", s)
} }
} }
@ -300,7 +351,8 @@ impl TryFrom<ChainHash> for Network {
match chain_hash { match chain_hash {
// Note: any new network entries must be matched against here. // Note: any new network entries must be matched against here.
ChainHash::BITCOIN => Ok(Network::Bitcoin), ChainHash::BITCOIN => Ok(Network::Bitcoin),
ChainHash::TESTNET => Ok(Network::Testnet), ChainHash::TESTNET3 => Ok(Network::Testnet(TestnetVersion::V3)),
ChainHash::TESTNET4 => Ok(Network::Testnet(TestnetVersion::V4)),
ChainHash::SIGNET => Ok(Network::Signet), ChainHash::SIGNET => Ok(Network::Signet),
ChainHash::REGTEST => Ok(Network::Regtest), ChainHash::REGTEST => Ok(Network::Regtest),
_ => Err(UnknownChainHashError(chain_hash)), _ => Err(UnknownChainHashError(chain_hash)),
@ -310,19 +362,33 @@ impl TryFrom<ChainHash> for Network {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Network; use super::{Network, TestnetVersion};
use crate::consensus::encode::{deserialize, serialize}; use crate::consensus::encode::{deserialize, serialize};
use crate::p2p::ServiceFlags; use crate::p2p::ServiceFlags;
#[test] #[test]
fn serialize_test() { fn serialize_test() {
assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]); assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]);
assert_eq!(serialize(&Network::Testnet.magic()), &[0x0b, 0x11, 0x09, 0x07]); assert_eq!(
serialize(&Network::Testnet(TestnetVersion::V3).magic()),
&[0x0b, 0x11, 0x09, 0x07]
);
assert_eq!(
serialize(&Network::Testnet(TestnetVersion::V4).magic()),
&[0x1c, 0x16, 0x3f, 0x28]
);
assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]); assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]);
assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]); assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]);
assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic())); assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic()));
assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet.magic())); assert_eq!(
deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(),
Some(Network::Testnet(TestnetVersion::V3).magic())
);
assert_eq!(
deserialize(&[0x1c, 0x16, 0x3f, 0x28]).ok(),
Some(Network::Testnet(TestnetVersion::V4).magic())
);
assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic())); assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic()));
assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic())); assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic()));
} }
@ -330,12 +396,14 @@ mod tests {
#[test] #[test]
fn string_test() { fn string_test() {
assert_eq!(Network::Bitcoin.to_string(), "bitcoin"); assert_eq!(Network::Bitcoin.to_string(), "bitcoin");
assert_eq!(Network::Testnet.to_string(), "testnet"); assert_eq!(Network::Testnet(TestnetVersion::V3).to_string(), "testnet");
assert_eq!(Network::Testnet(TestnetVersion::V4).to_string(), "testnet4");
assert_eq!(Network::Regtest.to_string(), "regtest"); assert_eq!(Network::Regtest.to_string(), "regtest");
assert_eq!(Network::Signet.to_string(), "signet"); assert_eq!(Network::Signet.to_string(), "signet");
assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin); assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet); assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet(TestnetVersion::V3));
assert_eq!("testnet4".parse::<Network>().unwrap(), Network::Testnet(TestnetVersion::V4));
assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest); assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
assert_eq!("signet".parse::<Network>().unwrap(), Network::Signet); assert_eq!("signet".parse::<Network>().unwrap(), Network::Signet);
assert!("fakenet".parse::<Network>().is_err()); assert!("fakenet".parse::<Network>().is_err());
@ -386,8 +454,13 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn serde_roundtrip() { fn serde_roundtrip() {
use Network::*; use Network::*;
let tests = let tests = vec![
[(Bitcoin, "bitcoin"), (Testnet, "testnet"), (Signet, "signet"), (Regtest, "regtest")]; (Bitcoin, "bitcoin"),
(Testnet(TestnetVersion::V3), "testnet"),
(Testnet(TestnetVersion::V4), "testnet4"),
(Signet, "signet"),
(Regtest, "regtest"),
];
for tc in tests { for tc in tests {
let network = tc.0; let network = tc.0;
@ -405,7 +478,8 @@ mod tests {
fn from_to_core_arg() { fn from_to_core_arg() {
let expected_pairs = [ let expected_pairs = [
(Network::Bitcoin, "main"), (Network::Bitcoin, "main"),
(Network::Testnet, "test"), (Network::Testnet(TestnetVersion::V3), "test"),
(Network::Testnet(TestnetVersion::V4), "testnet4"),
(Network::Regtest, "regtest"), (Network::Regtest, "regtest"),
(Network::Signet, "signet"), (Network::Signet, "signet"),
]; ];

View File

@ -3,7 +3,7 @@
//! Bitcoin consensus parameters. //! Bitcoin consensus parameters.
//! //!
//! This module provides a predefined set of parameters for different Bitcoin //! This module provides a predefined set of parameters for different Bitcoin
//! chains (such as mainnet, testnet). //! chains (such as mainnet, testnet, testnet4).
//! //!
//! # Custom Signets Example //! # Custom Signets Example
//! //!
@ -73,6 +73,7 @@ use crate::network::Network;
#[cfg(doc)] #[cfg(doc)]
use crate::pow::CompactTarget; use crate::pow::CompactTarget;
use crate::pow::Target; use crate::pow::Target;
use crate::TestnetVersion;
/// Parameters that influence chain consensus. /// Parameters that influence chain consensus.
#[non_exhaustive] #[non_exhaustive]
@ -127,8 +128,13 @@ pub struct Params {
/// ///
/// [using-statics-or-consts]: <https://doc.rust-lang.org/reference/items/static-items.html#using-statics-or-consts> /// [using-statics-or-consts]: <https://doc.rust-lang.org/reference/items/static-items.html#using-statics-or-consts>
pub static MAINNET: Params = Params::MAINNET; pub static MAINNET: Params = Params::MAINNET;
/// The testnet parameters. /// The testnet3 parameters.
pub static TESTNET: Params = Params::TESTNET; #[deprecated(since = "0.33.0", note = "Use TESTNET3 instead")]
pub static TESTNET: Params = Params::TESTNET3;
/// The testnet3 parameters.
pub static TESTNET3: Params = Params::TESTNET3;
/// The testnet4 parameters.
pub static TESTNET4: Params = Params::TESTNET4;
/// The signet parameters. /// The signet parameters.
pub static SIGNET: Params = Params::SIGNET; pub static SIGNET: Params = Params::SIGNET;
/// The regtest parameters. /// The regtest parameters.
@ -156,9 +162,10 @@ impl Params {
no_pow_retargeting: false, no_pow_retargeting: false,
}; };
/// The testnet parameters. /// The testnet3 parameters.
#[deprecated(since = "0.33.0", note = "Use TESTNET3 instead")]
pub const TESTNET: Params = Params { pub const TESTNET: Params = Params {
network: Network::Testnet, network: Network::Testnet(TestnetVersion::V3),
bip16_time: 1333238400, // Apr 1 2012 bip16_time: 1333238400, // Apr 1 2012
bip34_height: BlockHeight::from_u32(21111), // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8 bip34_height: BlockHeight::from_u32(21111), // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
bip65_height: BlockHeight::from_u32(581885), // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 bip65_height: BlockHeight::from_u32(581885), // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
@ -173,6 +180,40 @@ impl Params {
no_pow_retargeting: false, no_pow_retargeting: false,
}; };
/// The testnet3 parameters.
pub const TESTNET3: Params = Params {
network: Network::Testnet(TestnetVersion::V3),
bip16_time: 1333238400, // Apr 1 2012
bip34_height: BlockHeight::from_u32(21111), // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
bip65_height: BlockHeight::from_u32(581885), // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
bip66_height: BlockHeight::from_u32(330776), // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
rule_change_activation_threshold: BlockInterval::from_u32(1512), // 75%
miner_confirmation_window: BlockInterval::from_u32(2016),
pow_limit: Target::MAX_ATTAINABLE_TESTNET,
max_attainable_target: Target::MAX_ATTAINABLE_TESTNET,
pow_target_spacing: 10 * 60, // 10 minutes.
pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks.
allow_min_difficulty_blocks: true,
no_pow_retargeting: false,
};
/// The testnet4 parameters.
pub const TESTNET4: Params = Params {
network: Network::Testnet(TestnetVersion::V4),
bip16_time: 1333238400, // Apr 1 2012
bip34_height: BlockHeight::from_u32(1),
bip65_height: BlockHeight::from_u32(1),
bip66_height: BlockHeight::from_u32(1),
rule_change_activation_threshold: BlockInterval::from_u32(1512), // 75%
miner_confirmation_window: BlockInterval::from_u32(2016),
pow_limit: Target::MAX_ATTAINABLE_TESTNET,
max_attainable_target: Target::MAX_ATTAINABLE_TESTNET,
pow_target_spacing: 10 * 60, // 10 minutes.
pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks.
allow_min_difficulty_blocks: true,
no_pow_retargeting: false,
};
/// The signet parameters. /// The signet parameters.
pub const SIGNET: Params = Params { pub const SIGNET: Params = Params {
network: Network::Signet, network: Network::Signet,
@ -207,11 +248,12 @@ impl Params {
no_pow_retargeting: true, no_pow_retargeting: true,
}; };
/// Creates parameters set for the given network. /// Creates parameters set for the given network. /// Creates parameters set for the given network.
pub const fn new(network: Network) -> Self { pub const fn new(network: Network) -> Self {
match network { match network {
Network::Bitcoin => Params::MAINNET, Network::Bitcoin => Params::MAINNET,
Network::Testnet => Params::TESTNET, Network::Testnet(TestnetVersion::V3) => Params::TESTNET3,
Network::Testnet(TestnetVersion::V4) => Params::TESTNET4,
Network::Signet => Params::SIGNET, Network::Signet => Params::SIGNET,
Network::Regtest => Params::REGTEST, Network::Regtest => Params::REGTEST,
} }
@ -244,12 +286,5 @@ impl AsRef<Params> for Params {
} }
impl AsRef<Params> for Network { impl AsRef<Params> for Network {
fn as_ref(&self) -> &Params { fn as_ref(&self) -> &Params { Self::params(*self) }
match *self {
Network::Bitcoin => &MAINNET,
Network::Testnet => &TESTNET,
Network::Signet => &SIGNET,
Network::Regtest => &REGTEST,
}
}
} }

View File

@ -28,7 +28,7 @@ use internals::{debug_from_display, impl_to_hex_from_lower_hex, write_err};
use io::{BufRead, Write}; use io::{BufRead, Write};
use crate::consensus::encode::{self, Decodable, Encodable}; use crate::consensus::encode::{self, Decodable, Encodable};
use crate::network::{Network, Params}; use crate::network::{Network, Params, TestnetVersion};
use crate::prelude::{Borrow, BorrowMut, String, ToOwned}; use crate::prelude::{Borrow, BorrowMut, String, ToOwned};
#[rustfmt::skip] #[rustfmt::skip]
@ -216,8 +216,13 @@ pub struct Magic([u8; 4]);
impl Magic { impl Magic {
/// Bitcoin mainnet network magic bytes. /// Bitcoin mainnet network magic bytes.
pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]); pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]);
/// Bitcoin testnet network magic bytes. /// Bitcoin testnet3 network magic bytes.
#[deprecated(since = "0.33.0", note = "Use TESTNET3 instead")]
pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]); pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]);
/// Bitcoin testnet3 network magic bytes.
pub const TESTNET3: Self = Self([0x0B, 0x11, 0x09, 0x07]);
/// Bitcoin testnet4 network magic bytes.
pub const TESTNET4: Self = Self([0x1c, 0x16, 0x3f, 0x28]);
/// Bitcoin signet network magic bytes. /// Bitcoin signet network magic bytes.
pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]); pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]);
/// Bitcoin regtest network magic bytes. /// Bitcoin regtest network magic bytes.
@ -245,12 +250,12 @@ impl FromStr for Magic {
} }
macro_rules! generate_network_magic_conversion { macro_rules! generate_network_magic_conversion {
($(Network::$network:ident => Magic::$magic:ident,)*) => { ($(Network::$network:ident$((TestnetVersion::$testnet_version:ident))? => Magic::$magic:ident,)*) => {
impl From<Network> for Magic { impl From<Network> for Magic {
fn from(network: Network) -> Magic { fn from(network: Network) -> Magic {
match network { match network {
$( $(
Network::$network => Magic::$magic, Network::$network$((TestnetVersion::$testnet_version))? => Magic::$magic,
)* )*
} }
} }
@ -262,7 +267,7 @@ macro_rules! generate_network_magic_conversion {
fn try_from(magic: Magic) -> Result<Self, Self::Error> { fn try_from(magic: Magic) -> Result<Self, Self::Error> {
match magic { match magic {
$( $(
Magic::$magic => Ok(Network::$network), Magic::$magic => Ok(Network::$network$((TestnetVersion::$testnet_version))?),
)* )*
_ => Err(UnknownMagicError(magic)), _ => Err(UnknownMagicError(magic)),
} }
@ -270,10 +275,12 @@ macro_rules! generate_network_magic_conversion {
} }
}; };
} }
// Generate conversion functions for all known networks.
// `Network -> Magic` and `Magic -> Network`
generate_network_magic_conversion! { generate_network_magic_conversion! {
Network::Bitcoin => Magic::BITCOIN, Network::Bitcoin => Magic::BITCOIN,
Network::Testnet => Magic::TESTNET, Network::Testnet(TestnetVersion::V3) => Magic::TESTNET3,
Network::Testnet(TestnetVersion::V4) => Magic::TESTNET4,
Network::Signet => Magic::SIGNET, Network::Signet => Magic::SIGNET,
Network::Regtest => Magic::REGTEST, Network::Regtest => Magic::REGTEST,
} }
@ -430,7 +437,8 @@ mod tests {
fn magic_from_str() { fn magic_from_str() {
let known_network_magic_strs = [ let known_network_magic_strs = [
("f9beb4d9", Network::Bitcoin), ("f9beb4d9", Network::Bitcoin),
("0b110907", Network::Testnet), ("0b110907", Network::Testnet(TestnetVersion::V3)),
("1c163f28", Network::Testnet(TestnetVersion::V4)),
("fabfb5da", Network::Regtest), ("fabfb5da", Network::Regtest),
("0a03cf40", Network::Signet), ("0a03cf40", Network::Signet),
]; ];

View File

@ -94,7 +94,7 @@ fn psbt_sign_taproot() {
// //
let keystore = Keystore { let keystore = Keystore {
mfp: mfp.parse::<Fingerprint>().unwrap(), mfp: mfp.parse::<Fingerprint>().unwrap(),
sk: PrivateKey::new(kp.secret_key(), Network::Testnet), sk: PrivateKey::new(kp.secret_key(), Network::Testnet(bitcoin::TestnetVersion::V3)),
}; };
let _ = psbt_key_path_spend.sign(&keystore, secp); let _ = psbt_key_path_spend.sign(&keystore, secp);
@ -124,7 +124,7 @@ fn psbt_sign_taproot() {
let keystore = Keystore { let keystore = Keystore {
mfp: mfp.parse::<Fingerprint>().unwrap(), mfp: mfp.parse::<Fingerprint>().unwrap(),
sk: PrivateKey::new(kp.secret_key(), Network::Testnet), sk: PrivateKey::new(kp.secret_key(), Network::Testnet(bitcoin::TestnetVersion::V3)),
}; };
// //
@ -195,7 +195,7 @@ fn create_taproot_tree(
fn create_p2tr_address(tree: TaprootSpendInfo) -> Address { fn create_p2tr_address(tree: TaprootSpendInfo) -> Address {
let output_key = tree.output_key(); let output_key = tree.output_key();
Address::p2tr_tweaked(output_key, Network::Testnet) Address::p2tr_tweaked(output_key, Network::Testnet(bitcoin::TestnetVersion::V3))
} }
fn create_psbt_for_taproot_key_path_spend( fn create_psbt_for_taproot_key_path_spend(