@@ -764,7 +764,8 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, const uint256&
764764 * current chain tip unless we are not synced with the current chain
765765 */
766766static void DiscourageFeeSniping (CMutableTransaction& tx, FastRandomContext& rng_fast,
767- interfaces::Chain& chain, const uint256& block_hash, int block_height)
767+ interfaces::Chain& chain, const uint256& block_hash, int block_height,
768+ unsigned int min_locktime)
768769{
769770 // All inputs must be added by now
770771 assert (!tx.vin .empty ());
@@ -796,8 +797,11 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
796797 // e.g. high-latency mix networks and some CoinJoin implementations, have
797798 // better privacy.
798799 if (rng_fast.randrange (10 ) == 0 ) {
799- tx.nLockTime = std::max (0 , int (tx.nLockTime ) - int (rng_fast.randrange (100 )));
800+ // Ensure that the back-dated timelock does not go beneath the min_timelock
801+ int locktime_range = std::min (100 , int (block_height - min_locktime));
802+ if (locktime_range > 0 ) tx.nLockTime = std::max (int (min_locktime), int (tx.nLockTime ) - int (rng_fast.randrange (locktime_range)));
800803 }
804+ assert (tx.nLockTime >= min_locktime);
801805 } else {
802806 // If our chain is lagging behind, we can't discourage fee sniping nor help
803807 // the privacy of high-latency transactions. To avoid leaking a potentially
@@ -1011,7 +1015,20 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
10111015 for (const auto & coin : selected_coins) {
10121016 txNew.vin .push_back (CTxIn (coin->outpoint , CScript (), nSequence));
10131017 }
1014- DiscourageFeeSniping (txNew, rng_fast, wallet.chain (), wallet.GetLastBlockHash (), wallet.GetLastBlockHeight ());
1018+
1019+ // Figure out the highest locktime of all of the unconfirmed inputs
1020+ // so that the nLockTime for this transaction does not go beneath that.
1021+ // If the nLockTime goes beneath any of the previous transactions'
1022+ // locktimes, that can be a wallet fingerprint.
1023+ std::set<unsigned int > input_tx_locktimes{0 }; // If there aren't any unconfirmed inputs, the minimum locktime is 0
1024+ for (const auto & coin: selected_coins) {
1025+ if (coin->depth == 0 ) {
1026+ const CWalletTx* coin_wtx{wallet.GetWalletTx (coin->outpoint .hash )};
1027+ if (coin_wtx) input_tx_locktimes.insert (coin_wtx->tx ->nLockTime );
1028+ }
1029+ }
1030+
1031+ DiscourageFeeSniping (txNew, rng_fast, wallet.chain (), wallet.GetLastBlockHash (), wallet.GetLastBlockHeight (), /* min_locktime=*/ *input_tx_locktimes.rbegin ());
10151032
10161033 // Calculate the transaction fee
10171034 TxSize tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, &coin_control);
0 commit comments