From 72761ae0ea274a9f213a5fe4b44ff0d41c8fc4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Sat, 7 Sep 2024 14:59:16 +0800 Subject: [PATCH] feat!: use `u64` for weights instead of `u32` Also change tests and examples to use `v0.32` of the `bitcoin` crate. --- Cargo.toml | 2 +- README.md | 28 +++++++++++++---------- src/coin_selector.rs | 12 +++++----- src/drain.rs | 4 ++-- src/lib.rs | 20 ++++++++--------- src/target.rs | 10 ++++----- tests/changeless.rs | 6 ++--- tests/common.rs | 6 ++--- tests/lowest_fee.rs | 2 +- tests/rbf.rs | 2 +- tests/weight.rs | 53 +++++++++++++++++++++----------------------- 11 files changed, 73 insertions(+), 72 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8573a6a..f23acd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,4 @@ std = [] [dev-dependencies] rand = "0.8" proptest = "1.4" -bitcoin = "0.30" +bitcoin = "0.32" diff --git a/README.md b/README.md index ba2d8ad..0dffd53 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,20 @@ ```rust use std::str::FromStr; use bdk_coin_select::{ CoinSelector, Candidate, TR_KEYSPEND_TXIN_WEIGHT, Drain, FeeRate, Target, ChangePolicy, TargetOutputs, TargetFee, DrainWeights}; -use bitcoin::{ Address, Network, Transaction, TxIn, TxOut }; +use bitcoin::{ Amount, Address, Network, Transaction, TxIn, TxOut }; -let recipient_addr = - Address::from_str("tb1pvjf9t34fznr53u5tqhejz4nr69luzkhlvsdsdfq9pglutrpve2xq7hps46").unwrap(); +let recipient_addr: Address = "tb1pvjf9t34fznr53u5tqhejz4nr69luzkhlvsdsdfq9pglutrpve2xq7hps46" + .parse::>() + .unwrap() + .assume_checked(); let outputs = vec![TxOut { - value: 3_500_000, - script_pubkey: recipient_addr.payload.script_pubkey(), + value: Amount::from_sat(3_500_000), + script_pubkey: recipient_addr.script_pubkey(), }]; let target = Target { - outputs: TargetOutputs::fund_outputs(outputs.iter().map(|output| (output.weight() as u32, output.value))), + outputs: TargetOutputs::fund_outputs(outputs.iter().map(|output| (output.weight().to_wu(), output.value.to_sat()))), fee: TargetFee::from_feerate(FeeRate::from_sat_per_vb(42.0)) }; @@ -87,14 +89,16 @@ metric by implementing the [`BnbMetric`] yourself but we don't recommend this. use std::str::FromStr; use bdk_coin_select::{ Candidate, CoinSelector, FeeRate, Target, TargetFee, TargetOutputs, ChangePolicy, TR_KEYSPEND_TXIN_WEIGHT, TR_DUST_RELAY_MIN_VALUE}; use bdk_coin_select::metrics::LowestFee; -use bitcoin::{ Address, Network, Transaction, TxIn, TxOut }; +use bitcoin::{ Address, Amount, Network, Transaction, TxIn, TxOut }; -let recipient_addr = - Address::from_str("tb1pvjf9t34fznr53u5tqhejz4nr69luzkhlvsdsdfq9pglutrpve2xq7hps46").unwrap(); +let recipient_addr: Address = "tb1pvjf9t34fznr53u5tqhejz4nr69luzkhlvsdsdfq9pglutrpve2xq7hps46" + .parse::>() + .unwrap() + .assume_checked(); let outputs = vec![TxOut { - value: 210_000, - script_pubkey: recipient_addr.payload.script_pubkey(), + value: Amount::from_sat(210_000), + script_pubkey: recipient_addr.script_pubkey(), }]; let candidates = [ @@ -125,7 +129,7 @@ let mut coin_selector = CoinSelector::new(&candidates); let target = Target { fee: TargetFee::from_feerate(FeeRate::from_sat_per_vb(15.0)), - outputs: TargetOutputs::fund_outputs(outputs.iter().map(|output| (output.weight() as u32, output.value))), + outputs: TargetOutputs::fund_outputs(outputs.iter().map(|output| (output.weight().to_wu(), output.value.to_sat()))), }; // The change output must be at least this size to be relayed. diff --git a/src/coin_selector.rs b/src/coin_selector.rs index d8e6cd3..944332a 100644 --- a/src/coin_selector.rs +++ b/src/coin_selector.rs @@ -131,14 +131,14 @@ impl<'a> CoinSelector<'a> { /// The weight of the inputs including the witness header and the varint for the number of /// inputs. - pub fn input_weight(&self) -> u32 { + pub fn input_weight(&self) -> u64 { let is_segwit_tx = self.selected().any(|(_, wv)| wv.is_segwit); - let witness_header_extra_weight = is_segwit_tx as u32 * 2; + let witness_header_extra_weight = is_segwit_tx as u64 * 2; let input_count = self.selected().map(|(_, wv)| wv.input_count).sum::(); let input_varint_weight = varint_size(input_count) * 4; - let selected_weight: u32 = self + let selected_weight: u64 = self .selected() .map(|(_, candidate)| { let mut weight = candidate.weight; @@ -166,7 +166,7 @@ impl<'a> CoinSelector<'a> { /// /// If you don't have any drain outputs (only target outputs) just set drain_weights to /// [`DrainWeights::NONE`]. - pub fn weight(&self, target_ouputs: TargetOutputs, drain_weight: DrainWeights) -> u32 { + pub fn weight(&self, target_ouputs: TargetOutputs, drain_weight: DrainWeights) -> u64 { TX_FIXED_FIELD_WEIGHT + self.input_weight() + target_ouputs.output_weight_with_drain(drain_weight) @@ -642,7 +642,7 @@ pub struct Candidate { /// Total weight of including this/these UTXO(s). /// `txin` fields: `prevout`, `nSequence`, `scriptSigLen`, `scriptSig`, `scriptWitnessLen`, /// `scriptWitness` should all be included. - pub weight: u32, + pub weight: u64, /// Total number of inputs; so we can calculate extra `varint` weight due to `vin` len changes. pub input_count: usize, /// Whether this [`Candidate`] contains at least one segwit spend. @@ -660,7 +660,7 @@ impl Candidate { /// /// `satisfaction_weight` is the weight of `scriptSigLen + scriptSig + scriptWitnessLen + /// scriptWitness`. - pub fn new(value: u64, satisfaction_weight: u32, is_segwit: bool) -> Candidate { + pub fn new(value: u64, satisfaction_weight: u64, is_segwit: bool) -> Candidate { let weight = TXIN_BASE_WEIGHT + satisfaction_weight; Candidate { value, diff --git a/src/drain.rs b/src/drain.rs index 700d0dd..13ab3c6 100644 --- a/src/drain.rs +++ b/src/drain.rs @@ -10,9 +10,9 @@ pub struct DrainWeights { /// The weight of including this drain output. /// /// This must not take into account any weight change from varint output count. - pub output_weight: u32, + pub output_weight: u64, /// The weight of spending this drain output (in the future). - pub spend_weight: u32, + pub spend_weight: u64, /// The total number of outputs that the drain will use pub n_outputs: usize, } diff --git a/src/lib.rs b/src/lib.rs index 9bdabbd..ac237b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,35 +29,35 @@ pub use drain::*; /// Txin "base" fields include `outpoint` (32+4) and `nSequence` (4) and 1 byte for the scriptSig /// length. -pub const TXIN_BASE_WEIGHT: u32 = (32 + 4 + 4 + 1) * 4; +pub const TXIN_BASE_WEIGHT: u64 = (32 + 4 + 4 + 1) * 4; /// The weight of a TXOUT with a zero length `scriptPubKey` #[allow(clippy::identity_op)] -pub const TXOUT_BASE_WEIGHT: u32 = +pub const TXOUT_BASE_WEIGHT: u64 = // The value - 4 * core::mem::size_of::() as u32 + 4 * core::mem::size_of::() as u64 // The spk length + (4 * 1); /// The weight of the `nVersion` and `nLockTime` transaction fields -pub const TX_FIXED_FIELD_WEIGHT: u32 = (4 /* nVersion */ + 4/* nLockTime */) * 4; +pub const TX_FIXED_FIELD_WEIGHT: u64 = (4 /* nVersion */ + 4/* nLockTime */) * 4; /// The weight of a taproot keyspend witness -pub const TR_KEYSPEND_SATISFACTION_WEIGHT: u32 = 1 /*witness_len*/ + 1 /*item len*/ + 64 /*signature*/; +pub const TR_KEYSPEND_SATISFACTION_WEIGHT: u64 = 1 /*witness_len*/ + 1 /*item len*/ + 64 /*signature*/; /// The weight of a segwit `v1` (taproot) script pubkey in an output. This does not include the weight of /// the `TxOut` itself or the script pubkey length field. -pub const TR_SPK_WEIGHT: u32 = (1 + 1 + 32) * 4; // version + push + key +pub const TR_SPK_WEIGHT: u64 = (1 + 1 + 32) * 4; // version + push + key /// The weight of a taproot TxIn with witness -pub const TR_KEYSPEND_TXIN_WEIGHT: u32 = TXIN_BASE_WEIGHT + TR_KEYSPEND_SATISFACTION_WEIGHT; +pub const TR_KEYSPEND_TXIN_WEIGHT: u64 = TXIN_BASE_WEIGHT + TR_KEYSPEND_SATISFACTION_WEIGHT; /// The minimum value a taproot output can have to be relayed with Bitcoin core's default dust relay /// fee pub const TR_DUST_RELAY_MIN_VALUE: u64 = 330; /// Helper to calculate varint size. `v` is the value the varint represents. -const fn varint_size(v: usize) -> u32 { +const fn varint_size(v: usize) -> u64 { if v <= 0xfc { return 1; } @@ -71,6 +71,6 @@ const fn varint_size(v: usize) -> u32 { } #[allow(unused)] -fn txout_weight_from_spk_len(spk_len: usize) -> u32 { - (TXOUT_BASE_WEIGHT + varint_size(spk_len) + (spk_len as u32)) * 4 +fn txout_weight_from_spk_len(spk_len: usize) -> u64 { + (TXOUT_BASE_WEIGHT + varint_size(spk_len) + (spk_len as u64)) * 4 } diff --git a/src/target.rs b/src/target.rs index 8089420..0dddf7b 100644 --- a/src/target.rs +++ b/src/target.rs @@ -24,14 +24,14 @@ pub struct TargetOutputs { /// The sum of the values of the individual `TxOuts`s. pub value_sum: u64, /// The sum of the weights of the individual `TxOut`s. - pub weight_sum: u32, + pub weight_sum: u64, /// The total number of outputs pub n_outputs: usize, } impl TargetOutputs { /// The output weight of the outptus we're trying to fund - pub fn output_weight(&self) -> u32 { + pub fn output_weight(&self) -> u64 { self.weight_sum + varint_size(self.n_outputs) * 4 } @@ -42,13 +42,13 @@ impl TargetOutputs { /// adding the drain weights might add an extra vbyte for the length of the varint. /// /// [`output_weight`]: Self::output_weight - pub fn output_weight_with_drain(&self, drain_weight: DrainWeights) -> u32 { + pub fn output_weight_with_drain(&self, drain_weight: DrainWeights) -> u64 { let n_outputs = drain_weight.n_outputs + self.n_outputs; varint_size(n_outputs) * 4 + drain_weight.output_weight + self.weight_sum } /// Creates a `TargetOutputs` from a list of outputs represented as `(weight, value)` pairs. - pub fn fund_outputs(outputs: impl IntoIterator) -> Self { + pub fn fund_outputs(outputs: impl IntoIterator) -> Self { let mut n_outputs = 0; let mut weight_sum = 0; let mut value_sum = 0; @@ -135,7 +135,7 @@ impl Replace { /// This is defined by [RBF rule 4]. /// /// [RBF rule 4]: https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md#current-replace-by-fee-policy - pub fn min_fee_to_do_replacement(&self, replacing_tx_weight: u32) -> u64 { + pub fn min_fee_to_do_replacement(&self, replacing_tx_weight: u64) -> u64 { let min_fee_increment = (replacing_tx_weight as f32 * self.incremental_relay_feerate.spwu()).ceil() as u64; self.fee + min_fee_increment diff --git a/tests/changeless.rs b/tests/changeless.rs index 4b085ba..d028d49 100644 --- a/tests/changeless.rs +++ b/tests/changeless.rs @@ -46,8 +46,8 @@ proptest! { let mut rng = TestRng::deterministic_rng(RngAlgorithm::ChaCha); let feerate = FeeRate::from_sat_per_vb(feerate); let drain_weights = DrainWeights { - output_weight: drain_weight, - spend_weight: drain_spend_weight, + output_weight: drain_weight as u64, + spend_weight: drain_spend_weight as u64, n_outputs: n_drain_outputs, }; @@ -61,7 +61,7 @@ proptest! { outputs: TargetOutputs { n_outputs: n_target_outputs, value_sum: target_value, - weight_sum: target_weight, + weight_sum: target_weight as u64, }, fee: TargetFee { rate: feerate, diff --git a/tests/common.rs b/tests/common.rs index 642a42f..390470b 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -217,7 +217,7 @@ impl StrategyParams { }, outputs: TargetOutputs { value_sum: self.target_value, - weight_sum: self.target_weight, + weight_sum: self.target_weight as u64, n_outputs: self.n_target_outputs, }, } @@ -233,8 +233,8 @@ impl StrategyParams { pub fn drain_weights(&self) -> DrainWeights { DrainWeights { - output_weight: self.drain_weight, - spend_weight: self.drain_spend_weight, + output_weight: self.drain_weight as u64, + spend_weight: self.drain_spend_weight as u64, n_outputs: self.n_drain_outputs, } } diff --git a/tests/lowest_fee.rs b/tests/lowest_fee.rs index 3a6bf69..7b938e0 100644 --- a/tests/lowest_fee.rs +++ b/tests/lowest_fee.rs @@ -139,7 +139,7 @@ fn combined_changeless_metric() { let params = common::StrategyParams { n_candidates: 100, target_value: 100_000, - target_weight: 1000 - TX_FIXED_FIELD_WEIGHT - 1, + target_weight: 1000 - TX_FIXED_FIELD_WEIGHT as u32 - 1, replace: None, feerate: 5.0, feerate_lt_diff: -4.0, diff --git a/tests/rbf.rs b/tests/rbf.rs index 70e943e..64539f6 100644 --- a/tests/rbf.rs +++ b/tests/rbf.rs @@ -56,7 +56,7 @@ fn run_bitcoin_core_rbf_tests() { fn pays_for_rbf( original_fees: u64, replacement_fees: u64, - replacement_vsize: u32, + replacement_vsize: u64, relay_fee: FeeRate, ) -> bool { let min_fee = Replace { diff --git a/tests/weight.rs b/tests/weight.rs index b7b3eb2..1e4e696 100644 --- a/tests/weight.rs +++ b/tests/weight.rs @@ -24,9 +24,8 @@ pub fn hex_decode(hex: &str) -> Vec { #[test] fn segwit_one_input_one_output() { // FROM https://mempool.space/tx/e627fbb7f775a57fd398bf9b150655d4ac3e1f8afed4255e74ee10d7a345a9cc - let mut tx_bytes = hex_decode("01000000000101b2ec00fd7d3f2c89eb27e3e280960356f69fc88a324a4bca187dd4b020aa36690000000000ffffffff01d0bb9321000000001976a9141dc94fe723f43299c6187094b1dc5a032d47b06888ac024730440220669b764de7e9dcedcba6d6d57c8c761be2acc4e1a66938ceecacaa6d494f582d02202641df89d1758eeeed84290079dd9ad36611c73cd9e381dd090b83f5e5b1422e012103f6544e4ffaff4f8649222003ada5d74bd6d960162bcd85af2b619646c8c45a5298290c00"); - let mut cursor = std::io::Cursor::new(&mut tx_bytes); - let tx = Transaction::consensus_decode(&mut cursor).unwrap(); + let tx_bytes = hex_decode("01000000000101b2ec00fd7d3f2c89eb27e3e280960356f69fc88a324a4bca187dd4b020aa36690000000000ffffffff01d0bb9321000000001976a9141dc94fe723f43299c6187094b1dc5a032d47b06888ac024730440220669b764de7e9dcedcba6d6d57c8c761be2acc4e1a66938ceecacaa6d494f582d02202641df89d1758eeeed84290079dd9ad36611c73cd9e381dd090b83f5e5b1422e012103f6544e4ffaff4f8649222003ada5d74bd6d960162bcd85af2b619646c8c45a5298290c00"); + let tx = Transaction::consensus_decode(&mut tx_bytes.as_slice()).unwrap(); let input_values = vec![563_336_755]; let candidates = tx @@ -35,15 +34,15 @@ fn segwit_one_input_one_output() { .zip(input_values) .map(|(txin, value)| Candidate { value, - weight: txin.segwit_weight() as u32, + weight: txin.segwit_weight().to_wu(), input_count: 1, is_segwit: true, }) .collect::>(); let target_ouputs = TargetOutputs { - value_sum: tx.output.iter().map(|output| output.value).sum(), - weight_sum: tx.output.iter().map(|output| output.weight() as u32).sum(), + value_sum: tx.output.iter().map(|output| output.value.to_sat()).sum(), + weight_sum: tx.output.iter().map(|output| output.weight().to_wu()).sum(), n_outputs: tx.output.len(), }; @@ -52,7 +51,7 @@ fn segwit_one_input_one_output() { assert_eq!( coin_selector.weight(target_ouputs, DrainWeights::NONE), - tx.weight().to_wu() as u32 + tx.weight().to_wu() ); assert_eq!( (coin_selector @@ -68,9 +67,8 @@ fn segwit_one_input_one_output() { #[test] fn segwit_two_inputs_one_output() { // FROM https://mempool.space/tx/37d2883bdf1b4c110b54cb624d36ab6a30140f8710ed38a52678260a7685e708 - let mut tx_bytes = hex_decode("020000000001021edcae5160b1ba2370a45ea9342b4c883a8941274539612bddf1c379ba7ecf180700000000ffffffff5c85e19bf4f0e293c0d5f9665cb05d2a55d8bba959edc5ef02075f6a1eb9fc120100000000ffffffff0168ce3000000000001976a9145ff742d992276a1f46e5113dde7382896ff86e2a88ac0247304402202e588db55227e0c24db7f07b65f221ebcae323fb595d13d2e1c360b773d809b0022008d2f57a618bd346cfd031549a3971f22464e3e3308cee340a976f1b47a96f0b012102effbcc87e6c59b810c2fa20b0bc3eb909a20b40b25b091cf005d416b85db8c8402483045022100bdc115b86e9c863279132b4808459cf9b266c8f6a9c14a3dfd956986b807e3320220265833b85197679687c5d5eed1b2637489b34249d44cf5d2d40bc7b514181a51012102077741a668889ce15d59365886375aea47a7691941d7a0d301697edbc773b45b00000000"); - let mut cursor = std::io::Cursor::new(&mut tx_bytes); - let tx = Transaction::consensus_decode(&mut cursor).unwrap(); + let tx_bytes = hex_decode("020000000001021edcae5160b1ba2370a45ea9342b4c883a8941274539612bddf1c379ba7ecf180700000000ffffffff5c85e19bf4f0e293c0d5f9665cb05d2a55d8bba959edc5ef02075f6a1eb9fc120100000000ffffffff0168ce3000000000001976a9145ff742d992276a1f46e5113dde7382896ff86e2a88ac0247304402202e588db55227e0c24db7f07b65f221ebcae323fb595d13d2e1c360b773d809b0022008d2f57a618bd346cfd031549a3971f22464e3e3308cee340a976f1b47a96f0b012102effbcc87e6c59b810c2fa20b0bc3eb909a20b40b25b091cf005d416b85db8c8402483045022100bdc115b86e9c863279132b4808459cf9b266c8f6a9c14a3dfd956986b807e3320220265833b85197679687c5d5eed1b2637489b34249d44cf5d2d40bc7b514181a51012102077741a668889ce15d59365886375aea47a7691941d7a0d301697edbc773b45b00000000"); + let tx = Transaction::consensus_decode(&mut tx_bytes.as_slice()).unwrap(); let input_values = vec![003_194_967, 000_014_068]; let candidates = tx @@ -79,7 +77,7 @@ fn segwit_two_inputs_one_output() { .zip(input_values) .map(|(txin, value)| Candidate { value, - weight: txin.segwit_weight() as u32, + weight: txin.segwit_weight().to_wu(), input_count: 1, is_segwit: true, }) @@ -88,8 +86,8 @@ fn segwit_two_inputs_one_output() { let mut coin_selector = CoinSelector::new(&candidates); let target_ouputs = TargetOutputs { - value_sum: tx.output.iter().map(|output| output.value).sum(), - weight_sum: tx.output.iter().map(|output| output.weight() as u32).sum(), + value_sum: tx.output.iter().map(|output| output.value.to_sat()).sum(), + weight_sum: tx.output.iter().map(|output| output.weight().to_wu()).sum(), n_outputs: tx.output.len(), }; @@ -97,7 +95,7 @@ fn segwit_two_inputs_one_output() { assert_eq!( coin_selector.weight(target_ouputs, DrainWeights::NONE), - tx.weight().to_wu() as u32 + tx.weight().to_wu() ); assert_eq!( (coin_selector @@ -113,9 +111,8 @@ fn segwit_two_inputs_one_output() { #[test] fn legacy_three_inputs() { // FROM https://mempool.space/tx/5f231df4f73694b3cca9211e336451c20dab136e0a843c2e3166cdcb093e91f4 - let mut tx_bytes = hex_decode("0100000003fe785783e14669f638ba902c26e8e3d7036fb183237bc00f8a10542191c7171300000000fdfd00004730440220418996f20477d143d02ad47e74e5949641b6c2904159ab7c592d2cfc659f9bd802205b18f18ac86b714971f84a8b74a4cb14ad5c1a5b9d0d939bb32c6ae4032f4ea10148304502210091296ff8dd87b5ebfc3d47cb82cfe4750d52c544a2b88a85970354a4d0d4b1db022069632067ee6f30f06145f649bc76d5e5d5e6404dbe985e006fcde938f778c297014c695221030502b8ade694d57a6e86998180a64f4ce993372830dc796c3d561ad8b2a504de210272b68e1c037c4630eff7ea5858640cc0748e36f5de82fb38529ef1fd0a89670d2103ba0544a3a2aa9f2314022760b78b5c833aebf6f88468a089550f93834a2886ed53aeffffffff7e048a7c53a8af656e24442c65fe4c4299b1494f6c7579fe0fd9fa741ce83e3279000000fc004730440220018fa343acccd048ed8f8f179e1b6ae27435a41b5fb2c1d96a5a772777acc6dc022074783814f2100c6fc4d4c976f941212be50825814502ca0cbe3f929db789979e0147304402206373f01b73fb09876d0f5ee3087e0614cab3be249934bc2b7eb64ee67f53dc8302200b50f8a327020172b82aaba7480c77ecf07bb32322a05f4afbc543aa97d2fde8014c69522103039d906b2494e310f6c7774c98618be552720d04781e073dd3ff25d5906f22662103d82026baa529619b103ec6341d548a7eb6d924061a8469a7416155513a3071c12102e452bc4aa726d44646ba80db70465683b30efde282a19aa35c6029ae8925df5e53aeffffffffef80f0b1cc543de4f73d59c02a3c575ae5d0af17c1e11e6be7abe3325c777507ad000000fdfd00004730440220220fee11bf836621a11a8ea9100a4600c109c13895f11468d3e2062210c5481902201c5c8a462175538e87b8248e1ed3927c3a461c66d1b46215641c875e86eb22c4014830450221008d2de8c2f20a720129c372791e595b9602b1a9bce99618497aec5266148ffc1302203a493359d700ed96323f8805ed03e909959ff0f22eff359028db6861486b1555014c6952210374a4add33567f09967592c5bcdc3db421fdbba67bac4636328f96d941da31bd221039636c2ffac90afb7499b16e265078113dfb2d77b54270e37353217c9eaeaf3052103d0bcea6d10cdd2f16018ea71572631708e26f457f67cda36a7f816a87f7791d253aeffffffff04977261000000000016001470385d054721987f41521648d7b2f5c77f735d6bee92030000000000225120d0cda1b675a0b369964cbfa381721aae3549dd2c9c6f2cf71ff67d5bc277afd3f2aaf30000000000160014ed2d41ba08313dbb2630a7106b2fedafc14aa121d4f0c70000000000220020e5c7c00d174631d2d1e365d6347b016fb87b6a0c08902d8e443989cb771fa7ec00000000"); - let mut cursor = std::io::Cursor::new(&mut tx_bytes); - let tx = Transaction::consensus_decode(&mut cursor).unwrap(); + let tx_bytes = hex_decode("0100000003fe785783e14669f638ba902c26e8e3d7036fb183237bc00f8a10542191c7171300000000fdfd00004730440220418996f20477d143d02ad47e74e5949641b6c2904159ab7c592d2cfc659f9bd802205b18f18ac86b714971f84a8b74a4cb14ad5c1a5b9d0d939bb32c6ae4032f4ea10148304502210091296ff8dd87b5ebfc3d47cb82cfe4750d52c544a2b88a85970354a4d0d4b1db022069632067ee6f30f06145f649bc76d5e5d5e6404dbe985e006fcde938f778c297014c695221030502b8ade694d57a6e86998180a64f4ce993372830dc796c3d561ad8b2a504de210272b68e1c037c4630eff7ea5858640cc0748e36f5de82fb38529ef1fd0a89670d2103ba0544a3a2aa9f2314022760b78b5c833aebf6f88468a089550f93834a2886ed53aeffffffff7e048a7c53a8af656e24442c65fe4c4299b1494f6c7579fe0fd9fa741ce83e3279000000fc004730440220018fa343acccd048ed8f8f179e1b6ae27435a41b5fb2c1d96a5a772777acc6dc022074783814f2100c6fc4d4c976f941212be50825814502ca0cbe3f929db789979e0147304402206373f01b73fb09876d0f5ee3087e0614cab3be249934bc2b7eb64ee67f53dc8302200b50f8a327020172b82aaba7480c77ecf07bb32322a05f4afbc543aa97d2fde8014c69522103039d906b2494e310f6c7774c98618be552720d04781e073dd3ff25d5906f22662103d82026baa529619b103ec6341d548a7eb6d924061a8469a7416155513a3071c12102e452bc4aa726d44646ba80db70465683b30efde282a19aa35c6029ae8925df5e53aeffffffffef80f0b1cc543de4f73d59c02a3c575ae5d0af17c1e11e6be7abe3325c777507ad000000fdfd00004730440220220fee11bf836621a11a8ea9100a4600c109c13895f11468d3e2062210c5481902201c5c8a462175538e87b8248e1ed3927c3a461c66d1b46215641c875e86eb22c4014830450221008d2de8c2f20a720129c372791e595b9602b1a9bce99618497aec5266148ffc1302203a493359d700ed96323f8805ed03e909959ff0f22eff359028db6861486b1555014c6952210374a4add33567f09967592c5bcdc3db421fdbba67bac4636328f96d941da31bd221039636c2ffac90afb7499b16e265078113dfb2d77b54270e37353217c9eaeaf3052103d0bcea6d10cdd2f16018ea71572631708e26f457f67cda36a7f816a87f7791d253aeffffffff04977261000000000016001470385d054721987f41521648d7b2f5c77f735d6bee92030000000000225120d0cda1b675a0b369964cbfa381721aae3549dd2c9c6f2cf71ff67d5bc277afd3f2aaf30000000000160014ed2d41ba08313dbb2630a7106b2fedafc14aa121d4f0c70000000000220020e5c7c00d174631d2d1e365d6347b016fb87b6a0c08902d8e443989cb771fa7ec00000000"); + let tx = Transaction::consensus_decode(&mut tx_bytes.as_slice()).unwrap(); let orig_weight = tx.weight(); let input_values = vec![022_680_000, 006_558_175, 006_558_200]; let candidates = tx @@ -124,15 +121,15 @@ fn legacy_three_inputs() { .zip(input_values) .map(|(txin, value)| Candidate { value, - weight: txin.legacy_weight() as u32, + weight: txin.legacy_weight().to_wu(), input_count: 1, is_segwit: false, }) .collect::>(); let target_ouputs = TargetOutputs { - value_sum: tx.output.iter().map(|output| output.value).sum(), - weight_sum: tx.output.iter().map(|output| output.weight() as u32).sum(), + value_sum: tx.output.iter().map(|output| output.value.to_sat()).sum(), + weight_sum: tx.output.iter().map(|output| output.weight().to_wu()).sum(), n_outputs: tx.output.len(), }; @@ -141,7 +138,7 @@ fn legacy_three_inputs() { assert_eq!( coin_selector.weight(target_ouputs, DrainWeights::NONE), - orig_weight.to_wu() as u32 + orig_weight.to_wu() ); assert_eq!( (coin_selector @@ -158,9 +155,8 @@ fn legacy_three_inputs() { fn legacy_three_inputs_one_segwit() { // FROM https://mempool.space/tx/5f231df4f73694b3cca9211e336451c20dab136e0a843c2e3166cdcb093e91f4 // Except we change the middle input to segwit - let mut tx_bytes = hex_decode("0100000003fe785783e14669f638ba902c26e8e3d7036fb183237bc00f8a10542191c7171300000000fdfd00004730440220418996f20477d143d02ad47e74e5949641b6c2904159ab7c592d2cfc659f9bd802205b18f18ac86b714971f84a8b74a4cb14ad5c1a5b9d0d939bb32c6ae4032f4ea10148304502210091296ff8dd87b5ebfc3d47cb82cfe4750d52c544a2b88a85970354a4d0d4b1db022069632067ee6f30f06145f649bc76d5e5d5e6404dbe985e006fcde938f778c297014c695221030502b8ade694d57a6e86998180a64f4ce993372830dc796c3d561ad8b2a504de210272b68e1c037c4630eff7ea5858640cc0748e36f5de82fb38529ef1fd0a89670d2103ba0544a3a2aa9f2314022760b78b5c833aebf6f88468a089550f93834a2886ed53aeffffffff7e048a7c53a8af656e24442c65fe4c4299b1494f6c7579fe0fd9fa741ce83e3279000000fc004730440220018fa343acccd048ed8f8f179e1b6ae27435a41b5fb2c1d96a5a772777acc6dc022074783814f2100c6fc4d4c976f941212be50825814502ca0cbe3f929db789979e0147304402206373f01b73fb09876d0f5ee3087e0614cab3be249934bc2b7eb64ee67f53dc8302200b50f8a327020172b82aaba7480c77ecf07bb32322a05f4afbc543aa97d2fde8014c69522103039d906b2494e310f6c7774c98618be552720d04781e073dd3ff25d5906f22662103d82026baa529619b103ec6341d548a7eb6d924061a8469a7416155513a3071c12102e452bc4aa726d44646ba80db70465683b30efde282a19aa35c6029ae8925df5e53aeffffffffef80f0b1cc543de4f73d59c02a3c575ae5d0af17c1e11e6be7abe3325c777507ad000000fdfd00004730440220220fee11bf836621a11a8ea9100a4600c109c13895f11468d3e2062210c5481902201c5c8a462175538e87b8248e1ed3927c3a461c66d1b46215641c875e86eb22c4014830450221008d2de8c2f20a720129c372791e595b9602b1a9bce99618497aec5266148ffc1302203a493359d700ed96323f8805ed03e909959ff0f22eff359028db6861486b1555014c6952210374a4add33567f09967592c5bcdc3db421fdbba67bac4636328f96d941da31bd221039636c2ffac90afb7499b16e265078113dfb2d77b54270e37353217c9eaeaf3052103d0bcea6d10cdd2f16018ea71572631708e26f457f67cda36a7f816a87f7791d253aeffffffff04977261000000000016001470385d054721987f41521648d7b2f5c77f735d6bee92030000000000225120d0cda1b675a0b369964cbfa381721aae3549dd2c9c6f2cf71ff67d5bc277afd3f2aaf30000000000160014ed2d41ba08313dbb2630a7106b2fedafc14aa121d4f0c70000000000220020e5c7c00d174631d2d1e365d6347b016fb87b6a0c08902d8e443989cb771fa7ec00000000"); - let mut cursor = std::io::Cursor::new(&mut tx_bytes); - let mut tx = Transaction::consensus_decode(&mut cursor).unwrap(); + let tx_bytes = hex_decode("0100000003fe785783e14669f638ba902c26e8e3d7036fb183237bc00f8a10542191c7171300000000fdfd00004730440220418996f20477d143d02ad47e74e5949641b6c2904159ab7c592d2cfc659f9bd802205b18f18ac86b714971f84a8b74a4cb14ad5c1a5b9d0d939bb32c6ae4032f4ea10148304502210091296ff8dd87b5ebfc3d47cb82cfe4750d52c544a2b88a85970354a4d0d4b1db022069632067ee6f30f06145f649bc76d5e5d5e6404dbe985e006fcde938f778c297014c695221030502b8ade694d57a6e86998180a64f4ce993372830dc796c3d561ad8b2a504de210272b68e1c037c4630eff7ea5858640cc0748e36f5de82fb38529ef1fd0a89670d2103ba0544a3a2aa9f2314022760b78b5c833aebf6f88468a089550f93834a2886ed53aeffffffff7e048a7c53a8af656e24442c65fe4c4299b1494f6c7579fe0fd9fa741ce83e3279000000fc004730440220018fa343acccd048ed8f8f179e1b6ae27435a41b5fb2c1d96a5a772777acc6dc022074783814f2100c6fc4d4c976f941212be50825814502ca0cbe3f929db789979e0147304402206373f01b73fb09876d0f5ee3087e0614cab3be249934bc2b7eb64ee67f53dc8302200b50f8a327020172b82aaba7480c77ecf07bb32322a05f4afbc543aa97d2fde8014c69522103039d906b2494e310f6c7774c98618be552720d04781e073dd3ff25d5906f22662103d82026baa529619b103ec6341d548a7eb6d924061a8469a7416155513a3071c12102e452bc4aa726d44646ba80db70465683b30efde282a19aa35c6029ae8925df5e53aeffffffffef80f0b1cc543de4f73d59c02a3c575ae5d0af17c1e11e6be7abe3325c777507ad000000fdfd00004730440220220fee11bf836621a11a8ea9100a4600c109c13895f11468d3e2062210c5481902201c5c8a462175538e87b8248e1ed3927c3a461c66d1b46215641c875e86eb22c4014830450221008d2de8c2f20a720129c372791e595b9602b1a9bce99618497aec5266148ffc1302203a493359d700ed96323f8805ed03e909959ff0f22eff359028db6861486b1555014c6952210374a4add33567f09967592c5bcdc3db421fdbba67bac4636328f96d941da31bd221039636c2ffac90afb7499b16e265078113dfb2d77b54270e37353217c9eaeaf3052103d0bcea6d10cdd2f16018ea71572631708e26f457f67cda36a7f816a87f7791d253aeffffffff04977261000000000016001470385d054721987f41521648d7b2f5c77f735d6bee92030000000000225120d0cda1b675a0b369964cbfa381721aae3549dd2c9c6f2cf71ff67d5bc277afd3f2aaf30000000000160014ed2d41ba08313dbb2630a7106b2fedafc14aa121d4f0c70000000000220020e5c7c00d174631d2d1e365d6347b016fb87b6a0c08902d8e443989cb771fa7ec00000000"); + let mut tx = Transaction::consensus_decode(&mut tx_bytes.as_slice()).unwrap(); tx.input[1].script_sig = ScriptBuf::default(); tx.input[1].witness = vec![ // semi-realistic p2wpkh spend @@ -181,7 +177,8 @@ fn legacy_three_inputs_one_segwit() { txin.segwit_weight() } else { txin.legacy_weight() - } as u32, + } + .to_wu(), input_count: 1, is_segwit, } @@ -189,8 +186,8 @@ fn legacy_three_inputs_one_segwit() { .collect::>(); let target_ouputs = TargetOutputs { - value_sum: tx.output.iter().map(|output| output.value).sum(), - weight_sum: tx.output.iter().map(|output| output.weight() as u32).sum(), + value_sum: tx.output.iter().map(|output| output.value.to_sat()).sum(), + weight_sum: tx.output.iter().map(|output| output.weight().to_wu()).sum(), n_outputs: tx.output.len(), }; @@ -199,6 +196,6 @@ fn legacy_three_inputs_one_segwit() { assert_eq!( coin_selector.weight(target_ouputs, DrainWeights::NONE), - tx.weight().to_wu() as u32 + tx.weight().to_wu() ); }