Implement "feefilter" P2P message.
This commit is contained in:
@@ -314,6 +314,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
}
|
||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
|
||||
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
|
||||
strUsage += HelpMessageOpt("-feefilter", strprintf(_("Tell other nodes to filter invs to us by our mempool min fee (default: %u)"), DEFAULT_FEEFILTER));
|
||||
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup"));
|
||||
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
|
||||
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
|
||||
|
||||
75
src/main.cpp
75
src/main.cpp
@@ -18,12 +18,14 @@
|
||||
#include "key.h"
|
||||
#include "merkleblock.h"
|
||||
#include "net.h"
|
||||
#include "policy/fees.h"
|
||||
#include "policy/policy.h"
|
||||
#include "pos.h"
|
||||
#include "pow.h"
|
||||
#include "pubkey.h"
|
||||
#include "primitives/block.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "random.h"
|
||||
#include "script/drivechain.h"
|
||||
#include "script/script.h"
|
||||
#include "script/sigcache.h"
|
||||
@@ -91,6 +93,7 @@ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
|
||||
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
|
||||
|
||||
CTxMemPool mempool(::minRelayTxFee);
|
||||
FeeFilterRounder filterRounder(::minRelayTxFee);
|
||||
|
||||
struct COrphanTx {
|
||||
CTransaction tx;
|
||||
@@ -1058,8 +1061,8 @@ static bool RespendRelayExceeded(const CTransaction& doubleSpend)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee,
|
||||
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
|
||||
std::vector<uint256>& vHashTxnToUncache)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
@@ -1250,6 +1253,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
|
||||
|
||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
|
||||
unsigned int nSize = entry.GetTxSize();
|
||||
if (txFeeRate) {
|
||||
*txFeeRate = CFeeRate(nFees, nSize);
|
||||
}
|
||||
|
||||
// Check that the transaction doesn't have an excessive number of
|
||||
// sigops, making it impossible to mine. Since the coinbase transaction
|
||||
@@ -1502,10 +1508,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
|
||||
}
|
||||
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee)
|
||||
bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
|
||||
{
|
||||
std::vector<uint256> vHashTxToUncache;
|
||||
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, fRejectAbsurdFee, vHashTxToUncache);
|
||||
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
|
||||
if (!res) {
|
||||
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
|
||||
pcoinsTip->Uncache(hashTx);
|
||||
@@ -2857,7 +2863,7 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
|
||||
// ignore validation errors in resurrected transactions
|
||||
list<CTransaction> removed;
|
||||
CValidationState stateDummy;
|
||||
if (tx.IsCoinBase() || tx.IsCoinStake() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
|
||||
if (tx.IsCoinBase() || tx.IsCoinStake() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) {
|
||||
mempool.removeRecursive(tx, removed);
|
||||
} else if (mempool.exists(tx.GetHash())) {
|
||||
vHashUpdate.push_back(tx.GetHash());
|
||||
@@ -5328,10 +5334,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
pfrom->setAskFor.erase(inv.hash);
|
||||
mapAlreadyAskedFor.erase(inv);
|
||||
|
||||
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
||||
{
|
||||
CFeeRate txFeeRate = CFeeRate(0);
|
||||
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) {
|
||||
mempool.check(pcoinsTip);
|
||||
RelayTransaction(tx);
|
||||
RelayTransaction(tx, txFeeRate);
|
||||
vWorkQueue.push_back(inv.hash);
|
||||
|
||||
LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
|
||||
@@ -5362,10 +5368,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
|
||||
if (setMisbehaving.count(fromPeer))
|
||||
continue;
|
||||
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
|
||||
{
|
||||
CFeeRate orphanFeeRate = CFeeRate(0);
|
||||
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) {
|
||||
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
|
||||
RelayTransaction(orphanTx);
|
||||
RelayTransaction(orphanTx, orphanFeeRate);
|
||||
vWorkQueue.push_back(orphanHash);
|
||||
vEraseQueue.push_back(orphanHash);
|
||||
}
|
||||
@@ -5418,7 +5424,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
int nDoS = 0;
|
||||
if (!state.IsInvalid(nDoS) || nDoS == 0) {
|
||||
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
|
||||
RelayTransaction(tx);
|
||||
RelayTransaction(tx, txFeeRate);
|
||||
} else {
|
||||
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
|
||||
}
|
||||
@@ -5645,6 +5651,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
|
||||
if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
|
||||
}
|
||||
if (pfrom->minFeeFilter) {
|
||||
CFeeRate feeRate;
|
||||
mempool.lookupFeeRate(hash, feeRate);
|
||||
LOCK(pfrom->cs_feeFilter);
|
||||
if (feeRate.GetFeePerK() < pfrom->minFeeFilter)
|
||||
continue;
|
||||
}
|
||||
vInv.push_back(inv);
|
||||
if (vInv.size() == MAX_INV_SZ) {
|
||||
pfrom->PushMessage(NetMsgType::INV, vInv);
|
||||
@@ -5806,8 +5819,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
else if (strCommand == NetMsgType::FEEFILTER) {
|
||||
CAmount newFeeFilter = 0;
|
||||
vRecv >> newFeeFilter;
|
||||
if (MoneyRange(newFeeFilter)) {
|
||||
{
|
||||
LOCK(pfrom->cs_feeFilter);
|
||||
pfrom->minFeeFilter = newFeeFilter;
|
||||
}
|
||||
LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// Ignore unknown commands for extensibility
|
||||
LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
|
||||
}
|
||||
@@ -6280,6 +6304,29 @@ bool SendMessages(CNode* pto)
|
||||
if (!vGetData.empty())
|
||||
pto->PushMessage(NetMsgType::GETDATA, vGetData);
|
||||
|
||||
//
|
||||
// Message: feefilter
|
||||
//
|
||||
// We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
|
||||
if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
|
||||
!(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
|
||||
CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
|
||||
int64_t timeNow = GetTimeMicros();
|
||||
if (timeNow > pto->nextSendTimeFeeFilter) {
|
||||
CAmount filterToSend = filterRounder.round(currentFilter);
|
||||
if (filterToSend != pto->lastSentFeeFilter) {
|
||||
pto->PushMessage(NetMsgType::FEEFILTER, filterToSend);
|
||||
pto->lastSentFeeFilter = filterToSend;
|
||||
}
|
||||
pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
|
||||
}
|
||||
// If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
|
||||
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
|
||||
else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
|
||||
(currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
|
||||
pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -104,6 +104,10 @@ static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
|
||||
/** Average delay between trickled inventory broadcasts in seconds.
|
||||
* Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
|
||||
static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
|
||||
/** Average delay between feefilter broadcasts in seconds. */
|
||||
static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
|
||||
/** Maximum feefilter broadcast delay after significant change. */
|
||||
static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
|
||||
/** Block download timeout base, expressed in millionths of the block interval (i.e. 10 min) */
|
||||
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
|
||||
/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
|
||||
@@ -122,6 +126,8 @@ static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
|
||||
static const bool DEFAULT_TESTSAFEMODE = false;
|
||||
/** Default for -mempoolreplacement */
|
||||
static const bool DEFAULT_ENABLE_REPLACEMENT = true;
|
||||
/** Default for using fee filter */
|
||||
static const bool DEFAULT_FEEFILTER = true;
|
||||
|
||||
/** Maximum number of headers to announce when relaying blocks with headers message.*/
|
||||
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
|
||||
@@ -290,7 +296,7 @@ void PruneAndFlush();
|
||||
|
||||
/** (try to) add transaction to memory pool **/
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fOverrideMempoolLimit=false, bool fRejectAbsurdFee=false);
|
||||
bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
|
||||
|
||||
/** Convert CValidationState to a human-readable message for logging */
|
||||
std::string FormatStateMessage(const CValidationState &state);
|
||||
|
||||
19
src/net.cpp
19
src/net.cpp
@@ -2044,20 +2044,15 @@ public:
|
||||
instance_of_cnetcleanup;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void RelayTransaction(const CTransaction& tx)
|
||||
void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
|
||||
{
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss.reserve(10000);
|
||||
ss << tx;
|
||||
RelayTransaction(tx, ss);
|
||||
RelayTransaction(tx, feerate, ss);
|
||||
}
|
||||
|
||||
void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
||||
void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss)
|
||||
{
|
||||
CInv inv(MSG_TX, tx.GetHash());
|
||||
{
|
||||
@@ -2078,6 +2073,11 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
||||
{
|
||||
if(!pnode->fRelayTxes)
|
||||
continue;
|
||||
{
|
||||
LOCK(pnode->cs_feeFilter);
|
||||
if (feerate.GetFeePerK() < pnode->minFeeFilter)
|
||||
continue;
|
||||
}
|
||||
LOCK(pnode->cs_filter);
|
||||
if (pnode->pfilter)
|
||||
{
|
||||
@@ -2381,6 +2381,9 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
|
||||
nPingUsecTime = 0;
|
||||
fPingQueued = false;
|
||||
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
|
||||
minFeeFilter = 0;
|
||||
lastSentFeeFilter = 0;
|
||||
nextSendTimeFeeFilter = 0;
|
||||
|
||||
{
|
||||
LOCK(cs_nLastNodeId);
|
||||
|
||||
10
src/net.h
10
src/net.h
@@ -6,6 +6,7 @@
|
||||
#ifndef BITCOIN_NET_H
|
||||
#define BITCOIN_NET_H
|
||||
|
||||
#include "amount.h"
|
||||
#include "bloom.h"
|
||||
#include "compat.h"
|
||||
#include "limitedmap.h"
|
||||
@@ -411,6 +412,11 @@ public:
|
||||
int64_t nMinPingUsecTime;
|
||||
// Whether a ping is requested.
|
||||
bool fPingQueued;
|
||||
// Minimum fee rate with which to filter inv's to this node
|
||||
CAmount minFeeFilter;
|
||||
CCriticalSection cs_feeFilter;
|
||||
CAmount lastSentFeeFilter;
|
||||
int64_t nextSendTimeFeeFilter;
|
||||
|
||||
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
|
||||
~CNode();
|
||||
@@ -762,8 +768,8 @@ public:
|
||||
|
||||
|
||||
class CTransaction;
|
||||
void RelayTransaction(const CTransaction& tx);
|
||||
void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
|
||||
void RelayTransaction(const CTransaction& tx, CFeeRate feerate);
|
||||
void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss);
|
||||
|
||||
/** Access to the (IP) address database (peers.dat) */
|
||||
class CAddrDB
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "amount.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "random.h"
|
||||
#include "streams.h"
|
||||
#include "txmempool.h"
|
||||
#include "util.h"
|
||||
@@ -585,3 +586,21 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein)
|
||||
priStats.Read(filein);
|
||||
nBestSeenHeight = nFileBestSeenHeight;
|
||||
}
|
||||
|
||||
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
|
||||
{
|
||||
CAmount minFeeLimit = minIncrementalFee.GetFeePerK() / 2;
|
||||
feeset.insert(0);
|
||||
for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
|
||||
feeset.insert(bucketBoundary);
|
||||
}
|
||||
}
|
||||
|
||||
CAmount FeeFilterRounder::round(CAmount currentMinFee)
|
||||
{
|
||||
std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
|
||||
if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) {
|
||||
it--;
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
@@ -286,4 +286,17 @@ private:
|
||||
CFeeRate feeLikely, feeUnlikely;
|
||||
double priLikely, priUnlikely;
|
||||
};
|
||||
|
||||
class FeeFilterRounder
|
||||
{
|
||||
public:
|
||||
/** Create new FeeFilterRounder */
|
||||
FeeFilterRounder(const CFeeRate& minIncrementalFee);
|
||||
|
||||
/** Quantize a minimum fee for privacy purpose before broadcast **/
|
||||
CAmount round(CAmount currentMinFee);
|
||||
|
||||
private:
|
||||
std::set<double> feeset;
|
||||
};
|
||||
#endif /*BITCOIN_POLICYESTIMATOR_H */
|
||||
|
||||
@@ -34,6 +34,7 @@ const char *FILTERADD="filteradd";
|
||||
const char *FILTERCLEAR="filterclear";
|
||||
const char *REJECT="reject";
|
||||
const char *SENDHEADERS="sendheaders";
|
||||
const char *FEEFILTER="feefilter";
|
||||
};
|
||||
|
||||
static const char* ppszTypeName[] =
|
||||
@@ -68,7 +69,8 @@ const static std::string allNetMessageTypes[] = {
|
||||
NetMsgType::FILTERADD,
|
||||
NetMsgType::FILTERCLEAR,
|
||||
NetMsgType::REJECT,
|
||||
NetMsgType::SENDHEADERS
|
||||
NetMsgType::SENDHEADERS,
|
||||
NetMsgType::FEEFILTER
|
||||
};
|
||||
const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
|
||||
|
||||
|
||||
@@ -211,7 +211,12 @@ extern const char *REJECT;
|
||||
* @see https://bitcoin.org/en/developer-reference#sendheaders
|
||||
*/
|
||||
extern const char *SENDHEADERS;
|
||||
|
||||
/**
|
||||
* The feefilter message tells the receiving peer not to inv us any txs
|
||||
* which do not meet the specified min fee rate.
|
||||
* @since protocol version 70013 as described by BIP133
|
||||
*/
|
||||
extern const char *FEEFILTER;
|
||||
};
|
||||
|
||||
/* Get a vector of all valid message types (see above) */
|
||||
|
||||
@@ -873,19 +873,20 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
|
||||
uint256 hashTx = tx.GetHash();
|
||||
|
||||
bool fOverrideFees = false;
|
||||
if (params.size() > 1)
|
||||
fOverrideFees = params[1].get_bool();
|
||||
CAmount nMaxRawTxFee = maxTxFee;
|
||||
if (params.size() > 1 && params[1].get_bool())
|
||||
nMaxRawTxFee = 0;
|
||||
|
||||
CCoinsViewCache &view = *pcoinsTip;
|
||||
const CCoins* existingCoins = view.AccessCoins(hashTx);
|
||||
bool fHaveMempool = mempool.exists(hashTx);
|
||||
bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
|
||||
CFeeRate txFeeRate = CFeeRate(0);
|
||||
if (!fHaveMempool && !fHaveChain) {
|
||||
// push to local node and sync with wallets
|
||||
CValidationState state;
|
||||
bool fMissingInputs;
|
||||
if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, !fOverrideFees)) {
|
||||
if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) {
|
||||
if (state.IsInvalid()) {
|
||||
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
|
||||
} else {
|
||||
@@ -898,7 +899,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
|
||||
} else if (fHaveChain) {
|
||||
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
|
||||
}
|
||||
RelayTransaction(tx);
|
||||
RelayTransaction(tx, txFeeRate);
|
||||
|
||||
return hashTx.GetHex();
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
|
||||
LOCK(cs_main);
|
||||
|
||||
CValidationState state;
|
||||
return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, false);
|
||||
return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
||||
|
||||
@@ -770,6 +770,16 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const
|
||||
{
|
||||
LOCK(cs);
|
||||
indexed_transaction_set::const_iterator i = mapTx.find(hash);
|
||||
if (i == mapTx.end())
|
||||
return false;
|
||||
feeRate = CFeeRate(i->GetFee(), i->GetTxSize());
|
||||
return true;
|
||||
}
|
||||
|
||||
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
@@ -601,6 +601,7 @@ public:
|
||||
}
|
||||
|
||||
bool lookup(uint256 hash, CTransaction& result) const;
|
||||
bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
|
||||
|
||||
/** Estimate fee rate needed to get into the next nBlocks
|
||||
* If no answer can be given at nBlocks, return an estimate
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* network protocol versioning
|
||||
*/
|
||||
|
||||
static const int PROTOCOL_VERSION = 70012;
|
||||
static const int PROTOCOL_VERSION = 70013;
|
||||
|
||||
//! initial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
@@ -39,4 +39,7 @@ static const int NO_BLOOM_VERSION = 70011;
|
||||
//! "sendheaders" command and announcing blocks with headers starts with this version
|
||||
static const int SENDHEADERS_VERSION = 70012;
|
||||
|
||||
//! "feefilter" tells peers to filter invs to you by fee starts with this version
|
||||
static const int FEEFILTER_VERSION = 70013;
|
||||
|
||||
#endif // BITCOIN_VERSION_H
|
||||
|
||||
@@ -1835,7 +1835,9 @@ bool CWalletTx::RelayWalletTransaction()
|
||||
{
|
||||
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
|
||||
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
|
||||
RelayTransaction((CTransaction)*this);
|
||||
CFeeRate feeRate;
|
||||
mempool.lookupFeeRate(GetHash(), feeRate);
|
||||
RelayTransaction((CTransaction)*this, feeRate);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4058,14 +4060,14 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
|
||||
|
||||
int CMerkleTx::GetBlocksToMaturity() const
|
||||
{
|
||||
if (!(IsCoinBase() || IsCoinStake()))
|
||||
if (!(IsCoinBase() || IsCoinStake()))
|
||||
return 0;
|
||||
return max(0, (Params().GetConsensus().nCoinbaseMaturity+1) - GetDepthInMainChain());
|
||||
}
|
||||
|
||||
|
||||
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
|
||||
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
|
||||
{
|
||||
CValidationState state;
|
||||
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, fRejectAbsurdFee);
|
||||
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee);
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
|
||||
int GetBlocksToMaturity() const;
|
||||
/** Pass this transaction to the mempool. Fails if absolute fee exceeds maxTxFee. */
|
||||
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
|
||||
bool AcceptToMemoryPool(bool fLimitFree=true, const CAmount nAbsurdFee);
|
||||
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
|
||||
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
|
||||
void setAbandoned() { hashBlock = ABANDON_HASH; }
|
||||
|
||||
Reference in New Issue
Block a user