@@ -2516,6 +2516,65 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
2516
2516
return true ;
2517
2517
}
2518
2518
2519
+ static bool IsCurrentForAntiFeeSniping (interfaces::Chain::Lock& locked_chain)
2520
+ {
2521
+ if (IsInitialBlockDownload ()) {
2522
+ return false ;
2523
+ }
2524
+ constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60 ; // in seconds
2525
+ if (chainActive.Tip ()->GetBlockTime () < (GetTime () - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
2526
+ return false ;
2527
+ }
2528
+ return true ;
2529
+ }
2530
+
2531
+ /* *
2532
+ * Return a height-based locktime for new transactions (uses the height of the
2533
+ * current chain tip unless we are not synced with the current chain
2534
+ */
2535
+ static uint32_t GetLocktimeForNewTransaction (interfaces::Chain::Lock& locked_chain)
2536
+ {
2537
+ uint32_t locktime;
2538
+ // Discourage fee sniping.
2539
+ //
2540
+ // For a large miner the value of the transactions in the best block and
2541
+ // the mempool can exceed the cost of deliberately attempting to mine two
2542
+ // blocks to orphan the current best block. By setting nLockTime such that
2543
+ // only the next block can include the transaction, we discourage this
2544
+ // practice as the height restricted and limited blocksize gives miners
2545
+ // considering fee sniping fewer options for pulling off this attack.
2546
+ //
2547
+ // A simple way to think about this is from the wallet's point of view we
2548
+ // always want the blockchain to move forward. By setting nLockTime this
2549
+ // way we're basically making the statement that we only want this
2550
+ // transaction to appear in the next block; we don't want to potentially
2551
+ // encourage reorgs by allowing transactions to appear at lower heights
2552
+ // than the next block in forks of the best chain.
2553
+ //
2554
+ // Of course, the subsidy is high enough, and transaction volume low
2555
+ // enough, that fee sniping isn't a problem yet, but by implementing a fix
2556
+ // now we ensure code won't be written that makes assumptions about
2557
+ // nLockTime that preclude a fix later.
2558
+ if (IsCurrentForAntiFeeSniping (locked_chain)) {
2559
+ locktime = chainActive.Height ();
2560
+
2561
+ // Secondly occasionally randomly pick a nLockTime even further back, so
2562
+ // that transactions that are delayed after signing for whatever reason,
2563
+ // e.g. high-latency mix networks and some CoinJoin implementations, have
2564
+ // better privacy.
2565
+ if (GetRandInt (10 ) == 0 )
2566
+ locktime = std::max (0 , (int )locktime - GetRandInt (100 ));
2567
+ } else {
2568
+ // If our chain is lagging behind, we can't discourage fee sniping nor help
2569
+ // the privacy of high-latency transactions. To avoid leaking a potentially
2570
+ // unique "nLockTime fingerprint", set nLockTime to a constant.
2571
+ locktime = 0 ;
2572
+ }
2573
+ assert (locktime <= (unsigned int )chainActive.Height ());
2574
+ assert (locktime < LOCKTIME_THRESHOLD);
2575
+ return locktime;
2576
+ }
2577
+
2519
2578
OutputType CWallet::TransactionChangeType (OutputType change_type, const std::vector<CRecipient>& vecSend)
2520
2579
{
2521
2580
// If -changetype is specified, always use that change type.
@@ -2570,37 +2629,8 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
2570
2629
2571
2630
CMutableTransaction txNew;
2572
2631
2573
- // Discourage fee sniping.
2574
- //
2575
- // For a large miner the value of the transactions in the best block and
2576
- // the mempool can exceed the cost of deliberately attempting to mine two
2577
- // blocks to orphan the current best block. By setting nLockTime such that
2578
- // only the next block can include the transaction, we discourage this
2579
- // practice as the height restricted and limited blocksize gives miners
2580
- // considering fee sniping fewer options for pulling off this attack.
2581
- //
2582
- // A simple way to think about this is from the wallet's point of view we
2583
- // always want the blockchain to move forward. By setting nLockTime this
2584
- // way we're basically making the statement that we only want this
2585
- // transaction to appear in the next block; we don't want to potentially
2586
- // encourage reorgs by allowing transactions to appear at lower heights
2587
- // than the next block in forks of the best chain.
2588
- //
2589
- // Of course, the subsidy is high enough, and transaction volume low
2590
- // enough, that fee sniping isn't a problem yet, but by implementing a fix
2591
- // now we ensure code won't be written that makes assumptions about
2592
- // nLockTime that preclude a fix later.
2593
- txNew.nLockTime = chainActive.Height ();
2594
-
2595
- // Secondly occasionally randomly pick a nLockTime even further back, so
2596
- // that transactions that are delayed after signing for whatever reason,
2597
- // e.g. high-latency mix networks and some CoinJoin implementations, have
2598
- // better privacy.
2599
- if (GetRandInt (10 ) == 0 )
2600
- txNew.nLockTime = std::max (0 , (int )txNew.nLockTime - GetRandInt (100 ));
2632
+ txNew.nLockTime = GetLocktimeForNewTransaction (locked_chain);
2601
2633
2602
- assert (txNew.nLockTime <= (unsigned int )chainActive.Height ());
2603
- assert (txNew.nLockTime < LOCKTIME_THRESHOLD);
2604
2634
FeeCalculation feeCalc;
2605
2635
CAmount nFeeNeeded;
2606
2636
int nBytes;
0 commit comments