4354f37f51 Use NetworkKind in bip32 module (Tobin C. Harding)
35bbfcded7 Use NetworkKind in PrivateKey (Tobin C. Harding)
d22f3828f6 Use NetworkKind in address module (Tobin C. Harding)
6d5ef23e61 Add NetworkKind (Tobin C. Harding)

Pull request description:

  Add a new type `NetworkKind` the describes the kind of network we are on, ether mainnet or one of the test nets (testnet, regtest, signet).

  Use it in `Address`, `PrivateKey`, and `bip32`.

ACKs for top commit:
  Kixunil:
    ACK 4354f37f51
  apoelstra:
    ACK 4354f37f51

Tree-SHA512: d015283b55b2dc68c0a5cc5f17332fce648d3e4fb4e63e0b61943b7edfe4112e8ace760cb743cd3fd5ad0c34636e51a6a12382b34b6e62dfd7dab894d2ceefc0
This commit is contained in:
Andrew Poelstra 2023-12-15 15:23:21 +00:00
commit a90104af2d
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
10 changed files with 155 additions and 175 deletions

View File

@ -8,7 +8,7 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, Xpriv, Xpub};
use bitcoin::hex::FromHex;
use bitcoin::secp256k1::ffi::types::AlignedType;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::CompressedPublicKey;
use bitcoin::{Network, NetworkKind, CompressedPublicKey};
fn main() {
// This example derives root xprv from a 32-byte seed,
@ -26,10 +26,7 @@ fn main() {
let seed_hex = &args[1];
println!("Seed: {}", seed_hex);
// default network as mainnet
let network = bitcoin::Network::Bitcoin;
println!("Network: {:?}", network);
println!("Using mainnet network");
let seed = Vec::from_hex(seed_hex).unwrap();
@ -39,7 +36,7 @@ fn main() {
let secp = Secp256k1::preallocated_new(buf.as_mut_slice()).unwrap();
// calculate root key from seed
let root = Xpriv::new_master(network, &seed).unwrap();
let root = Xpriv::new_master(NetworkKind::Main, &seed).unwrap();
println!("Root key: {}", root);
// derive child xpub
@ -53,6 +50,6 @@ fn main() {
// manually creating indexes this time
let zero = ChildNumber::from_normal_idx(0).unwrap();
let public_key = xpub.derive_pub(&secp, &[zero, zero]).unwrap().public_key;
let address = Address::p2wpkh(&CompressedPublicKey(public_key), network);
let address = Address::p2wpkh(&CompressedPublicKey(public_key), Network::Bitcoin);
println!("First receiving address: {}", address);
}

View File

@ -46,7 +46,7 @@ use crate::blockdata::script::witness_program::WitnessProgram;
use crate::blockdata::script::witness_version::WitnessVersion;
use crate::blockdata::script::{self, PushBytesBuf, Script, ScriptBuf, ScriptHash};
use crate::crypto::key::{PubkeyHash, PublicKey, CompressedPublicKey, TweakedPublicKey, UntweakedPublicKey};
use crate::network::Network;
use crate::network::{Network, NetworkKind};
use crate::prelude::*;
use crate::taproot::TapNodeHash;
@ -135,8 +135,8 @@ impl NetworkValidation for NetworkUnchecked {
/// addresses are used only on the appropriate network.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum AddressInner {
P2pkh { hash: PubkeyHash, prefix: LegacyP2pkhPrefix },
P2sh { hash: ScriptHash, prefix: LegacyP2shPrefix },
P2pkh { hash: PubkeyHash, network: NetworkKind },
P2sh { hash: ScriptHash, network: NetworkKind },
Segwit { program: WitnessProgram, hrp: KnownHrp },
}
@ -145,15 +145,21 @@ impl fmt::Display for AddressInner {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use AddressInner::*;
match self {
P2pkh { hash, prefix } => {
P2pkh { hash, network } => {
let mut prefixed = [0; 21];
prefixed[0] = prefix.to_u8();
prefixed[0] = match network {
NetworkKind::Main => PUBKEY_ADDRESS_PREFIX_MAIN,
NetworkKind::Test => PUBKEY_ADDRESS_PREFIX_TEST,
};
prefixed[1..].copy_from_slice(&hash[..]);
base58::encode_check_to_fmt(fmt, &prefixed[..])
}
P2sh { hash, prefix } => {
P2sh { hash, network } => {
let mut prefixed = [0; 21];
prefixed[0] = prefix.to_u8();
prefixed[0] = match network {
NetworkKind::Main => SCRIPT_ADDRESS_PREFIX_MAIN,
NetworkKind::Test => SCRIPT_ADDRESS_PREFIX_TEST,
};
prefixed[1..].copy_from_slice(&hash[..]);
base58::encode_check_to_fmt(fmt, &prefixed[..])
}
@ -172,64 +178,6 @@ impl fmt::Display for AddressInner {
}
}
/// Prefix byte used for legacy P2PKH addresses.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum LegacyP2pkhPrefix {
/// Prefix used for legacy addresses on the main Bitcoin network.
Mainnet,
/// Prefix used for legacy addresses on all other test networks (testnet, signet, regtest).
AllTestnets,
}
impl LegacyP2pkhPrefix {
/// Creates a legacy prefix from the associated `network`.
fn from_network(network: Network) -> Self {
use Network::*;
match network {
Bitcoin => Self::Mainnet,
Signet | Testnet | Regtest => Self::AllTestnets,
}
}
/// Converts this prefix enum to the respective byte value.
fn to_u8(self) -> u8 {
match self {
Self::Mainnet => PUBKEY_ADDRESS_PREFIX_MAIN,
Self::AllTestnets => PUBKEY_ADDRESS_PREFIX_TEST,
}
}
}
/// Prefix byte used for legacy P2SH addresses.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum LegacyP2shPrefix {
/// Prefix used for legacy addresses on the main Bitcoin network.
Mainnet,
/// Prefix used for legacy addresses on all other test networks (testnet, signet, regtest).
AllTestnets,
}
impl LegacyP2shPrefix {
/// Creates a legacy prefix from the associated `network`.
fn from_network(network: Network) -> Self {
use Network::*;
match network {
Bitcoin => Self::Mainnet,
Signet | Testnet | Regtest => Self::AllTestnets,
}
}
/// Converts this prefix enum to the respective byte value.
fn to_u8(self) -> u8 {
match self {
Self::Mainnet => SCRIPT_ADDRESS_PREFIX_MAIN,
Self::AllTestnets => SCRIPT_ADDRESS_PREFIX_TEST,
}
}
}
/// Known bech32 human-readable parts.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
@ -277,6 +225,10 @@ impl KnownHrp {
}
}
impl From<Network> for KnownHrp {
fn from(n: Network) -> Self { Self::from_network(n) }
}
/// A Bitcoin address.
///
/// ### Parsing addresses
@ -412,10 +364,9 @@ impl Address {
///
/// This is the preferred non-witness type address.
#[inline]
pub fn p2pkh(pk: impl Into<PubkeyHash>, network: Network) -> Address {
pub fn p2pkh(pk: impl Into<PubkeyHash>, network: impl Into<NetworkKind>) -> Address {
let hash = pk.into();
let prefix = LegacyP2pkhPrefix::from_network(network);
Self(AddressInner::P2pkh { hash, prefix }, PhantomData)
Self(AddressInner::P2pkh { hash, network: network.into() }, PhantomData)
}
/// Creates a pay to script hash P2SH address from a script.
@ -423,7 +374,7 @@ impl Address {
/// This address type was introduced with BIP16 and is the popular type to implement multi-sig
/// these days.
#[inline]
pub fn p2sh(script: &Script, network: Network) -> Result<Address, Error> {
pub fn p2sh(script: &Script, network: impl Into<NetworkKind>) -> Result<Address, Error> {
if script.len() > MAX_SCRIPT_ELEMENT_SIZE {
return Err(Error::ExcessiveScriptSize);
}
@ -432,9 +383,8 @@ impl Address {
}
// This is intentionally not public so we enforce script length checks.
fn p2sh_from_hash(hash: ScriptHash, network: Network) -> Address {
let prefix = LegacyP2shPrefix::from_network(network);
Self(AddressInner::P2sh { hash, prefix }, PhantomData)
fn p2sh_from_hash(hash: ScriptHash, network: impl Into<NetworkKind>) -> Address {
Self(AddressInner::P2sh { hash, network: network.into() }, PhantomData)
}
/// Creates a witness pay to public key address from a public key.
@ -453,8 +403,8 @@ impl Address {
/// This is a segwit address type that looks familiar (as p2sh) to legacy clients.
pub fn p2shwpkh(
pk: &CompressedPublicKey,
network: Network,
) -> Self {
network: impl Into<NetworkKind>,
) -> Address {
let builder = script::Builder::new().push_int(0).push_slice(pk.wpubkey_hash());
let script_hash = builder.as_script().script_hash();
Address::p2sh_from_hash(script_hash, network)
@ -469,7 +419,7 @@ impl Address {
/// Creates a pay to script address that embeds a witness pay to script hash address.
///
/// This is a segwit address type that looks familiar (as p2sh) to legacy clients.
pub fn p2shwsh(script: &Script, network: Network) -> Address {
pub fn p2shwsh(script: &Script, network: impl Into<NetworkKind>) -> Address {
let builder = script::Builder::new().push_int(0).push_slice(script.wscript_hash());
let script_hash = builder.as_script().script_hash();
Address::p2sh_from_hash(script_hash, network)
@ -496,6 +446,7 @@ impl Address {
///
/// This only exists to support future witness versions. If you are doing normal mainnet things
/// then you likely do not need this constructor.
// TODO: This is still arguably wrong, could take a KnownHrp/Hrp instead of Network.
pub fn from_witness_program(program: WitnessProgram, network: Network) -> Address {
let hrp = KnownHrp::from_network(network);
let inner = AddressInner::Segwit { program, hrp };
@ -530,7 +481,7 @@ impl Address {
use AddressInner::*;
match self.0 {
P2pkh { ref hash, prefix: _ } => Some(*hash),
P2pkh { ref hash, network: _ } => Some(*hash),
_ => None,
}
}
@ -540,7 +491,7 @@ impl Address {
use AddressInner::*;
match self.0 {
P2sh { ref hash, prefix: _ } => Some(*hash),
P2sh { ref hash, network: _ } => Some(*hash),
_ => None,
}
}
@ -587,9 +538,13 @@ impl Address {
pub fn script_pubkey(&self) -> ScriptBuf {
use AddressInner::*;
match self.0 {
P2pkh { ref hash, prefix: _ } => ScriptBuf::new_p2pkh(hash),
P2sh { ref hash, prefix: _ } => ScriptBuf::new_p2sh(hash),
Segwit { ref program, hrp: _ } => ScriptBuf::new_witness_program(program),
P2pkh { ref hash, network: _ } => ScriptBuf::new_p2pkh(hash),
P2sh { ref hash, network: _ } => ScriptBuf::new_p2sh(hash),
Segwit { ref program, hrp: _ } => {
let prog = program.program();
let version = program.version();
ScriptBuf::new_witness_program_unchecked(version, prog)
}
}
}
@ -650,9 +605,9 @@ impl Address {
pub fn matches_script_pubkey(&self, script: &Script) -> bool {
use AddressInner::*;
match self.0 {
P2pkh { ref hash, prefix: _ } if script.is_p2pkh() =>
P2pkh { ref hash, network: _ } if script.is_p2pkh() =>
&script.as_bytes()[3..23] == <PubkeyHash as AsRef<[u8; 20]>>::as_ref(hash),
P2sh { ref hash, prefix: _ } if script.is_p2sh() =>
P2sh { ref hash, network: _ } if script.is_p2sh() =>
&script.as_bytes()[2..22] == <ScriptHash as AsRef<[u8; 20]>>::as_ref(hash),
Segwit { ref program, hrp: _ } if script.is_witness_program() =>
&script.as_bytes()[2..] == program.program().as_bytes(),
@ -671,8 +626,8 @@ impl Address {
fn payload_as_bytes(&self) -> &[u8] {
use AddressInner::*;
match self.0 {
P2sh { ref hash, prefix: _ } => hash.as_ref(),
P2pkh { ref hash, prefix: _ } => hash.as_ref(),
P2sh { ref hash, network: _ } => hash.as_ref(),
P2pkh { ref hash, network: _ } => hash.as_ref(),
Segwit { ref program, hrp: _ } => program.program().as_bytes(),
}
}
@ -706,12 +661,12 @@ impl Address<NetworkUnchecked> {
/// assert!(address.is_valid_for_network(Network::Bitcoin));
/// assert_eq!(address.is_valid_for_network(Network::Testnet), false);
/// ```
pub fn is_valid_for_network(&self, network: Network) -> bool {
pub fn is_valid_for_network(&self, n: Network) -> bool {
use AddressInner::*;
match self.0 {
P2pkh { hash: _, ref prefix } => *prefix == LegacyP2pkhPrefix::from_network(network),
P2sh { hash: _, ref prefix } => *prefix == LegacyP2shPrefix::from_network(network),
Segwit { program: _, ref hrp } => *hrp == KnownHrp::from_network(network),
P2pkh { hash: _, ref network } => *network == NetworkKind::from(n),
P2sh { hash: _, ref network } => *network == NetworkKind::from(n),
Segwit { program: _, ref hrp } => *hrp == KnownHrp::from_network(n),
}
}
@ -739,8 +694,8 @@ impl Address<NetworkUnchecked> {
use AddressInner::*;
let inner = match self.0 {
P2pkh { hash, prefix } => P2pkh { hash, prefix },
P2sh { hash, prefix } => P2sh { hash, prefix },
P2pkh { hash, network } => P2pkh { hash, network },
P2sh { hash, network } => P2sh { hash, network },
Segwit { program, hrp } => Segwit { program, hrp },
};
Address(inner, PhantomData)
@ -801,19 +756,19 @@ impl FromStr for Address<NetworkUnchecked> {
let inner = match *prefix {
PUBKEY_ADDRESS_PREFIX_MAIN => {
let hash = PubkeyHash::from_byte_array(data);
AddressInner::P2pkh { hash, prefix: LegacyP2pkhPrefix::Mainnet }
AddressInner::P2pkh { hash, network: NetworkKind::Main }
}
PUBKEY_ADDRESS_PREFIX_TEST => {
let hash = PubkeyHash::from_byte_array(data);
AddressInner::P2pkh { hash, prefix: LegacyP2pkhPrefix::AllTestnets }
AddressInner::P2pkh { hash, network: NetworkKind::Test }
}
SCRIPT_ADDRESS_PREFIX_MAIN => {
let hash = ScriptHash::from_byte_array(data);
AddressInner::P2sh { hash, prefix: LegacyP2shPrefix::Mainnet }
AddressInner::P2sh { hash, network: NetworkKind::Main }
}
SCRIPT_ADDRESS_PREFIX_TEST => {
let hash = ScriptHash::from_byte_array(data);
AddressInner::P2sh { hash, prefix: LegacyP2shPrefix::AllTestnets }
AddressInner::P2sh { hash, network: NetworkKind::Test }
}
x => return Err(ParseError::Base58(base58::Error::InvalidAddressVersion(x))),
};
@ -868,7 +823,7 @@ mod tests {
#[test]
fn test_p2pkh_address_58() {
let hash = "162c5ea71c0b23f5b9022ef047c4a86470a5b070".parse::<PubkeyHash>().unwrap();
let addr = Address::p2pkh(hash, Bitcoin);
let addr = Address::p2pkh(hash, NetworkKind::Main);
assert_eq!(
addr.script_pubkey(),
@ -882,13 +837,13 @@ mod tests {
#[test]
fn test_p2pkh_from_key() {
let key = "048d5141948c1702e8c95f438815794b87f706a8d4cd2bffad1dc1570971032c9b6042a0431ded2478b5c9cf2d81c124a5e57347a3c63ef0e7716cf54d613ba183".parse::<PublicKey>().unwrap();
let addr = Address::p2pkh(key, Bitcoin);
let addr = Address::p2pkh(key, NetworkKind::Main);
assert_eq!(&addr.to_string(), "1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY");
let key = "03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f"
.parse::<PublicKey>()
.unwrap();
let addr = Address::p2pkh(key, Testnet);
let addr = Address::p2pkh(key, NetworkKind::Test);
assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC");
assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
roundtrips(&addr, Testnet);
@ -897,7 +852,7 @@ mod tests {
#[test]
fn test_p2sh_address_58() {
let hash = "162c5ea71c0b23f5b9022ef047c4a86470a5b070".parse::<ScriptHash>().unwrap();
let addr = Address::p2sh_from_hash(hash, Bitcoin);
let addr = Address::p2sh_from_hash(hash, NetworkKind::Main);
assert_eq!(
addr.script_pubkey(),
@ -911,7 +866,7 @@ mod tests {
#[test]
fn test_p2sh_parse() {
let script = ScriptBuf::from_hex("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae").unwrap();
let addr = Address::p2sh(&script, Testnet).unwrap();
let addr = Address::p2sh(&script, NetworkKind::Test).unwrap();
assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr");
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
roundtrips(&addr, Testnet);
@ -920,7 +875,7 @@ mod tests {
#[test]
fn test_p2sh_parse_for_large_script() {
let script = ScriptBuf::from_hex("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123").unwrap();
assert_eq!(Address::p2sh(&script, Testnet), Err(Error::ExcessiveScriptSize));
assert_eq!(Address::p2sh(&script, NetworkKind::Test), Err(Error::ExcessiveScriptSize));
}
#[test]
@ -954,7 +909,7 @@ mod tests {
let key = "026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766"
.parse::<CompressedPublicKey>()
.unwrap();
let addr = Address::p2shwpkh(&key, Bitcoin);
let addr = Address::p2shwpkh(&key, NetworkKind::Main);
assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE");
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
roundtrips(&addr, Bitcoin);
@ -964,7 +919,7 @@ mod tests {
fn test_p2shwsh() {
// stolen from Bitcoin transaction f9ee2be4df05041d0e0a35d7caa3157495ca4f93b233234c9967b6901dacf7a9
let script = ScriptBuf::from_hex("522103e5529d8eaa3d559903adb2e881eb06c86ac2574ffa503c45f4e942e2a693b33e2102e5f10fcdcdbab211e0af6a481f5532536ec61a5fdbf7183770cf8680fe729d8152ae").unwrap();
let addr = Address::p2shwsh(&script, Bitcoin);
let addr = Address::p2shwsh(&script, NetworkKind::Main);
assert_eq!(&addr.to_string(), "36EqgNnsWW94SreZgBWc1ANC6wpFZwirHr");
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
roundtrips(&addr, Bitcoin);

View File

@ -21,7 +21,7 @@ use serde;
use crate::base58;
use crate::crypto::key::{self, Keypair, PrivateKey, CompressedPublicKey};
use crate::internal_macros::impl_bytes_newtype;
use crate::network::Network;
use crate::network::NetworkKind;
use crate::prelude::*;
/// Version bytes for extended public keys on the Bitcoin network.
@ -69,7 +69,7 @@ hash_newtype! {
#[cfg_attr(feature = "std", derive(Debug))]
pub struct Xpriv {
/// The network this key is to be used on
pub network: Network,
pub network: NetworkKind,
/// How many derivations this key is from the master (which is 0)
pub depth: u8,
/// Fingerprint of the parent key (0 for master)
@ -101,8 +101,8 @@ impl fmt::Debug for Xpriv {
/// Extended public key
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
pub struct Xpub {
/// The network this key is to be used on
pub network: Network,
/// The network kind this key is to be used on
pub network: NetworkKind,
/// How many derivations this key is from the master (which is 0)
pub depth: u8,
/// Fingerprint of the parent key
@ -558,13 +558,13 @@ impl From<base58::Error> for Error {
impl Xpriv {
/// Construct a new master key from a seed value
pub fn new_master(network: Network, seed: &[u8]) -> Result<Xpriv, Error> {
pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Result<Xpriv, Error> {
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(b"Bitcoin seed");
hmac_engine.input(seed);
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
Ok(Xpriv {
network,
network: network.into(),
depth: 0,
parent_fingerprint: Default::default(),
child_number: ChildNumber::from_normal_idx(0)?,
@ -645,9 +645,9 @@ impl Xpriv {
}
let network = if data.starts_with(&VERSION_BYTES_MAINNET_PRIVATE) {
Network::Bitcoin
NetworkKind::Main
} else if data.starts_with(&VERSION_BYTES_TESTNETS_PRIVATE) {
Network::Testnet
NetworkKind::Test
} else {
let (b0, b1, b2, b3) = (data[0], data[1], data[2], data[3]);
return Err(Error::UnknownVersion([b0, b1, b2, b3]));
@ -671,8 +671,8 @@ impl Xpriv {
pub fn encode(&self) -> [u8; 78] {
let mut ret = [0; 78];
ret[0..4].copy_from_slice(&match self.network {
Network::Bitcoin => VERSION_BYTES_MAINNET_PRIVATE,
Network::Testnet | Network::Signet | Network::Regtest => VERSION_BYTES_TESTNETS_PRIVATE,
NetworkKind::Main => VERSION_BYTES_MAINNET_PRIVATE,
NetworkKind::Test => VERSION_BYTES_TESTNETS_PRIVATE,
});
ret[4] = self.depth;
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
@ -777,9 +777,9 @@ impl Xpub {
}
let network = if data.starts_with(&VERSION_BYTES_MAINNET_PUBLIC) {
Network::Bitcoin
NetworkKind::Main
} else if data.starts_with(&VERSION_BYTES_TESTNETS_PUBLIC) {
Network::Testnet
NetworkKind::Test
} else {
let (b0, b1, b2, b3) = (data[0], data[1], data[2], data[3]);
return Err(Error::UnknownVersion([b0, b1, b2, b3]));
@ -803,8 +803,8 @@ impl Xpub {
pub fn encode(&self) -> [u8; 78] {
let mut ret = [0; 78];
ret[0..4].copy_from_slice(&match self.network {
Network::Bitcoin => VERSION_BYTES_MAINNET_PUBLIC,
Network::Testnet | Network::Signet | Network::Regtest => VERSION_BYTES_TESTNETS_PUBLIC,
NetworkKind::Main => VERSION_BYTES_MAINNET_PUBLIC,
NetworkKind::Test => VERSION_BYTES_TESTNETS_PUBLIC,
});
ret[4] = self.depth;
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
@ -884,7 +884,6 @@ mod tests {
use super::ChildNumber::{Hardened, Normal};
use super::*;
use crate::network::Network::{self, Bitcoin};
#[test]
fn test_parse_derivation_path() {
@ -965,7 +964,7 @@ mod tests {
fn test_path<C: secp256k1::Signing + secp256k1::Verification>(
secp: &Secp256k1<C>,
network: Network,
network: NetworkKind,
seed: &[u8],
path: DerivationPath,
expected_sk: &str,
@ -1060,32 +1059,32 @@ mod tests {
let seed = hex!("000102030405060708090a0b0c0d0e0f");
// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8");
// m/0h
test_path(&secp, Bitcoin, &seed, "m/0h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h".parse().unwrap(),
"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw");
// m/0h/1
test_path(&secp, Bitcoin, &seed, "m/0h/1".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1".parse().unwrap(),
"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ");
// m/0h/1/2h
test_path(&secp, Bitcoin, &seed, "m/0h/1/2h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h".parse().unwrap(),
"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5");
// m/0h/1/2h/2
test_path(&secp, Bitcoin, &seed, "m/0h/1/2h/2".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h/2".parse().unwrap(),
"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV");
// m/0h/1/2h/2/1000000000
test_path(&secp, Bitcoin, &seed, "m/0h/1/2h/2/1000000000".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h/1/2h/2/1000000000".parse().unwrap(),
"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy");
}
@ -1096,32 +1095,32 @@ mod tests {
let seed = hex!("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542");
// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB");
// m/0
test_path(&secp, Bitcoin, &seed, "m/0".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0".parse().unwrap(),
"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH");
// m/0/2147483647h
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h".parse().unwrap(),
"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a");
// m/0/2147483647h/1
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1".parse().unwrap(),
"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon");
// m/0/2147483647h/1/2147483646h
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1/2147483646h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1/2147483646h".parse().unwrap(),
"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL");
// m/0/2147483647h/1/2147483646h/2
test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1/2147483646h/2".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0/2147483647h/1/2147483646h/2".parse().unwrap(),
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt");
}
@ -1132,12 +1131,12 @@ mod tests {
let seed = hex!("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be");
// m
test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m".parse().unwrap(),
"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6",
"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13");
// m/0h
test_path(&secp, Bitcoin, &seed, "m/0h".parse().unwrap(),
test_path(&secp, NetworkKind::Main, &seed, "m/0h".parse().unwrap(),
"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y");
}
@ -1200,7 +1199,7 @@ mod tests {
}
let xpriv = Xpriv {
network: Network::Bitcoin,
network: NetworkKind::Main,
depth: 0,
parent_fingerprint: Default::default(),
child_number: ChildNumber::Normal { index: 0 },

View File

@ -16,7 +16,7 @@ use io::{Read, Write};
use crate::crypto::ecdsa;
use crate::internal_macros::impl_asref_push_bytes;
use crate::network::Network;
use crate::network::NetworkKind;
use crate::prelude::*;
use crate::taproot::{TapNodeHash, TapTweakHash};
use crate::{base58, io};
@ -390,8 +390,8 @@ impl From<&CompressedPublicKey> for WPubkeyHash {
pub struct PrivateKey {
/// Whether this private key should be serialized as compressed
pub compressed: bool,
/// The network on which this key should be used
pub network: Network,
/// The network kind on which this key should be used
pub network: NetworkKind,
/// The actual ECDSA key
pub inner: secp256k1::SecretKey,
}
@ -400,20 +400,23 @@ impl PrivateKey {
/// Constructs new compressed ECDSA private key using the secp256k1 algorithm and
/// a secure random number generator.
#[cfg(feature = "rand-std")]
pub fn generate(network: Network) -> PrivateKey {
pub fn generate(network: impl Into<NetworkKind>) -> PrivateKey {
let secret_key = secp256k1::SecretKey::new(&mut rand::thread_rng());
PrivateKey::new(secret_key, network)
PrivateKey::new(secret_key, network.into())
}
/// Constructs compressed ECDSA private key from the provided generic Secp256k1 private key
/// and the specified network
pub fn new(key: secp256k1::SecretKey, network: Network) -> PrivateKey {
PrivateKey { compressed: true, network, inner: key }
pub fn new(key: secp256k1::SecretKey, network: impl Into<NetworkKind>) -> PrivateKey {
PrivateKey { compressed: true, network: network.into(), inner: key }
}
/// Constructs uncompressed (legacy) ECDSA private key from the provided generic Secp256k1
/// private key and the specified network
pub fn new_uncompressed(key: secp256k1::SecretKey, network: Network) -> PrivateKey {
PrivateKey { compressed: false, network, inner: key }
pub fn new_uncompressed(
key: secp256k1::SecretKey,
network: impl Into<NetworkKind>,
) -> PrivateKey {
PrivateKey { compressed: false, network: network.into(), inner: key }
}
/// Creates a public key from this private key
@ -428,17 +431,16 @@ impl PrivateKey {
pub fn to_bytes(self) -> Vec<u8> { self.inner[..].to_vec() }
/// Deserialize a private key from a slice
pub fn from_slice(data: &[u8], network: Network) -> Result<PrivateKey, Error> {
pub fn from_slice(data: &[u8], network: impl Into<NetworkKind>) -> Result<PrivateKey, Error> {
Ok(PrivateKey::new(secp256k1::SecretKey::from_slice(data)?, network))
}
/// Format the private key to WIF format.
#[rustfmt::skip]
pub fn fmt_wif(&self, fmt: &mut dyn fmt::Write) -> fmt::Result {
let mut ret = [0; 34];
ret[0] = match self.network {
Network::Bitcoin => 128,
Network::Testnet | Network::Signet | Network::Regtest => 239,
};
ret[0] = if self.network.is_mainnet() { 128 } else { 239 };
ret[1..33].copy_from_slice(&self.inner[..]);
let privkey = if self.compressed {
ret[33] = 1;
@ -470,8 +472,8 @@ impl PrivateKey {
};
let network = match data[0] {
128 => Network::Bitcoin,
239 => Network::Testnet,
128 => NetworkKind::Main,
239 => NetworkKind::Test,
x => {
return Err(Error::Base58(base58::Error::InvalidAddressVersion(x)));
}
@ -953,14 +955,14 @@ mod tests {
use super::*;
use crate::address::Address;
use crate::network::Network::{Bitcoin, Testnet};
use crate::network::NetworkKind;
#[test]
fn test_key_derivation() {
// testnet compressed
let sk =
PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap();
assert_eq!(sk.network, Testnet);
assert_eq!(sk.network, NetworkKind::Test);
assert!(sk.compressed);
assert_eq!(&sk.to_wif(), "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy");
@ -977,7 +979,7 @@ mod tests {
// mainnet uncompressed
let sk =
PrivateKey::from_wif("5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3").unwrap();
assert_eq!(sk.network, Bitcoin);
assert_eq!(sk.network, NetworkKind::Main);
assert!(!sk.compressed);
assert_eq!(&sk.to_wif(), "5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3");
@ -1295,7 +1297,7 @@ mod tests {
fn private_key_debug_is_obfuscated() {
let sk =
PrivateKey::from_str("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap();
let want = "PrivateKey { compressed: true, network: Testnet, inner: SecretKey(#32014e414fdce702) }";
let want = "PrivateKey { compressed: true, network: Test, inner: SecretKey(#32014e414fdce702) }";
let got = format!("{:?}", sk);
assert_eq!(got, want)
}

View File

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

View File

@ -31,6 +31,33 @@ use crate::constants::ChainHash;
use crate::p2p::Magic;
use crate::prelude::{String, ToOwned};
/// What kind of network we are on.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum NetworkKind {
/// The Bitcoin mainnet network.
Main,
/// Some kind of testnet network.
Test,
}
// We explicitly do not provide `is_testnet`, using `!network.is_mainnet()` is less
// ambiguous due to confusion caused by signet/testnet/regtest.
impl NetworkKind {
/// Returns true if this is real mainnet bitcoin.
pub fn is_mainnet(&self) -> bool { *self == NetworkKind::Main }
}
impl From<Network> for NetworkKind {
fn from(n: Network) -> Self {
use Network::*;
match n {
Bitcoin => NetworkKind::Main,
Testnet | Signet | Regtest => NetworkKind::Test,
}
}
}
/// The cryptocurrency network to act on.
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

View File

@ -1014,7 +1014,7 @@ mod tests {
use crate::blockdata::script::ScriptBuf;
use crate::blockdata::transaction::{self, OutPoint, Sequence, Transaction, TxIn, TxOut};
use crate::blockdata::witness::Witness;
use crate::network::Network::Bitcoin;
use crate::network::NetworkKind;
use crate::psbt::map::{Input, Output};
use crate::psbt::raw;
use crate::psbt::serialize::{Deserialize, Serialize};
@ -1151,7 +1151,7 @@ mod tests {
let mut hd_keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = Default::default();
let mut sk: Xpriv = Xpriv::new_master(Bitcoin, &seed).unwrap();
let mut sk: Xpriv = Xpriv::new_master(NetworkKind::Main, &seed).unwrap();
let fprint = sk.fingerprint(secp);
@ -1926,7 +1926,7 @@ mod tests {
let secp = Secp256k1::new();
let sk = SecretKey::new(&mut thread_rng());
let priv_key = PrivateKey::new(sk, crate::Network::Regtest);
let priv_key = PrivateKey::new(sk, NetworkKind::Test);
let pk = PublicKey::from_private_key(&secp, &priv_key);
(priv_key, pk, secp)

View File

@ -226,7 +226,7 @@ mod tests {
use secp256k1;
use crate::{Address, AddressType, Network};
use crate::{Address, AddressType, Network, NetworkKind};
let secp = secp256k1::Secp256k1::new();
let message = "rust-bitcoin MessageSignature test";
@ -243,12 +243,14 @@ mod tests {
.try_into()
.expect("compressed was set to true");
let p2pkh = Address::p2pkh(pubkey, NetworkKind::Main);
assert_eq!(signature2.is_signed_by_address(&secp, &p2pkh, msg_hash), Ok(true));
let p2wpkh = Address::p2wpkh(&pubkey, Network::Bitcoin);
assert_eq!(
signature2.is_signed_by_address(&secp, &p2wpkh, msg_hash),
Err(MessageSignatureError::UnsupportedAddressType(AddressType::P2wpkh))
);
let p2shwpkh = Address::p2shwpkh(&pubkey, Network::Bitcoin);
let p2shwpkh = Address::p2shwpkh(&pubkey, NetworkKind::Main);
assert_eq!(
signature2.is_signed_by_address(&secp, &p2shwpkh, msg_hash),
Err(MessageSignatureError::UnsupportedAddressType(AddressType::P2sh))
@ -266,7 +268,7 @@ mod tests {
use secp256k1;
use crate::crypto::key::PublicKey;
use crate::{Address, Network};
use crate::{Address, NetworkKind};
let secp = secp256k1::Secp256k1::new();
let message = "a different message from what was signed";
@ -283,7 +285,7 @@ mod tests {
PublicKey::from_slice(&BASE64_STANDARD.decode(pubkey_base64).expect("base64 string"))
.expect("pubkey slice");
let p2pkh = Address::p2pkh(pubkey, Network::Bitcoin);
let p2pkh = Address::p2pkh(pubkey, NetworkKind::Main);
assert_eq!(signature.is_signed_by_address(&secp, &p2pkh, msg_hash), Ok(false));
}
}

View File

@ -13,12 +13,10 @@ use bitcoin::psbt::{Psbt, PsbtSighashType};
use bitcoin::script::PushBytes;
use bitcoin::secp256k1::{self, Secp256k1};
use bitcoin::{
absolute, Amount, Denomination, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence,
Transaction, TxIn, TxOut, Witness,
absolute, Amount, Denomination, NetworkKind, OutPoint, PrivateKey, PublicKey, ScriptBuf,
Sequence, Transaction, TxIn, TxOut, Witness,
};
const NETWORK: Network = Network::Testnet;
#[track_caller]
fn hex_psbt(s: &str) -> Psbt {
let v: Vec<u8> = Vec::from_hex(s).expect("valid hex digits");
@ -124,7 +122,7 @@ fn build_extended_private_key() -> Xpriv {
let xpriv = Xpriv::from_str(extended_private_key).unwrap();
let sk = PrivateKey::from_wif(seed).unwrap();
let seeded = Xpriv::new_master(NETWORK, &sk.inner.secret_bytes()).unwrap();
let seeded = Xpriv::new_master(NetworkKind::Test, &sk.inner.secret_bytes()).unwrap();
assert_eq!(xpriv, seeded);
xpriv

View File

@ -38,7 +38,7 @@ use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder};
use bitcoin::{
ecdsa, transaction, Address, Amount, Block, Network, OutPoint, PrivateKey, PublicKey,
ecdsa, transaction, Address, Amount, Block, NetworkKind, OutPoint, PrivateKey, PublicKey,
ScriptBuf, Sequence, Target, Transaction, TxIn, TxOut, Txid, Work,
};
@ -145,7 +145,7 @@ fn serde_regression_witness() {
fn serde_regression_address() {
let s = include_str!("data/serde/public_key_hex");
let pk = PublicKey::from_str(s.trim()).unwrap();
let addr = Address::p2pkh(pk, Network::Bitcoin);
let addr = Address::p2pkh(pk, NetworkKind::Main);
let got = serialize(&addr).unwrap();
let want = include_bytes!("data/serde/address_bincode") as &[_];