@@ -124,14 +124,13 @@ fn htlc_timeout_transaction_weight(context: &AnchorChannelReserveContext) -> u64
124124 }
125125}
126126
127- fn anchor_output_spend_transaction_weight ( context : & AnchorChannelReserveContext ) -> u64 {
127+ fn anchor_output_spend_transaction_weight (
128+ context : & AnchorChannelReserveContext , input_weight : Weight ,
129+ ) -> u64 {
128130 TRANSACTION_BASE_WEIGHT
129131 + ANCHOR_INPUT_WEIGHT
130- + if context. taproot_wallet {
131- P2TR_INPUT_WEIGHT + P2TR_OUTPUT_WEIGHT
132- } else {
133- P2WPKH_INPUT_WEIGHT + P2WPKH_OUTPUT_WEIGHT
134- }
132+ + input_weight. to_wu ( )
133+ + if context. taproot_wallet { P2TR_OUTPUT_WEIGHT } else { P2WPKH_OUTPUT_WEIGHT }
135134}
136135
137136/// Parameters defining the context around the anchor channel reserve requirement calculation.
@@ -167,19 +166,17 @@ impl Default for AnchorChannelReserveContext {
167166 }
168167}
169168
170- /// Returns the amount that needs to be maintained as a reserve per anchor channel.
171- ///
172- /// This reserve currently needs to be allocated as a disjoint set of UTXOs per channel,
173- /// as claims are not yet aggregated across channels.
174- pub fn get_reserve_per_channel ( context : & AnchorChannelReserveContext ) -> Amount {
169+ fn get_reserve_per_channel_with_input (
170+ context : & AnchorChannelReserveContext , initial_input_weight : Weight ,
171+ ) -> Amount {
175172 let weight = Weight :: from_wu (
176173 COMMITMENT_TRANSACTION_BASE_WEIGHT +
177174 // Reserves are calculated in terms of accepted HTLCs, as their timeout defines the urgency of
178175 // on-chain resolution. Each accepted HTLC is assumed to be forwarded to calculate an upper
179176 // bound for the reserve, resulting in `expected_accepted_htlcs` inbound HTLCs and
180177 // `expected_accepted_htlcs` outbound HTLCs per channel in aggregate.
181178 2 * ( context. expected_accepted_htlcs as u64 ) * COMMITMENT_TRANSACTION_PER_HTLC_WEIGHT +
182- anchor_output_spend_transaction_weight ( context) +
179+ anchor_output_spend_transaction_weight ( context, initial_input_weight ) +
183180 // As an upper bound, it is assumed that each HTLC is resolved in a separate transaction.
184181 // However, they might be aggregated when possible depending on timelocks and expiries.
185182 htlc_success_transaction_weight ( context) * ( context. expected_accepted_htlcs as u64 ) +
@@ -188,22 +185,33 @@ pub fn get_reserve_per_channel(context: &AnchorChannelReserveContext) -> Amount
188185 context. upper_bound_fee_rate . fee_wu ( weight) . unwrap_or ( Amount :: MAX )
189186}
190187
188+ /// Returns the amount that needs to be maintained as a reserve per anchor channel.
189+ ///
190+ /// This reserve currently needs to be allocated as a disjoint set of UTXOs per channel,
191+ /// as claims are not yet aggregated across channels.
192+ ///
193+ /// Note that the returned amount assumes that the reserve will be provided by a single UTXO of the
194+ /// type indicated by [AnchorChannelReserveContext::taproot_wallet]. Larger sets of UTXOs with more
195+ /// complex witnesses will require a correspondingly larger reserve due to the weight required to
196+ /// spend them.
197+ pub fn get_reserve_per_channel ( context : & AnchorChannelReserveContext ) -> Amount {
198+ get_reserve_per_channel_with_input (
199+ context,
200+ if context. taproot_wallet {
201+ Weight :: from_wu ( P2TR_INPUT_WEIGHT )
202+ } else {
203+ Weight :: from_wu ( P2WPKH_INPUT_WEIGHT )
204+ } ,
205+ )
206+ }
207+
191208/// Calculates the number of anchor channels that can be supported by the reserve provided
192209/// by `utxos`.
193210pub fn get_supportable_anchor_channels (
194211 context : & AnchorChannelReserveContext , utxos : & [ Utxo ] ,
195212) -> u64 {
196- // Get the reserve needed per channel, replacing the fee for an initial spend with the actual value
197- // below.
198- let default_satisfaction_fee = context
199- . upper_bound_fee_rate
200- . fee_wu ( Weight :: from_wu ( if context. taproot_wallet {
201- P2TR_INPUT_WEIGHT
202- } else {
203- P2WPKH_INPUT_WEIGHT
204- } ) )
205- . unwrap_or ( Amount :: MAX ) ;
206- let reserve_per_channel = get_reserve_per_channel ( context) - default_satisfaction_fee;
213+ // Get the reserve needed per channel, accounting for the actual satisfaction weight below.
214+ let reserve_per_channel = get_reserve_per_channel_with_input ( context, Weight :: ZERO ) ;
207215
208216 let mut total_fractional_amount = Amount :: from_sat ( 0 ) ;
209217 let mut num_whole_utxos = 0 ;
@@ -347,20 +355,20 @@ mod test {
347355 // https://mempool.space/tx/188b0f9f26999a48611dba4e2a88507251eba31f3695d005023de3514cba34bd
348356 // DER-encoded ECDSA signatures vary in size and can be 71-73 bytes.
349357 assert_eq ! (
350- anchor_output_spend_transaction_weight( & AnchorChannelReserveContext {
351- taproot_wallet: false ,
352- .. Default :: default ( )
353- } ) ,
358+ anchor_output_spend_transaction_weight(
359+ & AnchorChannelReserveContext { taproot_wallet: false , .. Default :: default ( ) } ,
360+ Weight :: from_wu ( P2WPKH_INPUT_WEIGHT ) ,
361+ ) ,
354362 717
355363 ) ;
356364
357365 // Example:
358366 // https://mempool.space/tx/9c493177e395ec77d9e725e1cfd465c5f06d4a5816dd0274c3a8c2442d854a85
359367 assert_eq ! (
360- anchor_output_spend_transaction_weight( & AnchorChannelReserveContext {
361- taproot_wallet: true ,
362- .. Default :: default ( )
363- } ) ,
368+ anchor_output_spend_transaction_weight(
369+ & AnchorChannelReserveContext { taproot_wallet: true , .. Default :: default ( ) } ,
370+ Weight :: from_wu ( P2TR_INPUT_WEIGHT ) ,
371+ ) ,
364372 723
365373 ) ;
366374 }
0 commit comments