Merge rust-bitcoin/rust-bitcoin#1811: Use Amount type for TxOut value field
d57ec019d5
Use Amount type for TxOut value field (yancy) Pull request description: Propose using `Amount` type for the `TxOut` `value` field. I only implemented `Decodable ` and `Encodable` enough to compile but this needs to completed obviously if using `Amount` seems like a good idea. ACKs for top commit: tcharding: ACKd57ec019d5
apoelstra: ACKd57ec019d5
Tree-SHA512: df3fd55294d5f9392ca90bb920be8fbb9d7d285d97669412e07d5a099f70f81fd73e7e259679de9c8ce5c6c855e64f62213700f0fb7db415e0c706c509485377
This commit is contained in:
commit
25f569adeb
|
@ -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>);
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() }],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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"),
|
||||||
},
|
},
|
||||||
|
|
|
@ -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())),
|
||||||
|
|
Loading…
Reference in New Issue