diff --git a/src/rust/include/rust/orchard/wallet.h b/src/rust/include/rust/orchard/wallet.h index 2c58b9206..fd787c054 100644 --- a/src/rust/include/rust/orchard/wallet.h +++ b/src/rust/include/rust/orchard/wallet.h @@ -333,6 +333,18 @@ void orchard_wallet_get_potential_spends( push_txid_callback_t push_cb ); +/** + * Returns a vector of transaction IDs for transactions that have been observed as + * spending the given nullifier by using the `push_cb` callback to push transaction + * IDs onto the provided result vector. + */ +void orchard_wallet_get_potential_spends_from_nullifier( + const OrchardWalletPtr* wallet, + const uint256& nullifier, + void* resultVector, + push_txid_callback_t push_cb + ); + /** * Fetches the information needed to spend the wallet note at the given outpoint, * relative to the current root known to the wallet of the Orchard commitment diff --git a/src/rust/src/wallet.rs b/src/rust/src/wallet.rs index 6d4670f47..28008e21b 100644 --- a/src/rust/src/wallet.rs +++ b/src/rust/src/wallet.rs @@ -1125,6 +1125,24 @@ pub extern "C" fn orchard_wallet_get_potential_spends( } } +#[no_mangle] +pub extern "C" fn orchard_wallet_get_potential_spends_from_nullifier( + wallet: *const Wallet, + nullifier: *const [c_uchar; 32], + result: Option, + push_cb: Option, +) { + let wallet = unsafe { wallet.as_ref() }.expect("Wallet pointer may not be null."); + let nullifier = + Nullifier::from_bytes(&*unsafe { nullifier.as_ref() }.expect("nullifier may not be null.")); + + if let Some(inpoints) = wallet.potential_spends.get(&nullifier.unwrap()) { + for inpoint in inpoints { + unsafe { (push_cb.unwrap())(result, inpoint.txid.as_ref()) }; + } + } +} + #[no_mangle] pub extern "C" fn orchard_wallet_get_spend_info( wallet: *const Wallet, diff --git a/src/wallet/orchard.h b/src/wallet/orchard.h index 894c21362..78c4cdb96 100644 --- a/src/wallet/orchard.h +++ b/src/wallet/orchard.h @@ -410,6 +410,17 @@ public: reinterpret_cast*>(txidsRet)->push_back(txid_out); } + std::vector GetPotentialSpendsFromNullifier(const uint256& nullifier) const { + std::vector result; + orchard_wallet_get_potential_spends_from_nullifier( + inner.get(), + nullifier, + &result, + PushTxId + ); + return result; + } + std::vector GetPotentialSpends(const OrchardOutPoint& outPoint) const { std::vector result; orchard_wallet_get_potential_spends( diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 4809189a1..2128f1f45 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1668,9 +1668,8 @@ set CWallet::GetConflicts(const uint256& txid) const } } - for (uint32_t i = 0; i < wtx.GetOrchardBundle().GetNumActions(); i++) { - OrchardOutPoint op(wtx.GetHash(), i); - auto potential_spends = orchardWallet.GetPotentialSpends(op); + for (const uint256& nullifier : wtx.GetOrchardBundle().GetNullifiers()) { + auto potential_spends = orchardWallet.GetPotentialSpendsFromNullifier(nullifier); if (potential_spends.size() <= 1) { continue; // No conflict if zero or one spends