mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
tx fees, policy: CBlockPolicyEstimator update from CValidationInterface
notifications
`CBlockPolicyEstimator` will implement `CValidationInterface` and subscribe to its notification to process transactions added and removed from the mempool. Re-delegate calculation of `validForFeeEstimation` from validation to fee estimator. Also clean up the validForFeeEstimation arg thats no longer needed in `CTxMempool`. Co-authored-by: Matt Corallo <git@bluematt.me>
This commit is contained in:
parent
dff5ad3b99
commit
714523918b
13 changed files with 158 additions and 74 deletions
|
@ -954,7 +954,6 @@ libbitcoinkernel_la_SOURCES = \
|
|||
node/chainstate.cpp \
|
||||
node/utxo_snapshot.cpp \
|
||||
policy/feerate.cpp \
|
||||
policy/fees.cpp \
|
||||
policy/packages.cpp \
|
||||
policy/policy.cpp \
|
||||
policy/rbf.cpp \
|
||||
|
|
10
src/init.cpp
10
src/init.cpp
|
@ -285,8 +285,12 @@ void Shutdown(NodeContext& node)
|
|||
DumpMempool(*node.mempool, MempoolPath(*node.args));
|
||||
}
|
||||
|
||||
// Drop transactions we were still watching, and record fee estimations.
|
||||
if (node.fee_estimator) node.fee_estimator->Flush();
|
||||
// Drop transactions we were still watching, record fee estimations and Unregister
|
||||
// fee estimator from validation interface.
|
||||
if (node.fee_estimator) {
|
||||
node.fee_estimator->Flush();
|
||||
UnregisterValidationInterface(node.fee_estimator.get());
|
||||
}
|
||||
|
||||
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
|
||||
if (node.chainman) {
|
||||
|
@ -1258,6 +1262,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||
// Flush estimates to disk periodically
|
||||
CBlockPolicyEstimator* fee_estimator = node.fee_estimator.get();
|
||||
node.scheduler->scheduleEvery([fee_estimator] { fee_estimator->FlushFeeEstimates(); }, FEE_FLUSH_INTERVAL);
|
||||
RegisterValidationInterface(fee_estimator);
|
||||
}
|
||||
|
||||
// Check port numbers
|
||||
|
@ -1471,7 +1476,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||
assert(!node.chainman);
|
||||
|
||||
CTxMemPool::Options mempool_opts{
|
||||
.estimator = node.fee_estimator.get(),
|
||||
.check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,
|
||||
};
|
||||
auto result{ApplyArgsManOptions(args, chainparams, mempool_opts)};
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
class CBlockPolicyEstimator;
|
||||
|
||||
/** Default for -maxmempool, maximum megabytes of mempool memory usage */
|
||||
static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300};
|
||||
/** Default for -maxmempool when blocksonly is set */
|
||||
|
@ -37,8 +35,6 @@ namespace kernel {
|
|||
* Most of the time, this struct should be referenced as CTxMemPool::Options.
|
||||
*/
|
||||
struct MemPoolOptions {
|
||||
/* Used to estimate appropriate transaction fees. */
|
||||
CBlockPolicyEstimator* estimator{nullptr};
|
||||
/* The ratio used to determine how often sanity checks will run. */
|
||||
int check_ratio{0};
|
||||
int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000};
|
||||
|
|
|
@ -515,15 +515,10 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
|
|||
}
|
||||
}
|
||||
|
||||
// This function is called from CTxMemPool::removeUnchecked to ensure
|
||||
// txs removed from the mempool for any reason are no longer
|
||||
// tracked. Txs that were part of a block have already been removed in
|
||||
// processBlockTx to ensure they are never double tracked, but it is
|
||||
// of no harm to try to remove them again.
|
||||
bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
|
||||
bool CBlockPolicyEstimator::removeTx(uint256 hash)
|
||||
{
|
||||
LOCK(m_cs_fee_estimator);
|
||||
return _removeTx(hash, inBlock);
|
||||
return _removeTx(hash, /*inBlock=*/false);
|
||||
}
|
||||
|
||||
bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock)
|
||||
|
@ -579,11 +574,26 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath
|
|||
|
||||
CBlockPolicyEstimator::~CBlockPolicyEstimator() = default;
|
||||
|
||||
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
|
||||
void CBlockPolicyEstimator::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t /*unused*/)
|
||||
{
|
||||
processTransaction(tx);
|
||||
}
|
||||
|
||||
void CBlockPolicyEstimator::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason /*unused*/, uint64_t /*unused*/)
|
||||
{
|
||||
removeTx(tx->GetHash());
|
||||
}
|
||||
|
||||
void CBlockPolicyEstimator::MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int nBlockHeight)
|
||||
{
|
||||
processBlock(txs_removed_for_block, nBlockHeight);
|
||||
}
|
||||
|
||||
void CBlockPolicyEstimator::processTransaction(const NewMempoolTransactionInfo& tx)
|
||||
{
|
||||
LOCK(m_cs_fee_estimator);
|
||||
unsigned int txHeight = entry.GetHeight();
|
||||
uint256 hash = entry.GetTx().GetHash();
|
||||
const unsigned int txHeight = tx.info.txHeight;
|
||||
const auto& hash = tx.info.m_tx->GetHash();
|
||||
if (mapMemPoolTxs.count(hash)) {
|
||||
LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
|
||||
hash.ToString());
|
||||
|
@ -597,17 +607,23 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
|
|||
// It will be synced next time a block is processed.
|
||||
return;
|
||||
}
|
||||
// This transaction should only count for fee estimation if:
|
||||
// - it's not being re-added during a reorg which bypasses typical mempool fee limits
|
||||
// - the node is not behind
|
||||
// - the transaction is not dependent on any other transactions in the mempool
|
||||
// - it's not part of a package.
|
||||
const bool validForFeeEstimation = !tx.m_from_disconnected_block && !tx.m_submitted_in_package && tx.m_chainstate_is_current && tx.m_has_no_mempool_parents;
|
||||
|
||||
// Only want to be updating estimates when our blockchain is synced,
|
||||
// otherwise we'll miscalculate how many blocks its taking to get included.
|
||||
if (!validFeeEstimate) {
|
||||
if (!validForFeeEstimation) {
|
||||
untrackedTxs++;
|
||||
return;
|
||||
}
|
||||
trackedTxs++;
|
||||
|
||||
// Feerates are stored and reported as BTC-per-kb:
|
||||
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
|
||||
const CFeeRate feeRate(tx.info.m_fee, tx.info.m_virtual_transaction_size);
|
||||
|
||||
mapMemPoolTxs[hash].blockHeight = txHeight;
|
||||
unsigned int bucketIndex = feeStats->NewTx(txHeight, static_cast<double>(feeRate.GetFeePerK()));
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <threadsafety.h>
|
||||
#include <uint256.h>
|
||||
#include <util/fs.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
|
@ -35,9 +36,9 @@ static constexpr std::chrono::hours MAX_FILE_AGE{60};
|
|||
static constexpr bool DEFAULT_ACCEPT_STALE_FEE_ESTIMATES{false};
|
||||
|
||||
class AutoFile;
|
||||
class CTxMemPoolEntry;
|
||||
class TxConfirmStats;
|
||||
struct RemovedMempoolTransactionInfo;
|
||||
struct NewMempoolTransactionInfo;
|
||||
|
||||
/* Identifier for each of the 3 different TxConfirmStats which will track
|
||||
* history over different time horizons. */
|
||||
|
@ -144,7 +145,7 @@ struct FeeCalculation
|
|||
* a certain number of blocks. Every time a block is added to the best chain, this class records
|
||||
* stats on the transactions included in that block
|
||||
*/
|
||||
class CBlockPolicyEstimator
|
||||
class CBlockPolicyEstimator : public CValidationInterface
|
||||
{
|
||||
private:
|
||||
/** Track confirm delays up to 12 blocks for short horizon */
|
||||
|
@ -199,7 +200,7 @@ private:
|
|||
public:
|
||||
/** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
|
||||
CBlockPolicyEstimator(const fs::path& estimation_filepath, const bool read_stale_estimates);
|
||||
~CBlockPolicyEstimator();
|
||||
virtual ~CBlockPolicyEstimator();
|
||||
|
||||
/** Process all the transactions that have been included in a block */
|
||||
void processBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block,
|
||||
|
@ -207,11 +208,11 @@ public:
|
|||
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
||||
|
||||
/** Process a transaction accepted to the mempool*/
|
||||
void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
|
||||
void processTransaction(const NewMempoolTransactionInfo& tx)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
||||
|
||||
/** Remove a transaction from the mempool tracking stats*/
|
||||
bool removeTx(uint256 hash, bool inBlock)
|
||||
/** Remove a transaction from the mempool tracking stats for non BLOCK removal reasons*/
|
||||
bool removeTx(uint256 hash)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
||||
|
||||
/** DEPRECATED. Return a feerate estimate */
|
||||
|
@ -261,6 +262,15 @@ public:
|
|||
/** Calculates the age of the file, since last modified */
|
||||
std::chrono::hours GetFeeEstimatorFileAge();
|
||||
|
||||
protected:
|
||||
/** Overridden from CValidationInterface. */
|
||||
void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t /*unused*/) override
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
||||
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason /*unused*/, uint64_t /*unused*/) override
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
||||
void MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int nBlockHeight) override
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
|
||||
|
||||
private:
|
||||
mutable Mutex m_cs_fee_estimator;
|
||||
|
||||
|
|
|
@ -121,7 +121,6 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte
|
|||
mempool_opts.expiry = std::chrono::hours{fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)};
|
||||
nBytesPerSigOp = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(1, 999);
|
||||
|
||||
mempool_opts.estimator = nullptr;
|
||||
mempool_opts.check_ratio = 1;
|
||||
mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
|
||||
|
||||
|
|
|
@ -44,9 +44,16 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
|
|||
return;
|
||||
}
|
||||
const CTransaction tx{*mtx};
|
||||
block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool());
|
||||
const CTxMemPoolEntry& entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, tx);
|
||||
const auto tx_info = NewMempoolTransactionInfo(entry.GetSharedTx(), entry.GetFee(),
|
||||
entry.GetTxSize(), entry.GetHeight(),
|
||||
/* m_from_disconnected_block */ false,
|
||||
/* m_submitted_in_package */ false,
|
||||
/* m_chainstate_is_current */ true,
|
||||
/* m_has_no_mempool_parents */ fuzzed_data_provider.ConsumeBool());
|
||||
block_policy_estimator.processTransaction(tx_info);
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
(void)block_policy_estimator.removeTx(tx.GetHash(), /*inBlock=*/fuzzed_data_provider.ConsumeBool());
|
||||
(void)block_policy_estimator.removeTx(tx.GetHash());
|
||||
}
|
||||
},
|
||||
[&] {
|
||||
|
@ -69,7 +76,7 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
|
|||
block_policy_estimator.processBlock(txs, fuzzed_data_provider.ConsumeIntegral<unsigned int>());
|
||||
},
|
||||
[&] {
|
||||
(void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /*inBlock=*/fuzzed_data_provider.ConsumeBool());
|
||||
(void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider));
|
||||
},
|
||||
[&] {
|
||||
block_policy_estimator.FlushUnconfirmed();
|
||||
|
|
|
@ -123,7 +123,6 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte
|
|||
CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
|
||||
|
||||
// ...override specific options for this specific fuzz suite
|
||||
mempool_opts.estimator = nullptr;
|
||||
mempool_opts.check_ratio = 1;
|
||||
mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
#include <util/time.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
|
@ -19,7 +20,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
{
|
||||
CBlockPolicyEstimator& feeEst = *Assert(m_node.fee_estimator);
|
||||
CTxMemPool& mpool = *Assert(m_node.mempool);
|
||||
LOCK2(cs_main, mpool.cs);
|
||||
RegisterValidationInterface(&feeEst);
|
||||
TestMemPoolEntryHelper entry;
|
||||
CAmount basefee(2000);
|
||||
CAmount deltaFee(100);
|
||||
|
@ -59,8 +60,23 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
for (int j = 0; j < 10; j++) { // For each fee
|
||||
for (int k = 0; k < 4; k++) { // add 4 fee txs
|
||||
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
|
||||
{
|
||||
LOCK2(cs_main, mpool.cs);
|
||||
mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
|
||||
// Since TransactionAddedToMempool callbacks are generated in ATMP,
|
||||
// not addUnchecked, we cheat and create one manually here
|
||||
const int64_t virtual_size = GetVirtualTransactionSize(*MakeTransactionRef(tx));
|
||||
const NewMempoolTransactionInfo tx_info{NewMempoolTransactionInfo(MakeTransactionRef(tx),
|
||||
feeV[j],
|
||||
virtual_size,
|
||||
entry.nHeight,
|
||||
/* m_from_disconnected_block */ false,
|
||||
/* m_submitted_in_package */ false,
|
||||
/* m_chainstate_is_current */ true,
|
||||
/* m_has_no_mempool_parents */ true)};
|
||||
GetMainSignals().TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
|
||||
}
|
||||
uint256 hash = tx.GetHash();
|
||||
mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
|
||||
txHashes[j].push_back(hash);
|
||||
}
|
||||
}
|
||||
|
@ -76,10 +92,17 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
txHashes[9-h].pop_back();
|
||||
}
|
||||
}
|
||||
mpool.removeForBlock(block, ++blocknum);
|
||||
|
||||
{
|
||||
LOCK(mpool.cs);
|
||||
mpool.removeForBlock(block, ++blocknum);
|
||||
}
|
||||
|
||||
block.clear();
|
||||
// Check after just a few txs that combining buckets works as expected
|
||||
if (blocknum == 3) {
|
||||
// Wait for fee estimator to catch up
|
||||
SyncWithValidationInterfaceQueue();
|
||||
// At this point we should need to combine 3 buckets to get enough data points
|
||||
// So estimateFee(1) should fail and estimateFee(2) should return somewhere around
|
||||
// 9*baserate. estimateFee(2) %'s are 100,100,90 = average 97%
|
||||
|
@ -114,8 +137,13 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
|
||||
// Mine 50 more blocks with no transactions happening, estimates shouldn't change
|
||||
// We haven't decayed the moving average enough so we still have enough data points in every bucket
|
||||
while (blocknum < 250)
|
||||
while (blocknum < 250) {
|
||||
LOCK(mpool.cs);
|
||||
mpool.removeForBlock(block, ++blocknum);
|
||||
}
|
||||
|
||||
// Wait for fee estimator to catch up
|
||||
SyncWithValidationInterfaceQueue();
|
||||
|
||||
BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
|
||||
for (int i = 2; i < 10;i++) {
|
||||
|
@ -130,14 +158,35 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
for (int j = 0; j < 10; j++) { // For each fee multiple
|
||||
for (int k = 0; k < 4; k++) { // add 4 fee txs
|
||||
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
|
||||
{
|
||||
LOCK2(cs_main, mpool.cs);
|
||||
mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
|
||||
// Since TransactionAddedToMempool callbacks are generated in ATMP,
|
||||
// not addUnchecked, we cheat and create one manually here
|
||||
const int64_t virtual_size = GetVirtualTransactionSize(*MakeTransactionRef(tx));
|
||||
const NewMempoolTransactionInfo tx_info{NewMempoolTransactionInfo(MakeTransactionRef(tx),
|
||||
feeV[j],
|
||||
virtual_size,
|
||||
entry.nHeight,
|
||||
/* m_from_disconnected_block */ false,
|
||||
/* m_submitted_in_package */ false,
|
||||
/* m_chainstate_is_current */ true,
|
||||
/* m_has_no_mempool_parents */ true)};
|
||||
GetMainSignals().TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
|
||||
}
|
||||
uint256 hash = tx.GetHash();
|
||||
mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
|
||||
txHashes[j].push_back(hash);
|
||||
}
|
||||
}
|
||||
mpool.removeForBlock(block, ++blocknum);
|
||||
{
|
||||
LOCK(mpool.cs);
|
||||
mpool.removeForBlock(block, ++blocknum);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for fee estimator to catch up
|
||||
SyncWithValidationInterfaceQueue();
|
||||
|
||||
for (int i = 1; i < 10;i++) {
|
||||
BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
|
||||
}
|
||||
|
@ -152,8 +201,16 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
txHashes[j].pop_back();
|
||||
}
|
||||
}
|
||||
mpool.removeForBlock(block, 266);
|
||||
|
||||
{
|
||||
LOCK(mpool.cs);
|
||||
mpool.removeForBlock(block, 266);
|
||||
}
|
||||
block.clear();
|
||||
|
||||
// Wait for fee estimator to catch up
|
||||
SyncWithValidationInterfaceQueue();
|
||||
|
||||
BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
|
||||
for (int i = 2; i < 10;i++) {
|
||||
BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
|
||||
|
@ -165,17 +222,39 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
for (int j = 0; j < 10; j++) { // For each fee multiple
|
||||
for (int k = 0; k < 4; k++) { // add 4 fee txs
|
||||
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
|
||||
{
|
||||
LOCK2(cs_main, mpool.cs);
|
||||
mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
|
||||
// Since TransactionAddedToMempool callbacks are generated in ATMP,
|
||||
// not addUnchecked, we cheat and create one manually here
|
||||
const int64_t virtual_size = GetVirtualTransactionSize(*MakeTransactionRef(tx));
|
||||
const NewMempoolTransactionInfo tx_info{NewMempoolTransactionInfo(MakeTransactionRef(tx),
|
||||
feeV[j],
|
||||
virtual_size,
|
||||
entry.nHeight,
|
||||
/* m_from_disconnected_block */ false,
|
||||
/* m_submitted_in_package */ false,
|
||||
/* m_chainstate_is_current */ true,
|
||||
/* m_has_no_mempool_parents */ true)};
|
||||
GetMainSignals().TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
|
||||
}
|
||||
uint256 hash = tx.GetHash();
|
||||
mpool.addUnchecked(entry.Fee(feeV[j]).Time(Now<NodeSeconds>()).Height(blocknum).FromTx(tx));
|
||||
CTransactionRef ptx = mpool.get(hash);
|
||||
if (ptx)
|
||||
block.push_back(ptx);
|
||||
|
||||
}
|
||||
}
|
||||
mpool.removeForBlock(block, ++blocknum);
|
||||
|
||||
{
|
||||
LOCK(mpool.cs);
|
||||
mpool.removeForBlock(block, ++blocknum);
|
||||
}
|
||||
|
||||
block.clear();
|
||||
}
|
||||
// Wait for fee estimator to catch up
|
||||
SyncWithValidationInterfaceQueue();
|
||||
BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
|
||||
for (int i = 2; i < 9; i++) { // At 9, the original estimate was already at the bottom (b/c scale = 2)
|
||||
BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
|
||||
|
|
|
@ -18,7 +18,6 @@ using node::NodeContext;
|
|||
CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node)
|
||||
{
|
||||
CTxMemPool::Options mempool_opts{
|
||||
.estimator = node.fee_estimator.get(),
|
||||
// Default to always checking mempool regardless of
|
||||
// chainparams.DefaultConsistencyChecks for tests
|
||||
.check_ratio = 1,
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include <consensus/tx_verify.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <logging.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <random.h>
|
||||
#include <reverse_iterator.h>
|
||||
#include <util/check.h>
|
||||
#include <util/moneystr.h>
|
||||
|
@ -402,7 +402,6 @@ void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee,
|
|||
|
||||
CTxMemPool::CTxMemPool(const Options& opts)
|
||||
: m_check_ratio{opts.check_ratio},
|
||||
minerPolicyEstimator{opts.estimator},
|
||||
m_max_size_bytes{opts.max_size_bytes},
|
||||
m_expiry{opts.expiry},
|
||||
m_incremental_relay_feerate{opts.incremental_relay_feerate},
|
||||
|
@ -433,7 +432,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
|
|||
nTransactionsUpdated += n;
|
||||
}
|
||||
|
||||
void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate)
|
||||
void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors)
|
||||
{
|
||||
// Add to memory pool without checking anything.
|
||||
// Used by AcceptToMemoryPool(), which DOES do
|
||||
|
@ -477,9 +476,6 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
|
|||
nTransactionsUpdated++;
|
||||
totalTxSize += entry.GetTxSize();
|
||||
m_total_fee += entry.GetFee();
|
||||
if (minerPolicyEstimator) {
|
||||
minerPolicyEstimator->processTransaction(entry, validFeeEstimate);
|
||||
}
|
||||
|
||||
txns_randomized.emplace_back(newit->GetSharedTx());
|
||||
newit->idx_randomized = txns_randomized.size() - 1;
|
||||
|
@ -497,16 +493,12 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
|
|||
// even if not directly reported below.
|
||||
uint64_t mempool_sequence = GetAndIncrementSequence();
|
||||
|
||||
const auto& hash = it->GetTx().GetHash();
|
||||
if (reason != MemPoolRemovalReason::BLOCK) {
|
||||
// Notify clients that a transaction has been removed from the mempool
|
||||
// for any reason except being included in a block. Clients interested
|
||||
// in transactions included in blocks can subscribe to the BlockConnected
|
||||
// notification.
|
||||
GetMainSignals().TransactionRemovedFromMempool(it->GetSharedTx(), reason, mempool_sequence);
|
||||
if (minerPolicyEstimator) {
|
||||
minerPolicyEstimator->removeTx(hash, false);
|
||||
}
|
||||
}
|
||||
TRACE5(mempool, removed,
|
||||
it->GetTx().GetHash().data(),
|
||||
|
@ -519,7 +511,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
|
|||
for (const CTxIn& txin : it->GetTx().vin)
|
||||
mapNextTx.erase(txin.prevout);
|
||||
|
||||
RemoveUnbroadcastTx(hash, true /* add logging because unchecked */ );
|
||||
RemoveUnbroadcastTx(it->GetTx().GetHash(), true /* add logging because unchecked */);
|
||||
|
||||
if (txns_randomized.size() > 1) {
|
||||
// Update idx_randomized of the to-be-moved entry.
|
||||
|
@ -638,7 +630,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx)
|
|||
}
|
||||
|
||||
/**
|
||||
* Called when a block is connected. Removes from mempool and updates the miner fee estimator.
|
||||
* Called when a block is connected. Removes from mempool.
|
||||
*/
|
||||
void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight)
|
||||
{
|
||||
|
@ -657,10 +649,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
|
|||
removeConflicts(*tx);
|
||||
ClearPrioritisation(tx->GetHash());
|
||||
}
|
||||
// Update policy estimates
|
||||
if (minerPolicyEstimator) {
|
||||
minerPolicyEstimator->processBlock(txs_removed_for_block, nBlockHeight);
|
||||
}
|
||||
GetMainSignals().MempoolTransactionsRemovedForBlock(txs_removed_for_block, nBlockHeight);
|
||||
lastRollingFeeUpdate = GetTime();
|
||||
blockSinceLastRollingFeeBump = true;
|
||||
|
@ -1091,10 +1079,10 @@ int CTxMemPool::Expire(std::chrono::seconds time)
|
|||
return stage.size();
|
||||
}
|
||||
|
||||
void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate)
|
||||
void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry)
|
||||
{
|
||||
auto ancestors{AssumeCalculateMemPoolAncestors(__func__, entry, Limits::NoLimits())};
|
||||
return addUnchecked(entry, ancestors, validFeeEstimate);
|
||||
return addUnchecked(entry, ancestors);
|
||||
}
|
||||
|
||||
void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)
|
||||
|
|
|
@ -202,8 +202,6 @@ struct entry_time {};
|
|||
struct ancestor_score {};
|
||||
struct index_by_wtxid {};
|
||||
|
||||
class CBlockPolicyEstimator;
|
||||
|
||||
/**
|
||||
* Information about a mempool transaction.
|
||||
*/
|
||||
|
@ -303,7 +301,6 @@ class CTxMemPool
|
|||
protected:
|
||||
const int m_check_ratio; //!< Value n means that 1 times in n we check.
|
||||
std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
|
||||
CBlockPolicyEstimator* const minerPolicyEstimator;
|
||||
|
||||
uint64_t totalTxSize GUARDED_BY(cs){0}; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
|
||||
CAmount m_total_fee GUARDED_BY(cs){0}; //!< sum of all mempool tx's fees (NOT modified fee)
|
||||
|
@ -472,8 +469,8 @@ public:
|
|||
// Note that addUnchecked is ONLY called from ATMP outside of tests
|
||||
// and any other callers may break wallet's in-mempool tracking (due to
|
||||
// lack of CValidationInterface::TransactionAddedToMempool callbacks).
|
||||
void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
void addUnchecked(const CTxMemPoolEntry& entry) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
|
||||
void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
/** After reorg, filter the entries that would no longer be valid in the next block, and update
|
||||
|
|
|
@ -1126,17 +1126,8 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
|
|||
ws.m_replaced_transactions.push_back(it->GetSharedTx());
|
||||
}
|
||||
m_pool.RemoveStaged(ws.m_all_conflicting, false, MemPoolRemovalReason::REPLACED);
|
||||
|
||||
// This transaction should only count for fee estimation if:
|
||||
// - it's not being re-added during a reorg which bypasses typical mempool fee limits
|
||||
// - the node is not behind
|
||||
// - the transaction is not dependent on any other transactions in the mempool
|
||||
// - it's not part of a package. Since package relay is not currently supported, this
|
||||
// transaction has not necessarily been accepted to miners' mempools.
|
||||
bool validForFeeEstimation = !bypass_limits && !args.m_package_submission && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
|
||||
|
||||
// Store transaction in memory
|
||||
m_pool.addUnchecked(*entry, ws.m_ancestors, validForFeeEstimation);
|
||||
m_pool.addUnchecked(*entry, ws.m_ancestors);
|
||||
|
||||
// trim mempool and check if tx was trimmed
|
||||
// If we are validating a package, don't trim here because we could evict a previous transaction
|
||||
|
|
Loading…
Add table
Reference in a new issue