@@ -37,7 +37,7 @@ use bitcoin::{
37
37
absolute,
38
38
consensus:: encode:: serialize,
39
39
constants:: genesis_block,
40
- psbt,
40
+ psbt, relative ,
41
41
secp256k1:: Secp256k1 ,
42
42
sighash:: { EcdsaSighashType , TapSighashType } ,
43
43
transaction, Address , Amount , Block , BlockHash , FeeRate , Network , OutPoint , Psbt , ScriptBuf ,
@@ -2793,42 +2793,56 @@ impl Wallet {
2793
2793
Ok ( ( psbt, finalizer) )
2794
2794
}
2795
2795
2796
- /// Plan the output with the available assets and return a new [`Input`].
2797
- fn plan_input ( & self , output : & LocalOutput , assets : & Assets ) -> Option < Input > {
2796
+ /// Plan the output with the available assets and return a new [`Input`] if possible. See also
2797
+ /// [`Self::try_plan`].
2798
+ fn plan_input ( & self , output : & LocalOutput , spend_assets : & Assets ) -> Option < Input > {
2798
2799
let op = output. outpoint ;
2799
2800
let txid = op. txid ;
2800
- if let Some ( plan) = self . try_plan ( op, assets) {
2801
- let tx = self . indexed_graph . graph ( ) . get_tx ( txid) . unwrap ( ) ;
2802
- return Some (
2803
- Input :: from_prev_tx (
2804
- plan,
2805
- tx,
2806
- op. vout as usize ,
2807
- status_from_position ( output. chain_position ) ,
2808
- )
2809
- . expect ( "invalid outpoint" ) ,
2810
- ) ;
2811
- }
2812
2801
2813
- None
2802
+ // We want to afford the output with as many assets as we can. The plan
2803
+ // will use only the ones needed to produce the minimum satisfaction.
2804
+ let cur_height = self . latest_checkpoint ( ) . height ( ) ;
2805
+ let abs_locktime = spend_assets
2806
+ . absolute_timelock
2807
+ . unwrap_or ( absolute:: LockTime :: from_consensus ( cur_height) ) ;
2808
+
2809
+ let rel_locktime = spend_assets. relative_timelock . unwrap_or_else ( || {
2810
+ let age = match output. chain_position . confirmation_height_upper_bound ( ) {
2811
+ Some ( conf_height) => cur_height
2812
+ . saturating_add ( 1 )
2813
+ . saturating_sub ( conf_height)
2814
+ . try_into ( )
2815
+ . unwrap_or ( u16:: MAX ) ,
2816
+ None => 0 ,
2817
+ } ;
2818
+ relative:: LockTime :: from_height ( age)
2819
+ } ) ;
2820
+
2821
+ let mut assets = Assets :: new ( ) ;
2822
+ assets. extend ( spend_assets) ;
2823
+ assets = assets. after ( abs_locktime) ;
2824
+ assets = assets. older ( rel_locktime) ;
2825
+
2826
+ let plan = self . try_plan ( op, & assets) ?;
2827
+ let tx = self . indexed_graph . graph ( ) . get_tx ( txid) ?;
2828
+ let tx_status = status_from_position ( output. chain_position ) ;
2829
+
2830
+ Input :: from_prev_tx ( plan, tx, op. vout as usize , tx_status) . ok ( )
2814
2831
}
2815
2832
2816
2833
/// Attempt to create a spending plan for the UTXO of the given `outpoint`
2817
2834
/// with the provided `assets`.
2818
2835
///
2819
2836
/// Return `None` if `outpoint` doesn't correspond to an indexed txout, or
2820
2837
/// if the assets are not sufficient to create a plan.
2821
- //
2822
- // TODO: This should internally set the after/older for `outpoint`
2823
- // based on the current height and age of the coin respectively.
2824
2838
fn try_plan ( & self , outpoint : OutPoint , assets : & Assets ) -> Option < Plan > {
2825
2839
let indexer = & self . indexed_graph . index ;
2826
2840
let ( ( keychain, index) , _) = indexer. txout ( outpoint) ?;
2827
- let desc = indexer
2841
+ let def_desc = indexer
2828
2842
. get_descriptor ( keychain) ?
2829
2843
. at_derivation_index ( index)
2830
2844
. expect ( "must be valid derivation index" ) ;
2831
- desc . plan ( assets) . ok ( )
2845
+ def_desc . plan ( assets) . ok ( )
2832
2846
}
2833
2847
}
2834
2848
0 commit comments