amount: add from_sat_i32 and from_sat_u32 methods for small constants
We have a ton of calls to `from_sat_unchecked` for small constants which were clearly in range, e.g. in fee.rs. Add a new constfn for these cases. Don't bother making a generic Into<u32>/Into<u16> variant because there isn't an obvious name for it. There are 7 instances where we're using this method with values that are out of range, which we leave as from_sat_unchecked for now.
This commit is contained in:
parent
82d9d1aeea
commit
beaa2db7e5
|
@ -47,12 +47,12 @@ const BIP84_DERIVATION_PATH: &str = "m/84'/0'/0'";
|
|||
const MASTER_FINGERPRINT: &str = "9680603f";
|
||||
|
||||
// The dummy UTXO amounts we are spending.
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_1: Amount = Amount::from_sat_unchecked(20_000_000);
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_2: Amount = Amount::from_sat_unchecked(10_000_000);
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_1: Amount = Amount::from_sat_u32(20_000_000);
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_2: Amount = Amount::from_sat_u32(10_000_000);
|
||||
|
||||
// The amounts we are sending to someone, and receiving back as change.
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_unchecked(25_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_unchecked(4_990_000); // 10_000 sat fee.
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_u32(25_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_u32(4_990_000); // 10_000 sat fee.
|
||||
|
||||
// Derive the external address xpriv.
|
||||
fn get_external_address_xpriv<C: Signing>(
|
||||
|
|
|
@ -148,7 +148,7 @@ fn sighash_p2wpkh() {
|
|||
let inp_idx = 0;
|
||||
//output value from the referenced vout:0 from the referenced tx:
|
||||
//bitcoin-cli getrawtransaction 752d675b9cc0bd14e0bd23969effee0005ad6d7e550dcc832f0216c7ffd4e15c 3
|
||||
let ref_out_value = Amount::from_sat_unchecked(200000000);
|
||||
let ref_out_value = Amount::from_sat_u32(200000000);
|
||||
|
||||
println!("\nsighash_p2wpkh:");
|
||||
compute_sighash_p2wpkh(&raw_tx, inp_idx, ref_out_value);
|
||||
|
@ -178,7 +178,7 @@ fn sighash_p2wsh_multisig_2x2() {
|
|||
//For the witness transaction sighash computation, we need its referenced output's value from the original transaction:
|
||||
//bitcoin-cli getrawtransaction 2845399a8cd7a52733f9f9d0e0b8b6c5d1c88aea4cee09f8d8fa762912b49e1b 3
|
||||
//we need vout 0 value in sats:
|
||||
let ref_out_value = Amount::from_sat_unchecked(968240);
|
||||
let ref_out_value = Amount::from_sat_u32(968240);
|
||||
|
||||
println!("\nsighash_p2wsh_multisig_2x2:");
|
||||
compute_sighash_p2wsh(&raw_tx, 0, ref_out_value);
|
||||
|
|
|
@ -13,9 +13,9 @@ use bitcoin::{
|
|||
Txid, Witness,
|
||||
};
|
||||
|
||||
const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_unchecked(20_000_000);
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_unchecked(5_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_unchecked(14_999_000); // 1000 sat fee.
|
||||
const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_u32(20_000_000);
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_u32(5_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_u32(14_999_000); // 1000 sat fee.
|
||||
|
||||
fn main() {
|
||||
let secp = Secp256k1::new();
|
||||
|
|
|
@ -13,9 +13,9 @@ use bitcoin::{
|
|||
Txid, Witness,
|
||||
};
|
||||
|
||||
const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_unchecked(20_000_000);
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_unchecked(5_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_unchecked(14_999_000); // 1000 sat fee.
|
||||
const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_u32(20_000_000);
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_u32(5_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_u32(14_999_000); // 1000 sat fee.
|
||||
|
||||
fn main() {
|
||||
let secp = Secp256k1::new();
|
||||
|
|
|
@ -45,12 +45,12 @@ const BIP86_DERIVATION_PATH: &str = "m/86'/0'/0'";
|
|||
const MASTER_FINGERPRINT: &str = "9680603f";
|
||||
|
||||
// The dummy UTXO amounts we are spending.
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_1: Amount = Amount::from_sat_unchecked(20_000_000);
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_2: Amount = Amount::from_sat_unchecked(10_000_000);
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_1: Amount = Amount::from_sat_u32(20_000_000);
|
||||
const DUMMY_UTXO_AMOUNT_INPUT_2: Amount = Amount::from_sat_u32(10_000_000);
|
||||
|
||||
// The amounts we are sending to someone, and receiving back as change.
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_unchecked(25_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_unchecked(4_990_000); // 10_000 sat fee.
|
||||
const SPEND_AMOUNT: Amount = Amount::from_sat_u32(25_000_000);
|
||||
const CHANGE_AMOUNT: Amount = Amount::from_sat_u32(4_990_000); // 10_000 sat fee.
|
||||
|
||||
// Derive the external address xpriv.
|
||||
fn get_external_address_xpriv<C: Signing>(
|
||||
|
|
|
@ -40,7 +40,7 @@ const UTXO_SCRIPT_PUBKEY: &str =
|
|||
"5120be27fa8b1f5278faf82cab8da23e8761f8f9bd5d5ebebbb37e0e12a70d92dd16";
|
||||
const UTXO_PUBKEY: &str = "a6ac32163539c16b6b5dbbca01b725b8e8acaa5f821ba42c80e7940062140d19";
|
||||
const UTXO_MASTER_FINGERPRINT: &str = "e61b318f";
|
||||
const ABSOLUTE_FEES: Amount = Amount::from_sat_unchecked(1_000);
|
||||
const ABSOLUTE_FEES: Amount = Amount::from_sat_u32(1_000);
|
||||
|
||||
// UTXO_1 will be used for spending example 1
|
||||
const UTXO_1: P2trUtxo = P2trUtxo {
|
||||
|
|
|
@ -675,7 +675,7 @@ fn bitcoinconsensus() {
|
|||
let spent_bytes = hex!("0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d");
|
||||
let spent = Script::from_bytes(&spent_bytes);
|
||||
let spending = hex!("010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000");
|
||||
spent.verify(0, Amount::from_sat_unchecked(18393430), &spending).unwrap();
|
||||
spent.verify(0, Amount::from_sat_u32(18393430), &spending).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -684,10 +684,10 @@ fn default_dust_value() {
|
|||
// well-known scriptPubKey types.
|
||||
let script_p2wpkh = Builder::new().push_int_unchecked(0).push_slice([42; 20]).into_script();
|
||||
assert!(script_p2wpkh.is_p2wpkh());
|
||||
assert_eq!(script_p2wpkh.minimal_non_dust(), Some(Amount::from_sat_unchecked(294)));
|
||||
assert_eq!(script_p2wpkh.minimal_non_dust(), Some(Amount::from_sat_u32(294)));
|
||||
assert_eq!(
|
||||
script_p2wpkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_unchecked(6)),
|
||||
Some(Amount::from_sat_unchecked(588))
|
||||
Some(Amount::from_sat_u32(588))
|
||||
);
|
||||
|
||||
let script_p2pkh = Builder::new()
|
||||
|
@ -698,10 +698,10 @@ fn default_dust_value() {
|
|||
.push_opcode(OP_CHECKSIG)
|
||||
.into_script();
|
||||
assert!(script_p2pkh.is_p2pkh());
|
||||
assert_eq!(script_p2pkh.minimal_non_dust(), Some(Amount::from_sat_unchecked(546)));
|
||||
assert_eq!(script_p2pkh.minimal_non_dust(), Some(Amount::from_sat_u32(546)));
|
||||
assert_eq!(
|
||||
script_p2pkh.minimal_non_dust_custom(FeeRate::from_sat_per_vb_unchecked(6)),
|
||||
Some(Amount::from_sat_unchecked(1092))
|
||||
Some(Amount::from_sat_u32(1092))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2089,7 +2089,7 @@ mod tests {
|
|||
).unwrap();
|
||||
|
||||
let spk = ScriptBuf::from_hex("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1").unwrap();
|
||||
let value = Amount::from_sat_unchecked(600_000_000);
|
||||
let value = Amount::from_sat_u32(600_000_000);
|
||||
|
||||
let mut cache = SighashCache::new(&tx);
|
||||
assert_eq!(
|
||||
|
@ -2130,7 +2130,7 @@ mod tests {
|
|||
|
||||
let redeem_script =
|
||||
ScriptBuf::from_hex("001479091972186c449eb1ded22b78e40d009bdf0089").unwrap();
|
||||
let value = Amount::from_sat_unchecked(1_000_000_000);
|
||||
let value = Amount::from_sat_u32(1_000_000_000);
|
||||
|
||||
let mut cache = SighashCache::new(&tx);
|
||||
assert_eq!(
|
||||
|
@ -2180,7 +2180,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let value = Amount::from_sat_unchecked(987_654_321);
|
||||
let value = Amount::from_sat_u32(987_654_321);
|
||||
(tx, witness_script, value)
|
||||
}
|
||||
|
||||
|
|
|
@ -1429,14 +1429,14 @@ mod tests {
|
|||
}],
|
||||
output: vec![
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(99_999_699),
|
||||
value: Amount::from_sat_u32(99_999_699),
|
||||
script_pubkey: ScriptBuf::from_hex(
|
||||
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(100_000_000),
|
||||
value: Amount::from_sat_u32(100_000_000),
|
||||
script_pubkey: ScriptBuf::from_hex(
|
||||
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
||||
)
|
||||
|
@ -1678,11 +1678,11 @@ mod tests {
|
|||
],
|
||||
output: vec![
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(99_999_699),
|
||||
value: Amount::from_sat_u32(99_999_699),
|
||||
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
||||
},
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(100_000_000),
|
||||
value: Amount::from_sat_u32(100_000_000),
|
||||
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
||||
},
|
||||
],
|
||||
|
@ -1725,7 +1725,7 @@ mod tests {
|
|||
],
|
||||
output: vec![
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(200_000_000),
|
||||
value: Amount::from_sat_u32(200_000_000),
|
||||
script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
|
||||
},
|
||||
TxOut {
|
||||
|
@ -2011,11 +2011,11 @@ mod tests {
|
|||
],
|
||||
output: vec![
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(99_999_699),
|
||||
value: Amount::from_sat_u32(99_999_699),
|
||||
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
||||
},
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(100_000_000),
|
||||
value: Amount::from_sat_u32(100_000_000),
|
||||
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
||||
},
|
||||
],
|
||||
|
@ -2058,7 +2058,7 @@ mod tests {
|
|||
],
|
||||
output: vec![
|
||||
TxOut {
|
||||
value: Amount::from_sat_unchecked(200_000_000),
|
||||
value: Amount::from_sat_u32(200_000_000),
|
||||
script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
|
||||
},
|
||||
TxOut {
|
||||
|
@ -2171,9 +2171,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn fee() {
|
||||
let output_0_val = Amount::from_sat_unchecked(99_999_699);
|
||||
let output_1_val = Amount::from_sat_unchecked(100_000_000);
|
||||
let prev_output_val = Amount::from_sat_unchecked(200_000_000);
|
||||
let output_0_val = Amount::from_sat_u32(99_999_699);
|
||||
let output_1_val = Amount::from_sat_u32(100_000_000);
|
||||
let prev_output_val = Amount::from_sat_u32(200_000_000);
|
||||
|
||||
let t = Psbt {
|
||||
unsigned_tx: Transaction {
|
||||
|
@ -2296,7 +2296,7 @@ mod tests {
|
|||
|
||||
// First input we can spend. See comment above on key_map for why we use defaults here.
|
||||
let txout_wpkh = TxOut {
|
||||
value: Amount::from_sat_unchecked(10),
|
||||
value: Amount::from_sat_u32(10),
|
||||
script_pubkey: ScriptBuf::new_p2wpkh(pk.wpubkey_hash().unwrap()),
|
||||
};
|
||||
psbt.inputs[0].witness_utxo = Some(txout_wpkh);
|
||||
|
@ -2308,7 +2308,7 @@ mod tests {
|
|||
// Second input is unspendable by us e.g., from another wallet that supports future upgrades.
|
||||
let unknown_prog = WitnessProgram::new(WitnessVersion::V4, &[0xaa; 34]).unwrap();
|
||||
let txout_unknown_future = TxOut {
|
||||
value: Amount::from_sat_unchecked(10),
|
||||
value: Amount::from_sat_u32(10),
|
||||
script_pubkey: ScriptBuf::new_witness_program(&unknown_prog),
|
||||
};
|
||||
psbt.inputs[1].witness_utxo = Some(txout_unknown_future);
|
||||
|
|
|
@ -57,6 +57,14 @@ mod encapsulate {
|
|||
/// See [`Self::MIN`] and [`Self::MAX`].
|
||||
pub const fn from_sat_unchecked(satoshi: i64) -> SignedAmount { SignedAmount(satoshi) }
|
||||
|
||||
/// Constructs a new [`SignedAmount`] with satoshi precision and the given number of satoshis.
|
||||
///
|
||||
/// Accepts an `i32` which is guaranteed to be in range for the type, but which can only
|
||||
/// represent roughly -21.47 to 21.47 BTC.
|
||||
pub const fn from_sat_i32(satoshi: i32) -> SignedAmount {
|
||||
SignedAmount(satoshi as i64) // cannot use i64::from in a constfn
|
||||
}
|
||||
|
||||
/// Gets the number of satoshis in this [`SignedAmount`].
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -73,9 +81,9 @@ pub use encapsulate::SignedAmount;
|
|||
|
||||
impl SignedAmount {
|
||||
/// The zero amount.
|
||||
pub const ZERO: Self = SignedAmount::from_sat_unchecked(0);
|
||||
pub const ZERO: Self = SignedAmount::from_sat_i32(0);
|
||||
/// Exactly one satoshi.
|
||||
pub const ONE_SAT: Self = SignedAmount::from_sat_unchecked(1);
|
||||
pub const ONE_SAT: Self = SignedAmount::from_sat_i32(1);
|
||||
/// Exactly one bitcoin.
|
||||
pub const ONE_BTC: Self = SignedAmount::from_btc_i16(1);
|
||||
/// Exactly fifty bitcoin.
|
||||
|
|
|
@ -55,6 +55,14 @@ mod encapsulate {
|
|||
/// Caller to guarantee that `satoshi` is within valid range. See [`Self::MAX`].
|
||||
pub const fn from_sat_unchecked(satoshi: u64) -> Amount { Self(satoshi) }
|
||||
|
||||
/// Constructs a new [`Amount`] with satoshi precision and the given number of satoshis.
|
||||
///
|
||||
/// Accepts an `u32` which is guaranteed to be in range for the type, but which can only
|
||||
/// represent roughly 0 to 42.95 BTC.
|
||||
pub const fn from_sat_u32(satoshi: u32) -> Amount {
|
||||
Amount(satoshi as u64) // cannot use u64::from in a constfn
|
||||
}
|
||||
|
||||
/// Gets the number of satoshis in this [`Amount`].
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -71,9 +79,9 @@ pub use encapsulate::Amount;
|
|||
|
||||
impl Amount {
|
||||
/// The zero amount.
|
||||
pub const ZERO: Self = Amount::from_sat_unchecked(0);
|
||||
pub const ZERO: Self = Amount::from_sat_u32(0);
|
||||
/// Exactly one satoshi.
|
||||
pub const ONE_SAT: Self = Amount::from_sat_unchecked(1);
|
||||
pub const ONE_SAT: Self = Amount::from_sat_u32(1);
|
||||
/// Exactly one bitcoin.
|
||||
pub const ONE_BTC: Self = Amount::from_btc_u16(1);
|
||||
/// Exactly fifty bitcoin.
|
||||
|
|
|
@ -216,7 +216,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn fee_rate_div_by_weight() {
|
||||
let fee_rate = Amount::from_sat_unchecked(329) / Weight::from_wu(381);
|
||||
let fee_rate = Amount::from_sat_u32(329) / Weight::from_wu(381);
|
||||
assert_eq!(fee_rate, FeeRate::from_sat_per_kwu(863));
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ mod tests {
|
|||
|
||||
let fee_rate = FeeRate::from_sat_per_vb(2).unwrap();
|
||||
let weight = Weight::from_vb(3).unwrap();
|
||||
assert_eq!(fee_rate.to_fee(weight).unwrap(), Amount::from_sat_unchecked(6));
|
||||
assert_eq!(fee_rate.to_fee(weight).unwrap(), Amount::from_sat_u32(6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -237,7 +237,7 @@ mod tests {
|
|||
.unwrap()
|
||||
.checked_mul_by_weight(weight)
|
||||
.expect("expected Amount");
|
||||
assert_eq!(Amount::from_sat_unchecked(100), fee);
|
||||
assert_eq!(Amount::from_sat_u32(100), fee);
|
||||
|
||||
let fee = FeeRate::from_sat_per_kwu(10).checked_mul_by_weight(Weight::MAX);
|
||||
assert!(fee.is_none());
|
||||
|
@ -245,14 +245,14 @@ mod tests {
|
|||
let weight = Weight::from_vb(3).unwrap();
|
||||
let fee_rate = FeeRate::from_sat_per_vb(3).unwrap();
|
||||
let fee = fee_rate.checked_mul_by_weight(weight).unwrap();
|
||||
assert_eq!(Amount::from_sat_unchecked(9), fee);
|
||||
assert_eq!(Amount::from_sat_u32(9), fee);
|
||||
|
||||
let weight = Weight::from_wu(381);
|
||||
let fee_rate = FeeRate::from_sat_per_kwu(864);
|
||||
let fee = weight.checked_mul_by_fee_rate(fee_rate).unwrap();
|
||||
// 381 * 0.864 yields 329.18.
|
||||
// The result is then rounded up to 330.
|
||||
assert_eq!(fee, Amount::from_sat_unchecked(330));
|
||||
assert_eq!(fee, Amount::from_sat_u32(330));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -260,7 +260,7 @@ mod tests {
|
|||
fn multiply() {
|
||||
let two = FeeRate::from_sat_per_vb(2).unwrap();
|
||||
let three = Weight::from_vb(3).unwrap();
|
||||
let six = Amount::from_sat_unchecked(6);
|
||||
let six = Amount::from_sat_u32(6);
|
||||
|
||||
assert_eq!(two * three, six.into());
|
||||
|
||||
|
@ -274,7 +274,7 @@ mod tests {
|
|||
#[allow(clippy::op_ref)]
|
||||
fn amount_div_by_fee_rate() {
|
||||
// Test exact division
|
||||
let amount = Amount::from_sat_unchecked(1000);
|
||||
let amount = Amount::from_sat_u32(1000);
|
||||
let fee_rate = FeeRate::from_sat_per_kwu(2);
|
||||
let weight = amount / fee_rate;
|
||||
assert_eq!(weight, Weight::from_wu(500_000));
|
||||
|
@ -288,7 +288,7 @@ mod tests {
|
|||
assert_eq!(weight_ref3, Weight::from_wu(500_000));
|
||||
|
||||
// Test truncation behavior
|
||||
let amount = Amount::from_sat_unchecked(1000);
|
||||
let amount = Amount::from_sat_u32(1000);
|
||||
let fee_rate = FeeRate::from_sat_per_kwu(3);
|
||||
let weight = amount / fee_rate;
|
||||
// 1000 * 1000 = 1,000,000 msats
|
||||
|
|
Loading…
Reference in New Issue