Summary
Closes #34987.
Previously, nLockTime anti-fee-sniping (current block height ±100 blocks) was
only applied by the send RPC and GUI wallet flow. walletcreatefundedpsbt and
fundrawtransaction both defaulted to nLockTime=0, creating a wallet
fingerprinting discrepancy.
Root cause (two issues):
wallet::FundTransactionunconditionally setcoinControl.m_locktime = tx.nLockTimeeven whentx.nLockTimewas the default0. SincecoinControl.m_locktimeisstd::optional<uint32_t>, assigning0makes it non-empty, which suppressesDiscourageFeeSniping()inCreateTransaction. Fixed by only settingm_locktimewhentx.nLockTime != 0.walletcreatefundedpsbtdocumented itslocktimeparameter default as0rather than the anti-fee-sniping default. Updated to matchsend.
After this change: all wallet-funded RPCs uniformly apply anti-fee-sniping unless the caller provides an explicit locktime value.
Behavior
| RPC | Before | After |
|---|---|---|
send |
anti-fee-sniping ✓ | anti-fee-sniping ✓ (unchanged) |
walletcreatefundedpsbt (no locktime) |
nLockTime=0 |
anti-fee-sniping ✓ |
fundrawtransaction (raw tx with default locktime) |
nLockTime=0 |
anti-fee-sniping ✓ |
Any RPC with explicit locktime=N |
nLockTime=N |
nLockTime=N (unchanged) |
Test plan
wallet_create_tx.py— newtest_walletcreatefundedpsbt_anti_fee_sniping()andtest_fundrawtransaction_anti_fee_sniping()rpc_psbt.py— updated existing assertion that expectedlocktime=0fromwalletcreatefundedpsbtwith no argumentswallet_send.py,wallet_sendall.py,wallet_fundrawtransaction.py— all pass, no regressions