Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ismaelsadeeq committed Aug 26, 2023
1 parent 6695456 commit 49b3189
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 60 deletions.
19 changes: 19 additions & 0 deletions src/kernel/mempool_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,23 @@ class CTxMemPoolEntry
mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms
};

struct NewMempoolTransactionInfo {
//! A shared pointer to the transaction which was added.
CTransactionRef m_tx;
//! The fee the added transaction paid
CAmount m_fee;
/**
* The virtual transaction size.
*
* This is a policy field which considers the sigop cost of the
* transaction as well as its weight, and reinterprets it as bytes.
*
* It is the primary metric by which the mining algorithm selects
* transactions.
*/
int64_t m_virtual_transaction_size;
//! Whether this transaction should be considered for fee estimation
bool m_valid_for_estimation;
};

#endif // BITCOIN_KERNEL_MEMPOOL_ENTRY_H
4 changes: 2 additions & 2 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,9 @@ class NotificationsProxy : public CValidationInterface
explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)
: m_notifications(std::move(notifications)) {}
virtual ~NotificationsProxy() = default;
void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override
void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx_info, uint64_t mempool_sequence) override
{
m_notifications->transactionAddedToMempool(tx);
m_notifications->transactionAddedToMempool(tx_info.m_tx);
}
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
{
Expand Down
69 changes: 48 additions & 21 deletions src/policy/fees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,12 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath

CBlockPolicyEstimator::~CBlockPolicyEstimator() = default;

void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
void CBlockPolicyEstimator::processTransaction(const NewMempoolTransactionInfo& tx_info)
{
LOCK(m_cs_fee_estimator);
unsigned int txHeight = entry.GetHeight();
uint256 hash = entry.GetTx().GetHash();
unsigned int txHeight = nBestSeenHeight;
uint256 hash = tx_info.m_tx->GetHash();
LogPrintf("Adding Tx %s \n", hash.ToString());
if (mapMemPoolTxs.count(hash)) {
LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
hash.ToString());
Expand All @@ -587,56 +588,79 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo

// 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 (!tx_info.m_valid_for_estimation) {
LogPrintf("Inalid for fee estimation \n");
untrackedTxs++;
return;
}
trackedTxs++;

LogPrintf("Valid for fee estimation \n");
// Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());

CFeeRate feeRate(tx_info.m_fee, tx_info.m_virtual_transaction_size);
LogPrintf("Tx fee rate %s \n", feeRate.GetFeePerK());
mapMemPoolTxs[hash].blockHeight = txHeight;
mapMemPoolTxs[hash].m_fee_per_k = feeRate.GetFeePerK();
unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
mapMemPoolTxs[hash].bucketIndex = bucketIndex;
unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
assert(bucketIndex == bucketIndex2);
unsigned int bucketIndex3 = longStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
assert(bucketIndex == bucketIndex3);

LogPrintf("Lets check whether it's in \n");
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
LogPrintf("TX %s\n", hash.ToString());
if (pos == mapMemPoolTxs.end()) {
LogPrintf("Tx %s is not added\n", hash.ToString());
}
LogPrintf("Tx %s added yess\n", hash.ToString());
LogPrintf("The size of mapMemPoolTxs after insert block is %s \n", mapMemPoolTxs.size());
}

bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTransactionRef& tx)
{
AssertLockHeld(m_cs_fee_estimator);
if (!_removeTx(entry->GetTx().GetHash(), true)) {
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(tx->GetHash());
LogPrintf("Processing transaction %s\n", tx->GetHash().ToString());
if (pos == mapMemPoolTxs.end()) {
LogPrintf("Tx not in ops\n");
// This transaction wasn't being tracked for fee estimation
return false;
}

LogPrintf("Yay tx in :-.\n");
// How many blocks did it take for miners to include this transaction?
// blocksToConfirm is 1-based, so a transaction included in the earliest
// possible block has confirmation count of 1
int blocksToConfirm = nBlockHeight - entry->GetHeight();
int blocksToConfirm = nBlockHeight - pos->second.blockHeight;

// Feerates are stored and reported as BTC-per-kb:
CAmount feerate = pos->second.m_fee_per_k;

_removeTx(pos->first, true);
if (blocksToConfirm <= 0) {
// This can't happen because we don't process transactions from a block with a height
// lower than our greatest seen height
LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
return false;
}

// Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());

feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
shortStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
longStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
LogPrintf("Tx fee rate %s\n", feerate);
feeStats->Record(blocksToConfirm, (double)feerate);
shortStats->Record(blocksToConfirm, (double)feerate);
longStats->Record(blocksToConfirm, (double)feerate);
return true;
}

int CBlockPolicyEstimator::GetMapSize()
{
LOCK(m_cs_fee_estimator);
return static_cast<int>(mapMemPoolTxs.size());
}
void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries)
const std::vector<CTransactionRef>& txs_removed_in_block)
{
LOCK(m_cs_fee_estimator);
LogPrintf("The initial size of mapMemPoolTxs before processing block is %s \n", mapMemPoolTxs.size());
if (nBlockHeight <= nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random
// they don't affect the estimate.
Expand All @@ -663,8 +687,10 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,

unsigned int countedTxs = 0;
// Update averages with data points from current block
for (const auto& entry : entries) {
if (processBlockTx(nBlockHeight, entry))
LogPrintf("The size of mapMemPoolTxs before processing block is %s \n", mapMemPoolTxs.size());
LogPrintf("Process blocks with %s transactions \n", txs_removed_in_block.size());
for (const auto& tx : txs_removed_in_block) {
if (processBlockTx(nBlockHeight, tx))
countedTxs++;
}

Expand All @@ -675,7 +701,7 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,


LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n",
countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
countedTxs, txs_removed_in_block.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");

trackedTxs = 0;
Expand Down Expand Up @@ -839,6 +865,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
{
LOCK(m_cs_fee_estimator);

LogPrintf("The size of mapMemPoolTxs when calling estimatesmartfee is %s \n", mapMemPoolTxs.size());
if (feeCalc) {
feeCalc->desiredTarget = confTarget;
feeCalc->returnedTarget = confTarget;
Expand Down
10 changes: 7 additions & 3 deletions src/policy/fees.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#define BITCOIN_POLICY_FEES_H

#include <consensus/amount.h>
#include <kernel/mempool_entry.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <random.h>
#include <sync.h>
#include <threadsafety.h>
Expand Down Expand Up @@ -202,13 +204,14 @@ class CBlockPolicyEstimator

/** Process all the transactions that have been included in a block */
void processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries)
const std::vector<CTransactionRef>& txs_removed_in_block)
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_info)
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);

int GetMapSize() EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Remove a transaction from the mempool tracking stats*/
bool removeTx(uint256 hash, bool inBlock)
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
Expand Down Expand Up @@ -272,6 +275,7 @@ class CBlockPolicyEstimator
{
unsigned int blockHeight{0};
unsigned int bucketIndex{0};
CAmount m_fee_per_k;
TxStatsInfo() {}
};

Expand All @@ -290,7 +294,7 @@ class CBlockPolicyEstimator
std::map<double, unsigned int> bucketMap GUARDED_BY(m_cs_fee_estimator); // Map of bucket upper-bound to index into all vectors by bucket

/** Process a transaction confirmed in a block*/
bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
bool processBlockTx(unsigned int nBlockHeight, const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);

/** Helper for estimateSmartFee */
double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
Expand Down
12 changes: 7 additions & 5 deletions src/test/fuzz/policy_estimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ 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 NewMempoolTransactionInfo tx_info = { entry.GetSharedTx(), entry.GetFee(), entry.GetTxSize(), 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());
}
Expand All @@ -56,12 +58,12 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
const CTransaction tx{*mtx};
mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx));
}
std::vector<const CTxMemPoolEntry*> ptrs;
ptrs.reserve(mempool_entries.size());
std::vector<CTransactionRef> txs;
txs.reserve(mempool_entries.size());
for (const CTxMemPoolEntry& mempool_entry : mempool_entries) {
ptrs.push_back(&mempool_entry);
txs.push_back(mempool_entry.GetSharedTx());
}
block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs);
block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), txs);
},
[&] {
(void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /*inBlock=*/fuzzed_data_provider.ConsumeBool());
Expand Down
5 changes: 3 additions & 2 deletions src/test/fuzz/tx_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <consensus/validation.h>
#include <kernel/mempool_entry.h>
#include <node/context.h>
#include <node/mempool_args.h>
#include <node/miner.h>
Expand Down Expand Up @@ -59,9 +60,9 @@ struct TransactionsDelta final : public CValidationInterface {
explicit TransactionsDelta(std::set<CTransactionRef>& r, std::set<CTransactionRef>& a)
: m_removed{r}, m_added{a} {}

void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t /* mempool_sequence */) override
void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx_info, uint64_t /* mempool_sequence */) override
{
Assert(m_added.insert(tx).second);
Assert(m_added.insert(tx_info.m_tx).second);
}

void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t /* mempool_sequence */) override
Expand Down
20 changes: 18 additions & 2 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,15 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
results.emplace(ws.m_ptx->GetWitnessHash(),
MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize,
ws.m_base_fees, effective_feerate, effective_feerate_wtxids));
GetMainSignals().TransactionAddedToMempool(ws.m_ptx, m_pool.GetAndIncrementSequence());
const CTransaction& tx = *ws.m_ptx;
bool validForFeeEstimation = !args.m_bypass_limits && !args.m_package_submission && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
NewMempoolTransactionInfo tx_info = {
ws.m_ptx,
ws.m_base_fees,
ws.m_vsize,
validForFeeEstimation
};
GetMainSignals().TransactionAddedToMempool(tx_info, m_pool.GetAndIncrementSequence());
} else {
all_submitted = false;
ws.m_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");
Expand Down Expand Up @@ -1234,7 +1242,15 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef

if (!Finalize(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);

GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
const CTransaction& tx = *ws.m_ptx;
bool validForFeeEstimation = !args.m_bypass_limits && !args.m_package_submission && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
NewMempoolTransactionInfo tx_info = {
ws.m_ptx,
ws.m_base_fees,
ws.m_vsize,
validForFeeEstimation
};
GetMainSignals().TransactionAddedToMempool(tx_info, m_pool.GetAndIncrementSequence());

return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees,
effective_feerate, single_wtxid);
Expand Down
23 changes: 6 additions & 17 deletions src/validationinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <kernel/mempool_entry.h>
#include <validationinterface.h>

#include <attributes.h>
Expand Down Expand Up @@ -205,32 +204,22 @@ void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInd
fInitialDownload);
}

void CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {
auto event = [tx, mempool_sequence, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx, mempool_sequence); });
void CMainSignals::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx_info, uint64_t mempool_sequence) {
auto event = [tx_info, mempool_sequence, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx_info, mempool_sequence); });
};
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
tx->GetHash().ToString(),
tx->GetWitnessHash().ToString());
tx_info.m_tx->GetHash().ToString(),
tx_info.m_tx->GetWitnessHash().ToString());
}


void CMainSignals::MempoolAcceptNewTransaction(const CTxMemPoolEntry& tx, bool validFeeEstimate)
{
auto event = [tx, validFeeEstimate, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.MempoolAcceptNewTransaction(tx, validFeeEstimate); });
};
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
tx.GetSharedTx()->GetHash().ToString(),
tx.GetSharedTx()->GetWitnessHash().ToString());
}

void CMainSignals::MempoolBlockConnect(const std::vector<CTransactionRef>& txs_removed_for_block, unsigned int nBlockHeight)
{
auto event = [txs_removed_for_block, nBlockHeight, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.MempoolBlockConnect(txs_removed_for_block, nBlockHeight); });
};
ENQUEUE_AND_LOG_EVENT(event, "block height=%s txs=%s", __func__,
ENQUEUE_AND_LOG_EVENT(event, "%s: block height=%s txs=%s", __func__,
nBlockHeight,
txs_removed_for_block.size());
}
Expand Down
8 changes: 3 additions & 5 deletions src/validationinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class CValidationInterface {
*
* Called on a background thread.
*/
virtual void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {}
virtual void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx_info, uint64_t mempool_sequence) {}

/**
* Notifies listeners of a transaction leaving mempool.
Expand Down Expand Up @@ -131,7 +131,6 @@ class CValidationInterface {
* Called on a background thread.
*/
virtual void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {}
virtual void MempoolAcceptNewTransaction(const CTxMemPoolEntry& tx, bool validFeeEstimate) {}
virtual void MempoolBlockConnect(const std::vector<CTransactionRef>& txs_removed_for_block, bool nBlockHeight) {}
/**
* Notifies listeners of a block being connected.
Expand Down Expand Up @@ -200,10 +199,9 @@ class CMainSignals {


void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
void TransactionAddedToMempool(const CTransactionRef&, uint64_t mempool_sequence);
void TransactionAddedToMempool(const NewMempoolTransactionInfo&, uint64_t mempool_sequence);
void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence);
void MempoolAcceptNewTransaction(const CTxMemPoolEntry& tx, bool validFeeEstimate);
void MempoolBlockConnect(const std::vector<CTransactionRef>& txs_removed_for_block, unsigned int nBlockHeight);
void MempoolBlockConnect(const std::vector<CTransactionRef>&, unsigned int nBlockHeight);
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex);
void BlockDisconnected(const std::shared_ptr<const CBlock> &, const CBlockIndex* pindex);
void ChainStateFlushed(const CBlockLocator &);
Expand Down
4 changes: 2 additions & 2 deletions src/zmq/zmqnotificationinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, co
});
}

void CZMQNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx, uint64_t mempool_sequence)
void CZMQNotificationInterface::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx_info, uint64_t mempool_sequence)
{
const CTransaction& tx = *ptx;
const CTransaction& tx = *(tx_info.m_tx);

TryForEachAndRemoveFailed(notifiers, [&tx, mempool_sequence](CZMQAbstractNotifier* notifier) {
return notifier->NotifyTransaction(tx) && notifier->NotifyTransactionAcceptance(tx, mempool_sequence);
Expand Down
Loading

0 comments on commit 49b3189

Please sign in to comment.