Skip to content

Commit 6958a5b

Browse files
committed
merge bitcoin#24225: Add sanity checks to DiscourageFeeSniping
1 parent 63dc779 commit 6958a5b

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

src/wallet/spend.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -581,12 +581,13 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, const uint256&
581581
}
582582

583583
/**
584-
* Return a height-based locktime for new transactions (uses the height of the
584+
* Set a height-based locktime for new transactions (uses the height of the
585585
* current chain tip unless we are not synced with the current chain
586586
*/
587-
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uint256& block_hash, int block_height)
587+
static void DiscourageFeeSniping(CMutableTransaction& tx, interfaces::Chain& chain, const uint256& block_hash, int block_height)
588588
{
589-
uint32_t locktime;
589+
// All inputs must be added by now
590+
assert(!tx.vin.empty());
590591
// Discourage fee sniping.
591592
//
592593
// For a large miner the value of the transactions in the best block and
@@ -608,22 +609,32 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uin
608609
// now we ensure code won't be written that makes assumptions about
609610
// nLockTime that preclude a fix later.
610611
if (IsCurrentForAntiFeeSniping(chain, block_hash)) {
611-
locktime = block_height;
612+
tx.nLockTime = block_height;
612613

613614
// Secondly occasionally randomly pick a nLockTime even further back, so
614615
// that transactions that are delayed after signing for whatever reason,
615616
// e.g. high-latency mix networks and some CoinJoin implementations, have
616617
// better privacy.
617-
if (GetRandInt(10) == 0)
618-
locktime = std::max(0, (int)locktime - GetRandInt(100));
618+
if (GetRandInt(10) == 0) {
619+
tx.nLockTime = std::max(0, int(tx.nLockTime) - GetRandInt(100));
620+
}
619621
} else {
620622
// If our chain is lagging behind, we can't discourage fee sniping nor help
621623
// the privacy of high-latency transactions. To avoid leaking a potentially
622624
// unique "nLockTime fingerprint", set nLockTime to a constant.
623-
locktime = 0;
625+
tx.nLockTime = 0;
626+
}
627+
// Sanity check all values
628+
assert(tx.nLockTime < LOCKTIME_THRESHOLD); // Type must be block height
629+
assert(tx.nLockTime <= uint64_t(block_height));
630+
for (const auto& in : tx.vin) {
631+
// Can not be FINAL for locktime to work
632+
assert(in.nSequence != CTxIn::SEQUENCE_FINAL);
633+
// May be MAX NONFINAL to disable BIP68
634+
if (in.nSequence == CTxIn::MAX_SEQUENCE_NONFINAL) continue;
635+
// The wallet does not support any other sequence-use right now.
636+
assert(false);
624637
}
625-
assert(locktime < LOCKTIME_THRESHOLD);
626-
return locktime;
627638
}
628639

629640
static bool CreateTransactionInternal(
@@ -641,7 +652,6 @@ static bool CreateTransactionInternal(
641652
AssertLockHeld(wallet.cs_wallet);
642653

643654
CMutableTransaction txNew; // The resulting transaction that we make
644-
txNew.nLockTime = GetLocktimeForNewTransaction(wallet.chain(), wallet.GetLastBlockHash(), wallet.GetLastBlockHeight());
645655

646656
CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
647657
coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends;
@@ -811,12 +821,13 @@ static bool CreateTransactionInternal(
811821
}
812822
};
813823

814-
// Note how the sequence number is set to non-maxint so that
815-
// the nLockTime set above actually works.
816-
const uint32_t nSequence = CTxIn::SEQUENCE_FINAL - 1;
824+
// The sequence number is set to non-maxint so that DiscourageFeeSniping
825+
// works.
826+
const uint32_t nSequence{CTxIn::SEQUENCE_FINAL - 1};
817827
for (const auto& coin : setCoins) {
818828
txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence));
819829
}
830+
DiscourageFeeSniping(txNew, wallet.chain(), wallet.GetLastBlockHash(), wallet.GetLastBlockHeight());
820831

821832
// Fill in final vin and shuffle/sort it
822833
if (sort_bip69) { std::sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69()); }

0 commit comments

Comments
 (0)