diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/addrman.h | 8 | ||||
-rw-r--r-- | src/base58.h | 6 | ||||
-rw-r--r-- | src/bloom.cpp | 83 | ||||
-rw-r--r-- | src/bloom.h | 36 | ||||
-rw-r--r-- | src/chain.h | 2 | ||||
-rw-r--r-- | src/chainparams.cpp | 9 | ||||
-rw-r--r-- | src/chainparams.h | 6 | ||||
-rw-r--r-- | src/chainparamsbase.h | 4 | ||||
-rw-r--r-- | src/checkpoints.cpp | 7 | ||||
-rw-r--r-- | src/checkpoints.h | 2 | ||||
-rw-r--r-- | src/checkqueue.h | 6 | ||||
-rw-r--r-- | src/init.cpp | 4 | ||||
-rw-r--r-- | src/main.cpp | 55 | ||||
-rw-r--r-- | src/main.h | 2 | ||||
-rw-r--r-- | src/merkleblock.cpp | 4 | ||||
-rw-r--r-- | src/merkleblock.h | 2 | ||||
-rw-r--r-- | src/mruset.h | 36 | ||||
-rw-r--r-- | src/net.cpp | 6 | ||||
-rw-r--r-- | src/net.h | 10 | ||||
-rw-r--r-- | src/qt/askpassphrasedialog.cpp | 2 | ||||
-rw-r--r-- | src/qt/bitcoinstrings.cpp | 6 | ||||
-rw-r--r-- | src/qt/coincontroldialog.cpp | 20 | ||||
-rw-r--r-- | src/qt/locale/bitcoin_en.ts | 108 | ||||
-rw-r--r-- | src/qt/optionsdialog.cpp | 2 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 4 | ||||
-rw-r--r-- | src/qt/sendcoinsentry.cpp | 2 | ||||
-rw-r--r-- | src/rpcserver.cpp | 4 | ||||
-rw-r--r-- | src/test/bloom_tests.cpp | 78 | ||||
-rw-r--r-- | src/test/mruset_tests.cpp | 126 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 10 |
30 files changed, 395 insertions, 255 deletions
diff --git a/src/addrman.h b/src/addrman.h index 5badd4ef95..b72dda49d1 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -17,8 +17,8 @@ #include <stdint.h> #include <vector> -/** - * Extended statistics about a CAddress +/** + * Extended statistics about a CAddress */ class CAddrInfo : public CAddress { @@ -105,14 +105,14 @@ public: /** Stochastic address manager * * Design goals: - * * Keep the address tables in-memory, and asynchronously dump the entire to able in peers.dat. + * * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat. * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses. * * To that end: * * Addresses are organized into buckets. * * Address that have not yet been tried go into 1024 "new" buckets. * * Based on the address range (/16 for IPv4) of source of the information, 64 buckets are selected at random - * * The actual bucket is chosen from one of these, based on the range the address itself is located. + * * The actual bucket is chosen from one of these, based on the range in which the address itself is located. * * One single address can occur in up to 8 different buckets, to increase selection chances for addresses that * are seen frequently. The chance for increasing this multiplicity decreases exponentially. * * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen diff --git a/src/base58.h b/src/base58.h index 8de90046a9..787979c827 100644 --- a/src/base58.h +++ b/src/base58.h @@ -6,10 +6,10 @@ /** * Why base-58 instead of standard base-64 encoding? * - Don't want 0OIl characters that look the same in some fonts and - * could be used to create visually identical looking account numbers. - * - A string with non-alphanumeric characters is not as easily accepted as an account number. + * could be used to create visually identical looking data. + * - A string with non-alphanumeric characters is not as easily accepted as input. * - E-mail usually won't line-break if there's no punctuation to break at. - * - Double-clicking selects the whole number as one word if it's all alphanumeric. + * - Double-clicking selects the whole string as one word if it's all alphanumeric. */ #ifndef BITCOIN_BASE58_H #define BITCOIN_BASE58_H diff --git a/src/bloom.cpp b/src/bloom.cpp index e60576f4b4..36cba491c4 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -21,22 +21,33 @@ using namespace std; CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) : -/** - * The ideal size for a bloom filter with a given number of elements and false positive rate is: - * - nElements * log(fp rate) / ln(2)^2 - * We ignore filter parameters which will create a bloom filter larger than the protocol limits - */ -vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8), -/** - * The ideal number of hash functions is filter size * ln(2) / number of elements - * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits - * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas - */ -isFull(false), -isEmpty(false), -nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)), -nTweak(nTweakIn), -nFlags(nFlagsIn) + /** + * The ideal size for a bloom filter with a given number of elements and false positive rate is: + * - nElements * log(fp rate) / ln(2)^2 + * We ignore filter parameters which will create a bloom filter larger than the protocol limits + */ + vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8), + /** + * The ideal number of hash functions is filter size * ln(2) / number of elements + * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits + * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas + */ + isFull(false), + isEmpty(false), + nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)), + nTweak(nTweakIn), + nFlags(nFlagsIn) +{ +} + +// Private constructor used by CRollingBloomFilter +CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn) : + vData((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)) / 8), + isFull(false), + isEmpty(true), + nHashFuncs((unsigned int)(vData.size() * 8 / nElements * LN2)), + nTweak(nTweakIn), + nFlags(BLOOM_UPDATE_NONE) { } @@ -197,3 +208,43 @@ void CBloomFilter::UpdateEmptyFull() isFull = full; isEmpty = empty; } + +CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate, unsigned int nTweak) : + b1(nElements * 2, fpRate, nTweak), b2(nElements * 2, fpRate, nTweak) +{ + // 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. + nBloomSize = nElements * 2; + nInsertions = 0; +} + +void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey) +{ + if (nInsertions == 0) { + b1.clear(); + } else if (nInsertions == nBloomSize / 2) { + b2.clear(); + } + b1.insert(vKey); + b2.insert(vKey); + if (++nInsertions == nBloomSize) { + nInsertions = 0; + } +} + +bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const +{ + if (nInsertions < nBloomSize / 2) { + return b2.contains(vKey); + } + return b1.contains(vKey); +} + +void CRollingBloomFilter::clear() +{ + b1.clear(); + b2.clear(); + nInsertions = 0; +} diff --git a/src/bloom.h b/src/bloom.h index 191ffa19b3..bb17f59c86 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -32,14 +32,14 @@ enum bloomflags /** * BloomFilter is a probabilistic filter which SPV clients provide - * so that we can filter the transactions we sends them. + * so that we can filter the transactions we send them. * * This allows for significantly more efficient transaction and block downloads. * - * Because bloom filters are probabilistic, an SPV node can increase the false- - * positive rate, making us send them transactions which aren't actually theirs, + * Because bloom filters are probabilistic, a SPV node can increase the false- + * positive rate, making us send it transactions which aren't actually its, * allowing clients to trade more bandwidth for more privacy by obfuscating which - * keys are owned by them. + * keys are controlled by them. */ class CBloomFilter { @@ -53,6 +53,10 @@ private: unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const; + // Private constructor for CRollingBloomFilter, no restrictions on size + CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak); + friend class CRollingBloomFilter; + public: /** * Creates a new bloom filter which will provide the given fp rate when filled with the given number of elements @@ -97,4 +101,28 @@ public: void UpdateEmptyFull(); }; +/** + * RollingBloomFilter is a probabilistic "keep track of most recently inserted" set. + * Construct it with the number of items to keep track of, and a false-positive rate. + * + * contains(item) will always return true if item was one of the last N things + * insert()'ed ... but may also return true for items that were not inserted. + */ +class CRollingBloomFilter +{ +public: + CRollingBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak); + + void insert(const std::vector<unsigned char>& vKey); + bool contains(const std::vector<unsigned char>& vKey) const; + + void clear(); + +private: + unsigned int nBloomSize; + unsigned int nInsertions; + CBloomFilter b1, b2; +}; + + #endif // BITCOIN_BLOOM_H diff --git a/src/chain.h b/src/chain.h index 02f53cd2f2..01be2d6e5c 100644 --- a/src/chain.h +++ b/src/chain.h @@ -74,7 +74,7 @@ enum BlockStatus { */ BLOCK_VALID_TRANSACTIONS = 3, - //! Outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30. + //! Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends, BIP30. //! Implies all parents are also at least CHAIN. BLOCK_VALID_CHAIN = 4, diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a3434bd6e8..1e044ad491 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -87,7 +87,7 @@ public: /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce - * a large 4-byte int at any alignment. + * a large 32-bit integer with any alignment. */ pchMessageStart[0] = 0xf9; pchMessageStart[1] = 0xbe; @@ -99,9 +99,10 @@ public: nPruneAfterHeight = 100000; /** - * Build the genesis block. Note that the output of the genesis coinbase cannot - * be spent as it did not originally exist in the database. - * + * Build the genesis block. Note that the output of its generation + * transaction cannot be spent since it did not originally exist in the + * database. + * * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) diff --git a/src/chainparams.h b/src/chainparams.h index bf76eb110a..bfefe242b7 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -62,7 +62,7 @@ public: bool MiningRequiresPeers() const { return fMiningRequiresPeers; } /** Default value for -checkmempool and -checkblockindex argument */ bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } - /** Make standard checks */ + /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } int64_t PruneAfterHeight() const { return nPruneAfterHeight; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ @@ -99,8 +99,8 @@ protected: }; /** - * Return the currently selected parameters. This won't change after app startup - * outside of the unit tests. + * Return the currently selected parameters. This won't change after app + * startup, except for unit tests. */ const CChainParams &Params(); diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index 421a3a06ff..4369d0aef7 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -34,8 +34,8 @@ protected: }; /** - * Return the currently selected parameters. This won't change after app startup - * outside of the unit tests. + * Return the currently selected parameters. This won't change after app + * startup, except for unit tests. */ const CBaseChainParams& BaseParams(); diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 71579bb309..e3d42c2957 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -15,9 +15,10 @@ namespace Checkpoints { /** - * How many times we expect transactions after the last checkpoint to - * be slower. This number is a compromise, as it can't be accurate for - * every system. When reindexing from a fast disk with a slow CPU, it + * How many times slower we expect checking transactions after the last + * checkpoint to be (from checking signatures, which is skipped up to the + * last checkpoint). This number is a compromise, as it can't be accurate + * for every system. When reindexing from a fast disk with a slow CPU, it * can be up to 20, while when downloading from a slow network with a * fast multicore CPU, it won't be much higher than 1. */ diff --git a/src/checkpoints.h b/src/checkpoints.h index 29dc5f83a9..b0e5076788 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -11,7 +11,7 @@ class CBlockIndex; -/** +/** * Block-chain checkpoints are compiled-in sanity checks. * They are updated every release or three. */ diff --git a/src/checkqueue.h b/src/checkqueue.h index 6f6b97e3a7..20ba25bb41 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -54,7 +54,7 @@ private: /** * Number of verifications that haven't completed yet. - * This includes elements that are not anymore in queue, but still in + * This includes elements that are no longer queued, but still in the * worker's own batches. */ unsigned int nTodo; @@ -81,7 +81,7 @@ private: fAllOk &= fOk; nTodo -= nNow; if (nTodo == 0 && !fMaster) - // We processed the last element; inform the master he or she can exit and return the result + // We processed the last element; inform the master it can exit and return the result condMaster.notify_one(); } else { // first iteration @@ -136,7 +136,7 @@ public: Loop(); } - //! Wait until execution finishes, and return whether all evaluations where successful. + //! Wait until execution finishes, and return whether all evaluations were successful. bool Wait() { return Loop(true); diff --git a/src/init.cpp b/src/init.cpp index 5272541722..f4caa4717f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -52,7 +52,7 @@ bool fFeeEstimatesInitialized = false; #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for -// accessing block files, don't count towards to fd_set size limit +// accessing block files don't count towards the fd_set size limit // anyway. #define MIN_CORE_FILEDESCRIPTORS 0 #else @@ -334,7 +334,7 @@ strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0)); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1)); strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), 1)); - strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)"), + strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"), FormatMoney(maxTxFee))); strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup")); strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat")); diff --git a/src/main.cpp b/src/main.cpp index e6248c6617..7d7e670119 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -142,8 +142,9 @@ namespace { uint32_t nBlockSequenceId = 1; /** - * Sources of received blocks, to be able to send them reject messages or ban - * them, if processing happens afterwards. Protected by cs_main. + * Sources of received blocks, saved to be able to send them reject + * messages or ban them when processing happens afterwards. Protected by + * cs_main. */ map<uint256, NodeId> mapBlockSource; @@ -389,7 +390,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl } // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor - // of their current tip anymore. Go back enough to fix that. + // of its current tip anymore. Go back enough to fix that. state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock); if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) return; @@ -941,7 +942,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), - // only helps filling in pfMissingInputs (to determine missing vs spent). + // and only helps with filling in pfMissingInputs (to determine missing vs spent). BOOST_FOREACH(const CTxIn txin, tx.vin) { if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) @@ -1277,8 +1278,8 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) pfork = pfork->pprev; } - // We define a condition which we should warn the user about as a fork of at least 7 blocks - // who's tip is within 72 blocks (+/- 12 hours if no one mines it) of ours + // We define a condition where we should warn the user about as a fork of at least 7 blocks + // with a tip within 72 blocks (+/- 12 hours if no one mines it) of ours // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network // hash rate operating on the fork. // or a chain that is entirely longer than ours and invalid (note that this should be detected by both) @@ -1719,9 +1720,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information. // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool // already refuses previously-known transaction ids entirely. - // This rule was originally applied all blocks whose timestamp was after March 15, 2012, 0:00 UTC. + // This rule was originally applied to all blocks with a timestamp after March 15, 2012, 0:00 UTC. // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the - // two in the chain that violate it. This prevents exploiting the issue against nodes in their + // two in the chain that violate it. This prevents exploiting the issue against nodes during their // initial block download. bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash. !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || @@ -1984,7 +1985,7 @@ void static UpdateTip(CBlockIndex *pindexNew) { if (nUpgraded > 100/2) { // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); + strMiscWarning = _("Warning: This version is obsolete; upgrade required!"); CAlert::Notify(strMiscWarning, true); fWarned = true; } @@ -2315,7 +2316,7 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { } // The resulting new best tip may not be in setBlockIndexCandidates anymore, so - // add them again. + // add it again. BlockMap::iterator it = mapBlockIndex.begin(); while (it != mapBlockIndex.end()) { if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { @@ -3733,7 +3734,7 @@ void static ProcessGetData(CNode* pfrom) pfrom->PushMessage("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 didnt send here - + // Note that there is currently no way for a node to request any single transactions we didn't send here - // they must either disconnect and retry or request the full block. // Thus, the protocol spec specified allows for us to provide duplicate txn here, // however we MUST always provide at least what the remote peer needs @@ -3746,7 +3747,7 @@ void static ProcessGetData(CNode* pfrom) // no response } - // Trigger them to send a getblocks request for the next batch of inventory + // Trigger the peer node to send a getblocks request for the next batch of inventory if (inv.hash == pfrom->hashContinue) { // Bypass PushInventory, this must send even if redundant, @@ -3995,7 +3996,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { LOCK(cs_vNodes); // Use deterministic randomness to send to the same nodes for 24 hours - // at a time so the setAddrKnowns of the chosen nodes prevent repeats + // at a time so the addrKnowns of the chosen nodes prevent repeats static uint256 hashSalt; if (hashSalt.IsNull()) hashSalt = GetRandHash(); @@ -4060,7 +4061,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (inv.type == MSG_BLOCK) { UpdateBlockAvailability(pfrom->GetId(), inv.hash); if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { - // First request the headers preceeding the announced block. In the normal fully-synced + // First request the headers preceding the announced block. In the normal fully-synced // case where a new block is announced that succeeds the current tip (no reorganization), // there are no such headers. // Secondly, and only when we are close to being synced, we request the announced block directly, @@ -4142,8 +4143,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); if (--nLimit <= 0) { - // When this block is requested, we'll send an inv that'll make them - // getblocks the next batch of inventory. + // When this block is requested, we'll send an inv that'll + // trigger the peer to getblocks the next batch of inventory. LogPrint("net", " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); pfrom->hashContinue = pindex->GetBlockHash(); break; @@ -4380,9 +4381,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // This asymmetric behavior for inbound and outbound connections was introduced // to prevent a fingerprinting attack: an attacker can send specific fake addresses - // to users' AddrMan and later request them by sending getaddr messages. - // Making users (which are behind NAT and can only make outgoing connections) ignore - // getaddr message mitigates the attack. + // 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)) { pfrom->vAddrToSend.clear(); @@ -4467,7 +4468,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Nonce mismatches are normal when pings are overlapping sProblem = "Nonce mismatch"; if (nonce == 0) { - // This is most likely a bug in another implementation somewhere, cancel this ping + // This is most likely a bug in another implementation somewhere; cancel this ping bPingFinished = true; sProblem = "Nonce zero"; } @@ -4476,7 +4477,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, sProblem = "Unsolicited pong without ping"; } } else { - // This is most likely a bug in another implementation somewhere, cancel this ping + // This is most likely a bug in another implementation somewhere; cancel this ping bPingFinished = true; sProblem = "Short payload"; } @@ -4735,7 +4736,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) { const Consensus::Params& consensusParams = Params().GetConsensus(); { - // Don't send anything until we get their version message + // Don't send anything until we get its version message if (pto->nVersion == 0) return true; @@ -4779,9 +4780,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - // Periodically clear setAddrKnown to allow refresh broadcasts + // Periodically clear addrKnown to allow refresh broadcasts if (nLastRebroadcast) - pnode->setAddrKnown.clear(); + pnode->addrKnown.clear(); // Rebroadcast our address AdvertizeLocal(pnode); @@ -4799,9 +4800,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) vAddr.reserve(pto->vAddrToSend.size()); BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) { - // returns true if wasn't already contained in the set - if (pto->setAddrKnown.insert(addr).second) + if (!pto->addrKnown.contains(addr.GetKey())) { + pto->addrKnown.insert(addr.GetKey()); vAddr.push_back(addr); // receiver rejects addr messages larger than 1000 if (vAddr.size() >= 1000) @@ -4919,7 +4920,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link - // being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes + // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes // to unreasonably increase our timeout. if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * consensusParams.nPowTargetSpacing * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id); diff --git a/src/main.h b/src/main.h index b0aec6662d..38d867675e 100644 --- a/src/main.h +++ b/src/main.h @@ -75,7 +75,7 @@ static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16; /** Timeout in seconds during which a peer must stall block download progress before being disconnected. */ static const unsigned int BLOCK_STALLING_TIMEOUT = 2; /** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends - * less than this number, we reached their tip. Changing this value is a protocol upgrade. */ + * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ static const unsigned int MAX_HEADERS_RESULTS = 2000; /** Size of the "block download window": how far ahead of our current height do we fetch? * Larger windows tolerate larger download speed differences between peer, but increase the potential diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index dc87d0377a..4d90fd8cd7 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -119,8 +119,8 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns if (pos*2+1 < CalcTreeWidth(height-1)) { right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch); if (right == left) { - // If the left and right branch should never be identical as the transaction - // hashes covered by them must be unique. + // The left and right branches should never be identical, as the transaction + // hashes covered by them must each be unique. fBad = true; } } else { diff --git a/src/merkleblock.h b/src/merkleblock.h index d90face17c..904c22abc2 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -104,7 +104,7 @@ public: } } - /** Construct a partial merkle tree from a list of transaction id's, and a mask that selects a subset of them */ + /** Construct a partial merkle tree from a list of transaction ids, and a mask that selects a subset of them */ CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch); CPartialMerkleTree(); diff --git a/src/mruset.h b/src/mruset.h index 1969f419cb..398aa173bf 100644 --- a/src/mruset.h +++ b/src/mruset.h @@ -1,12 +1,12 @@ -// Copyright (c) 2012 The Bitcoin Core developers +// 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 <deque> #include <set> +#include <vector> #include <utility> /** STL-like set container that only keeps the most recent N elements. */ @@ -22,11 +22,13 @@ public: protected: std::set<T> set; - std::deque<T> queue; - size_type nMaxSize; + std::vector<iterator> order; + size_type first_used; + size_type first_unused; + const size_type nMaxSize; public: - mruset(size_type nMaxSizeIn = 0) { nMaxSize = nMaxSizeIn; } + 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(); } @@ -36,7 +38,9 @@ public: void clear() { set.clear(); - queue.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; } @@ -45,25 +49,17 @@ public: { std::pair<iterator, bool> ret = set.insert(x); if (ret.second) { - if (nMaxSize && queue.size() == nMaxSize) { - set.erase(queue.front()); - queue.pop_front(); + if (set.size() == nMaxSize + 1) { + set.erase(order[first_used]); + order[first_used] = set.end(); + if (++first_used == nMaxSize) first_used = 0; } - queue.push_back(x); + order[first_unused] = ret.first; + if (++first_unused == nMaxSize) first_unused = 0; } return ret; } size_type max_size() const { return nMaxSize; } - size_type max_size(size_type s) - { - if (s) - while (queue.size() > s) { - set.erase(queue.front()); - queue.pop_front(); - } - nMaxSize = s; - return nMaxSize; - } }; #endif // BITCOIN_MRUSET_H diff --git a/src/net.cpp b/src/net.cpp index 731c810935..2de04fc574 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1905,7 +1905,10 @@ bool CAddrDB::Read(CAddrMan& addr) unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } -CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000) +CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : + ssSend(SER_NETWORK, INIT_PROTO_VERSION), + addrKnown(5000, 0.001, insecure_rand()), + setInventoryKnown(SendBufferSize() / 1000) { nServices = 0; hSocket = hSocketIn; @@ -1934,7 +1937,6 @@ CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fIn nStartingHeight = -1; fGetAddr = false; fRelayTxes = false; - setInventoryKnown.max_size(SendBufferSize() / 1000); pfilter = new CBloomFilter(); nPingNonceSent = 0; nPingUsecStart = 0; @@ -271,8 +271,8 @@ public: bool fDisconnect; // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message - // b) the peer may tell us in their version message that we should not relay tx invs - // until they have initialized their bloom filter. + // b) the peer may tell us in its version message that we should not relay tx invs + // until it has initialized its bloom filter. bool fRelayTxes; CSemaphoreGrant grantOutbound; CCriticalSection cs_filter; @@ -300,7 +300,7 @@ public: // flood relay std::vector<CAddress> vAddrToSend; - mruset<CAddress> setAddrKnown; + CRollingBloomFilter addrKnown; bool fGetAddr; std::set<uint256> setKnown; @@ -380,7 +380,7 @@ public: void AddAddressKnown(const CAddress& addr) { - setAddrKnown.insert(addr); + addrKnown.insert(addr.GetKey()); } void PushAddress(const CAddress& addr) @@ -388,7 +388,7 @@ public: // Known checking here is only to save space from duplicates. // SendMessages will filter it again for knowns that were added // after addresses were pushed. - if (addr.IsValid() && !setAddrKnown.count(addr)) { + if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr; } else { diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 229139e65c..441814ff07 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -62,7 +62,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) : break; case ChangePass: // Ask old passphrase + new passphrase x2 setWindowTitle(tr("Change passphrase")); - ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet.")); + ui->warningLabel->setText(tr("Enter the old passphrase and new passphrase to the wallet.")); break; } textChanged(); diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 7f372debad..aeabfc424d 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -93,8 +93,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Maximum size of data in data carrier transactions we relay and mine " "(default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Maximum total fees to use in a single wallet transaction, setting too low " -"may abort large transactions (default: %s)"), +"Maximum total fees to use in a single wallet transaction; setting this too " +"low may abort large transactions (default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -332,7 +332,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Wallet %s resides outside data directory %s") QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin Core to complete"), QT_TRANSLATE_NOOP("bitcoin-core", "Wallet options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning"), -QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade required!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete; upgrade required!"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Unsupported argument -benchmark ignored, use -debug=bench."), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Unsupported argument -debugnet ignored, use -debug=net."), QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the database using -reindex to change -txindex"), diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 0a60632bfa..7531fbddcb 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -129,11 +129,11 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) : 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 dont show it - ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but dont show it - ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but dont show it - ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but dont show it - ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but dont show it + ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton 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 + ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it // default view is sorted by amount desc sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder); @@ -408,8 +408,8 @@ 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 childs are partially selected. But the parent node should be fully selected - // as well as the childs. Childs should never be partially selected in the first place. + // 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. #if QT_VERSION >= 0x050000 else if (column == COLUMN_CHECKBOX && item->childCount() > 0) @@ -635,15 +635,15 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes" // tool tips - QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "<br /><br />"; + 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::minTxFee.GetFeePerK())) + "<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 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::minTxFee.GetFeePerK())); - 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 %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546))); // how many satoshis the estimated fee can vary per byte we guess wrong double dFeeVary; diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 2555cdbb62..ae6f60f6ec 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -195,12 +195,7 @@ <translation>Change passphrase</translation> </message> <message> - <location line="+1"/> - <source>Enter the old and new passphrase to the wallet.</source> - <translation>Enter the old and new passphrase to the wallet.</translation> - </message> - <message> - <location line="+45"/> + <location line="+46"/> <source>Confirm wallet encryption</source> <translation>Confirm wallet encryption</translation> </message> @@ -242,7 +237,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+93"/> + <location line="+23"/> + <source>Enter the old passphrase and new passphrase to the wallet.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+70"/> <location line="+7"/> <location line="+42"/> <location line="+6"/> @@ -912,7 +912,22 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+161"/> + <source>This label turns red if the transaction size is greater than 1000 bytes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>This label turns red if the priority is smaller than "medium".</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>This label turns red if any recipient receives an amount smaller than %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> <source>Can vary +/- %1 satoshi(s) per input.</source> <translation type="unfinished"></translation> </message> @@ -927,12 +942,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+16"/> - <source>This label turns red, if the transaction size is greater than 1000 bytes.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> + <location line="+17"/> <location line="+5"/> <source>This means a fee of at least %1 per kB is required.</source> <translation type="unfinished"></translation> @@ -948,17 +958,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>This label turns red, if the priority is smaller than "medium".</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>This label turns red, if any recipient receives an amount smaller than %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+55"/> + <location line="+59"/> <location line="+61"/> <source>(no label)</source> <translation type="unfinished">(no label)</translation> @@ -1437,7 +1437,7 @@ </message> <message> <location line="-29"/> - <source>Client will be shutdown, do you want to proceed?</source> + <source>Client will be shut down. Do you want to proceed?</source> <translation type="unfinished"></translation> </message> <message> @@ -2557,12 +2557,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+193"/> - <source>The recipient address is not valid, please recheck.</source> - <translation>The recipient address is not valid, please recheck.</translation> - </message> - <message> - <location line="+3"/> + <location line="+196"/> <source>The amount to pay must be larger than 0.</source> <translation>The amount to pay must be larger than 0.</translation> </message> @@ -2577,12 +2572,7 @@ <translation>The total exceeds your balance when the %1 transaction fee is included.</translation> </message> <message> - <location line="+3"/> - <source>Duplicate address found, can only send to each address once per send operation.</source> - <translation>Duplicate address found, can only send to each address once per send operation.</translation> - </message> - <message> - <location line="+3"/> + <location line="+6"/> <source>Transaction creation failed!</source> <translation type="unfinished"></translation> </message> @@ -2615,7 +2605,17 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+129"/> + <location line="-114"/> + <source>The recipient address is not valid. Please recheck.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+231"/> <source>Warning: Invalid Bitcoin address</source> <translation type="unfinished"></translation> </message> @@ -2978,7 +2978,7 @@ <context> <name>TransactionDesc</name> <message> - <location filename="../transactiondesc.cpp" line="+35"/> + <location filename="../transactiondesc.cpp" line="+34"/> <source>Open until %1</source> <translation>Open until %1</translation> </message> @@ -3659,7 +3659,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+36"/> + <location line="+14"/> + <source>Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+22"/> <source>Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)</source> <translation type="unfinished"></translation> </message> @@ -3879,7 +3884,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> + <location line="+2"/> + <source>Warning: This version is obsolete; upgrade required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>You need to rebuild the database using -reindex to change -txindex</source> <translation>You need to rebuild the database using -reindex to change -txindex</translation> </message> @@ -3964,12 +3974,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> - <source>Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+7"/> + <location line="+10"/> <source>Prune configured below the minimum of %d MB. Please use a higher number.</source> <translation type="unfinished"></translation> </message> @@ -4309,12 +4314,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Warning</translation> </message> <message> - <location line="+1"/> - <source>Warning: This version is obsolete, upgrade required!</source> - <translation>Warning: This version is obsolete, upgrade required!</translation> - </message> - <message> - <location line="+1"/> + <location line="+2"/> <source>Warning: Unsupported argument -benchmark ignored, use -debug=bench.</source> <translation type="unfinished"></translation> </message> diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index a9e4b339e4..efb2bf4158 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -208,7 +208,7 @@ void OptionsDialog::on_resetButton_clicked() { // confirmation dialog QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"), - tr("Client restart required to activate changes.") + "<br><br>" + tr("Client will be shutdown, do you want to proceed?"), + tr("Client restart required to activate changes.") + "<br><br>" + tr("Client will be shut down. Do you want to proceed?"), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); if(btnRetVal == QMessageBox::Cancel) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0360f160d8..7a33e3567b 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -505,7 +505,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn switch(sendCoinsReturn.status) { case WalletModel::InvalidAddress: - msgParams.first = tr("The recipient address is not valid, please recheck."); + msgParams.first = tr("The recipient address is not valid. Please recheck."); break; case WalletModel::InvalidAmount: msgParams.first = tr("The amount to pay must be larger than 0."); @@ -517,7 +517,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg); break; case WalletModel::DuplicateAddress: - msgParams.first = tr("Duplicate address found, can only send to each address once per send operation."); + msgParams.first = tr("Duplicate address found: addresses should only be used once each."); break; case WalletModel::TransactionCreationFailed: msgParams.first = tr("Transaction creation failed!"); diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index ea35ed1d53..6eec33ffd4 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -216,7 +216,7 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value) ui->addAsLabel->clear(); ui->payTo->setText(recipient.address); // this may set a label from addressbook - if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, dont overwrite with an empty label + if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, don't overwrite with an empty label ui->addAsLabel->setText(recipient.label); ui->payAmount->setValue(recipient.amount); } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 61dda9125b..12a5c4aef9 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -912,8 +912,8 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, { LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string()); /* Deter brute-forcing - If this results in a DoS the user really - shouldn't have their RPC port exposed. */ + We don't support exposing the RPC port, so this shouldn't result + in a DoS. */ MilliSleep(250); conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush; diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 73a146f05c..1bda8a7ea1 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -8,6 +8,7 @@ #include "clientversion.h" #include "key.h" #include "merkleblock.h" +#include "random.h" #include "serialize.h" #include "streams.h" #include "uint256.h" @@ -459,4 +460,81 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0))); } +static std::vector<unsigned char> RandomData() +{ + uint256 r = GetRandHash(); + return std::vector<unsigned char>(r.begin(), r.end()); +} + +BOOST_AUTO_TEST_CASE(rolling_bloom) +{ + // last-100-entry, 1% false positive: + CRollingBloomFilter rb1(100, 0.01, 0); + + // Overfill: + static const int DATASIZE=399; + std::vector<unsigned char> data[DATASIZE]; + for (int i = 0; i < DATASIZE; i++) { + data[i] = RandomData(); + rb1.insert(data[i]); + } + // Last 100 guaranteed to be remembered: + for (int i = 299; i < DATASIZE; i++) { + BOOST_CHECK(rb1.contains(data[i])); + } + + // false positive rate is 1%, so we should get about 100 hits if + // testing 10,000 random keys. We get worst-case false positive + // behavior when the filter is as full as possible, which is + // when we've inserted one minus an integer multiple of nElement*2. + unsigned int nHits = 0; + for (int i = 0; i < 10000; i++) { + if (rb1.contains(RandomData())) + ++nHits; + } + // Run test_bitcoin with --log_level=message to see BOOST_TEST_MESSAGEs: + BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~100 expected)"); + + // Insanely unlikely to get a fp count outside this range: + BOOST_CHECK(nHits > 25); + BOOST_CHECK(nHits < 175); + + BOOST_CHECK(rb1.contains(data[DATASIZE-1])); + rb1.clear(); + BOOST_CHECK(!rb1.contains(data[DATASIZE-1])); + + // Now roll through data, make sure last 100 entries + // are always remembered: + for (int i = 0; i < DATASIZE; i++) { + if (i >= 100) + BOOST_CHECK(rb1.contains(data[i-100])); + rb1.insert(data[i]); + } + + // Insert 999 more random entries: + for (int i = 0; i < 999; i++) { + rb1.insert(RandomData()); + } + // Sanity check to make sure the filter isn't just filling up: + nHits = 0; + for (int i = 0; i < DATASIZE; i++) { + if (rb1.contains(data[i])) + ++nHits; + } + // Expect about 5 false positives, more than 100 means + // something is definitely broken. + BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~5 expected)"); + BOOST_CHECK(nHits < 100); + + // last-1000-entry, 0.01% false positive: + CRollingBloomFilter rb2(1000, 0.001, 0); + for (int i = 0; i < DATASIZE; i++) { + rb2.insert(data[i]); + } + // ... room for all of them: + for (int i = 0; i < DATASIZE; i++) { + BOOST_CHECK(rb2.contains(data[i])); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp index bd4e9c1d38..2b68f8899e 100644 --- a/src/test/mruset_tests.cpp +++ b/src/test/mruset_tests.cpp @@ -17,83 +17,65 @@ using namespace std; -class mrutester -{ -private: - mruset<int> mru; - std::set<int> set; - -public: - mrutester() { mru.max_size(MAX_SIZE); } - int size() const { return set.size(); } - - void insert(int n) - { - mru.insert(n); - set.insert(n); - BOOST_CHECK(mru == set); - } -}; - BOOST_FIXTURE_TEST_SUITE(mruset_tests, BasicTestingSetup) -// Test that an mruset behaves like a set, as long as no more than MAX_SIZE elements are in it -BOOST_AUTO_TEST_CASE(mruset_like_set) -{ - - for (int nTest=0; nTest<NUM_TESTS; nTest++) - { - mrutester tester; - while (tester.size() < MAX_SIZE) - tester.insert(GetRandInt(2 * MAX_SIZE)); - } - -} - -// Test that an mruset's size never exceeds its max_size -BOOST_AUTO_TEST_CASE(mruset_limited_size) +BOOST_AUTO_TEST_CASE(mruset_test) { - for (int nTest=0; nTest<NUM_TESTS; nTest++) - { - mruset<int> mru(MAX_SIZE); - for (int nAction=0; nAction<3*MAX_SIZE; nAction++) - { - int n = GetRandInt(2 * MAX_SIZE); - mru.insert(n); - BOOST_CHECK(mru.size() <= MAX_SIZE); + // 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)); + } + } } } } -// 16-bit permutation function -int static permute(int n) -{ - // hexadecimals of pi; verified to be linearly independent - static const int table[16] = {0x243F, 0x6A88, 0x85A3, 0x08D3, 0x1319, 0x8A2E, 0x0370, 0x7344, - 0xA409, 0x3822, 0x299F, 0x31D0, 0x082E, 0xFA98, 0xEC4E, 0x6C89}; - - int ret = 0; - for (int bit=0; bit<16; bit++) - if (n & (1<<bit)) - ret ^= table[bit]; - - return ret; -} - -// Test that an mruset acts like a moving window, if no duplicate elements are added -BOOST_AUTO_TEST_CASE(mruset_window) -{ - mruset<int> mru(MAX_SIZE); - for (int n=0; n<10*MAX_SIZE; n++) - { - mru.insert(permute(n)); - - set<int> tester; - for (int m=max(0,n-MAX_SIZE+1); m<=n; m++) - tester.insert(permute(m)); - - BOOST_CHECK(mru == tester); - } -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bb73038b97..cb20998d26 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -35,8 +35,8 @@ bool bSpendZeroConfChange = true; bool fSendFreeTransactions = false; bool fPayAtLeastCustomFee = true; -/** - * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) +/** + * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) * Override with -mintxfee */ CFeeRate CWallet::minTxFee = CFeeRate(1000); @@ -529,7 +529,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) delete pwalletdbEncryption; } // We now probably have half of our keys encrypted in memory, and half not... - // die and let the user reload their unencrypted wallet. + // die and let the user reload the unencrypted wallet. assert(false); } @@ -541,7 +541,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) if (!pwalletdbEncryption->TxnCommit()) { delete pwalletdbEncryption; // We now have keys encrypted in memory, but not on disk... - // die to avoid confusion and let the user reload their unencrypted wallet. + // die to avoid confusion and let the user reload the unencrypted wallet. assert(false); } @@ -1097,7 +1097,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) void CWallet::ReacceptWalletTransactions() { - // If transcations aren't broadcasted, don't let them into local mempool either + // If transactions aren't being broadcasted, don't let them into local mempool either if (!fBroadcastTransactions) return; LOCK2(cs_main, cs_wallet); |