mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge #7542: Implement "feefilter" P2P message
0371797
modify release-notes.md and bips.md (Alex Morcos)b536a6f
Add p2p test for feefilter (Alex Morcos)5fa66e4
Create SingleNodeConnCB class for RPC tests (Alex Morcos)9e072a6
Implement "feefilter" P2P message. (Alex Morcos)
This commit is contained in:
parent
2839222434
commit
11ac70af9e
@ -20,3 +20,4 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.12.0**):
|
|||||||
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
|
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
|
||||||
* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)).
|
* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)).
|
||||||
* [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)).
|
* [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)).
|
||||||
|
* [`BIP 133`](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki): feefilter messages are respected and sent for peer versions `>=70013` as of **v0.13.0** ([PR 7542](https://github.com/bitcoin/bitcoin/pull/7542)).
|
||||||
|
@ -152,7 +152,6 @@ testScriptsExt = [
|
|||||||
'getblocktemplate_proposals.py',
|
'getblocktemplate_proposals.py',
|
||||||
'txn_doublespend.py',
|
'txn_doublespend.py',
|
||||||
'txn_clone.py --mineblock',
|
'txn_clone.py --mineblock',
|
||||||
# 'pruning.py', # Prune mode is incompatible with -txindex.
|
|
||||||
'forknotify.py',
|
'forknotify.py',
|
||||||
'invalidateblock.py',
|
'invalidateblock.py',
|
||||||
# 'rpcbind_test.py', #temporary, bug in libevent, see #6655
|
# 'rpcbind_test.py', #temporary, bug in libevent, see #6655
|
||||||
@ -162,6 +161,8 @@ testScriptsExt = [
|
|||||||
'mempool_packages.py',
|
'mempool_packages.py',
|
||||||
'maxuploadtarget.py',
|
'maxuploadtarget.py',
|
||||||
# 'replace-by-fee.py', # RBF is disabled in Dash Core
|
# 'replace-by-fee.py', # RBF is disabled in Dash Core
|
||||||
|
'p2p-feefilter.py',
|
||||||
|
# 'pruning.py', # leave pruning last as it takes a REALLY long time #### Prune mode is incompatible with -txindex.
|
||||||
]
|
]
|
||||||
|
|
||||||
def runtests():
|
def runtests():
|
||||||
|
99
qa/rpc-tests/p2p-feefilter.py
Executable file
99
qa/rpc-tests/p2p-feefilter.py
Executable file
@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
#
|
||||||
|
|
||||||
|
from test_framework.mininode import *
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import *
|
||||||
|
import time
|
||||||
|
|
||||||
|
'''
|
||||||
|
FeeFilterTest -- test processing of feefilter messages
|
||||||
|
'''
|
||||||
|
|
||||||
|
def hashToHex(hash):
|
||||||
|
return format(hash, '064x').decode('utf-8')
|
||||||
|
|
||||||
|
# Wait up to 60 secs to see if the testnode has received all the expected invs
|
||||||
|
def allInvsMatch(invsExpected, testnode):
|
||||||
|
for x in xrange(60):
|
||||||
|
with mininode_lock:
|
||||||
|
if (sorted(invsExpected) == sorted(testnode.txinvs)):
|
||||||
|
return True;
|
||||||
|
time.sleep(1)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
# TestNode: bare-bones "peer". Used to track which invs are received from a node
|
||||||
|
# and to send the node feefilter messages.
|
||||||
|
class TestNode(SingleNodeConnCB):
|
||||||
|
def __init__(self):
|
||||||
|
SingleNodeConnCB.__init__(self)
|
||||||
|
self.txinvs = []
|
||||||
|
|
||||||
|
def on_inv(self, conn, message):
|
||||||
|
for i in message.inv:
|
||||||
|
if (i.type == 1):
|
||||||
|
self.txinvs.append(hashToHex(i.hash))
|
||||||
|
|
||||||
|
def clear_invs(self):
|
||||||
|
with mininode_lock:
|
||||||
|
self.txinvs = []
|
||||||
|
|
||||||
|
def send_filter(self, feerate):
|
||||||
|
self.send_message(msg_feefilter(feerate))
|
||||||
|
self.sync_with_ping()
|
||||||
|
|
||||||
|
class FeeFilterTest(BitcoinTestFramework):
|
||||||
|
def setup_network(self):
|
||||||
|
# Node1 will be used to generate txs which should be relayed from Node0
|
||||||
|
# to our test node
|
||||||
|
self.nodes = []
|
||||||
|
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"]))
|
||||||
|
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"]))
|
||||||
|
connect_nodes(self.nodes[0], 1)
|
||||||
|
|
||||||
|
def run_test(self):
|
||||||
|
node1 = self.nodes[1]
|
||||||
|
# Get out of IBD
|
||||||
|
node1.generate(1)
|
||||||
|
sync_blocks(self.nodes)
|
||||||
|
|
||||||
|
# Setup the p2p connections and start up the network thread.
|
||||||
|
test_node = TestNode()
|
||||||
|
connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)
|
||||||
|
test_node.add_connection(connection)
|
||||||
|
NetworkThread().start()
|
||||||
|
test_node.wait_for_verack()
|
||||||
|
|
||||||
|
# Test that invs are received for all txs at feerate of 20 sat/byte
|
||||||
|
node1.settxfee(Decimal("0.00020000"))
|
||||||
|
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
|
||||||
|
assert(allInvsMatch(txids, test_node))
|
||||||
|
test_node.clear_invs()
|
||||||
|
|
||||||
|
# Set a filter of 15 sat/byte
|
||||||
|
test_node.send_filter(15000)
|
||||||
|
|
||||||
|
# Test that txs are still being received (paying 20 sat/byte)
|
||||||
|
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
|
||||||
|
assert(allInvsMatch(txids, test_node))
|
||||||
|
test_node.clear_invs()
|
||||||
|
|
||||||
|
# Change tx fee rate to 10 sat/byte and test they are no longer received
|
||||||
|
node1.settxfee(Decimal("0.00010000"))
|
||||||
|
[node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
|
||||||
|
sync_mempools(self.nodes) # must be sure node 0 has received all txs
|
||||||
|
time.sleep(10) # wait 10 secs to be sure its doesn't relay any
|
||||||
|
assert(allInvsMatch([], test_node))
|
||||||
|
test_node.clear_invs()
|
||||||
|
|
||||||
|
# Remove fee filter and check that txs are received again
|
||||||
|
test_node.send_filter(0)
|
||||||
|
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in xrange(3)]
|
||||||
|
assert(allInvsMatch(txids, test_node))
|
||||||
|
test_node.clear_invs()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
FeeFilterTest().main()
|
@ -1031,6 +1031,23 @@ def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
class msg_feefilter(object):
|
||||||
|
command = "feefilter"
|
||||||
|
|
||||||
|
def __init__(self, feerate=0L):
|
||||||
|
self.feerate = feerate
|
||||||
|
|
||||||
|
def deserialize(self, f):
|
||||||
|
self.feerate = struct.unpack("<Q", f.read(8))[0]
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
r = ""
|
||||||
|
r += struct.pack("<Q", self.feerate)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "msg_feefilter(feerate=%08x)" % self.feerate
|
||||||
|
|
||||||
# This is what a callback should look like for NodeConn
|
# This is what a callback should look like for NodeConn
|
||||||
# Reimplement the on_* functions to provide handling for events
|
# Reimplement the on_* functions to provide handling for events
|
||||||
class NodeConnCB(object):
|
class NodeConnCB(object):
|
||||||
@ -1106,6 +1123,7 @@ class NodeConnCB(object):
|
|||||||
def on_close(self, conn): pass
|
def on_close(self, conn): pass
|
||||||
def on_mempool(self, conn): pass
|
def on_mempool(self, conn): pass
|
||||||
def on_pong(self, conn, message): pass
|
def on_pong(self, conn, message): pass
|
||||||
|
def on_feefilter(self, conn, message): pass
|
||||||
|
|
||||||
# More useful callbacks and functions for NodeConnCB's which have a single NodeConn
|
# More useful callbacks and functions for NodeConnCB's which have a single NodeConn
|
||||||
class SingleNodeConnCB(NodeConnCB):
|
class SingleNodeConnCB(NodeConnCB):
|
||||||
@ -1154,6 +1172,7 @@ class NodeConn(asyncore.dispatcher):
|
|||||||
b"getheaders": msg_getheaders,
|
b"getheaders": msg_getheaders,
|
||||||
b"reject": msg_reject,
|
b"reject": msg_reject,
|
||||||
b"mempool": msg_mempool,
|
b"mempool": msg_mempool,
|
||||||
|
b"feefilter": msg_feefilter
|
||||||
}
|
}
|
||||||
MAGIC_BYTES = {
|
MAGIC_BYTES = {
|
||||||
"mainnet": b"\xbf\x0c\x6b\xbd", # mainnet
|
"mainnet": b"\xbf\x0c\x6b\xbd", # mainnet
|
||||||
|
@ -406,6 +406,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
}
|
}
|
||||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
|
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("-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("-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("-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));
|
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
|
||||||
|
14
src/net.cpp
14
src/net.cpp
@ -2474,7 +2474,7 @@ bool CConnman::DisconnectNode(NodeId id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConnman::RelayTransaction(const CTransaction& tx)
|
void CConnman::RelayTransaction(const CTransaction& tx, CFeeRate feerate)
|
||||||
{
|
{
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss.reserve(10000);
|
ss.reserve(10000);
|
||||||
@ -2488,10 +2488,10 @@ void CConnman::RelayTransaction(const CTransaction& tx)
|
|||||||
} else { // MSG_TX
|
} else { // MSG_TX
|
||||||
ss << tx;
|
ss << tx;
|
||||||
}
|
}
|
||||||
RelayTransaction(tx, ss);
|
RelayTransaction(tx, feerate, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConnman::RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
void CConnman::RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss)
|
||||||
{
|
{
|
||||||
uint256 hash = tx.GetHash();
|
uint256 hash = tx.GetHash();
|
||||||
int nInv = static_cast<bool>(CPrivateSend::GetDSTX(hash)) ? MSG_DSTX :
|
int nInv = static_cast<bool>(CPrivateSend::GetDSTX(hash)) ? MSG_DSTX :
|
||||||
@ -2515,6 +2515,11 @@ void CConnman::RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
|||||||
{
|
{
|
||||||
if(!pnode->fRelayTxes)
|
if(!pnode->fRelayTxes)
|
||||||
continue;
|
continue;
|
||||||
|
{
|
||||||
|
LOCK(pnode->cs_feeFilter);
|
||||||
|
if (feerate.GetFeePerK() < pnode->minFeeFilter)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
LOCK(pnode->cs_filter);
|
LOCK(pnode->cs_filter);
|
||||||
if (pnode->pfilter)
|
if (pnode->pfilter)
|
||||||
{
|
{
|
||||||
@ -2711,6 +2716,9 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
|
|||||||
fPingQueued = false;
|
fPingQueued = false;
|
||||||
fMasternode = false;
|
fMasternode = false;
|
||||||
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
|
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
|
||||||
|
minFeeFilter = 0;
|
||||||
|
lastSentFeeFilter = 0;
|
||||||
|
nextSendTimeFeeFilter = 0;
|
||||||
vchKeyedNetGroup = CalculateKeyedNetGroup(addr);
|
vchKeyedNetGroup = CalculateKeyedNetGroup(addr);
|
||||||
id = idIn;
|
id = idIn;
|
||||||
nLocalServices = nLocalServicesIn;
|
nLocalServices = nLocalServicesIn;
|
||||||
|
10
src/net.h
10
src/net.h
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "addrdb.h"
|
#include "addrdb.h"
|
||||||
#include "addrman.h"
|
#include "addrman.h"
|
||||||
|
#include "amount.h"
|
||||||
#include "bloom.h"
|
#include "bloom.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "limitedmap.h"
|
#include "limitedmap.h"
|
||||||
@ -304,8 +305,8 @@ public:
|
|||||||
std::vector<CNode*> CopyNodeVector();
|
std::vector<CNode*> CopyNodeVector();
|
||||||
void ReleaseNodeVector(const std::vector<CNode*>& vecNodes);
|
void ReleaseNodeVector(const std::vector<CNode*>& vecNodes);
|
||||||
|
|
||||||
void RelayTransaction(const CTransaction& tx);
|
void RelayTransaction(const CTransaction& tx, CFeeRate feerate);
|
||||||
void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
|
void RelayTransaction(const CTransaction& tx, CFeeRate feerate, const CDataStream& ss);
|
||||||
void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION);
|
void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION);
|
||||||
|
|
||||||
// Addrman functions
|
// Addrman functions
|
||||||
@ -765,6 +766,11 @@ public:
|
|||||||
int64_t nMinPingUsecTime;
|
int64_t nMinPingUsecTime;
|
||||||
// Whether a ping is requested.
|
// Whether a ping is requested.
|
||||||
bool fPingQueued;
|
bool fPingQueued;
|
||||||
|
// Minimum fee rate with which to filter inv's to this node
|
||||||
|
CAmount minFeeFilter;
|
||||||
|
CCriticalSection cs_feeFilter;
|
||||||
|
CAmount lastSentFeeFilter;
|
||||||
|
int64_t nextSendTimeFeeFilter;
|
||||||
|
|
||||||
std::vector<unsigned char> vchKeyedNetGroup;
|
std::vector<unsigned char> vchKeyedNetGroup;
|
||||||
|
|
||||||
|
@ -50,6 +50,8 @@ using namespace std;
|
|||||||
|
|
||||||
int64_t nTimeBestReceived = 0; // Used only to inform the wallet of when we last received a block
|
int64_t nTimeBestReceived = 0; // Used only to inform the wallet of when we last received a block
|
||||||
|
|
||||||
|
extern FeeFilterRounder filterRounder;
|
||||||
|
|
||||||
struct COrphanTx {
|
struct COrphanTx {
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
NodeId fromPeer;
|
NodeId fromPeer;
|
||||||
@ -1624,8 +1626,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
|
|
||||||
mapAlreadyAskedFor.erase(inv.hash);
|
mapAlreadyAskedFor.erase(inv.hash);
|
||||||
|
|
||||||
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
CFeeRate txFeeRate = CFeeRate(0);
|
||||||
{
|
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) {
|
||||||
// Process custom txes, this changes AlreadyHave to "true"
|
// Process custom txes, this changes AlreadyHave to "true"
|
||||||
if (strCommand == NetMsgType::DSTX) {
|
if (strCommand == NetMsgType::DSTX) {
|
||||||
LogPrintf("DSTX -- Masternode transaction accepted, txid=%s, peer=%d\n",
|
LogPrintf("DSTX -- Masternode transaction accepted, txid=%s, peer=%d\n",
|
||||||
@ -1638,7 +1640,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mempool.check(pcoinsTip);
|
mempool.check(pcoinsTip);
|
||||||
connman.RelayTransaction(tx);
|
connman.RelayTransaction(tx, txFeeRate);
|
||||||
vWorkQueue.push_back(inv.hash);
|
vWorkQueue.push_back(inv.hash);
|
||||||
|
|
||||||
pfrom->nLastTXTime = GetTime();
|
pfrom->nLastTXTime = GetTime();
|
||||||
@ -1671,10 +1673,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
|
|
||||||
if (setMisbehaving.count(fromPeer))
|
if (setMisbehaving.count(fromPeer))
|
||||||
continue;
|
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());
|
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
|
||||||
connman.RelayTransaction(orphanTx);
|
connman.RelayTransaction(orphanTx, orphanFeeRate);
|
||||||
vWorkQueue.push_back(orphanHash);
|
vWorkQueue.push_back(orphanHash);
|
||||||
vEraseQueue.push_back(orphanHash);
|
vEraseQueue.push_back(orphanHash);
|
||||||
}
|
}
|
||||||
@ -1725,7 +1728,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
instantsend.RejectLockRequest(txLockRequest);
|
instantsend.RejectLockRequest(txLockRequest);
|
||||||
// this lets other nodes to create lock request candidate i.e.
|
// this lets other nodes to create lock request candidate i.e.
|
||||||
// this allows multiple conflicting lock requests to compete for votes
|
// this allows multiple conflicting lock requests to compete for votes
|
||||||
connman.RelayTransaction(tx);
|
connman.RelayTransaction(tx, txFeeRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
|
if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
|
||||||
@ -1740,7 +1743,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
int nDoS = 0;
|
int nDoS = 0;
|
||||||
if (!state.IsInvalid(nDoS) || nDoS == 0) {
|
if (!state.IsInvalid(nDoS) || nDoS == 0) {
|
||||||
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
|
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
|
||||||
connman.RelayTransaction(tx);
|
connman.RelayTransaction(tx, txFeeRate);
|
||||||
} else {
|
} else {
|
||||||
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
|
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
@ -1952,6 +1955,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
|
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
|
||||||
if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
|
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);
|
vInv.push_back(inv);
|
||||||
if (vInv.size() == MAX_INV_SZ) {
|
if (vInv.size() == MAX_INV_SZ) {
|
||||||
connman.PushMessage(pfrom, NetMsgType::INV, vInv);
|
connman.PushMessage(pfrom, NetMsgType::INV, vInv);
|
||||||
@ -2151,8 +2161,20 @@ 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 {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
const std::vector<std::string> &allMessages = getAllNetMessageTypes();
|
const std::vector<std::string> &allMessages = getAllNetMessageTypes();
|
||||||
BOOST_FOREACH(const std::string msg, allMessages) {
|
BOOST_FOREACH(const std::string msg, allMessages) {
|
||||||
@ -2707,6 +2729,29 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
|
|||||||
LogPrint("net", "SendMessages -- GETDATA -- pushed size = %lu peer=%d\n", vGetData.size(), pto->id);
|
LogPrint("net", "SendMessages -- GETDATA -- pushed size = %lu peer=%d\n", vGetData.size(), pto->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
connman.PushMessage(pto, 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
#include "random.h"
|
||||||
#include "streams.h"
|
#include "streams.h"
|
||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -578,3 +579,21 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein)
|
|||||||
priStats.Read(filein);
|
priStats.Read(filein);
|
||||||
nBestSeenHeight = nFileBestSeenHeight;
|
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;
|
CFeeRate feeLikely, feeUnlikely;
|
||||||
double priLikely, priUnlikely;
|
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 */
|
#endif /*BITCOIN_POLICYESTIMATOR_H */
|
||||||
|
@ -35,6 +35,7 @@ const char *FILTERADD="filteradd";
|
|||||||
const char *FILTERCLEAR="filterclear";
|
const char *FILTERCLEAR="filterclear";
|
||||||
const char *REJECT="reject";
|
const char *REJECT="reject";
|
||||||
const char *SENDHEADERS="sendheaders";
|
const char *SENDHEADERS="sendheaders";
|
||||||
|
const char *FEEFILTER="feefilter";
|
||||||
// Dash message types
|
// Dash message types
|
||||||
const char *TXLOCKREQUEST="ix";
|
const char *TXLOCKREQUEST="ix";
|
||||||
const char *TXLOCKVOTE="txlvote";
|
const char *TXLOCKVOTE="txlvote";
|
||||||
@ -119,6 +120,7 @@ const static std::string allNetMessageTypes[] = {
|
|||||||
NetMsgType::FILTERCLEAR,
|
NetMsgType::FILTERCLEAR,
|
||||||
NetMsgType::REJECT,
|
NetMsgType::REJECT,
|
||||||
NetMsgType::SENDHEADERS,
|
NetMsgType::SENDHEADERS,
|
||||||
|
NetMsgType::FEEFILTER,
|
||||||
// Dash message types
|
// Dash message types
|
||||||
// NOTE: do NOT include non-implmented here, we want them to be "Unknown command" in ProcessMessage()
|
// NOTE: do NOT include non-implmented here, we want them to be "Unknown command" in ProcessMessage()
|
||||||
NetMsgType::TXLOCKREQUEST,
|
NetMsgType::TXLOCKREQUEST,
|
||||||
|
@ -218,6 +218,12 @@ extern const char *REJECT;
|
|||||||
* @see https://bitcoin.org/en/developer-reference#sendheaders
|
* @see https://bitcoin.org/en/developer-reference#sendheaders
|
||||||
*/
|
*/
|
||||||
extern const char *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;
|
||||||
|
|
||||||
// Dash message types
|
// Dash message types
|
||||||
// NOTE: do NOT declare non-implmented here, we don't want them to be exposed to the outside
|
// NOTE: do NOT declare non-implmented here, we don't want them to be exposed to the outside
|
||||||
|
@ -875,6 +875,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
fHaveChain = !existingCoin.IsSpent();
|
fHaveChain = !existingCoin.IsSpent();
|
||||||
}
|
}
|
||||||
bool fHaveMempool = mempool.exists(hashTx);
|
bool fHaveMempool = mempool.exists(hashTx);
|
||||||
|
CFeeRate txFeeRate = CFeeRate(0);
|
||||||
if (!fHaveMempool && !fHaveChain) {
|
if (!fHaveMempool && !fHaveChain) {
|
||||||
// push to local node and sync with wallets
|
// push to local node and sync with wallets
|
||||||
if (fInstantSend && !instantsend.ProcessTxLockRequest(tx, *g_connman)) {
|
if (fInstantSend && !instantsend.ProcessTxLockRequest(tx, *g_connman)) {
|
||||||
@ -882,7 +883,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
}
|
}
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool fMissingInputs;
|
bool fMissingInputs;
|
||||||
if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
|
if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
|
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
|
||||||
} else {
|
} else {
|
||||||
@ -898,7 +899,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
if(!g_connman)
|
if(!g_connman)
|
||||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||||
|
|
||||||
g_connman->RelayTransaction(tx);
|
g_connman->RelayTransaction(tx, txFeeRate);
|
||||||
|
|
||||||
return hashTx.GetHex();
|
return hashTx.GetHex();
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
|
|||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0);
|
return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
||||||
|
@ -907,6 +907,16 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
|
|||||||
return true;
|
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
|
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
|
@ -646,6 +646,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool lookup(uint256 hash, CTransaction& result) const;
|
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
|
/** Estimate fee rate needed to get into the next nBlocks
|
||||||
* If no answer can be given at nBlocks, return an estimate
|
* If no answer can be given at nBlocks, return an estimate
|
||||||
|
@ -16,10 +16,12 @@
|
|||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
|
#include "policy/fees.h"
|
||||||
#include "policy/policy.h"
|
#include "policy/policy.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "primitives/block.h"
|
#include "primitives/block.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
#include "random.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/sigcache.h"
|
#include "script/sigcache.h"
|
||||||
#include "script/standard.h"
|
#include "script/standard.h"
|
||||||
@ -95,6 +97,7 @@ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
|
|||||||
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
|
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
|
||||||
|
|
||||||
CTxMemPool mempool(::minRelayTxFee);
|
CTxMemPool mempool(::minRelayTxFee);
|
||||||
|
FeeFilterRounder filterRounder(::minRelayTxFee);
|
||||||
map<uint256, int64_t> mapRejectedBlocks GUARDED_BY(cs_main);
|
map<uint256, int64_t> mapRejectedBlocks GUARDED_BY(cs_main);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -553,7 +556,7 @@ std::string FormatStateMessage(const CValidationState &state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
|
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
|
||||||
bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee,
|
bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
|
||||||
std::vector<COutPoint>& coins_to_uncache, bool fDryRun)
|
std::vector<COutPoint>& coins_to_uncache, bool fDryRun)
|
||||||
{
|
{
|
||||||
const uint256 hash = tx.GetHash();
|
const uint256 hash = tx.GetHash();
|
||||||
@ -748,6 +751,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||||||
|
|
||||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
|
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp);
|
||||||
unsigned int nSize = entry.GetTxSize();
|
unsigned int nSize = entry.GetTxSize();
|
||||||
|
if (txFeeRate) {
|
||||||
|
*txFeeRate = CFeeRate(nFees, nSize);
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the transaction doesn't have an excessive number of
|
// Check that the transaction doesn't have an excessive number of
|
||||||
// sigops, making it impossible to mine. Since the coinbase transaction
|
// sigops, making it impossible to mine. Since the coinbase transaction
|
||||||
@ -1010,10 +1016,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||||
bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee, bool fDryRun)
|
bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee, bool fDryRun)
|
||||||
{
|
{
|
||||||
std::vector<COutPoint> coins_to_uncache;
|
std::vector<COutPoint> coins_to_uncache;
|
||||||
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache, fDryRun);
|
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache, fDryRun);
|
||||||
if (!res || fDryRun) {
|
if (!res || fDryRun) {
|
||||||
if(!res) LogPrint("mempool", "%s: %s %s\n", __func__, tx.GetHash().ToString(), state.GetRejectReason());
|
if(!res) LogPrint("mempool", "%s: %s %s\n", __func__, tx.GetHash().ToString(), state.GetRejectReason());
|
||||||
BOOST_FOREACH(const COutPoint& hashTx, coins_to_uncache)
|
BOOST_FOREACH(const COutPoint& hashTx, coins_to_uncache)
|
||||||
@ -2497,7 +2503,7 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
|
|||||||
// ignore validation errors in resurrected transactions
|
// ignore validation errors in resurrected transactions
|
||||||
list<CTransaction> removed;
|
list<CTransaction> removed;
|
||||||
CValidationState stateDummy;
|
CValidationState stateDummy;
|
||||||
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
|
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) {
|
||||||
mempool.removeRecursive(tx, removed);
|
mempool.removeRecursive(tx, removed);
|
||||||
} else if (mempool.exists(tx.GetHash())) {
|
} else if (mempool.exists(tx.GetHash())) {
|
||||||
vHashUpdate.push_back(tx.GetHash());
|
vHashUpdate.push_back(tx.GetHash());
|
||||||
|
@ -110,6 +110,10 @@ static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
|
|||||||
/** Average delay between trickled inventory broadcasts in seconds.
|
/** Average delay between trickled inventory broadcasts in seconds.
|
||||||
* Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
|
* Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
|
||||||
static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
|
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. 2.5 min) */
|
/** Block download timeout base, expressed in millionths of the block interval (i.e. 2.5 min) */
|
||||||
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 250000;
|
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 250000;
|
||||||
/** Additional block download timeout per parallel downloading peer (i.e. 1.25 min) */
|
/** Additional block download timeout per parallel downloading peer (i.e. 1.25 min) */
|
||||||
@ -132,6 +136,8 @@ static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
|
|||||||
static const bool DEFAULT_TESTSAFEMODE = false;
|
static const bool DEFAULT_TESTSAFEMODE = false;
|
||||||
/** Default for -mempoolreplacement */
|
/** Default for -mempoolreplacement */
|
||||||
static const bool DEFAULT_ENABLE_REPLACEMENT = false;
|
static const bool DEFAULT_ENABLE_REPLACEMENT = false;
|
||||||
|
/** Default for using fee filter */
|
||||||
|
static const bool DEFAULT_FEEFILTER = true;
|
||||||
|
|
||||||
/** Maximum number of headers to announce when relaying blocks with headers message.*/
|
/** Maximum number of headers to announce when relaying blocks with headers message.*/
|
||||||
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
|
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
|
||||||
@ -310,7 +316,7 @@ void PruneAndFlush();
|
|||||||
|
|
||||||
/** (try to) add transaction to memory pool **/
|
/** (try to) add transaction to memory pool **/
|
||||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||||
bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0, bool fDryRun=false);
|
bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0, bool fDryRun=false);
|
||||||
|
|
||||||
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin);
|
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin);
|
||||||
int GetUTXOHeight(const COutPoint& outpoint);
|
int GetUTXOHeight(const COutPoint& outpoint);
|
||||||
|
@ -37,7 +37,10 @@ static const int NO_BLOOM_VERSION = 70201;
|
|||||||
//! "sendheaders" command and announcing blocks with headers starts with this version
|
//! "sendheaders" command and announcing blocks with headers starts with this version
|
||||||
static const int SENDHEADERS_VERSION = 70201;
|
static const int SENDHEADERS_VERSION = 70201;
|
||||||
|
|
||||||
|
//! "feefilter" tells peers to filter invs to you by fee starts with this version
|
||||||
|
static const int FEEFILTER_VERSION = 70209;
|
||||||
|
|
||||||
//! DIP0001 was activated in this version
|
//! DIP0001 was activated in this version
|
||||||
static const int DIP0001_PROTOCOL_VERSION = 70208;
|
static const int DIP0001_PROTOCOL_VERSION = 99999; // disable for now (clarify deployment later)
|
||||||
|
|
||||||
#endif // BITCOIN_VERSION_H
|
#endif // BITCOIN_VERSION_H
|
||||||
|
@ -1759,12 +1759,14 @@ bool CWalletTx::RelayWalletTransaction(CConnman* connman, std::string strCommand
|
|||||||
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
|
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
|
||||||
uint256 hash = GetHash();
|
uint256 hash = GetHash();
|
||||||
LogPrintf("Relaying wtx %s\n", hash.ToString());
|
LogPrintf("Relaying wtx %s\n", hash.ToString());
|
||||||
|
CFeeRate feeRate;
|
||||||
|
mempool.lookupFeeRate(GetHash(), feeRate);
|
||||||
|
|
||||||
if(strCommand == NetMsgType::TXLOCKREQUEST) {
|
if(strCommand == NetMsgType::TXLOCKREQUEST) {
|
||||||
instantsend.ProcessTxLockRequest(((CTxLockRequest)*this), *connman);
|
instantsend.ProcessTxLockRequest(((CTxLockRequest)*this), *connman);
|
||||||
}
|
}
|
||||||
if (connman) {
|
if (connman) {
|
||||||
connman->RelayTransaction((CTransaction)*this);
|
connman->RelayTransaction((CTransaction)*this, feeRate);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4695,5 +4697,5 @@ int CMerkleTx::GetBlocksToMaturity() const
|
|||||||
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
|
bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
|
||||||
{
|
{
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
|
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user