Skip to content

Policy: Refactor: inline main:GetMinRelayFee() in main:AcceptToMemoryPool() #5709

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
2 changes: 1 addition & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-minrelaytxfee"))
{
CAmount n = 0;
if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
if (ParseMoney(mapArgs["-minrelaytxfee"], n) && MoneyRange(n))
::minRelayTxFee = CFeeRate(n);
else
return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
Expand Down
111 changes: 47 additions & 64 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ bool fAlerts = DEFAULT_ALERTS;

/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(1000);
bool fAllowFree = true;

CTxMemPool mempool(::minRelayTxFee);

Expand Down Expand Up @@ -718,36 +719,6 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return true;
}

CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
{
{
LOCK(mempool.cs);
uint256 hash = tx.GetHash();
double dPriorityDelta = 0;
CAmount nFeeDelta = 0;
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
if (dPriorityDelta > 0 || nFeeDelta > 0)
return 0;
}

CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);

if (fAllowFree)
{
// There is a free transaction area in blocks created by most miners,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
nMinFee = 0;
}

if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
}


bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee)
{
Expand Down Expand Up @@ -835,6 +806,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
view.SetBackend(dummy);
}

CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
// Don't accept it if it can't get into a block
if (nFees < 0)
return state.DoS(0, error("%s: negative fees %s, %d", __func__, hash.ToString(), nFees),
REJECT_INSUFFICIENTFEE, "insufficient fee");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably "insufficient fee" should be replaced with "bad-txns-fee-negative" to better keep track of the validation duplication.


// Check for non-standard pay-to-script-hash in inputs
if (fRequireStandard && !AreInputsStandard(tx, view))
return error("AcceptToMemoryPool: nonstandard transaction input");
Expand All @@ -852,48 +830,53 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),
REJECT_NONSTANDARD, "bad-txns-too-many-sigops");

CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
double dPriority = view.GetPriority(tx, chainActive.Height());

CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx));
unsigned int nSize = entry.GetTxSize();

// Don't accept it if it can't get into a block
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee)
return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",
hash.ToString(), nFees, txMinFee),
REJECT_INSUFFICIENTFEE, "insufficient fee");
bool fValidateFee = nFees >= ::minRelayTxFee.GetFee(nSize);
if (fLimitFree && !fValidateFee) {
double dPriorityDelta = 0;
CAmount nFeeDelta = 0;
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
if (!((dPriorityDelta > 0 || nFeeDelta > 0) ||
// There is a free transaction area in blocks created by most miners,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
(fAllowFree && nSize < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))))
return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",
hash.ToString(), nFees, ::minRelayTxFee.GetFee(nSize)),
REJECT_INSUFFICIENTFEE, "insufficient fee");

// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();

LOCK(csFreeLimiter);

// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"),
REJECT_INSUFFICIENTFEE, "rate limited free transaction");
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
}

// Require that free transactions have sufficient priority to be mined in the next block.
if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
if (GetBoolArg("-relaypriority", true) && !fValidateFee && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1)))
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}

// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize))
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();

LOCK(csFreeLimiter);

// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"),
REJECT_INSUFFICIENTFEE, "rate limited free transaction");
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}

if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",
Expand Down
3 changes: 0 additions & 3 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,6 @@ struct CDiskTxPos : public CDiskBlockPos
}
};


CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);

/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent
Expand Down