|
17 | 17 | #include "init.h" |
18 | 18 | #include "merkleblock.h" |
19 | 19 | #include "net.h" |
| 20 | +#include "policy/fees.h" |
20 | 21 | #include "policy/policy.h" |
21 | 22 | #include "pow.h" |
22 | 23 | #include "primitives/block.h" |
23 | 24 | #include "primitives/transaction.h" |
| 25 | +#include "random.h" |
24 | 26 | #include "script/script.h" |
25 | 27 | #include "script/sigcache.h" |
26 | 28 | #include "script/standard.h" |
@@ -81,6 +83,7 @@ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); |
81 | 83 | CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; |
82 | 84 |
|
83 | 85 | CTxMemPool mempool(::minRelayTxFee); |
| 86 | +FeeFilterRounder filterRounder(::minRelayTxFee); |
84 | 87 |
|
85 | 88 | struct COrphanTx { |
86 | 89 | CTransaction tx; |
@@ -987,7 +990,7 @@ std::string FormatStateMessage(const CValidationState &state) |
987 | 990 | } |
988 | 991 |
|
989 | 992 | bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, |
990 | | - bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee, |
| 993 | + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, |
991 | 994 | std::vector<uint256>& vHashTxnToUncache) |
992 | 995 | { |
993 | 996 | const uint256 hash = tx.GetHash(); |
@@ -1144,6 +1147,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C |
1144 | 1147 |
|
1145 | 1148 | CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); |
1146 | 1149 | unsigned int nSize = entry.GetTxSize(); |
| 1150 | + if (txFeeRate) { |
| 1151 | + *txFeeRate = CFeeRate(nFees, nSize); |
| 1152 | + } |
1147 | 1153 |
|
1148 | 1154 | // Check that the transaction doesn't have an excessive number of |
1149 | 1155 | // sigops, making it impossible to mine. Since the coinbase transaction |
@@ -1392,10 +1398,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C |
1392 | 1398 | } |
1393 | 1399 |
|
1394 | 1400 | bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, |
1395 | | - bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee) |
| 1401 | + bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee) |
1396 | 1402 | { |
1397 | 1403 | std::vector<uint256> vHashTxToUncache; |
1398 | | - bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); |
| 1404 | + bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); |
1399 | 1405 | if (!res) { |
1400 | 1406 | BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache) |
1401 | 1407 | pcoinsTip->Uncache(hashTx); |
@@ -2620,7 +2626,7 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons |
2620 | 2626 | // ignore validation errors in resurrected transactions |
2621 | 2627 | list<CTransaction> removed; |
2622 | 2628 | CValidationState stateDummy; |
2623 | | - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { |
| 2629 | + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) { |
2624 | 2630 | mempool.removeRecursive(tx, removed); |
2625 | 2631 | } else if (mempool.exists(tx.GetHash())) { |
2626 | 2632 | vHashUpdate.push_back(tx.GetHash()); |
@@ -4916,10 +4922,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
4916 | 4922 | pfrom->setAskFor.erase(inv.hash); |
4917 | 4923 | mapAlreadyAskedFor.erase(inv); |
4918 | 4924 |
|
4919 | | - if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) |
4920 | | - { |
| 4925 | + CFeeRate txFeeRate = CFeeRate(0); |
| 4926 | + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) { |
4921 | 4927 | mempool.check(pcoinsTip); |
4922 | | - RelayTransaction(tx); |
| 4928 | + RelayTransaction(tx, txFeeRate); |
4923 | 4929 | vWorkQueue.push_back(inv.hash); |
4924 | 4930 |
|
4925 | 4931 | LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", |
@@ -4950,10 +4956,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
4950 | 4956 |
|
4951 | 4957 | if (setMisbehaving.count(fromPeer)) |
4952 | 4958 | continue; |
4953 | | - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) |
4954 | | - { |
| 4959 | + CFeeRate orphanFeeRate = CFeeRate(0); |
| 4960 | + if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) { |
4955 | 4961 | LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); |
4956 | | - RelayTransaction(orphanTx); |
| 4962 | + RelayTransaction(orphanTx, orphanFeeRate); |
4957 | 4963 | vWorkQueue.push_back(orphanHash); |
4958 | 4964 | vEraseQueue.push_back(orphanHash); |
4959 | 4965 | } |
@@ -5006,7 +5012,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
5006 | 5012 | int nDoS = 0; |
5007 | 5013 | if (!state.IsInvalid(nDoS) || nDoS == 0) { |
5008 | 5014 | LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); |
5009 | | - RelayTransaction(tx); |
| 5015 | + RelayTransaction(tx, txFeeRate); |
5010 | 5016 | } else { |
5011 | 5017 | LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); |
5012 | 5018 | } |
@@ -5200,6 +5206,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
5200 | 5206 | if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... |
5201 | 5207 | if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue; |
5202 | 5208 | } |
| 5209 | + if (pfrom->minFeeFilter) { |
| 5210 | + CFeeRate feeRate; |
| 5211 | + mempool.lookupFeeRate(hash, feeRate); |
| 5212 | + LOCK(pfrom->cs_feeFilter); |
| 5213 | + if (feeRate.GetFeePerK() < pfrom->minFeeFilter) |
| 5214 | + continue; |
| 5215 | + } |
5203 | 5216 | vInv.push_back(inv); |
5204 | 5217 | if (vInv.size() == MAX_INV_SZ) { |
5205 | 5218 | pfrom->PushMessage(NetMsgType::INV, vInv); |
@@ -5362,8 +5375,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
5362 | 5375 | } |
5363 | 5376 | } |
5364 | 5377 |
|
5365 | | - else |
5366 | | - { |
| 5378 | + else if (strCommand == NetMsgType::FEEFILTER) { |
| 5379 | + CAmount newFeeFilter = 0; |
| 5380 | + vRecv >> newFeeFilter; |
| 5381 | + if (MoneyRange(newFeeFilter)) { |
| 5382 | + { |
| 5383 | + LOCK(pfrom->cs_feeFilter); |
| 5384 | + pfrom->minFeeFilter = newFeeFilter; |
| 5385 | + } |
| 5386 | + LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id); |
| 5387 | + } |
| 5388 | + } |
| 5389 | + |
| 5390 | + else { |
5367 | 5391 | // Ignore unknown commands for extensibility |
5368 | 5392 | LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); |
5369 | 5393 | } |
@@ -5845,6 +5869,29 @@ bool SendMessages(CNode* pto) |
5845 | 5869 | if (!vGetData.empty()) |
5846 | 5870 | pto->PushMessage(NetMsgType::GETDATA, vGetData); |
5847 | 5871 |
|
| 5872 | + // |
| 5873 | + // Message: feefilter |
| 5874 | + // |
| 5875 | + // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay |
| 5876 | + if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && |
| 5877 | + !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) { |
| 5878 | + CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); |
| 5879 | + int64_t timeNow = GetTimeMicros(); |
| 5880 | + if (timeNow > pto->nextSendTimeFeeFilter) { |
| 5881 | + CAmount filterToSend = filterRounder.round(currentFilter); |
| 5882 | + if (filterToSend != pto->lastSentFeeFilter) { |
| 5883 | + pto->PushMessage(NetMsgType::FEEFILTER, filterToSend); |
| 5884 | + pto->lastSentFeeFilter = filterToSend; |
| 5885 | + } |
| 5886 | + pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); |
| 5887 | + } |
| 5888 | + // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY |
| 5889 | + // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. |
| 5890 | + else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter && |
| 5891 | + (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) { |
| 5892 | + pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000; |
| 5893 | + } |
| 5894 | + } |
5848 | 5895 | } |
5849 | 5896 | return true; |
5850 | 5897 | } |
|
0 commit comments