Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 2,908 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx_new->vin) { | ||||
LockCoin(txin.prevout); | LockCoin(txin.prevout); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock &locked_chain) { | |||||
if (IsInitialBlockDownload()) { | |||||
return false; | |||||
} | |||||
// in seconds | |||||
constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; | |||||
if (ChainActive().Tip()->GetBlockTime() < | |||||
(GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Return a height-based locktime for new transactions (uses the height of the | |||||
* current chain tip unless we are not synced with the current chain | |||||
*/ | |||||
static uint32_t | |||||
GetLocktimeForNewTransaction(interfaces::Chain::Lock &locked_chain) { | |||||
uint32_t locktime; | |||||
// Discourage fee sniping. | |||||
// | |||||
// For a large miner the value of the transactions in the best block and | |||||
// the mempool can exceed the cost of deliberately attempting to mine two | |||||
// blocks to orphan the current best block. By setting nLockTime such that | |||||
// only the next block can include the transaction, we discourage this | |||||
// practice as the height restricted and limited blocksize gives miners | |||||
// considering fee sniping fewer options for pulling off this attack. | |||||
// | |||||
// A simple way to think about this is from the wallet's point of view we | |||||
// always want the blockchain to move forward. By setting nLockTime this | |||||
// way we're basically making the statement that we only want this | |||||
// transaction to appear in the next block; we don't want to potentially | |||||
// encourage reorgs by allowing transactions to appear at lower heights | |||||
// than the next block in forks of the best chain. | |||||
// | |||||
// Of course, the subsidy is high enough, and transaction volume low | |||||
// enough, that fee sniping isn't a problem yet, but by implementing a fix | |||||
// now we ensure code won't be written that makes assumptions about | |||||
// nLockTime that preclude a fix later. | |||||
if (IsCurrentForAntiFeeSniping(locked_chain)) { | |||||
locktime = ChainActive().Height(); | |||||
// Secondly occasionally randomly pick a nLockTime even further back, so | |||||
// that transactions that are delayed after signing for whatever reason, | |||||
// e.g. high-latency mix networks and some CoinJoin implementations, | |||||
// have better privacy. | |||||
if (GetRandInt(10) == 0) { | |||||
locktime = std::max(0, int(locktime) - GetRandInt(100)); | |||||
} | |||||
} else { | |||||
// If our chain is lagging behind, we can't discourage fee sniping nor | |||||
// help the privacy of high-latency transactions. To avoid leaking a | |||||
// potentially unique "nLockTime fingerprint", set nLockTime to a | |||||
// constant. | |||||
locktime = 0; | |||||
} | |||||
assert(locktime <= uint32_t(ChainActive().Height())); | |||||
assert(locktime < LOCKTIME_THRESHOLD); | |||||
return locktime; | |||||
} | |||||
OutputType | OutputType | ||||
CWallet::TransactionChangeType(OutputType change_type, | CWallet::TransactionChangeType(OutputType change_type, | ||||
const std::vector<CRecipient> &vecSend) { | const std::vector<CRecipient> &vecSend) { | ||||
// If -changetype is specified, always use that change type. | // If -changetype is specified, always use that change type. | ||||
if (change_type != OutputType::CHANGE_AUTO) { | if (change_type != OutputType::CHANGE_AUTO) { | ||||
return change_type; | return change_type; | ||||
} | } | ||||
Show All 30 Lines | bool CWallet::CreateTransaction(interfaces::Chain::Lock &locked_chainIn, | ||||
if (vecSend.empty()) { | if (vecSend.empty()) { | ||||
strFailReason = _("Transaction must have at least one recipient"); | strFailReason = _("Transaction must have at least one recipient"); | ||||
return false; | return false; | ||||
} | } | ||||
CMutableTransaction txNew; | CMutableTransaction txNew; | ||||
// Discourage fee sniping. | txNew.nLockTime = GetLocktimeForNewTransaction(locked_chainIn); | ||||
// | |||||
// For a large miner the value of the transactions in the best block and the | |||||
// mempool can exceed the cost of deliberately attempting to mine two blocks | |||||
// to orphan the current best block. By setting nLockTime such that only the | |||||
// next block can include the transaction, we discourage this practice as | |||||
// the height restricted and limited blocksize gives miners considering fee | |||||
// sniping fewer options for pulling off this attack. | |||||
// | |||||
// A simple way to think about this is from the wallet's point of view we | |||||
// always want the blockchain to move forward. By setting nLockTime this way | |||||
// we're basically making the statement that we only want this transaction | |||||
// to appear in the next block; we don't want to potentially encourage | |||||
// reorgs by allowing transactions to appear at lower heights than the next | |||||
// block in forks of the best chain. | |||||
// | |||||
// Of course, the subsidy is high enough, and transaction volume low enough, | |||||
// that fee sniping isn't a problem yet, but by implementing a fix now we | |||||
// ensure code won't be written that makes assumptions about nLockTime that | |||||
// preclude a fix later. | |||||
txNew.nLockTime = ::ChainActive().Height(); | |||||
// Secondly occasionally randomly pick a nLockTime even further back, so | |||||
// that transactions that are delayed after signing for whatever reason, | |||||
// e.g. high-latency mix networks and some CoinJoin implementations, have | |||||
// better privacy. | |||||
if (GetRandInt(10) == 0) { | |||||
txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100)); | |||||
} | |||||
assert(txNew.nLockTime <= (unsigned int)::ChainActive().Height()); | |||||
assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | |||||
{ | { | ||||
std::set<CInputCoin> setCoins; | std::set<CInputCoin> setCoins; | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::vector<COutput> vAvailableCoins; | std::vector<COutput> vAvailableCoins; | ||||
AvailableCoins(*locked_chain, vAvailableCoins, true, &coinControl); | AvailableCoins(*locked_chain, vAvailableCoins, true, &coinControl); | ||||
▲ Show 20 Lines • Show All 1,902 Lines • Show Last 20 Lines |