merge bitcoin#8365: Treat high-sigop transactions as larger rather than rejecting them (#4562)

This commit is contained in:
Kittywhiskers Van Gogh 2021-11-09 00:13:24 +05:30 committed by GitHub
parent d4910cab3b
commit 0a760bb809
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 42 additions and 19 deletions

View File

@ -14,11 +14,11 @@ static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& po
int64_t nTime = 0;
unsigned int nHeight = 1;
bool spendsCoinbase = false;
unsigned int sigOpCost = 4;
unsigned int sigOps = 1;
LockPoints lp;
pool.addUnchecked(CTxMemPoolEntry(
tx, nFee, nTime, nHeight,
spendsCoinbase, sigOpCost, lp));
spendsCoinbase, sigOps, lp));
}
// Right now this is only testing eviction performance in an extremely small

View File

@ -15,7 +15,7 @@
static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
{
LockPoints lp;
pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOpCost */ 4, lp));
pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOps */ 1, lp));
}
static void RpcMempool(benchmark::Bench& bench)

View File

@ -698,7 +698,7 @@ void SetupServerArgs()
gArgs.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), true, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), true, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), true, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-bytespersigop", strprintf("Minimum bytes per sigop in transactions we relay and mine (default: %u)", DEFAULT_BYTES_PER_SIGOP), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",

View File

@ -170,5 +170,16 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
return true;
}
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
int64_t GetVirtualTransactionSize(int64_t nSize, int64_t nSigOp)
{
return std::max(nSize, nSigOp * nBytesPerSigOp);
}
int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOp)
{
return GetVirtualTransactionSize(tx.GetTotalSize(), nSigOp);
}

View File

@ -32,6 +32,8 @@ static const unsigned int MAX_STANDARD_TX_SIGOPS = 4000;
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/
static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
/** Default for -bytespersigop */
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
/** Min feerate for defining dust. Historically this has been based on the
* minRelayTxFee, however changing the dust limit changes which transactions are
* standard and should be done with care and ideally rarely. It makes sense to
@ -81,6 +83,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason);
*/
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
extern unsigned int nBytesPerSigOp;
/** Compute the virtual transaction size (taking sigops into account). */
int64_t GetVirtualTransactionSize(int64_t nSize, int64_t nSigOp);
int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOp = 0);
extern CFeeRate incrementalRelayFee;
extern CFeeRate dustRelayFee;
#endif // BITCOIN_POLICY_POLICY_H

View File

@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <txmempool.h>
#include <policy/policy.h>
#include <util/system.h>
#include <test/setup_common.h>
@ -308,7 +309,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx2.vout[0].nValue = 2 * COIN;
pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2));
uint64_t tx2Size = ::GetSerializeSize(tx2, SER_NETWORK, PROTOCOL_VERSION);
uint64_t tx2Size = GetVirtualTransactionSize(CTransaction(tx2));
/* lowest fee */
CMutableTransaction tx3 = CMutableTransaction();
@ -356,7 +357,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx6.vout.resize(1);
tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx6.vout[0].nValue = 20 * COIN;
uint64_t tx6Size = ::GetSerializeSize(tx6, SER_NETWORK, PROTOCOL_VERSION);
uint64_t tx6Size = GetVirtualTransactionSize(CTransaction(tx6));
pool.addUnchecked(entry.Fee(0LL).FromTx(tx6));
BOOST_CHECK_EQUAL(pool.size(), 6U);
@ -375,7 +376,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx7.vout.resize(1);
tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx7.vout[0].nValue = 10 * COIN;
uint64_t tx7Size = ::GetSerializeSize(tx7, SER_NETWORK, PROTOCOL_VERSION);
uint64_t tx7Size = GetVirtualTransactionSize(CTransaction(tx7));
/* set the fee to just below tx2's feerate when including ancestor */
CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
@ -463,12 +464,12 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(tx2.GetHash()));
BOOST_CHECK(pool.exists(tx3.GetHash()));
pool.TrimToSize(::GetSerializeSize(CTransaction(tx1), SER_NETWORK, PROTOCOL_VERSION)); // mempool is limited to tx1's size in memory usage, so nothing fits
pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits
BOOST_CHECK(!pool.exists(tx1.GetHash()));
BOOST_CHECK(!pool.exists(tx2.GetHash()));
BOOST_CHECK(!pool.exists(tx3.GetHash()));
CFeeRate maxFeeRateRemoved(25000, ::GetSerializeSize(CTransaction(tx3), SER_NETWORK, PROTOCOL_VERSION) + ::GetSerializeSize(CTransaction(tx2), SER_NETWORK, PROTOCOL_VERSION));
CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
CMutableTransaction tx4 = CMutableTransaction();

View File

@ -135,7 +135,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript&
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
uint256 hashFreeTx = tx.GetHash();
mempool.addUnchecked(entry.Fee(0).FromTx(tx));
size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
size_t freeTxSize = GetVirtualTransactionSize(CTransaction(tx));
// Calculate a fee on child transaction that will put the package just
// below the block min tx fee (assuming 1 child tx of the same size).

View File

@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <policy/fees.h>
#include <policy/policy.h>
#include <txmempool.h>
#include <uint256.h>
#include <util/system.h>
@ -43,7 +44,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
tx.vin[0].scriptSig = garbage;
tx.vout.resize(1);
tx.vout[0].nValue=0LL;
CFeeRate baseRate(basefee, ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
CFeeRate baseRate(basefee, GetVirtualTransactionSize(CTransaction(tx)));
// Create a fake block
std::vector<CTransactionRef> block;

View File

@ -135,7 +135,7 @@ struct TestMemPoolEntryHelper
TestMemPoolEntryHelper() :
nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCount(4) { }
spendsCoinbase(false), sigOpCount(1) { }
CTxMemPoolEntry FromTx(const CMutableTransaction& tx);
CTxMemPoolEntry FromTx(const CTransactionRef& tx);

View File

@ -32,13 +32,13 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFe
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp), m_epoch(0)
{
nCountWithDescendants = 1;
nSizeWithDescendants = nTxSize;
nSizeWithDescendants = GetTxSize();
nModFeesWithDescendants = nFee;
feeDelta = 0;
nCountWithAncestors = 1;
nSizeWithAncestors = nTxSize;
nSizeWithAncestors = GetTxSize();
nModFeesWithAncestors = nFee;
nSigOpCountWithAncestors = sigOpCount;
}
@ -55,6 +55,11 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)
lockPoints = lp;
}
size_t CTxMemPoolEntry::GetTxSize() const
{
return GetVirtualTransactionSize(nTxSize, sigOpCount);
}
// Update the given tx for any in-mempool descendants.
// Assumes that setMemPoolChildren is correct for the given tx and all
// descendants.

View File

@ -103,7 +103,7 @@ public:
const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; }
const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const { return nTxSize; }
size_t GetTxSize() const;
int64_t GetTime() const { return nTime; }
unsigned int GetHeight() const { return entryHeight; }
unsigned int GetSigOpCount() const { return sigOpCount; }

View File

@ -143,7 +143,6 @@ bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
bool fRequireStandard = true;
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
@ -682,7 +681,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
if ((nSigOps > MAX_STANDARD_TX_SIGOPS) || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp))
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
strprintf("%d", nSigOps));

View File

@ -85,7 +85,6 @@ static const int64_t DEFAULT_MAX_TIP_AGE = 6 * 60 * 60; // ~144 blocks behind ->
/** Default for -permitbaremultisig */
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = true;
static const bool DEFAULT_ADDRESSINDEX = false;
@ -146,7 +145,6 @@ extern bool fIsBareMultisigStd;
*/
extern bool g_parallel_script_checks;
extern bool fRequireStandard;
extern unsigned int nBytesPerSigOp;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;