aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/alert.cpp2
-rw-r--r--src/bloom.cpp77
-rw-r--r--src/bloom.h26
-rw-r--r--src/chainparams.cpp1
-rw-r--r--src/clientversion.h2
-rw-r--r--src/main.cpp245
-rw-r--r--src/main.h13
-rw-r--r--src/mruset.h65
-rw-r--r--src/net.cpp42
-rw-r--r--src/net.h46
-rw-r--r--src/protocol.cpp67
-rw-r--r--src/protocol.h159
-rw-r--r--src/qt/bitcoinunits.cpp7
-rw-r--r--src/qt/bitcoinunits.h1
-rw-r--r--src/qt/coincontroldialog.cpp10
-rw-r--r--src/qt/guiutil.cpp11
-rw-r--r--src/qt/locale/bitcoin_en.ts2
-rw-r--r--src/qt/receiverequestdialog.cpp2
-rw-r--r--src/qt/transactiondesc.cpp4
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/rpcblockchain.cpp4
-rw-r--r--src/rpcnet.cpp22
-rw-r--r--src/rpcrawtransaction.cpp1
-rw-r--r--src/script/script.cpp2
-rw-r--r--src/script/script.h4
-rw-r--r--src/test/DoS_tests.cpp14
-rw-r--r--src/test/data/script_invalid.json6
-rw-r--r--src/test/data/script_valid.json6
-rw-r--r--src/test/data/tx_invalid.json32
-rw-r--r--src/test/data/tx_valid.json20
-rw-r--r--src/test/mruset_tests.cpp81
-rw-r--r--src/test/script_tests.cpp8
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txmempool.cpp53
-rw-r--r--src/txmempool.h43
-rw-r--r--src/wallet/test/wallet_tests.cpp18
-rw-r--r--src/wallet/wallet.cpp30
-rw-r--r--src/wallet/wallet.h1
40 files changed, 665 insertions, 468 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index bb627a5448..5da1a873de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -117,7 +117,6 @@ BITCOIN_CORE_H = \
memusage.h \
merkleblock.h \
miner.h \
- mruset.h \
net.h \
netbase.h \
noui.h \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 4d0894b711..d89132f806 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -59,7 +59,6 @@ BITCOIN_TESTS =\
test/mempool_tests.cpp \
test/merkle_tests.cpp \
test/miner_tests.cpp \
- test/mruset_tests.cpp \
test/multisig_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
diff --git a/src/alert.cpp b/src/alert.cpp
index 91e54a9178..b705069407 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -138,7 +138,7 @@ bool CAlert::RelayTo(CNode* pnode) const
AppliesToMe() ||
GetAdjustedTime() < nRelayUntil)
{
- pnode->PushMessage("alert", *this);
+ pnode->PushMessage(NetMsgType::ALERT, *this);
return true;
}
}
diff --git a/src/bloom.cpp b/src/bloom.cpp
index de87206592..4bda2bbce4 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -216,30 +216,54 @@ void CBloomFilter::UpdateEmptyFull()
isEmpty = empty;
}
-CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate) :
- b1(nElements * 2, fpRate, 0), b2(nElements * 2, fpRate, 0)
+CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate)
{
- // Implemented using two bloom filters of 2 * nElements each.
- // We fill them up, and clear them, staggered, every nElements
- // inserted, so at least one always contains the last nElements
- // inserted.
- nInsertions = 0;
- nBloomSize = nElements * 2;
-
+ double logFpRate = log(fpRate);
+ /* The optimal number of hash functions is log(fpRate) / log(0.5), but
+ * restrict it to the range 1-50. */
+ nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));
+ /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
+ nEntriesPerGeneration = (nElements + 1) / 2;
+ uint32_t nMaxElements = nEntriesPerGeneration * 3;
+ /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
+ * => pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
+ * => 1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
+ * => log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
+ * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
+ * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
+ */
+ uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
+ data.clear();
+ /* We store up to 16 'bits' per data element. */
+ data.resize((nFilterBits + 15) / 16);
reset();
}
+/* Similar to CBloomFilter::Hash */
+inline unsigned int CRollingBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const {
+ return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (data.size() * 16);
+}
+
void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
- if (nInsertions == 0) {
- b1.clear();
- } else if (nInsertions == nBloomSize / 2) {
- b2.clear();
+ if (nEntriesThisGeneration == nEntriesPerGeneration) {
+ nEntriesThisGeneration = 0;
+ nGeneration++;
+ if (nGeneration == 4) {
+ nGeneration = 1;
+ }
+ /* Wipe old entries that used this generation number. */
+ for (uint32_t p = 0; p < data.size() * 16; p++) {
+ if (get(p) == nGeneration) {
+ put(p, 0);
+ }
+ }
}
- b1.insert(vKey);
- b2.insert(vKey);
- if (++nInsertions == nBloomSize) {
- nInsertions = 0;
+ nEntriesThisGeneration++;
+
+ for (int n = 0; n < nHashFuncs; n++) {
+ uint32_t h = Hash(n, vKey);
+ put(h, nGeneration);
}
}
@@ -251,10 +275,13 @@ void CRollingBloomFilter::insert(const uint256& hash)
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
- if (nInsertions < nBloomSize / 2) {
- return b2.contains(vKey);
+ for (int n = 0; n < nHashFuncs; n++) {
+ uint32_t h = Hash(n, vKey);
+ if (get(h) == 0) {
+ return false;
+ }
}
- return b1.contains(vKey);
+ return true;
}
bool CRollingBloomFilter::contains(const uint256& hash) const
@@ -265,8 +292,10 @@ bool CRollingBloomFilter::contains(const uint256& hash) const
void CRollingBloomFilter::reset()
{
- unsigned int nNewTweak = GetRand(std::numeric_limits<unsigned int>::max());
- b1.reset(nNewTweak);
- b2.reset(nNewTweak);
- nInsertions = 0;
+ nTweak = GetRand(std::numeric_limits<unsigned int>::max());
+ nEntriesThisGeneration = 0;
+ nGeneration = 1;
+ for (std::vector<uint32_t>::iterator it = data.begin(); it != data.end(); it++) {
+ *it = 0;
+ }
}
diff --git a/src/bloom.h b/src/bloom.h
index a4dba8cb4f..98cfbdb833 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -110,8 +110,11 @@ public:
* reset() is provided, which also changes nTweak to decrease the impact of
* false-positives.
*
- * contains(item) will always return true if item was one of the last N things
+ * contains(item) will always return true if item was one of the last N to 1.5*N
* insert()'ed ... but may also return true for items that were not inserted.
+ *
+ * It needs around 1.8 bytes per element per factor 0.1 of false positive rate.
+ * (More accurately: 3/(log(256)*log(2)) * log(1/fpRate) * nElements bytes)
*/
class CRollingBloomFilter
{
@@ -129,10 +132,23 @@ public:
void reset();
private:
- unsigned int nBloomSize;
- unsigned int nInsertions;
- CBloomFilter b1, b2;
-};
+ int nEntriesPerGeneration;
+ int nEntriesThisGeneration;
+ int nGeneration;
+ std::vector<uint32_t> data;
+ unsigned int nTweak;
+ int nHashFuncs;
+
+ unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;
+ inline int get(uint32_t position) const {
+ return (data[(position >> 4) % data.size()] >> (2 * (position & 0xF))) & 0x3;
+ }
+
+ inline void put(uint32_t position, uint32_t val) {
+ uint32_t& cell = data[(position >> 4) % data.size()];
+ cell = (cell & ~(((uint32_t)3) << (2 * (position & 0xF)))) | (val << (2 * (position & 0xF)));
+ }
+};
#endif // BITCOIN_BLOOM_H
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index a46866a2be..abeaaf927c 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -179,7 +179,6 @@ public:
vFixedSeeds.clear();
vSeeds.clear();
- vSeeds.push_back(CDNSSeedData("alexykot.me", "testnet-seed.alexykot.me"));
vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org"));
vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
diff --git a/src/clientversion.h b/src/clientversion.h
index 5a06b310a3..cd947a9761 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -15,7 +15,7 @@
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
-#define CLIENT_VERSION_MINOR 11
+#define CLIENT_VERSION_MINOR 12
#define CLIENT_VERSION_REVISION 99
#define CLIENT_VERSION_BUILD 0
diff --git a/src/main.cpp b/src/main.cpp
index cb3f8f39f8..0766b1458b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -181,7 +181,7 @@ namespace {
* million to make it highly unlikely for users to have issues with this
* filter.
*
- * Memory used: 1.7MB
+ * Memory used: 1.3 MB
*/
boost::scoped_ptr<CRollingBloomFilter> recentRejects;
uint256 hashRecentRejectsChainTip;
@@ -800,32 +800,6 @@ void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) {
pcoinsTip->Uncache(removed);
}
-CAmount GetMinRelayFee(const CTransaction& tx, const CTxMemPool& pool, unsigned int nBytes, bool fAllowFree)
-{
- uint256 hash = tx.GetHash();
- double dPriorityDelta = 0;
- CAmount nFeeDelta = 0;
- pool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
- if (dPriorityDelta > 0 || nFeeDelta > 0)
- return 0;
-
- CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);
-
- if (fAllowFree)
- {
- // There is a free transaction area in blocks created by most miners,
- // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
- // to be considered to fall into this category. We don't want to encourage sending
- // multiple transactions instead of one big transaction to avoid fees.
- if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
- nMinFee = 0;
- }
-
- if (!MoneyRange(nMinFee))
- nMinFee = MAX_MONEY;
- return nMinFee;
-}
-
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state)
{
@@ -968,6 +942,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
+ // nModifiedFees includes any fee deltas from PrioritiseTransaction
+ CAmount nModifiedFees = nFees;
+ double nPriorityDummy = 0;
+ pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
+
CAmount inChainInputValue;
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
@@ -985,16 +964,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps);
unsigned int nSize = entry.GetTxSize();
- // Don't accept it if it can't get into a block
- CAmount txMinFee = GetMinRelayFee(tx, pool, nSize, true);
- if (fLimitFree && nFees < txMinFee)
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
- strprintf("%d < %d", nFees, txMinFee));
-
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
- if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
+ if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
- } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
+ } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
@@ -1002,7 +975,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
- if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize))
+ if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
@@ -1067,7 +1040,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
LOCK(pool.cs);
if (setConflicts.size())
{
- CFeeRate newFeeRate(nFees, nSize);
+ CFeeRate newFeeRate(nModifiedFees, nSize);
set<uint256> setConflictsParents;
const int maxDescendantsToVisit = 100;
CTxMemPool::setEntries setIterConflicting;
@@ -1110,7 +1083,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
// ignored when deciding whether or not to replace, we do
// require the replacement to pay more overall fees too,
// mitigating most cases.
- CFeeRate oldFeeRate(mi->GetFee(), mi->GetTxSize());
+ CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
if (newFeeRate <= oldFeeRate)
{
return state.DoS(0,
@@ -1138,7 +1111,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
pool.CalculateDescendants(it, allConflicting);
}
BOOST_FOREACH(CTxMemPool::txiter it, allConflicting) {
- nConflictingFees += it->GetFee();
+ nConflictingFees += it->GetModifiedFee();
nConflictingSize += it->GetTxSize();
}
} else {
@@ -1171,16 +1144,16 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
// The replacement must pay greater fees than the transactions it
// replaces - if we did the bandwidth used by those conflicting
// transactions would not be paid for.
- if (nFees < nConflictingFees)
+ if (nModifiedFees < nConflictingFees)
{
return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s",
- hash.ToString(), FormatMoney(nFees), FormatMoney(nConflictingFees)),
+ hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)),
REJECT_INSUFFICIENTFEE, "insufficient fee");
}
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
- CAmount nDeltaFees = nFees - nConflictingFees;
+ CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::minRelayTxFee.GetFee(nSize))
{
return state.DoS(0,
@@ -1218,7 +1191,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
LogPrint("mempool", "replacing tx %s with %s for %s BTC additional fees, %d delta bytes\n",
it->GetTx().GetHash().ToString(),
hash.ToString(),
- FormatMoney(nFees - nConflictingFees),
+ FormatMoney(nModifiedFees - nConflictingFees),
(int)nSize - (int)nConflictingSize);
}
pool.RemoveStaged(allConflicting);
@@ -1680,9 +1653,9 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
- CScriptCheck check(*coins, tx, i,
+ CScriptCheck check2(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
- if (check())
+ if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
// Failures of other flags indicate a transaction that is
@@ -4171,14 +4144,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams))
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
- pfrom->PushMessage("block", block);
+ pfrom->PushMessage(NetMsgType::BLOCK, block);
else // MSG_FILTERED_BLOCK)
{
LOCK(pfrom->cs_filter);
if (pfrom->pfilter)
{
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
- pfrom->PushMessage("merkleblock", merkleBlock);
+ pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
// Note that there is currently no way for a node to request any single transactions we didn't send here -
@@ -4187,8 +4160,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
- if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
- pfrom->PushMessage("tx", block.vtx[pair.first]);
+ pfrom->PushMessage(NetMsgType::TX, block.vtx[pair.first]);
}
// else
// no response
@@ -4202,7 +4174,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// wait for other stuff first.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
- pfrom->PushMessage("inv", vInv);
+ pfrom->PushMessage(NetMsgType::INV, vInv);
pfrom->hashContinue.SetNull();
}
}
@@ -4225,7 +4197,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(1000);
ss << tx;
- pfrom->PushMessage("tx", ss);
+ pfrom->PushMessage(NetMsgType::TX, ss);
pushed = true;
}
}
@@ -4252,7 +4224,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// do that because they want to know about (and store and rebroadcast and
// risk analyze) the dependencies of transactions relevant to them, without
// having to download the entire memory pool.
- pfrom->PushMessage("notfound", vNotFound);
+ pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound);
}
}
@@ -4269,9 +4241,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!(nLocalServices & NODE_BLOOM) &&
- (strCommand == "filterload" ||
- strCommand == "filteradd" ||
- strCommand == "filterclear"))
+ (strCommand == NetMsgType::FILTERLOAD ||
+ strCommand == NetMsgType::FILTERADD ||
+ strCommand == NetMsgType::FILTERCLEAR))
{
if (pfrom->nVersion >= NO_BLOOM_VERSION) {
Misbehaving(pfrom->GetId(), 100);
@@ -4283,12 +4255,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- if (strCommand == "version")
+ if (strCommand == NetMsgType::VERSION)
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
- pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
Misbehaving(pfrom->GetId(), 1);
return false;
}
@@ -4302,7 +4274,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// disconnect from peers older than this proto version
LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
- pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE,
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION));
pfrom->fDisconnect = true;
return false;
@@ -4347,7 +4319,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
// Change version
- pfrom->PushMessage("verack");
+ pfrom->PushMessage(NetMsgType::VERACK);
pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
if (!pfrom->fInbound)
@@ -4370,7 +4342,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Get recent addresses
if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
{
- pfrom->PushMessage("getaddr");
+ pfrom->PushMessage(NetMsgType::GETADDR);
pfrom->fGetAddr = true;
}
addrman.Good(pfrom->addr);
@@ -4414,7 +4386,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "verack")
+ else if (strCommand == NetMsgType::VERACK)
{
pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
@@ -4429,12 +4401,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
- pfrom->PushMessage("sendheaders");
+ pfrom->PushMessage(NetMsgType::SENDHEADERS);
}
}
- else if (strCommand == "addr")
+ else if (strCommand == NetMsgType::ADDR)
{
vector<CAddress> vAddr;
vRecv >> vAddr;
@@ -4500,14 +4472,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fDisconnect = true;
}
- else if (strCommand == "sendheaders")
+ else if (strCommand == NetMsgType::SENDHEADERS)
{
LOCK(cs_main);
State(pfrom->GetId())->fPreferHeaders = true;
}
- else if (strCommand == "inv")
+ else if (strCommand == NetMsgType::INV)
{
vector<CInv> vInv;
vRecv >> vInv;
@@ -4548,7 +4520,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// time the block arrives, the header chain leading up to it is already validated. Not
// doing this will result in the received block being rejected as an orphan in case it is
// not a direct successor.
- pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash);
+ pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash);
CNodeState *nodestate = State(pfrom->GetId());
if (CanDirectFetch(chainparams.GetConsensus()) &&
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
@@ -4578,11 +4550,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
if (!vToFetch.empty())
- pfrom->PushMessage("getdata", vToFetch);
+ pfrom->PushMessage(NetMsgType::GETDATA, vToFetch);
}
- else if (strCommand == "getdata")
+ else if (strCommand == NetMsgType::GETDATA)
{
vector<CInv> vInv;
vRecv >> vInv;
@@ -4603,7 +4575,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "getblocks")
+ else if (strCommand == NetMsgType::GETBLOCKS)
{
CBlockLocator locator;
uint256 hashStop;
@@ -4647,7 +4619,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "getheaders")
+ else if (strCommand == NetMsgType::GETHEADERS)
{
CBlockLocator locator;
uint256 hashStop;
@@ -4692,11 +4664,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
- pfrom->PushMessage("headers", vHeaders);
+ pfrom->PushMessage(NetMsgType::HEADERS, vHeaders);
}
- else if (strCommand == "tx")
+ else if (strCommand == NetMsgType::TX)
{
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistalwaysrelay is off
@@ -4825,7 +4797,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->id,
FormatStateMessage(state));
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
- pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0)
Misbehaving(pfrom->GetId(), nDoS);
@@ -4834,7 +4806,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "headers" && !fImporting && !fReindex) // Ignore headers received while importing
+ else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
{
std::vector<CBlockHeader> headers;
@@ -4882,7 +4854,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
- pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256());
+ pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256());
}
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
@@ -4927,7 +4899,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
}
if (vGetData.size() > 0) {
- pfrom->PushMessage("getdata", vGetData);
+ pfrom->PushMessage(NetMsgType::GETDATA, vGetData);
}
}
}
@@ -4935,7 +4907,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CheckBlockIndex(chainparams.GetConsensus());
}
- else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing
+ else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
{
CBlock block;
vRecv >> block;
@@ -4955,7 +4927,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0) {
LOCK(cs_main);
@@ -4971,7 +4943,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// to users' AddrMan and later request them by sending getaddr messages.
// Making nodes which are behind NAT and can only make outgoing connections ignore
// the getaddr message mitigates the attack.
- else if ((strCommand == "getaddr") && (pfrom->fInbound))
+ else if ((strCommand == NetMsgType::GETADDR) && (pfrom->fInbound))
{
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
@@ -4980,8 +4952,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "mempool")
+ else if (strCommand == NetMsgType::MEMPOOL)
{
+ if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted)
+ {
+ LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ return true;
+ }
LOCK2(cs_main, pfrom->cs_filter);
std::vector<uint256> vtxid;
@@ -4989,23 +4967,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vector<CInv> vInv;
BOOST_FOREACH(uint256& hash, vtxid) {
CInv inv(MSG_TX, hash);
- CTransaction tx;
- bool fInMemPool = mempool.lookup(hash, tx);
- if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
- if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) ||
- (!pfrom->pfilter))
- vInv.push_back(inv);
+ if (pfrom->pfilter) {
+ CTransaction tx;
+ bool fInMemPool = mempool.lookup(hash, tx);
+ if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
+ if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
+ }
+ vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
- pfrom->PushMessage("inv", vInv);
+ pfrom->PushMessage(NetMsgType::INV, vInv);
vInv.clear();
}
}
if (vInv.size() > 0)
- pfrom->PushMessage("inv", vInv);
+ pfrom->PushMessage(NetMsgType::INV, vInv);
}
- else if (strCommand == "ping")
+ else if (strCommand == NetMsgType::PING)
{
if (pfrom->nVersion > BIP0031_VERSION)
{
@@ -5022,12 +5001,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
- pfrom->PushMessage("pong", nonce);
+ pfrom->PushMessage(NetMsgType::PONG, nonce);
}
}
- else if (strCommand == "pong")
+ else if (strCommand == NetMsgType::PONG)
{
int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
@@ -5084,7 +5063,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (fAlerts && strCommand == "alert")
+ else if (fAlerts && strCommand == NetMsgType::ALERT)
{
CAlert alert;
vRecv >> alert;
@@ -5115,7 +5094,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "filterload")
+ else if (strCommand == NetMsgType::FILTERLOAD)
{
CBloomFilter filter;
vRecv >> filter;
@@ -5134,7 +5113,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "filteradd")
+ else if (strCommand == NetMsgType::FILTERADD)
{
vector<unsigned char> vData;
vRecv >> vData;
@@ -5154,7 +5133,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "filterclear")
+ else if (strCommand == NetMsgType::FILTERCLEAR)
{
LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
@@ -5163,7 +5142,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "reject")
+ else if (strCommand == NetMsgType::REJECT)
{
if (fDebug) {
try {
@@ -5173,7 +5152,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
ostringstream ss;
ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
- if (strMsg == "block" || strMsg == "tx")
+ if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX)
{
uint256 hash;
vRecv >> hash;
@@ -5281,7 +5260,7 @@ bool ProcessMessages(CNode* pfrom)
}
catch (const std::ios_base::failure& e)
{
- pfrom->PushMessage("reject", strCommand, REJECT_MALFORMED, string("error parsing message"));
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message"));
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
@@ -5320,7 +5299,7 @@ bool ProcessMessages(CNode* pfrom)
}
-bool SendMessages(CNode* pto, bool fSendTrickle)
+bool SendMessages(CNode* pto)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
@@ -5349,11 +5328,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- pto->PushMessage("ping", nonce);
+ pto->PushMessage(NetMsgType::PING, nonce);
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
- pto->PushMessage("ping");
+ pto->PushMessage(NetMsgType::PING);
}
}
@@ -5362,28 +5341,17 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
return true;
// Address refresh broadcast
- static int64_t nLastRebroadcast;
- if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- {
- // Periodically clear addrKnown to allow refresh broadcasts
- if (nLastRebroadcast)
- pnode->addrKnown.reset();
-
- // Rebroadcast our address
- AdvertizeLocal(pnode);
- }
- if (!vNodes.empty())
- nLastRebroadcast = GetTime();
+ int64_t nNow = GetTimeMicros();
+ if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
+ AdvertizeLocal(pto);
+ pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
//
// Message: addr
//
- if (fSendTrickle)
- {
+ if (pto->nNextAddrSend < nNow) {
+ pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
@@ -5395,14 +5363,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
- pto->PushMessage("addr", vAddr);
+ pto->PushMessage(NetMsgType::ADDR, vAddr);
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
- pto->PushMessage("addr", vAddr);
+ pto->PushMessage(NetMsgType::ADDR, vAddr);
}
CNodeState &state = *State(pto->GetId());
@@ -5422,7 +5390,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
BOOST_FOREACH(const CBlockReject& reject, state.rejects)
- pto->PushMessage("reject", (string)"block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
+ pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
state.rejects.clear();
// Start block sync
@@ -5445,7 +5413,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
- pto->PushMessage("getheaders", chainActive.GetLocator(pindexStart), uint256());
+ pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256());
}
}
@@ -5545,7 +5513,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
vHeaders.front().GetHash().ToString(), pto->id);
}
- pto->PushMessage("headers", vHeaders);
+ pto->PushMessage(NetMsgType::HEADERS, vHeaders);
state.pindexBestHeaderSent = pBestIndex;
}
pto->vBlockHashesToAnnounce.clear();
@@ -5557,12 +5525,17 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
vector<CInv> vInv;
vector<CInv> vInvWait;
{
+ bool fSendTrickle = pto->fWhitelisted;
+ if (pto->nNextInvSend < nNow) {
+ fSendTrickle = true;
+ pto->nNextInvSend = PoissonNextSend(nNow, AVG_INVENTORY_BROADCAST_INTERVAL);
+ }
LOCK(pto->cs_inventory);
- vInv.reserve(pto->vInventoryToSend.size());
+ vInv.reserve(std::min<size_t>(1000, pto->vInventoryToSend.size()));
vInvWait.reserve(pto->vInventoryToSend.size());
BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
{
- if (pto->setInventoryKnown.count(inv))
+ if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash))
continue;
// trickle out tx inv to protect privacy
@@ -5583,24 +5556,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
}
- // returns true if wasn't already contained in the set
- if (pto->setInventoryKnown.insert(inv).second)
+ pto->filterInventoryKnown.insert(inv.hash);
+
+ vInv.push_back(inv);
+ if (vInv.size() >= 1000)
{
- vInv.push_back(inv);
- if (vInv.size() >= 1000)
- {
- pto->PushMessage("inv", vInv);
- vInv.clear();
- }
+ pto->PushMessage(NetMsgType::INV, vInv);
+ vInv.clear();
}
}
pto->vInventoryToSend = vInvWait;
}
if (!vInv.empty())
- pto->PushMessage("inv", vInv);
+ pto->PushMessage(NetMsgType::INV, vInv);
// Detect whether we're stalling
- int64_t nNow = GetTimeMicros();
+ nNow = GetTimeMicros();
if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
@@ -5666,7 +5637,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
- pto->PushMessage("getdata", vGetData);
+ pto->PushMessage(NetMsgType::GETDATA, vGetData);
vGetData.clear();
}
} else {
@@ -5676,7 +5647,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
- pto->PushMessage("getdata", vGetData);
+ pto->PushMessage(NetMsgType::GETDATA, vGetData);
}
return true;
diff --git a/src/main.h b/src/main.h
index 19623f4d96..7ae4893e07 100644
--- a/src/main.h
+++ b/src/main.h
@@ -87,6 +87,14 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
+/** Average delay between local address broadcasts in seconds. */
+static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60;
+/** Average delay between peer address broadcasts in seconds. */
+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;
+
static const unsigned int DEFAULT_LIMITFREERELAY = 15;
static const bool DEFAULT_RELAYPRIORITY = true;
@@ -197,9 +205,8 @@ bool ProcessMessages(CNode* pfrom);
* Send queued protocol messages to be sent to a give node.
*
* @param[in] pto The node which we are sending messages to.
- * @param[in] fSendTrickle When true send the trickled data, otherwise trickle the data until true.
*/
-bool SendMessages(CNode* pto, bool fSendTrickle);
+bool SendMessages(CNode* pto);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Try to detect Partition (network isolation) attacks against us */
@@ -293,8 +300,6 @@ struct CDiskTxPos : public CDiskBlockPos
};
-CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
-
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent
diff --git a/src/mruset.h b/src/mruset.h
deleted file mode 100644
index 398aa173bf..0000000000
--- a/src/mruset.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_MRUSET_H
-#define BITCOIN_MRUSET_H
-
-#include <set>
-#include <vector>
-#include <utility>
-
-/** STL-like set container that only keeps the most recent N elements. */
-template <typename T>
-class mruset
-{
-public:
- typedef T key_type;
- typedef T value_type;
- typedef typename std::set<T>::iterator iterator;
- typedef typename std::set<T>::const_iterator const_iterator;
- typedef typename std::set<T>::size_type size_type;
-
-protected:
- std::set<T> set;
- std::vector<iterator> order;
- size_type first_used;
- size_type first_unused;
- const size_type nMaxSize;
-
-public:
- mruset(size_type nMaxSizeIn = 1) : nMaxSize(nMaxSizeIn) { clear(); }
- iterator begin() const { return set.begin(); }
- iterator end() const { return set.end(); }
- size_type size() const { return set.size(); }
- bool empty() const { return set.empty(); }
- iterator find(const key_type& k) const { return set.find(k); }
- size_type count(const key_type& k) const { return set.count(k); }
- void clear()
- {
- set.clear();
- order.assign(nMaxSize, set.end());
- first_used = 0;
- first_unused = 0;
- }
- bool inline friend operator==(const mruset<T>& a, const mruset<T>& b) { return a.set == b.set; }
- bool inline friend operator==(const mruset<T>& a, const std::set<T>& b) { return a.set == b; }
- bool inline friend operator<(const mruset<T>& a, const mruset<T>& b) { return a.set < b.set; }
- std::pair<iterator, bool> insert(const key_type& x)
- {
- std::pair<iterator, bool> ret = set.insert(x);
- if (ret.second) {
- if (set.size() == nMaxSize + 1) {
- set.erase(order[first_used]);
- order[first_used] = set.end();
- if (++first_used == nMaxSize) first_used = 0;
- }
- order[first_unused] = ret.first;
- if (++first_unused == nMaxSize) first_unused = 0;
- }
- return ret;
- }
- size_type max_size() const { return nMaxSize; }
-};
-
-#endif // BITCOIN_MRUSET_H
diff --git a/src/net.cpp b/src/net.cpp
index e5659efc01..e0d96a2dc8 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -36,6 +36,8 @@
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
+#include <math.h>
+
// Dump addresses to peers.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900
@@ -67,6 +69,8 @@ namespace {
};
}
+const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
+
//
// Global state variables
//
@@ -459,7 +463,7 @@ void CNode::PushVersion()
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
else
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
- PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
+ PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY));
}
@@ -627,7 +631,9 @@ void CNode::copyStats(CNodeStats &stats)
X(fInbound);
X(nStartingHeight);
X(nSendBytes);
+ X(mapSendBytesPerMsgCmd);
X(nRecvBytes);
+ X(mapRecvBytesPerMsgCmd);
X(fWhitelisted);
// It is common for nodes with good ping times to suddenly become lagged,
@@ -682,6 +688,15 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
nBytes -= handled;
if (msg.complete()) {
+
+ //store received bytes per message command
+ //to prevent a memory DOS, only allow valid commands
+ mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand);
+ if (i == mapRecvBytesPerMsgCmd.end())
+ i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);
+ assert(i != mapRecvBytesPerMsgCmd.end());
+ i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
+
msg.nTime = GetTimeMicros();
messageHandlerCondition.notify_one();
}
@@ -1720,11 +1735,6 @@ void ThreadMessageHandler()
}
}
- // Poll the connected nodes for messages
- CNode* pnodeTrickle = NULL;
- if (!vNodesCopy.empty())
- pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
-
bool fSleep = true;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
@@ -1755,7 +1765,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
- g_signals.SendMessages(pnode, pnode == pnodeTrickle || pnode->fWhitelisted);
+ g_signals.SendMessages(pnode);
}
boost::this_thread::interruption_point();
}
@@ -2342,7 +2352,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX
CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
addrKnown(5000, 0.001),
- setInventoryKnown(SendBufferSize() / 1000)
+ filterInventoryKnown(50000, 0.000001)
{
nServices = 0;
hSocket = hSocketIn;
@@ -2369,7 +2379,11 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nSendOffset = 0;
hashContinue = uint256();
nStartingHeight = -1;
+ filterInventoryKnown.reset();
fGetAddr = false;
+ nNextLocalAddrSend = 0;
+ nNextAddrSend = 0;
+ nNextInvSend = 0;
fRelayTxes = false;
pfilter = new CBloomFilter();
nPingNonceSent = 0;
@@ -2377,6 +2391,9 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nPingUsecTime = 0;
fPingQueued = false;
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
+ BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
+ mapRecvBytesPerMsgCmd[msg] = 0;
+ mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
{
LOCK(cs_nLastNodeId);
@@ -2456,7 +2473,7 @@ void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
LogPrint("net", "(aborted)\n");
}
-void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
+void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend)
{
// The -*messagestest options are intentionally not documented in the help message,
// since they are only used during development to debug the networking code and are
@@ -2479,6 +2496,9 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
+ //log total amount of bytes per command
+ mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE;
+
// Set the checksum
uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
unsigned int nChecksum = 0;
@@ -2614,3 +2634,7 @@ void DumpBanlist()
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
banmap.size(), GetTimeMillis() - nStart);
}
+
+int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
+ return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
+}
diff --git a/src/net.h b/src/net.h
index a5a5c770d6..bc64571aeb 100644
--- a/src/net.h
+++ b/src/net.h
@@ -9,7 +9,6 @@
#include "bloom.h"
#include "compat.h"
#include "limitedmap.h"
-#include "mruset.h"
#include "netbase.h"
#include "protocol.h"
#include "random.h"
@@ -114,7 +113,7 @@ struct CNodeSignals
{
boost::signals2::signal<int ()> GetHeight;
boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
- boost::signals2::signal<bool (CNode*, bool), CombinerAll> SendMessages;
+ boost::signals2::signal<bool (CNode*), CombinerAll> SendMessages;
boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
boost::signals2::signal<void (NodeId)> FinalizeNode;
};
@@ -183,6 +182,7 @@ struct LocalServiceInfo {
extern CCriticalSection cs_mapLocalHost;
extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
+typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes
class CNodeStats
{
@@ -200,7 +200,9 @@ public:
bool fInbound;
int nStartingHeight;
uint64_t nSendBytes;
+ mapMsgCmdSize mapSendBytesPerMsgCmd;
uint64_t nRecvBytes;
+ mapMsgCmdSize mapRecvBytesPerMsgCmd;
bool fWhitelisted;
double dPingTime;
double dPingWait;
@@ -374,6 +376,9 @@ protected:
static std::vector<CSubNet> vWhitelistedRange;
static CCriticalSection cs_vWhitelistedRange;
+ mapMsgCmdSize mapSendBytesPerMsgCmd;
+ mapMsgCmdSize mapRecvBytesPerMsgCmd;
+
// Basic fuzz-testing
void Fuzz(int nChance); // modifies ssSend
@@ -386,13 +391,16 @@ public:
CRollingBloomFilter addrKnown;
bool fGetAddr;
std::set<uint256> setKnown;
+ int64_t nNextAddrSend;
+ int64_t nNextLocalAddrSend;
// inventory based relay
- mruset<CInv> setInventoryKnown;
+ CRollingBloomFilter filterInventoryKnown;
std::vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
std::set<uint256> setAskFor;
std::multimap<int64_t, CInv> mapAskFor;
+ int64_t nNextInvSend;
// Used for headers announcements - unfiltered blocks to relay
// Also protected by cs_inventory
std::vector<uint256> vBlockHashesToAnnounce;
@@ -497,7 +505,7 @@ public:
{
{
LOCK(cs_inventory);
- setInventoryKnown.insert(inv);
+ filterInventoryKnown.insert(inv.hash);
}
}
@@ -505,8 +513,9 @@ public:
{
{
LOCK(cs_inventory);
- if (!setInventoryKnown.count(inv))
- vInventoryToSend.push_back(inv);
+ if (inv.type == MSG_TX && filterInventoryKnown.contains(inv.hash))
+ return;
+ vInventoryToSend.push_back(inv);
}
}
@@ -525,7 +534,7 @@ public:
void AbortMessage() UNLOCK_FUNCTION(cs_vSend);
// TODO: Document the precondition of this function. Is cs_vSend locked?
- void EndMessage() UNLOCK_FUNCTION(cs_vSend);
+ void EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend);
void PushVersion();
@@ -535,7 +544,7 @@ public:
try
{
BeginMessage(pszCommand);
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -551,7 +560,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -567,7 +576,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -583,7 +592,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -599,7 +608,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -615,7 +624,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -631,7 +640,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -647,7 +656,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -663,7 +672,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -679,7 +688,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -785,4 +794,7 @@ public:
void DumpBanlist();
+/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
+int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
+
#endif // BITCOIN_NET_H
diff --git a/src/protocol.cpp b/src/protocol.cpp
index dd855aa33a..5d3ae87de8 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -12,13 +12,67 @@
# include <arpa/inet.h>
#endif
+namespace NetMsgType {
+const char *VERSION="version";
+const char *VERACK="verack";
+const char *ADDR="addr";
+const char *INV="inv";
+const char *GETDATA="getdata";
+const char *MERKLEBLOCK="merkleblock";
+const char *GETBLOCKS="getblocks";
+const char *GETHEADERS="getheaders";
+const char *TX="tx";
+const char *HEADERS="headers";
+const char *BLOCK="block";
+const char *GETADDR="getaddr";
+const char *MEMPOOL="mempool";
+const char *PING="ping";
+const char *PONG="pong";
+const char *ALERT="alert";
+const char *NOTFOUND="notfound";
+const char *FILTERLOAD="filterload";
+const char *FILTERADD="filteradd";
+const char *FILTERCLEAR="filterclear";
+const char *REJECT="reject";
+const char *SENDHEADERS="sendheaders";
+};
+
static const char* ppszTypeName[] =
{
- "ERROR",
- "tx",
- "block",
- "filtered block"
+ "ERROR", // Should never occur
+ NetMsgType::TX,
+ NetMsgType::BLOCK,
+ "filtered block" // Should never occur
+};
+
+/** All known message types. Keep this in the same order as the list of
+ * messages above and in protocol.h.
+ */
+const static std::string allNetMessageTypes[] = {
+ NetMsgType::VERSION,
+ NetMsgType::VERACK,
+ NetMsgType::ADDR,
+ NetMsgType::INV,
+ NetMsgType::GETDATA,
+ NetMsgType::MERKLEBLOCK,
+ NetMsgType::GETBLOCKS,
+ NetMsgType::GETHEADERS,
+ NetMsgType::TX,
+ NetMsgType::HEADERS,
+ NetMsgType::BLOCK,
+ NetMsgType::GETADDR,
+ NetMsgType::MEMPOOL,
+ NetMsgType::PING,
+ NetMsgType::PONG,
+ NetMsgType::ALERT,
+ NetMsgType::NOTFOUND,
+ NetMsgType::FILTERLOAD,
+ NetMsgType::FILTERADD,
+ NetMsgType::FILTERCLEAR,
+ NetMsgType::REJECT,
+ NetMsgType::SENDHEADERS
};
+const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
{
@@ -140,3 +194,8 @@ std::string CInv::ToString() const
{
return strprintf("%s %s", GetCommand(), hash.ToString());
}
+
+const std::vector<std::string> &getAllNetMessageTypes()
+{
+ return allNetMessageTypesVec;
+}
diff --git a/src/protocol.h b/src/protocol.h
index 50aeaf44ba..b84c78baca 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -65,6 +65,165 @@ public:
unsigned int nChecksum;
};
+/**
+ * Bitcoin protocol message types. When adding new message types, don't forget
+ * to update allNetMessageTypes in protocol.cpp.
+ */
+namespace NetMsgType {
+
+/**
+ * The version message provides information about the transmitting node to the
+ * receiving node at the beginning of a connection.
+ * @see https://bitcoin.org/en/developer-reference#version
+ */
+extern const char *VERSION;
+/**
+ * The verack message acknowledges a previously-received version message,
+ * informing the connecting node that it can begin to send other messages.
+ * @see https://bitcoin.org/en/developer-reference#verack
+ */
+extern const char *VERACK;
+/**
+ * The addr (IP address) message relays connection information for peers on the
+ * network.
+ * @see https://bitcoin.org/en/developer-reference#addr
+ */
+extern const char *ADDR;
+/**
+ * The inv message (inventory message) transmits one or more inventories of
+ * objects known to the transmitting peer.
+ * @see https://bitcoin.org/en/developer-reference#inv
+ */
+extern const char *INV;
+/**
+ * The getdata message requests one or more data objects from another node.
+ * @see https://bitcoin.org/en/developer-reference#getdata
+ */
+extern const char *GETDATA;
+/**
+ * The merkleblock message is a reply to a getdata message which requested a
+ * block using the inventory type MSG_MERKLEBLOCK.
+ * @since protocol version 70001 as described by BIP37.
+ * @see https://bitcoin.org/en/developer-reference#merkleblock
+ */
+extern const char *MERKLEBLOCK;
+/**
+ * The getblocks message requests an inv message that provides block header
+ * hashes starting from a particular point in the block chain.
+ * @see https://bitcoin.org/en/developer-reference#getblocks
+ */
+extern const char *GETBLOCKS;
+/**
+ * The getheaders message requests a headers message that provides block
+ * headers starting from a particular point in the block chain.
+ * @since protocol version 31800.
+ * @see https://bitcoin.org/en/developer-reference#getheaders
+ */
+extern const char *GETHEADERS;
+/**
+ * The tx message transmits a single transaction.
+ * @see https://bitcoin.org/en/developer-reference#tx
+ */
+extern const char *TX;
+/**
+ * The headers message sends one or more block headers to a node which
+ * previously requested certain headers with a getheaders message.
+ * @since protocol version 31800.
+ * @see https://bitcoin.org/en/developer-reference#headers
+ */
+extern const char *HEADERS;
+/**
+ * The block message transmits a single serialized block.
+ * @see https://bitcoin.org/en/developer-reference#block
+ */
+extern const char *BLOCK;
+/**
+ * The getaddr message requests an addr message from the receiving node,
+ * preferably one with lots of IP addresses of other receiving nodes.
+ * @see https://bitcoin.org/en/developer-reference#getaddr
+ */
+extern const char *GETADDR;
+/**
+ * The mempool message requests the TXIDs of transactions that the receiving
+ * node has verified as valid but which have not yet appeared in a block.
+ * @since protocol version 60002.
+ * @see https://bitcoin.org/en/developer-reference#mempool
+ */
+extern const char *MEMPOOL;
+/**
+ * The ping message is sent periodically to help confirm that the receiving
+ * peer is still connected.
+ * @see https://bitcoin.org/en/developer-reference#ping
+ */
+extern const char *PING;
+/**
+ * The pong message replies to a ping message, proving to the pinging node that
+ * the ponging node is still alive.
+ * @since protocol version 60001 as described by BIP31.
+ * @see https://bitcoin.org/en/developer-reference#pong
+ */
+extern const char *PONG;
+/**
+ * The alert message warns nodes of problems that may affect them or the rest
+ * of the network.
+ * @since protocol version 311.
+ * @see https://bitcoin.org/en/developer-reference#alert
+ */
+extern const char *ALERT;
+/**
+ * The notfound message is a reply to a getdata message which requested an
+ * object the receiving node does not have available for relay.
+ * @ince protocol version 70001.
+ * @see https://bitcoin.org/en/developer-reference#notfound
+ */
+extern const char *NOTFOUND;
+/**
+ * The filterload message tells the receiving peer to filter all relayed
+ * transactions and requested merkle blocks through the provided filter.
+ * @since protocol version 70001 as described by BIP37.
+ * Only available with service bit NODE_BLOOM since protocol version
+ * 70011 as described by BIP111.
+ * @see https://bitcoin.org/en/developer-reference#filterload
+ */
+extern const char *FILTERLOAD;
+/**
+ * The filteradd message tells the receiving peer to add a single element to a
+ * previously-set bloom filter, such as a new public key.
+ * @since protocol version 70001 as described by BIP37.
+ * Only available with service bit NODE_BLOOM since protocol version
+ * 70011 as described by BIP111.
+ * @see https://bitcoin.org/en/developer-reference#filteradd
+ */
+extern const char *FILTERADD;
+/**
+ * The filterclear message tells the receiving peer to remove a previously-set
+ * bloom filter.
+ * @since protocol version 70001 as described by BIP37.
+ * Only available with service bit NODE_BLOOM since protocol version
+ * 70011 as described by BIP111.
+ * @see https://bitcoin.org/en/developer-reference#filterclear
+ */
+extern const char *FILTERCLEAR;
+/**
+ * The reject message informs the receiving node that one of its previous
+ * messages has been rejected.
+ * @since protocol version 70002 as described by BIP61.
+ * @see https://bitcoin.org/en/developer-reference#reject
+ */
+extern const char *REJECT;
+/**
+ * Indicates that a node prefers to receive new block announcements via a
+ * "headers" message rather than an "inv".
+ * @since protocol version 70012 as described by BIP130.
+ * @see https://bitcoin.org/en/developer-reference#sendheaders
+ */
+extern const char *SENDHEADERS;
+
+};
+
+/* Get a vector of all valid message types (see above) */
+const std::vector<std::string> &getAllNetMessageTypes();
+
/** nServices flags */
enum {
// NODE_NETWORK means that the node is capable of serving the block chain. It is currently
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 425b45d918..9c86cb71d4 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -111,13 +111,6 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator
}
-// TODO: Review all remaining calls to BitcoinUnits::formatWithUnit to
-// TODO: determine whether the output is used in a plain text context
-// TODO: or an HTML context (and replace with
-// TODO: BtcoinUnits::formatHtmlWithUnit in the latter case). Hopefully
-// TODO: there aren't instances where the result could be used in
-// TODO: either context.
-
// NOTE: Using formatWithUnit in an HTML context risks wrapping
// quantities at the thousands separator. More subtly, it also results
// in a standard space rather than a thin space, due to a bug in Qt's
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 1871c33a78..f9f67c9f11 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -88,6 +88,7 @@ public:
static QString format(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
//! Format as string (with unit)
static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
+ //! Format as HTML string (with unit)
static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
//! Parse string to coin amount
static bool parse(int unit, const QString &value, CAmount *val_out);
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 0f42243047..e2e8601402 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -130,7 +130,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->treeWidget->setColumnWidth(COLUMN_DATE, 110);
ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
- ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but don't show it
+ ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it
@@ -411,7 +411,7 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
// todo: this is a temporary qt5 fix: when clicking a parent node in tree mode, the parent node
// including all children are partially selected. But the parent node should be fully selected
// as well as the children. Children should never be partially selected in the first place.
- // Please remove this ugly fix, once the bug is solved upstream.
+ // Should be fixed in Qt5.4 and above. https://bugreports.qt.io/browse/QTBUG-43473
#if QT_VERSION >= 0x050000
else if (column == COLUMN_CHECKBOX && item->childCount() > 0)
{
@@ -637,14 +637,14 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// tool tips
QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
+ toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
toolTip1 += tr("Can vary +/- 1 byte per input.");
QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
+ toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
- QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546)));
+ QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
double dFeeVary;
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 6dce9370d7..34675b53dc 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -62,6 +62,10 @@
#include <QUrlQuery>
#endif
+#if QT_VERSION >= 0x50200
+#include <QFontDatabase>
+#endif
+
#if BOOST_FILESYSTEM_VERSION >= 3
static boost::filesystem::detail::utf8_codecvt_facet utf8;
#endif
@@ -90,6 +94,9 @@ QString dateTimeStr(qint64 nTime)
QFont fixedPitchFont()
{
+#if QT_VERSION >= 0x50200
+ return QFontDatabase::systemFont(QFontDatabase::FixedFont);
+#else
QFont font("Monospace");
#if QT_VERSION >= 0x040800
font.setStyleHint(QFont::Monospace);
@@ -97,6 +104,7 @@ QFont fixedPitchFont()
font.setStyleHint(QFont::TypeWriter);
#endif
return font;
+#endif
}
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
@@ -898,6 +906,9 @@ QString formatServicesStr(quint64 mask)
case NODE_GETUTXO:
strList.append("GETUTXO");
break;
+ case NODE_BLOOM:
+ strList.append("BLOOM");
+ break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index e709f8515b..00411741f1 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -1153,7 +1153,7 @@
</message>
<message>
<location line="+1"/>
- <source>Reset all settings changes made over the GUI</source>
+ <source>Reset all settings changed in the GUI</source>
<translation type="unfinished"></translation>
</message>
</context>
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 0c4a20cf92..75108e0a10 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -144,7 +144,7 @@ void ReceiveRequestDialog::update()
html += "<a href=\""+uri+"\">" + GUIUtil::HtmlEscape(uri) + "</a><br>";
html += "<b>"+tr("Address")+"</b>: " + GUIUtil::HtmlEscape(info.address) + "<br>";
if(info.amount)
- html += "<b>"+tr("Amount")+"</b>: " + BitcoinUnits::formatWithUnit(model->getDisplayUnit(), info.amount) + "<br>";
+ html += "<b>"+tr("Amount")+"</b>: " + BitcoinUnits::formatHtmlWithUnit(model->getDisplayUnit(), info.amount) + "<br>";
if(!info.label.isEmpty())
html += "<b>"+tr("Label")+"</b>: " + GUIUtil::HtmlEscape(info.label) + "<br>";
if(!info.message.isEmpty())
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 801c6c62d2..920ff06351 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -35,9 +35,11 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < 0)
- return tr("conflicted");
+ return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return tr("%1/offline").arg(nDepth);
+ else if (nDepth == 0)
+ return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool")));
else if (nDepth < 6)
return tr("%1/unconfirmed").arg(nDepth);
else
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 81b597e2eb..088578b7a9 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -84,7 +84,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
strUsage += HelpMessageOpt("-min", tr("Start minimized").toStdString());
strUsage += HelpMessageOpt("-rootcertificates=<file>", tr("Set SSL root certificates for payment request (default: -system-)").toStdString());
strUsage += HelpMessageOpt("-splash", strprintf(tr("Show splash screen on startup (default: %u)").toStdString(), DEFAULT_SPLASHSCREEN));
- strUsage += HelpMessageOpt("-resetguisettings", tr("Reset all settings changes made over the GUI").toStdString());
+ strUsage += HelpMessageOpt("-resetguisettings", tr("Reset all settings changed in the GUI").toStdString());
if (showDebug) {
strUsage += HelpMessageOpt("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM));
}
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index ee04636ce8..73e6f8029b 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -197,7 +197,7 @@ UniValue mempoolToJSON(bool fVerbose = false)
info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
info.push_back(Pair("descendantcount", e.GetCountWithDescendants()));
info.push_back(Pair("descendantsize", e.GetSizeWithDescendants()));
- info.push_back(Pair("descendantfees", e.GetFeesWithDescendants()));
+ info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants()));
const CTransaction& tx = e.GetTx();
set<string> setDepends;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
@@ -255,7 +255,7 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
" \"currentpriority\" : n, (numeric) transaction priority now\n"
" \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
" \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n"
- " \"descendantfees\" : n, (numeric) fees of in-mempool descendants (including this one)\n"
+ " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n"
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 2578848891..0ce108b06e 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -111,6 +111,14 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
" ]\n"
+ " \"bytessent_per_msg\": {\n"
+ " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " ...\n"
+ " }\n"
+ " \"bytesrecv_per_msg\": {\n"
+ " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
+ " ...\n"
+ " }\n"
" }\n"
" ,...\n"
"]\n"
@@ -165,6 +173,20 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
}
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
+ UniValue sendPerMsgCmd(UniValue::VOBJ);
+ BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapSendBytesPerMsgCmd) {
+ if (i.second > 0)
+ sendPerMsgCmd.push_back(Pair(i.first, i.second));
+ }
+ obj.push_back(Pair("bytessent_per_msg", sendPerMsgCmd));
+
+ UniValue recvPerMsgCmd(UniValue::VOBJ);
+ BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapRecvBytesPerMsgCmd) {
+ if (i.second > 0)
+ recvPerMsgCmd.push_back(Pair(i.first, i.second));
+ }
+ obj.push_back(Pair("bytesrecv_per_msg", recvPerMsgCmd));
+
ret.push_back(obj);
}
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 1f2d77aef0..4947ad1f70 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -353,7 +353,6 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
if (params[0].isNull() || params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 9c77ed9fc1..a7ba57e65b 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -131,7 +131,7 @@ const char* GetOpName(opcodetype opcode)
// expanson
case OP_NOP1 : return "OP_NOP1";
- case OP_NOP2 : return "OP_NOP2";
+ case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
case OP_NOP3 : return "OP_NOP3";
case OP_NOP4 : return "OP_NOP4";
case OP_NOP5 : return "OP_NOP5";
diff --git a/src/script/script.h b/src/script/script.h
index 3650957fc9..7a37b66ccf 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -162,8 +162,8 @@ enum opcodetype
// expansion
OP_NOP1 = 0xb0,
- OP_NOP2 = 0xb1,
- OP_CHECKLOCKTIMEVERIFY = OP_NOP2,
+ OP_CHECKLOCKTIMEVERIFY = 0xb1,
+ OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
OP_NOP3 = 0xb2,
OP_NOP4 = 0xb3,
OP_NOP5 = 0xb4,
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index da296a0461..51d296502e 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(CNode::IsBanned(addr1));
BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
@@ -57,11 +57,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
dummyNode2.nVersion = 1;
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, false);
+ SendMessages(&dummyNode2);
BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, false);
+ SendMessages(&dummyNode2);
BOOST_CHECK(CNode::IsBanned(addr2));
}
@@ -73,13 +73,13 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100);
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(!CNode::IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 10);
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(!CNode::IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 1);
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(CNode::IsBanned(addr1));
mapArgs.erase("-banscore");
}
@@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
dummyNode.nVersion = 1;
Misbehaving(dummyNode.GetId(), 100);
- SendMessages(&dummyNode, false);
+ SendMessages(&dummyNode);
BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60);
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 7afa2abf49..7ce7e0879c 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -160,12 +160,12 @@
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"],
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"],
-["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"],
-["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"],
+["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"],
+["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"],
["Ensure 100% coverage of discouraged NOPS"],
["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP2", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index a4e15faeaf..e5f0d17b04 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -232,8 +232,8 @@
["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC"],
-["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"],
-["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"],
+["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"],
+["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"],
["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "Discourage NOPx flag allows OP_NOP"],
@@ -442,7 +442,7 @@
["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC"],
["NOP", "NOP1 1", "P2SH,STRICTENC"],
-["NOP", "NOP2 1", "P2SH,STRICTENC"],
+["NOP", "CHECKLOCKTIMEVERIFY 1", "P2SH,STRICTENC"],
["NOP", "NOP3 1", "P2SH,STRICTENC"],
["NOP", "NOP4 1", "P2SH,STRICTENC"],
["NOP", "NOP5 1", "P2SH,STRICTENC"],
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index cc059e814f..9025841949 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -127,66 +127,66 @@
["CHECKLOCKTIMEVERIFY tests"],
["By-height locks, with argument just beyond tx nLockTime"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument missing"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument negative with by-blockheight nLockTime=0"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument negative with by-blocktime nLockTime=500,000,000"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Input locked"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] ,
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"] ,
["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]],
"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument/tx height/time mismatch, both versions"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument 2^32 with nLockTime=2^32-1"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["Same, but with nLockTime=2^31-1"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"],
["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"],
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 0dfef73ae5..76d29bcf26 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -190,35 +190,35 @@
["CHECKLOCKTIMEVERIFY tests"],
["By-height locks, with argument == 0 and == tx nLockTime"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["Any non-maxint nSequence is fine"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["The argument can be calculated rather than created directly by a PUSHDATA"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["5 byte non-minimally-encoded arguments are valid"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Valid CHECKLOCKTIMEVERIFY in scriptSig"],
diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp
deleted file mode 100644
index 2b68f8899e..0000000000
--- a/src/test/mruset_tests.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2012-2013 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "mruset.h"
-
-#include "random.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
-
-#include <set>
-
-#include <boost/test/unit_test.hpp>
-
-#define NUM_TESTS 16
-#define MAX_SIZE 100
-
-using namespace std;
-
-BOOST_FIXTURE_TEST_SUITE(mruset_tests, BasicTestingSetup)
-
-BOOST_AUTO_TEST_CASE(mruset_test)
-{
- // The mruset being tested.
- mruset<int> mru(5000);
-
- // Run the test 10 times.
- for (int test = 0; test < 10; test++) {
- // Reset mru.
- mru.clear();
-
- // A deque + set to simulate the mruset.
- std::deque<int> rep;
- std::set<int> all;
-
- // Insert 10000 random integers below 15000.
- for (int j=0; j<10000; j++) {
- int add = GetRandInt(15000);
- mru.insert(add);
-
- // Add the number to rep/all as well.
- if (all.count(add) == 0) {
- all.insert(add);
- rep.push_back(add);
- if (all.size() == 5001) {
- all.erase(rep.front());
- rep.pop_front();
- }
- }
-
- // Do a full comparison between mru and the simulated mru every 1000 and every 5001 elements.
- if (j % 1000 == 0 || j % 5001 == 0) {
- mruset<int> mru2 = mru; // Also try making a copy
-
- // Check that all elements that should be in there, are in there.
- BOOST_FOREACH(int x, rep) {
- BOOST_CHECK(mru.count(x));
- BOOST_CHECK(mru2.count(x));
- }
-
- // Check that all elements that are in there, should be in there.
- BOOST_FOREACH(int x, mru) {
- BOOST_CHECK(all.count(x));
- }
-
- // Check that all elements that are in there, should be in there.
- BOOST_FOREACH(int x, mru2) {
- BOOST_CHECK(all.count(x));
- }
-
- for (int t = 0; t < 10; t++) {
- int r = GetRandInt(15000);
- BOOST_CHECK(all.count(r) == mru.count(r));
- BOOST_CHECK(all.count(r) == mru2.count(r));
- }
- }
- }
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 0059e4a998..9eff6d0c63 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -985,10 +985,10 @@ BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts)
BOOST_AUTO_TEST_CASE(script_GetScriptAsm)
{
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_NOP2, true));
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true));
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_NOP2));
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));
string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090");
string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2");
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 8eccc81e30..4ebcb9b667 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -618,7 +618,7 @@ void TorController::disconnected_cb(TorControlConnection& conn)
if (!reconnect)
return;
- LogPrint("tor", "tor: Disconnected from Tor control port %s, trying to reconnect\n", target);
+ LogPrint("tor", "tor: Not connected to Tor control port %s, trying to reconnect\n", target);
// Single-shot timer for reconnect. Use exponential backoff.
struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index fea5da8029..c72a1e8c19 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -33,7 +33,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
nCountWithDescendants = 1;
nSizeWithDescendants = nTxSize;
- nFeesWithDescendants = nFee;
+ nModFeesWithDescendants = nFee;
CAmount nValueIn = tx.GetValueOut()+nFee;
assert(inChainInputValue <= nValueIn);
@@ -57,6 +57,7 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{
+ nModFeesWithDescendants += newFeeDelta - feeDelta;
feeDelta = newFeeDelta;
}
@@ -114,7 +115,7 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit
BOOST_FOREACH(txiter cit, setAllDescendants) {
if (!setExclude.count(cit->GetTx().GetHash())) {
modifySize += cit->GetTxSize();
- modifyFee += cit->GetFee();
+ modifyFee += cit->GetModifiedFee();
modifyCount++;
cachedDescendants[updateIt].insert(cit);
}
@@ -244,7 +245,7 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
}
const int64_t updateCount = (add ? 1 : -1);
const int64_t updateSize = updateCount * it->GetTxSize();
- const CAmount updateFee = updateCount * it->GetFee();
+ const CAmount updateFee = updateCount * it->GetModifiedFee();
BOOST_FOREACH(txiter ancestorIt, setAncestors) {
mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));
}
@@ -304,7 +305,7 @@ void CTxMemPoolEntry::SetDirty()
{
nCountWithDescendants = 0;
nSizeWithDescendants = nTxSize;
- nFeesWithDescendants = nFee;
+ nModFeesWithDescendants = GetModifiedFee();
}
void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
@@ -312,8 +313,7 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
if (!IsDirty()) {
nSizeWithDescendants += modifySize;
assert(int64_t(nSizeWithDescendants) > 0);
- nFeesWithDescendants += modifyFee;
- assert(nFeesWithDescendants >= 0);
+ nModFeesWithDescendants += modifyFee;
nCountWithDescendants += modifyCount;
assert(int64_t(nCountWithDescendants) > 0);
}
@@ -372,6 +372,17 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
mapLinks.insert(make_pair(newit, TxLinks()));
+ // Update transaction for any feeDelta created by PrioritiseTransaction
+ // TODO: refactor so that the fee delta is calculated before inserting
+ // into mapTx.
+ std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
+ if (pos != mapDeltas.end()) {
+ const std::pair<double, CAmount> &deltas = pos->second;
+ if (deltas.second) {
+ mapTx.modify(newit, update_fee_delta(deltas.second));
+ }
+ }
+
// Update cachedInnerUsage to include contained transaction's usage.
// (When we update the entry for in-mempool parents, memory usage will be
// further updated.)
@@ -399,15 +410,6 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
}
UpdateAncestorsOf(true, newit, setAncestors);
- // Update transaction's score for any feeDelta created by PrioritiseTransaction
- std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
- if (pos != mapDeltas.end()) {
- const std::pair<double, CAmount> &deltas = pos->second;
- if (deltas.second) {
- mapTx.modify(newit, update_fee_delta(deltas.second));
- }
- }
-
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
@@ -644,27 +646,24 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
CTxMemPool::setEntries setChildrenCheck;
std::map<COutPoint, CInPoint>::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
int64_t childSizes = 0;
- CAmount childFees = 0;
+ CAmount childModFee = 0;
for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) {
txiter childit = mapTx.find(iter->second.ptx->GetHash());
assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
if (setChildrenCheck.insert(childit).second) {
childSizes += childit->GetTxSize();
- childFees += childit->GetFee();
+ childModFee += childit->GetModifiedFee();
}
}
assert(setChildrenCheck == GetMemPoolChildren(it));
- // Also check to make sure size/fees is greater than sum with immediate children.
+ // Also check to make sure size is greater than sum with immediate children.
// just a sanity check, not definitive that this calc is correct...
- // also check that the size is less than the size of the entire mempool.
if (!it->IsDirty()) {
assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
- assert(it->GetFeesWithDescendants() >= childFees + it->GetFee());
} else {
assert(it->GetSizeWithDescendants() == it->GetTxSize());
- assert(it->GetFeesWithDescendants() == it->GetFee());
+ assert(it->GetModFeesWithDescendants() == it->GetModifiedFee());
}
- assert(it->GetFeesWithDescendants() >= 0);
if (fDependsWait)
waitingOnDependants.push_back(&(*it));
@@ -788,6 +787,14 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash,
txiter it = mapTx.find(hash);
if (it != mapTx.end()) {
mapTx.modify(it, update_fee_delta(deltas.second));
+ // Now update all ancestors' modified fees with descendants
+ setEntries setAncestors;
+ uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
+ std::string dummy;
+ CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+ BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0));
+ }
}
}
LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta));
@@ -956,7 +963,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
// "minimum reasonable fee rate" (ie some value under which we consider txn
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
// equal to txn which were removed with no block in between.
- CFeeRate removed(it->GetFeesWithDescendants(), it->GetSizeWithDescendants());
+ CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
removed += minReasonableRelayFee;
trackPackageRemoved(removed);
maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
diff --git a/src/txmempool.h b/src/txmempool.h
index 9203171868..4b726cc902 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -44,12 +44,12 @@ class CTxMemPool;
* ("descendant" transactions).
*
* When a new entry is added to the mempool, we update the descendant state
- * (nCountWithDescendants, nSizeWithDescendants, and nFeesWithDescendants) for
+ * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for
* all ancestors of the newly added transaction.
*
* If updating the descendant state is skipped, we can mark the entry as
- * "dirty", and set nSizeWithDescendants/nFeesWithDescendants to equal nTxSize/
- * nTxFee. (This can potentially happen during a reorg, where we limit the
+ * "dirty", and set nSizeWithDescendants/nModFeesWithDescendants to equal nTxSize/
+ * nFee+feeDelta. (This can potentially happen during a reorg, where we limit the
* amount of work we're willing to do to avoid consuming too much CPU.)
*
*/
@@ -74,11 +74,11 @@ private:
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
// descendants as well. if nCountWithDescendants is 0, treat this entry as
- // dirty, and nSizeWithDescendants and nFeesWithDescendants will not be
+ // dirty, and nSizeWithDescendants and nModFeesWithDescendants will not be
// correct.
uint64_t nCountWithDescendants; //! number of descendant transactions
uint64_t nSizeWithDescendants; //! ... and size
- CAmount nFeesWithDescendants; //! ... and total fees (all including us)
+ CAmount nModFeesWithDescendants; //! ... and total fees (all including us)
public:
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
@@ -104,7 +104,8 @@ public:
// Adjusts the descendant state, if this entry is not dirty.
void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
- // Updates the fee delta used for mining priority score
+ // Updates the fee delta used for mining priority score, and the
+ // modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
/** We can set the entry to be dirty if doing the full calculation of in-
@@ -116,7 +117,7 @@ public:
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
- CAmount GetFeesWithDescendants() const { return nFeesWithDescendants; }
+ CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
};
@@ -163,27 +164,27 @@ struct mempoolentry_txid
}
};
-/** \class CompareTxMemPoolEntryByFee
+/** \class CompareTxMemPoolEntryByDescendantScore
*
- * Sort an entry by max(feerate of entry's tx, feerate with all descendants).
+ * Sort an entry by max(score/size of entry's tx, score/size with all descendants).
*/
-class CompareTxMemPoolEntryByFee
+class CompareTxMemPoolEntryByDescendantScore
{
public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
{
- bool fUseADescendants = UseDescendantFeeRate(a);
- bool fUseBDescendants = UseDescendantFeeRate(b);
+ bool fUseADescendants = UseDescendantScore(a);
+ bool fUseBDescendants = UseDescendantScore(b);
- double aFees = fUseADescendants ? a.GetFeesWithDescendants() : a.GetFee();
+ double aModFee = fUseADescendants ? a.GetModFeesWithDescendants() : a.GetModifiedFee();
double aSize = fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize();
- double bFees = fUseBDescendants ? b.GetFeesWithDescendants() : b.GetFee();
+ double bModFee = fUseBDescendants ? b.GetModFeesWithDescendants() : b.GetModifiedFee();
double bSize = fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize();
// Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
- double f1 = aFees * bSize;
- double f2 = aSize * bFees;
+ double f1 = aModFee * bSize;
+ double f2 = aSize * bModFee;
if (f1 == f2) {
return a.GetTime() >= b.GetTime();
@@ -191,11 +192,11 @@ public:
return f1 < f2;
}
- // Calculate which feerate to use for an entry (avoiding division).
- bool UseDescendantFeeRate(const CTxMemPoolEntry &a)
+ // Calculate which score to use for an entry (avoiding division).
+ bool UseDescendantScore(const CTxMemPoolEntry &a)
{
- double f1 = (double)a.GetFee() * a.GetSizeWithDescendants();
- double f2 = (double)a.GetFeesWithDescendants() * a.GetTxSize();
+ double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants();
+ double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();
return f2 > f1;
}
};
@@ -350,7 +351,7 @@ public:
// sorted by fee rate
boost::multi_index::ordered_non_unique<
boost::multi_index::identity<CTxMemPoolEntry>,
- CompareTxMemPoolEntryByFee
+ CompareTxMemPoolEntryByDescendantScore
>,
// sorted by entry time
boost::multi_index::ordered_non_unique<
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 8b9292bd14..5e8ccd90ab 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -328,4 +328,22 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet();
}
+BOOST_AUTO_TEST_CASE(pruning_in_ApproximateBestSet)
+{
+ CoinSet setCoinsRet;
+ CAmount nValueRet;
+
+ LOCK(wallet.cs_wallet);
+
+ empty_wallet();
+ for (int i = 0; i < 12; i++)
+ {
+ add_coin(10*CENT);
+ }
+ add_coin(100*CENT);
+ add_coin(100*CENT);
+ BOOST_CHECK(wallet.SelectCoinsMinConf(221*CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 230*CENT);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d23d54e678..2cbb89e5a8 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1034,7 +1034,8 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
// In either case, we need to get the destination address
CTxDestination address;
- if (!ExtractDestination(txout.scriptPubKey, address))
+
+ if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
{
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
@@ -1359,6 +1360,15 @@ CAmount CWalletTx::GetChange() const
return nChangeCached;
}
+bool CWalletTx::InMempool() const
+{
+ LOCK(mempool.cs);
+ if (mempool.exists(GetHash())) {
+ return true;
+ }
+ return false;
+}
+
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
@@ -1373,12 +1383,8 @@ bool CWalletTx::IsTrusted() const
return false;
// Don't trust unconfirmed transactions from us unless they are in the mempool.
- {
- LOCK(mempool.cs);
- if (!mempool.exists(GetHash())) {
- return false;
- }
- }
+ if (!InMempool())
+ return false;
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH(const CTxIn& txin, vin)
@@ -1632,6 +1638,16 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
}
+
+ //Reduces the approximate best subset by removing any inputs that are smaller than the surplus of nTotal beyond nTargetValue.
+ for (unsigned int i = 0; i < vValue.size(); i++)
+ {
+ if (vfBest[i] && (nBest - vValue[i].first) >= nTargetValue )
+ {
+ vfBest[i] = false;
+ nBest -= vValue[i].first;
+ }
+ }
}
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 859788893c..7354ff19c7 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -384,6 +384,7 @@ public:
// True if only scriptSigs are different
bool IsEquivalentTo(const CWalletTx& tx) const;
+ bool InMempool() const;
bool IsTrusted() const;
bool WriteToDisk(CWalletDB *pwalletdb);