From 6dac1a067c1f8730e03e7b84505b15b24f27f25b Mon Sep 17 00:00:00 2001 From: none34829 Date: Thu, 23 Apr 2026 15:55:59 +0530 Subject: [PATCH] fix(wallet)!: make TxBuilder::current_height type-safe via absolute::Height --- src/wallet/mod.rs | 6 +++++- src/wallet/tx_builder.rs | 9 ++++++--- tests/wallet.rs | 8 ++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 1cdd1cc7..ba9a4126 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -1305,7 +1305,11 @@ impl Wallet { // If they didn't tell us the current height, we assume it's the latest sync height. None => { let tip_height = self.chain.tip().height(); - absolute::LockTime::from_height(tip_height).expect("invalid height") + // If the local chain tip height is not a valid block height for a locktime, + // that's an invariant violation in `LocalChain` (block heights are + // always below the locktime threshold) and should be addressed upstream. + absolute::LockTime::from_height(tip_height) + .expect("LocalChain tip height should be a valid block height") } Some(h) => h, }; diff --git a/src/wallet/tx_builder.rs b/src/wallet/tx_builder.rs index f22a62cf..ca61d943 100644 --- a/src/wallet/tx_builder.rs +++ b/src/wallet/tx_builder.rs @@ -649,9 +649,12 @@ impl<'a, Cs> TxBuilder<'a, Cs> { /// them using [`TxBuilder::add_utxos`]. /// /// In both cases, if you don't provide a current height, we use the last sync height. - pub fn current_height(&mut self, height: u32) -> &mut Self { - self.params.current_height = - Some(absolute::LockTime::from_height(height).expect("Invalid height")); + /// + /// This method takes an [`absolute::Height`], which is guaranteed by the type system to + /// be a valid block height for a locktime (below 500_000_000). Callers can construct one + /// with [`absolute::Height::from_consensus`]. + pub fn current_height(&mut self, height: absolute::Height) -> &mut Self { + self.params.current_height = Some(absolute::LockTime::from(height)); self } diff --git a/tests/wallet.rs b/tests/wallet.rs index ae50334a..e59dba31 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -298,7 +298,7 @@ fn test_create_tx_custom_locktime() { let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) - .current_height(630_001) + .current_height(absolute::Height::from_consensus(630_001).unwrap()) .nlocktime(absolute::LockTime::from_height(630_000).unwrap()); let psbt = builder.finish().unwrap(); @@ -2537,7 +2537,7 @@ fn test_spend_coinbase() { let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), balance.immature / 2) - .current_height(confirmation_height); + .current_height(absolute::Height::from_consensus(confirmation_height).unwrap()); assert!(matches!( builder.finish(), Err(CreateTxError::CoinSelection( @@ -2552,7 +2552,7 @@ fn test_spend_coinbase() { let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), balance.immature / 2) - .current_height(not_yet_mature_time); + .current_height(absolute::Height::from_consensus(not_yet_mature_time).unwrap()); assert_matches!( builder.finish(), Err(CreateTxError::CoinSelection( @@ -2583,7 +2583,7 @@ fn test_spend_coinbase() { let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), balance.confirmed / 2) - .current_height(maturity_time); + .current_height(absolute::Height::from_consensus(maturity_time).unwrap()); builder.finish().unwrap(); }