aboutsummaryrefslogtreecommitdiff
path: root/src/policy
diff options
context:
space:
mode:
Diffstat (limited to 'src/policy')
-rw-r--r--src/policy/fees.cpp19
-rw-r--r--src/policy/fees.h136
-rw-r--r--src/policy/policy.cpp29
-rw-r--r--src/policy/rbf.cpp2
4 files changed, 91 insertions, 95 deletions
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index aee6fbee1a..c49b9fa36b 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -10,7 +10,7 @@
#include <primitives/transaction.h>
#include <streams.h>
#include <txmempool.h>
-#include <util.h>
+#include <util/system.h>
static constexpr double INF_FEERATE = 1e99;
@@ -511,7 +511,7 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
// of no harm to try to remove them again.
bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
if (pos != mapMemPoolTxs.end()) {
feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
@@ -548,7 +548,7 @@ CBlockPolicyEstimator::~CBlockPolicyEstimator()
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
unsigned int txHeight = entry.GetHeight();
uint256 hash = entry.GetTx().GetHash();
if (mapMemPoolTxs.count(hash)) {
@@ -615,7 +615,7 @@ bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries)
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
if (nBlockHeight <= nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random
// they don't affect the estimate.
@@ -693,7 +693,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
}
}
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
// Return failure if trying to analyze a target we're not tracking
if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
return CFeeRate(0);
@@ -710,6 +710,7 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
{
+ LOCK(m_cs_fee_estimator);
switch (horizon) {
case FeeEstimateHorizon::SHORT_HALFLIFE: {
return shortStats->GetMaxConfirms();
@@ -819,7 +820,7 @@ double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget,
*/
CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
{
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
if (feeCalc) {
feeCalc->desiredTarget = confTarget;
@@ -899,7 +900,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
{
try {
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
fileout << 149900; // version required to read: 0.14.99 or later
fileout << CLIENT_VERSION; // version that wrote the file
fileout << nBestSeenHeight;
@@ -924,7 +925,7 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
bool CBlockPolicyEstimator::Read(CAutoFile& filein)
{
try {
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
int nVersionRequired, nVersionThatWrote;
filein >> nVersionRequired >> nVersionThatWrote;
if (nVersionRequired > CLIENT_VERSION)
@@ -983,7 +984,7 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
void CBlockPolicyEstimator::FlushUnconfirmed() {
int64_t startclear = GetTimeMicros();
- LOCK(cs_feeEstimator);
+ LOCK(m_cs_fee_estimator);
size_t num_entries = mapMemPoolTxs.size();
// Remove every entry in mapMemPoolTxs
while (!mapMemPoolTxs.empty()) {
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 136fb481f7..c8472a12f5 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -22,51 +22,6 @@ class CTxMemPoolEntry;
class CTxMemPool;
class TxConfirmStats;
-/** \class CBlockPolicyEstimator
- * The BlockPolicyEstimator is used for estimating the feerate needed
- * for a transaction to be included in a block within a certain number of
- * blocks.
- *
- * At a high level the algorithm works by grouping transactions into buckets
- * based on having similar feerates and then tracking how long it
- * takes transactions in the various buckets to be mined. It operates under
- * the assumption that in general transactions of higher feerate will be
- * included in blocks before transactions of lower feerate. So for
- * example if you wanted to know what feerate you should put on a transaction to
- * be included in a block within the next 5 blocks, you would start by looking
- * at the bucket with the highest feerate transactions and verifying that a
- * sufficiently high percentage of them were confirmed within 5 blocks and
- * then you would look at the next highest feerate bucket, and so on, stopping at
- * the last bucket to pass the test. The average feerate of transactions in this
- * bucket will give you an indication of the lowest feerate you can put on a
- * transaction and still have a sufficiently high chance of being confirmed
- * within your desired 5 blocks.
- *
- * Here is a brief description of the implementation:
- * When a transaction enters the mempool, we track the height of the block chain
- * at entry. All further calculations are conducted only on this set of "seen"
- * transactions. Whenever a block comes in, we count the number of transactions
- * in each bucket and the total amount of feerate paid in each bucket. Then we
- * calculate how many blocks Y it took each transaction to be mined. We convert
- * from a number of blocks to a number of periods Y' each encompassing "scale"
- * blocks. This is tracked in 3 different data sets each up to a maximum
- * number of periods. Within each data set we have an array of counters in each
- * feerate bucket and we increment all the counters from Y' up to max periods
- * representing that a tx was successfully confirmed in less than or equal to
- * that many periods. We want to save a history of this information, so at any
- * time we have a counter of the total number of transactions that happened in a
- * given feerate bucket and the total number that were confirmed in each of the
- * periods or less for any bucket. We save this history by keeping an
- * exponentially decaying moving average of each one of these stats. This is
- * done for a different decay in each of the 3 data sets to keep relevant data
- * from different time horizons. Furthermore we also keep track of the number
- * unmined (in mempool or left mempool without being included in a block)
- * transactions in each bucket and for how many blocks they have been
- * outstanding and use both of these numbers to increase the number of transactions
- * we've seen in that feerate bucket when calculating an estimate for any number
- * of confirmations below the number of blocks they've been outstanding.
- */
-
/* Identifier for each of the 3 different TxConfirmStats which will track
* history over different time horizons. */
enum class FeeEstimateHorizon {
@@ -95,9 +50,9 @@ std::string StringForFeeReason(FeeReason reason);
/* Used to determine type of fee estimation requested */
enum class FeeEstimateMode {
- UNSET, //! Use default settings based on other criteria
- ECONOMICAL, //! Force estimateSmartFee to use non-conservative estimates
- CONSERVATIVE, //! Force estimateSmartFee to use conservative estimates
+ UNSET, //!< Use default settings based on other criteria
+ ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates
+ CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
};
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
@@ -130,7 +85,50 @@ struct FeeCalculation
int returnedTarget = 0;
};
-/**
+/** \class CBlockPolicyEstimator
+ * The BlockPolicyEstimator is used for estimating the feerate needed
+ * for a transaction to be included in a block within a certain number of
+ * blocks.
+ *
+ * At a high level the algorithm works by grouping transactions into buckets
+ * based on having similar feerates and then tracking how long it
+ * takes transactions in the various buckets to be mined. It operates under
+ * the assumption that in general transactions of higher feerate will be
+ * included in blocks before transactions of lower feerate. So for
+ * example if you wanted to know what feerate you should put on a transaction to
+ * be included in a block within the next 5 blocks, you would start by looking
+ * at the bucket with the highest feerate transactions and verifying that a
+ * sufficiently high percentage of them were confirmed within 5 blocks and
+ * then you would look at the next highest feerate bucket, and so on, stopping at
+ * the last bucket to pass the test. The average feerate of transactions in this
+ * bucket will give you an indication of the lowest feerate you can put on a
+ * transaction and still have a sufficiently high chance of being confirmed
+ * within your desired 5 blocks.
+ *
+ * Here is a brief description of the implementation:
+ * When a transaction enters the mempool, we track the height of the block chain
+ * at entry. All further calculations are conducted only on this set of "seen"
+ * transactions. Whenever a block comes in, we count the number of transactions
+ * in each bucket and the total amount of feerate paid in each bucket. Then we
+ * calculate how many blocks Y it took each transaction to be mined. We convert
+ * from a number of blocks to a number of periods Y' each encompassing "scale"
+ * blocks. This is tracked in 3 different data sets each up to a maximum
+ * number of periods. Within each data set we have an array of counters in each
+ * feerate bucket and we increment all the counters from Y' up to max periods
+ * representing that a tx was successfully confirmed in less than or equal to
+ * that many periods. We want to save a history of this information, so at any
+ * time we have a counter of the total number of transactions that happened in a
+ * given feerate bucket and the total number that were confirmed in each of the
+ * periods or less for any bucket. We save this history by keeping an
+ * exponentially decaying moving average of each one of these stats. This is
+ * done for a different decay in each of the 3 data sets to keep relevant data
+ * from different time horizons. Furthermore we also keep track of the number
+ * unmined (in mempool or left mempool without being included in a block)
+ * transactions in each bucket and for how many blocks they have been
+ * outstanding and use both of these numbers to increase the number of transactions
+ * we've seen in that feerate bucket when calculating an estimate for any number
+ * of confirmations below the number of blocks they've been outstanding.
+ *
* We want to be able to estimate feerates that are needed on tx's to be included in
* 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
@@ -230,10 +228,12 @@ public:
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
private:
- unsigned int nBestSeenHeight;
- unsigned int firstRecordedHeight;
- unsigned int historicalFirst;
- unsigned int historicalBest;
+ mutable CCriticalSection m_cs_fee_estimator;
+
+ unsigned int nBestSeenHeight GUARDED_BY(m_cs_fee_estimator);
+ unsigned int firstRecordedHeight GUARDED_BY(m_cs_fee_estimator);
+ unsigned int historicalFirst GUARDED_BY(m_cs_fee_estimator);
+ unsigned int historicalBest GUARDED_BY(m_cs_fee_estimator);
struct TxStatsInfo
{
@@ -243,34 +243,32 @@ private:
};
// map of txids to information about that transaction
- std::map<uint256, TxStatsInfo> mapMemPoolTxs;
+ std::map<uint256, TxStatsInfo> mapMemPoolTxs GUARDED_BY(m_cs_fee_estimator);
/** Classes to track historical data on transaction confirmations */
- std::unique_ptr<TxConfirmStats> feeStats;
- std::unique_ptr<TxConfirmStats> shortStats;
- std::unique_ptr<TxConfirmStats> longStats;
-
- unsigned int trackedTxs;
- unsigned int untrackedTxs;
+ std::unique_ptr<TxConfirmStats> feeStats PT_GUARDED_BY(m_cs_fee_estimator);
+ std::unique_ptr<TxConfirmStats> shortStats PT_GUARDED_BY(m_cs_fee_estimator);
+ std::unique_ptr<TxConfirmStats> longStats PT_GUARDED_BY(m_cs_fee_estimator);
- std::vector<double> buckets; // The upper-bound of the range for the bucket (inclusive)
- std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
+ unsigned int trackedTxs GUARDED_BY(m_cs_fee_estimator);
+ unsigned int untrackedTxs GUARDED_BY(m_cs_fee_estimator);
- mutable CCriticalSection cs_feeEstimator;
+ std::vector<double> buckets GUARDED_BY(m_cs_fee_estimator); // The upper-bound of the range for the bucket (inclusive)
+ 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);
+ bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Helper for estimateSmartFee */
- double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const;
+ double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Helper for estimateSmartFee */
- double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const;
+ double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Number of blocks of data recorded while fee estimates have been running */
- unsigned int BlockSpan() const;
+ unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Number of blocks of recorded fee estimate data represented in saved data file */
- unsigned int HistoricalBlockSpan() const;
+ unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** Calculation of highest target that reasonable estimate can be provided for */
- unsigned int MaxUsableEstimate() const;
+ unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
};
class FeeFilterRounder
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index b8f7963a0c..d4cc538492 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -11,8 +11,8 @@
#include <validation.h>
#include <coins.h>
#include <tinyformat.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
@@ -34,7 +34,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
if (txout.scriptPubKey.IsUnspendable())
return 0;
- size_t nSize = GetSerializeSize(txout, SER_DISK, 0);
+ size_t nSize = GetSerializeSize(txout);
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
@@ -57,11 +57,11 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TX_MULTISIG)
- {
+ if (whichType == TX_NONSTANDARD || whichType == TX_WITNESS_UNKNOWN) {
+ return false;
+ } else if (whichType == TX_MULTISIG) {
unsigned char m = vSolutions.front()[0];
unsigned char n = vSolutions.back()[0];
// Support up to x-of-3 multisig txns as standard
@@ -70,10 +70,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
if (m < 1 || m > n)
return false;
} else if (whichType == TX_NULL_DATA &&
- (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))
+ (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
return false;
+ }
- return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
+ return true;
}
bool IsStandardTx(const CTransaction& tx, std::string& reason)
@@ -166,14 +167,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
std::vector<std::vector<unsigned char> > vSolutions;
- txnouttype whichType;
- // get the scriptPubKey corresponding to this input:
- const CScript& prevScript = prev.scriptPubKey;
- if (!Solver(prevScript, whichType, vSolutions))
+ txnouttype whichType = Solver(prev.scriptPubKey, vSolutions);
+ if (whichType == TX_NONSTANDARD) {
return false;
-
- if (whichType == TX_SCRIPTHASH)
- {
+ } else if (whichType == TX_SCRIPTHASH) {
std::vector<std::vector<unsigned char> > stack;
// convert the scriptSig into a stack, so we can inspect the redeemScript
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE))
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 18f9c0c2a8..0dc130d104 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -7,7 +7,7 @@
bool SignalsOptInRBF(const CTransaction &tx)
{
for (const CTxIn &txin : tx.vin) {
- if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1) {
+ if (txin.nSequence <= MAX_BIP125_RBF_SEQUENCE) {
return true;
}
}