Skip to content

Commit fa8e76b

Browse files
author
MarcoFalke
committed
wallet: Add sanity checks to AntiFeeSnipe
1 parent a41976a commit fa8e76b

File tree

1 file changed

+25
-12
lines changed

1 file changed

+25
-12
lines changed

src/wallet/spend.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -583,12 +583,13 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, const uint256&
583583
}
584584

585585
/**
586-
* Return a height-based locktime for new transactions (uses the height of the
586+
* Set a height-based locktime for new transactions (uses the height of the
587587
* current chain tip unless we are not synced with the current chain
588588
*/
589-
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uint256& block_hash, int block_height)
589+
static void DiscourageFeeSniping(CMutableTransaction& tx, interfaces::Chain& chain, const uint256& block_hash, int block_height)
590590
{
591-
uint32_t locktime;
591+
// All inputs must be added by now
592+
assert(!tx.vin.empty());
592593
// Discourage fee sniping.
593594
//
594595
// For a large miner the value of the transactions in the best block and
@@ -610,22 +611,34 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uin
610611
// now we ensure code won't be written that makes assumptions about
611612
// nLockTime that preclude a fix later.
612613
if (IsCurrentForAntiFeeSniping(chain, block_hash)) {
613-
locktime = block_height;
614+
tx.nLockTime = block_height;
614615

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

631644
static bool CreateTransactionInternal(
@@ -642,7 +655,6 @@ static bool CreateTransactionInternal(
642655
AssertLockHeld(wallet.cs_wallet);
643656

644657
CMutableTransaction txNew; // The resulting transaction that we make
645-
txNew.nLockTime = GetLocktimeForNewTransaction(wallet.chain(), wallet.GetLastBlockHash(), wallet.GetLastBlockHeight());
646658

647659
CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
648660
coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends;
@@ -788,8 +800,8 @@ static bool CreateTransactionInternal(
788800
// Shuffle selected coins and fill in final vin
789801
std::vector<CInputCoin> selected_coins = result->GetShuffledInputVector();
790802

791-
// Note how the sequence number is set to non-maxint so that
792-
// the nLockTime set above actually works.
803+
// The sequence number is set to non-maxint so that DiscourageFeeSniping
804+
// works.
793805
//
794806
// BIP125 defines opt-in RBF as any nSequence < maxint-1, so
795807
// we use the highest possible value in that range (maxint-2)
@@ -800,6 +812,7 @@ static bool CreateTransactionInternal(
800812
for (const auto& coin : selected_coins) {
801813
txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence));
802814
}
815+
DiscourageFeeSniping(txNew, wallet.chain(), wallet.GetLastBlockHash(), wallet.GetLastBlockHeight());
803816

804817
// Calculate the transaction fee
805818
TxSize tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);

0 commit comments

Comments
 (0)