Use Amount type for TxOut value field

This commit is contained in:
yancy 2023-04-24 16:47:55 +02:00
parent ac664106be
commit d57ec019d5
10 changed files with 91 additions and 85 deletions

View File

@ -192,11 +192,8 @@ impl WatchOnly {
witness: Witness::default(), witness: Witness::default(),
}], }],
output: vec![ output: vec![
TxOut { value: to_amount.to_sat(), script_pubkey: to_address.script_pubkey() }, TxOut { value: to_amount, script_pubkey: to_address.script_pubkey() },
TxOut { TxOut { value: change_amount, script_pubkey: change_address.script_pubkey() },
value: change_amount.to_sat(),
script_pubkey: change_address.script_pubkey(),
},
], ],
}; };
@ -282,7 +279,7 @@ fn previous_output() -> TxOut {
.expect("failed to parse input utxo scriptPubkey"); .expect("failed to parse input utxo scriptPubkey");
let amount = Amount::from_str(INPUT_UTXO_VALUE).expect("failed to parse input utxo value"); let amount = Amount::from_str(INPUT_UTXO_VALUE).expect("failed to parse input utxo value");
TxOut { value: amount.to_sat(), script_pubkey } TxOut { value: amount, script_pubkey }
} }
struct Error(Box<dyn std::error::Error>); struct Error(Box<dyn std::error::Error>);

View File

@ -40,7 +40,7 @@ const UTXO_SCRIPT_PUBKEY: &str =
"5120be27fa8b1f5278faf82cab8da23e8761f8f9bd5d5ebebbb37e0e12a70d92dd16"; "5120be27fa8b1f5278faf82cab8da23e8761f8f9bd5d5ebebbb37e0e12a70d92dd16";
const UTXO_PUBKEY: &str = "a6ac32163539c16b6b5dbbca01b725b8e8acaa5f821ba42c80e7940062140d19"; const UTXO_PUBKEY: &str = "a6ac32163539c16b6b5dbbca01b725b8e8acaa5f821ba42c80e7940062140d19";
const UTXO_MASTER_FINGERPRINT: &str = "e61b318f"; const UTXO_MASTER_FINGERPRINT: &str = "e61b318f";
const ABSOLUTE_FEES_IN_SATS: u64 = 1000; const ABSOLUTE_FEES_IN_SATS: Amount = Amount::from_sat(1_000);
// UTXO_1 will be used for spending example 1 // UTXO_1 will be used for spending example 1
const UTXO_1: P2trUtxo = P2trUtxo { const UTXO_1: P2trUtxo = P2trUtxo {
@ -49,7 +49,7 @@ const UTXO_1: P2trUtxo = P2trUtxo {
script_pubkey: UTXO_SCRIPT_PUBKEY, script_pubkey: UTXO_SCRIPT_PUBKEY,
pubkey: UTXO_PUBKEY, pubkey: UTXO_PUBKEY,
master_fingerprint: UTXO_MASTER_FINGERPRINT, master_fingerprint: UTXO_MASTER_FINGERPRINT,
amount_in_sats: 50 * COIN_VALUE, // 50 BTC amount_in_sats: Amount::from_sat(50 * 100_000_000), // 50 BTC
derivation_path: BIP86_DERIVATION_PATH, derivation_path: BIP86_DERIVATION_PATH,
}; };
@ -60,7 +60,7 @@ const UTXO_2: P2trUtxo = P2trUtxo {
script_pubkey: UTXO_SCRIPT_PUBKEY, script_pubkey: UTXO_SCRIPT_PUBKEY,
pubkey: UTXO_PUBKEY, pubkey: UTXO_PUBKEY,
master_fingerprint: UTXO_MASTER_FINGERPRINT, master_fingerprint: UTXO_MASTER_FINGERPRINT,
amount_in_sats: 50 * COIN_VALUE, amount_in_sats: Amount::from_sat(50 * 100_000_000), // 50 BTC
derivation_path: BIP86_DERIVATION_PATH, derivation_path: BIP86_DERIVATION_PATH,
}; };
@ -71,7 +71,7 @@ const UTXO_3: P2trUtxo = P2trUtxo {
script_pubkey: UTXO_SCRIPT_PUBKEY, script_pubkey: UTXO_SCRIPT_PUBKEY,
pubkey: UTXO_PUBKEY, pubkey: UTXO_PUBKEY,
master_fingerprint: UTXO_MASTER_FINGERPRINT, master_fingerprint: UTXO_MASTER_FINGERPRINT,
amount_in_sats: 50 * COIN_VALUE, amount_in_sats: Amount::from_sat(50 * 100_000_000), // 50 BTC
derivation_path: BIP86_DERIVATION_PATH, derivation_path: BIP86_DERIVATION_PATH,
}; };
@ -80,7 +80,6 @@ use std::str::FromStr;
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint}; use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint};
use bitcoin::consensus::encode; use bitcoin::consensus::encode;
use bitcoin::constants::COIN_VALUE;
use bitcoin::key::{TapTweak, XOnlyPublicKey}; use bitcoin::key::{TapTweak, XOnlyPublicKey};
use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP}; use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP};
use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType}; use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType};
@ -105,7 +104,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let change_address = let change_address =
Address::from_str("bcrt1pz449kexzydh2kaypatup5ultru3ej284t6eguhnkn6wkhswt0l7q3a7j76")? Address::from_str("bcrt1pz449kexzydh2kaypatup5ultru3ej284t6eguhnkn6wkhswt0l7q3a7j76")?
.require_network(Network::Regtest)?; .require_network(Network::Regtest)?;
let amount_to_send_in_sats = COIN_VALUE; let amount_to_send_in_sats = Amount::ONE_BTC;
let change_amount = UTXO_1 let change_amount = UTXO_1
.amount_in_sats .amount_in_sats
.checked_sub(amount_to_send_in_sats) .checked_sub(amount_to_send_in_sats)
@ -216,7 +215,7 @@ struct P2trUtxo<'a> {
script_pubkey: &'a str, script_pubkey: &'a str,
pubkey: &'a str, pubkey: &'a str,
master_fingerprint: &'a str, master_fingerprint: &'a str,
amount_in_sats: u64, amount_in_sats: Amount,
derivation_path: &'a str, derivation_path: &'a str,
} }
@ -259,9 +258,7 @@ fn generate_bip86_key_spend_tx(
witness_utxo: { witness_utxo: {
let script_pubkey = ScriptBuf::from_hex(input_utxo.script_pubkey) let script_pubkey = ScriptBuf::from_hex(input_utxo.script_pubkey)
.expect("failed to parse input utxo scriptPubkey"); .expect("failed to parse input utxo scriptPubkey");
let amount = Amount::from_sat(from_amount); Some(TxOut { value: from_amount, script_pubkey })
Some(TxOut { value: amount.to_sat(), script_pubkey })
}, },
tap_key_origins: origins, tap_key_origins: origins,
..Default::default() ..Default::default()
@ -448,9 +445,7 @@ impl BenefactorWallet {
let input = Input { let input = Input {
witness_utxo: { witness_utxo: {
let script_pubkey = script_pubkey; let script_pubkey = script_pubkey;
let amount = Amount::from_sat(value); Some(TxOut { value, script_pubkey })
Some(TxOut { value: amount.to_sat(), script_pubkey })
}, },
tap_key_origins: origins, tap_key_origins: origins,
tap_merkle_root: taproot_spend_info.merkle_root(), tap_merkle_root: taproot_spend_info.merkle_root(),
@ -594,9 +589,9 @@ impl BenefactorWallet {
let input = Input { let input = Input {
witness_utxo: { witness_utxo: {
let script_pubkey = output_script_pubkey; let script_pubkey = output_script_pubkey;
let amount = Amount::from_sat(output_value); let amount = output_value;
Some(TxOut { value: amount.to_sat(), script_pubkey }) Some(TxOut { value: amount, script_pubkey })
}, },
tap_key_origins: origins, tap_key_origins: origins,
tap_merkle_root: taproot_spend_info.merkle_root(), tap_merkle_root: taproot_spend_info.merkle_root(),

View File

@ -11,6 +11,8 @@ use core::fmt::{self, Write};
use core::str::FromStr; use core::str::FromStr;
use core::{default, ops}; use core::{default, ops};
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::io;
use crate::prelude::*; use crate::prelude::*;
/// A set of denominations in which amounts can be expressed. /// A set of denominations in which amounts can be expressed.
@ -483,6 +485,8 @@ fn fmt_satoshi_in(
/// the checked arithmetic methods. /// the checked arithmetic methods.
/// ///
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
pub struct Amount(u64); pub struct Amount(u64);
impl Amount { impl Amount {
@ -660,6 +664,20 @@ impl Amount {
} }
} }
impl Decodable for Amount {
#[inline]
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(Amount(Decodable::consensus_decode(r)?))
}
}
impl Encodable for Amount {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.0.consensus_encode(w)
}
}
impl default::Default for Amount { impl default::Default for Amount {
fn default() -> Self { Amount::ZERO } fn default() -> Self { Amount::ZERO }
} }

View File

@ -378,7 +378,8 @@ mod test {
use crate::consensus::encode::{deserialize, serialize}; use crate::consensus::encode::{deserialize, serialize};
use crate::hash_types::TxMerkleNode; use crate::hash_types::TxMerkleNode;
use crate::{ use crate::{
CompactTarget, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, Amount, CompactTarget, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid,
Witness,
}; };
fn dummy_tx(nonce: &[u8]) -> Transaction { fn dummy_tx(nonce: &[u8]) -> Transaction {
@ -391,7 +392,7 @@ mod test {
sequence: Sequence(1), sequence: Sequence(1),
witness: Witness::new(), witness: Witness::new(),
}], }],
output: vec![TxOut { value: 1, script_pubkey: ScriptBuf::new() }], output: vec![TxOut { value: Amount::ONE_SAT, script_pubkey: ScriptBuf::new() }],
} }
} }

View File

@ -22,9 +22,8 @@ use crate::blockdata::witness::Witness;
use crate::internal_macros::impl_bytes_newtype; use crate::internal_macros::impl_bytes_newtype;
use crate::network::constants::Network; use crate::network::constants::Network;
use crate::pow::CompactTarget; use crate::pow::CompactTarget;
use crate::Amount;
/// How many satoshis are in "one bitcoin".
pub const COIN_VALUE: u64 = 100_000_000;
/// 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;
/// How many blocks between diffchanges. /// How many blocks between diffchanges.
@ -61,11 +60,6 @@ pub const MAX_SCRIPTNUM_VALUE: u32 = 0x80000000; // 2^31
/// Number of blocks needed for an output from a coinbase transaction to be spendable. /// Number of blocks needed for an output from a coinbase transaction to be spendable.
pub const COINBASE_MATURITY: u32 = 100; pub const COINBASE_MATURITY: u32 = 100;
/// The maximum value allowed in an output (useful for sanity checking,
/// since keeping everything below this value should prevent overflows
/// if you are doing anything remotely sane with monetary values).
pub const MAX_MONEY: u64 = 21_000_000 * COIN_VALUE;
/// 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() -> Transaction {
// Base // Base
@ -93,7 +87,7 @@ fn bitcoin_genesis_tx() -> Transaction {
let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
let out_script = let out_script =
script::Builder::new().push_slice(script_bytes).push_opcode(OP_CHECKSIG).into_script(); script::Builder::new().push_slice(script_bytes).push_opcode(OP_CHECKSIG).into_script();
ret.output.push(TxOut { value: 50 * COIN_VALUE, script_pubkey: out_script }); ret.output.push(TxOut { value: Amount::from_sat(50 * 100_000_000), script_pubkey: out_script });
// end // end
ret ret
@ -198,6 +192,8 @@ impl ChainHash {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use core::str::FromStr;
use super::*; use super::*;
use crate::blockdata::locktime::absolute; use crate::blockdata::locktime::absolute;
use crate::consensus::encode::serialize; use crate::consensus::encode::serialize;
@ -219,7 +215,7 @@ mod test {
assert_eq!(gen.output.len(), 1); assert_eq!(gen.output.len(), 1);
assert_eq!(serialize(&gen.output[0].script_pubkey), assert_eq!(serialize(&gen.output[0].script_pubkey),
hex!("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac")); hex!("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac"));
assert_eq!(gen.output[0].value, 50 * COIN_VALUE); assert_eq!(gen.output[0].value, Amount::from_str("50 BTC").unwrap());
assert_eq!(gen.lock_time, absolute::LockTime::ZERO); assert_eq!(gen.lock_time, absolute::LockTime::ZERO);
assert_eq!( assert_eq!(

View File

@ -35,7 +35,7 @@ use crate::prelude::*;
#[cfg(doc)] #[cfg(doc)]
use crate::sighash::{EcdsaSighashType, TapSighashType}; use crate::sighash::{EcdsaSighashType, TapSighashType};
use crate::string::FromHexStr; use crate::string::FromHexStr;
use crate::{io, VarInt}; use crate::{io, Amount, VarInt};
/// A reference to a transaction output. /// A reference to a transaction output.
/// ///
@ -478,7 +478,7 @@ impl_parse_str_from_int_infallible!(Sequence, u32, from_consensus);
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
pub struct TxOut { pub struct TxOut {
/// The value of the output, in satoshis. /// The value of the output, in satoshis.
pub value: u64, pub value: Amount,
/// The script which must be satisfied for the output to be spent. /// The script which must be satisfied for the output to be spent.
pub script_pubkey: ScriptBuf, pub script_pubkey: ScriptBuf,
} }
@ -512,7 +512,7 @@ impl TxOut {
let dust_amount = (len as u64) * 3; let dust_amount = (len as u64) * 3;
TxOut { TxOut {
value: dust_amount + 1, // minimal non-dust amount is one higher than dust amount value: Amount::from_sat(dust_amount + 1), // minimal non-dust amount is one higher than dust amount
script_pubkey, script_pubkey,
} }
} }
@ -520,7 +520,9 @@ impl TxOut {
// This is used as a "null txout" in consensus signing code. // This is used as a "null txout" in consensus signing code.
impl Default for TxOut { impl Default for TxOut {
fn default() -> TxOut { TxOut { value: 0xffffffffffffffff, script_pubkey: ScriptBuf::new() } } fn default() -> TxOut {
TxOut { value: Amount::from_sat(0xffffffffffffffff), script_pubkey: ScriptBuf::new() }
}
} }
/// Result of [`Transaction::encode_signing_data_to`]. /// Result of [`Transaction::encode_signing_data_to`].
@ -962,12 +964,7 @@ impl Transaction {
let flags: u32 = flags.into(); let flags: u32 = flags.into();
for (idx, input) in self.input.iter().enumerate() { for (idx, input) in self.input.iter().enumerate() {
if let Some(output) = spent(&input.previous_output) { if let Some(output) = spent(&input.previous_output) {
output.script_pubkey.verify_with_flags( output.script_pubkey.verify_with_flags(idx, output.value, tx.as_slice(), flags)?;
idx,
crate::Amount::from_sat(output.value),
tx.as_slice(),
flags,
)?;
} else { } else {
return Err(script::Error::UnknownSpentOutput(input.previous_output)); return Err(script::Error::UnknownSpentOutput(input.previous_output));
} }

View File

@ -22,7 +22,7 @@ use crate::consensus::{encode, Encodable};
use crate::error::impl_std_error; use crate::error::impl_std_error;
use crate::prelude::*; use crate::prelude::*;
use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX}; use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX};
use crate::{io, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut}; use crate::{io, Amount, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut};
/// Used for signature hash for invalid use of SIGHASH_SINGLE. /// Used for signature hash for invalid use of SIGHASH_SINGLE.
#[rustfmt::skip] #[rustfmt::skip]
@ -751,7 +751,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
mut writer: Write, mut writer: Write,
input_index: usize, input_index: usize,
script_code: &Script, script_code: &Script,
value: u64, value: Amount,
sighash_type: EcdsaSighashType, sighash_type: EcdsaSighashType,
) -> Result<(), Error> { ) -> Result<(), Error> {
let zero_hash = sha256d::Hash::all_zeros(); let zero_hash = sha256d::Hash::all_zeros();
@ -810,7 +810,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
&mut self, &mut self,
input_index: usize, input_index: usize,
script_code: &Script, script_code: &Script,
value: u64, value: Amount,
sighash_type: EcdsaSighashType, sighash_type: EcdsaSighashType,
) -> Result<SegwitV0Sighash, Error> { ) -> Result<SegwitV0Sighash, Error> {
let mut enc = SegwitV0Sighash::engine(); let mut enc = SegwitV0Sighash::engine();
@ -1062,7 +1062,7 @@ impl<R: BorrowMut<Transaction>> SighashCache<R> {
/// ///
/// This allows in-line signing such as /// This allows in-line signing such as
/// ``` /// ```
/// use bitcoin::{absolute, Transaction, Script}; /// use bitcoin::{absolute, Amount, Transaction, Script};
/// use bitcoin::sighash::{EcdsaSighashType, SighashCache}; /// use bitcoin::sighash::{EcdsaSighashType, SighashCache};
/// ///
/// let mut tx_to_sign = Transaction { version: 2, lock_time: absolute::LockTime::ZERO, input: Vec::new(), output: Vec::new() }; /// let mut tx_to_sign = Transaction { version: 2, lock_time: absolute::LockTime::ZERO, input: Vec::new(), output: Vec::new() };
@ -1071,7 +1071,7 @@ impl<R: BorrowMut<Transaction>> SighashCache<R> {
/// let mut sig_hasher = SighashCache::new(&mut tx_to_sign); /// let mut sig_hasher = SighashCache::new(&mut tx_to_sign);
/// for inp in 0..input_count { /// for inp in 0..input_count {
/// let prevout_script = Script::empty(); /// let prevout_script = Script::empty();
/// let _sighash = sig_hasher.segwit_signature_hash(inp, prevout_script, 42, EcdsaSighashType::All); /// let _sighash = sig_hasher.segwit_signature_hash(inp, prevout_script, Amount::ONE_SAT, EcdsaSighashType::All);
/// // ... sign the sighash /// // ... sign the sighash
/// sig_hasher.witness_mut(inp).unwrap().push(&Vec::new()); /// sig_hasher.witness_mut(inp).unwrap().push(&Vec::new());
/// } /// }
@ -1468,7 +1468,7 @@ mod tests {
#[serde(rename = "scriptPubKey")] #[serde(rename = "scriptPubKey")]
script_pubkey: ScriptBuf, script_pubkey: ScriptBuf,
#[serde(rename = "amountSats")] #[serde(rename = "amountSats")]
value: u64, value: Amount,
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
@ -1685,7 +1685,7 @@ mod tests {
let witness_script = let witness_script =
p2pkh_hex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"); p2pkh_hex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357");
let value = 600_000_000; let value = Amount::from_sat(600_000_000);
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
@ -1726,7 +1726,7 @@ mod tests {
let witness_script = let witness_script =
p2pkh_hex("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873"); p2pkh_hex("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873");
let value = 1_000_000_000; let value = Amount::from_sat(1_000_000_000);
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
@ -1773,7 +1773,7 @@ mod tests {
56ae", 56ae",
) )
.unwrap(); .unwrap();
let value = 987654321; let value = Amount::from_sat(987_654_321);
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(

View File

@ -459,11 +459,11 @@ impl PartiallySignedTransaction {
pub fn fee(&self) -> Result<Amount, Error> { pub fn fee(&self) -> Result<Amount, Error> {
let mut inputs: u64 = 0; let mut inputs: u64 = 0;
for utxo in self.iter_funding_utxos() { for utxo in self.iter_funding_utxos() {
inputs = inputs.checked_add(utxo?.value).ok_or(Error::FeeOverflow)?; inputs = inputs.checked_add(utxo?.value.to_sat()).ok_or(Error::FeeOverflow)?;
} }
let mut outputs: u64 = 0; let mut outputs: u64 = 0;
for out in &self.unsigned_tx.output { for out in &self.unsigned_tx.output {
outputs = outputs.checked_add(out.value).ok_or(Error::FeeOverflow)?; outputs = outputs.checked_add(out.value.to_sat()).ok_or(Error::FeeOverflow)?;
} }
inputs.checked_sub(outputs).map(Amount::from_sat).ok_or(Error::NegativeFee) inputs.checked_sub(outputs).map(Amount::from_sat).ok_or(Error::NegativeFee)
} }
@ -922,14 +922,14 @@ mod tests {
}], }],
output: vec![ output: vec![
TxOut { TxOut {
value: 99999699, value: Amount::from_sat(99_999_699),
script_pubkey: ScriptBuf::from_hex( script_pubkey: ScriptBuf::from_hex(
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac", "76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
) )
.unwrap(), .unwrap(),
}, },
TxOut { TxOut {
value: 100000000, value: Amount::from_sat(100_000_000),
script_pubkey: ScriptBuf::from_hex( script_pubkey: ScriptBuf::from_hex(
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787", "a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
) )
@ -995,7 +995,7 @@ mod tests {
)]), )]),
}], }],
output: vec![TxOut { output: vec![TxOut {
value: 190303501938, value: Amount::from_sat(190_303_501_938),
script_pubkey: ScriptBuf::from_hex( script_pubkey: ScriptBuf::from_hex(
"a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587", "a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
) )
@ -1046,7 +1046,7 @@ mod tests {
Input { Input {
non_witness_utxo: Some(tx), non_witness_utxo: Some(tx),
witness_utxo: Some(TxOut { witness_utxo: Some(TxOut {
value: 190303501938, value: Amount::from_sat(190_303_501_938),
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(), script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
}), }),
sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::<PsbtSighashType>().unwrap()), sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::<PsbtSighashType>().unwrap()),
@ -1190,11 +1190,11 @@ mod tests {
], ],
output: vec![ output: vec![
TxOut { TxOut {
value: 99999699, value: Amount::from_sat(99_999_699),
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(), script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
}, },
TxOut { TxOut {
value: 100000000, value: Amount::from_sat(100_000_000),
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(), script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
}, },
], ],
@ -1237,11 +1237,11 @@ mod tests {
], ],
output: vec![ output: vec![
TxOut { TxOut {
value: 200000000, value: Amount::from_sat(200_000_000),
script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(), script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
}, },
TxOut { TxOut {
value: 190303501938, value: Amount::from_sat(190_303_501_938),
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(), script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
}, },
], ],
@ -1522,11 +1522,11 @@ mod tests {
], ],
output: vec![ output: vec![
TxOut { TxOut {
value: 99999699, value: Amount::from_sat(99_999_699),
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(), script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
}, },
TxOut { TxOut {
value: 100000000, value: Amount::from_sat(100_000_000),
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(), script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
}, },
], ],
@ -1569,11 +1569,11 @@ mod tests {
], ],
output: vec![ output: vec![
TxOut { TxOut {
value: 200000000, value: Amount::from_sat(200_000_000),
script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(), script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
}, },
TxOut { TxOut {
value: 190303501938, value: Amount::from_sat(190_303_501_938),
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(), script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
}, },
], ],
@ -1670,9 +1670,9 @@ mod tests {
#[test] #[test]
fn test_fee() { fn test_fee() {
let output_0_val = 99999699; let output_0_val = Amount::from_sat(99_999_699);
let output_1_val = 100000000; let output_1_val = Amount::from_sat(100_000_000);
let prev_output_val = 200000000; let prev_output_val = Amount::from_sat(200_000_000);
let mut t = PartiallySignedTransaction { let mut t = PartiallySignedTransaction {
unsigned_tx: Transaction { unsigned_tx: Transaction {
@ -1733,7 +1733,7 @@ mod tests {
..Default::default() ..Default::default()
}, },
TxOut { TxOut {
value: 190303501938, value: Amount::from_sat(190_303_501_938),
..Default::default() ..Default::default()
}, },
], ],
@ -1752,7 +1752,7 @@ mod tests {
}; };
assert_eq!( assert_eq!(
t.fee().expect("fee calculation"), t.fee().expect("fee calculation"),
Amount::from_sat(prev_output_val - (output_0_val + output_1_val)) prev_output_val - (output_0_val + output_1_val)
); );
// no previous output // no previous output
let mut t2 = t.clone(); let mut t2 = t.clone();
@ -1769,8 +1769,8 @@ mod tests {
e => panic!("unexpected error: {:?}", e), e => panic!("unexpected error: {:?}", e),
} }
// overflow // overflow
t.unsigned_tx.output[0].value = u64::MAX; t.unsigned_tx.output[0].value = Amount::MAX;
t.unsigned_tx.output[1].value = u64::MAX; t.unsigned_tx.output[1].value = Amount::MAX;
match t.fee().unwrap_err() { match t.fee().unwrap_err() {
Error::FeeOverflow => {} Error::FeeOverflow => {}
e => panic!("unexpected error: {:?}", e), e => panic!("unexpected error: {:?}", e),
@ -1801,7 +1801,7 @@ mod tests {
// First input we can spend. See comment above on key_map for why we use defaults here. // First input we can spend. See comment above on key_map for why we use defaults here.
let txout_wpkh = TxOut { let txout_wpkh = TxOut {
value: 10, value: Amount::from_sat(10),
script_pubkey: ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::hash(&pk.to_bytes())), script_pubkey: ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::hash(&pk.to_bytes())),
}; };
psbt.inputs[0].witness_utxo = Some(txout_wpkh); psbt.inputs[0].witness_utxo = Some(txout_wpkh);
@ -1813,8 +1813,10 @@ mod tests {
// Second input is unspendable by us e.g., from another wallet that supports future upgrades. // Second input is unspendable by us e.g., from another wallet that supports future upgrades.
let unknown_prog = let unknown_prog =
WitnessProgram::new(crate::address::WitnessVersion::V4, vec![0xaa; 34]).unwrap(); WitnessProgram::new(crate::address::WitnessVersion::V4, vec![0xaa; 34]).unwrap();
let txout_unknown_future = let txout_unknown_future = TxOut {
TxOut { value: 10, script_pubkey: ScriptBuf::new_witness_program(&unknown_prog) }; value: Amount::from_sat(10),
script_pubkey: ScriptBuf::new_witness_program(&unknown_prog),
};
psbt.inputs[1].witness_utxo = Some(txout_unknown_future); psbt.inputs[1].witness_utxo = Some(txout_unknown_future);
let sigs = psbt.sign(&key_map, &secp).unwrap(); let sigs = psbt.sign(&key_map, &secp).unwrap();

View File

@ -188,15 +188,13 @@ fn create_transaction() -> Transaction {
output: vec![ output: vec![
TxOut { TxOut {
value: Amount::from_str_in(output_0.amount, Denomination::Bitcoin) value: Amount::from_str_in(output_0.amount, Denomination::Bitcoin)
.expect("failed to parse amount") .expect("failed to parse amount"),
.to_sat(),
script_pubkey: ScriptBuf::from_hex(output_0.script_pubkey) script_pubkey: ScriptBuf::from_hex(output_0.script_pubkey)
.expect("failed to parse script"), .expect("failed to parse script"),
}, },
TxOut { TxOut {
value: Amount::from_str_in(output_1.amount, Denomination::Bitcoin) value: Amount::from_str_in(output_1.amount, Denomination::Bitcoin)
.expect("failed to parse amount") .expect("failed to parse amount"),
.to_sat(),
script_pubkey: ScriptBuf::from_hex(output_1.script_pubkey) script_pubkey: ScriptBuf::from_hex(output_1.script_pubkey)
.expect("failed to parse script"), .expect("failed to parse script"),
}, },

View File

@ -38,8 +38,8 @@ use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder}; use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder};
use bitcoin::{ use bitcoin::{
ecdsa, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target, ecdsa, Address, Amount, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence,
Transaction, TxIn, TxOut, Txid, Work, Target, Transaction, TxIn, TxOut, Txid, Work,
}; };
/// Implicitly does regression test for `BlockHeader` also. /// Implicitly does regression test for `BlockHeader` also.
@ -110,8 +110,10 @@ fn serde_regression_txin() {
#[test] #[test]
fn serde_regression_txout() { fn serde_regression_txout() {
let txout = let txout = TxOut {
TxOut { value: 0xDEADBEEFCAFEBABE, script_pubkey: ScriptBuf::from(vec![0u8, 1u8, 2u8]) }; value: Amount::from_sat(0xDEADBEEFCAFEBABE),
script_pubkey: ScriptBuf::from(vec![0u8, 1u8, 2u8]),
};
let got = serialize(&txout).unwrap(); let got = serialize(&txout).unwrap();
let want = include_bytes!("data/serde/txout_bincode") as &[_]; let want = include_bytes!("data/serde/txout_bincode") as &[_];
assert_eq!(got, want) assert_eq!(got, want)
@ -237,7 +239,7 @@ fn serde_regression_psbt() {
.unwrap()]), .unwrap()]),
}], }],
output: vec![TxOut { output: vec![TxOut {
value: 190303501938, value: Amount::from_sat(190_303_501_938),
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587") script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587")
.unwrap(), .unwrap(),
}], }],
@ -282,7 +284,7 @@ fn serde_regression_psbt() {
inputs: vec![Input { inputs: vec![Input {
non_witness_utxo: Some(tx), non_witness_utxo: Some(tx),
witness_utxo: Some(TxOut { witness_utxo: Some(TxOut {
value: 190303501938, value: Amount::from_sat(190_303_501_938),
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(), script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
}), }),
sighash_type: Some(PsbtSighashType::from(EcdsaSighashType::from_str("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY").unwrap())), sighash_type: Some(PsbtSighashType::from(EcdsaSighashType::from_str("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY").unwrap())),