diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bitcoin-cli.cpp | 2 | ||||
-rw-r--r-- | src/bitcoin-tx.cpp | 2 | ||||
-rw-r--r-- | src/bitcoind.cpp | 1 | ||||
-rw-r--r-- | src/bloom.cpp | 83 | ||||
-rw-r--r-- | src/bloom.h | 28 | ||||
-rw-r--r-- | src/chainparams.cpp | 29 | ||||
-rw-r--r-- | src/chainparams.h | 10 | ||||
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/main.cpp | 19 | ||||
-rw-r--r-- | src/mruset.h | 36 | ||||
-rw-r--r-- | src/net.cpp | 29 | ||||
-rw-r--r-- | src/net.h | 6 | ||||
-rw-r--r-- | src/netbase.cpp | 4 | ||||
-rw-r--r-- | src/pow.cpp | 17 | ||||
-rw-r--r-- | src/pow.h | 3 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 2 | ||||
-rw-r--r-- | src/qt/transactiondesc.cpp | 1 | ||||
-rw-r--r-- | src/rpcclient.cpp | 1 | ||||
-rw-r--r-- | src/test/bloom_tests.cpp | 78 | ||||
-rw-r--r-- | src/test/data/script_invalid.json | 20 | ||||
-rw-r--r-- | src/test/mruset_tests.cpp | 126 | ||||
-rw-r--r-- | src/test/pow_tests.cpp | 24 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 2 | ||||
-rw-r--r-- | src/ui_interface.h | 13 | ||||
-rw-r--r-- | src/util.cpp | 5 | ||||
-rw-r--r-- | src/util.h | 20 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 2 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 19 |
28 files changed, 398 insertions, 186 deletions
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 2fa8de6fd8..1269d7a119 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -12,8 +12,6 @@ #include <boost/filesystem/operations.hpp> -#define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ - using namespace std; using namespace json_spirit; diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index f1c1c0ff8b..d024b48020 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -11,7 +11,6 @@ #include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" -#include "ui_interface.h" // for _(...) #include "univalue/univalue.h" #include "util.h" #include "utilmoneystr.h" @@ -26,7 +25,6 @@ using namespace std; static bool fCreateBlank; static map<string,UniValue> registers; -CClientUIInterface uiInterface; static bool AppInitRawTx(int argc, char* argv[]) { diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 2172f4a21b..eeca8655c9 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -8,7 +8,6 @@ #include "init.h" #include "main.h" #include "noui.h" -#include "ui_interface.h" #include "util.h" #include <boost/algorithm/string/predicate.hpp> 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 15bc312c4b..bb17f59c86 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -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/chainparams.cpp b/src/chainparams.cpp index a9dd4c257a..1e044ad491 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -5,7 +5,6 @@ #include "chainparams.h" -#include "random.h" #include "util.h" #include "utilstrencodings.h" @@ -15,35 +14,11 @@ using namespace std; -struct SeedSpec6 { - uint8_t addr[16]; - uint16_t port; -}; - #include "chainparamsseeds.h" /** * Main network */ - -//! Convert the pnSeeds6 array into usable address objects. -static void convertSeed6(std::vector<CAddress> &vSeedsOut, const SeedSpec6 *data, unsigned int count) -{ - // It'll only connect to one or two seed nodes because once it connects, - // it'll get a pile of addresses with newer timestamps. - // Seed nodes are given a random 'last seen time' of between one and two - // weeks ago. - const int64_t nOneWeek = 7*24*60*60; - for (unsigned int i = 0; i < count; i++) - { - struct in6_addr ip; - memcpy(&ip, data[i].addr, sizeof(ip)); - CAddress addr(CService(ip, data[i].port)); - addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek; - vSeedsOut.push_back(addr); - } -} - /** * What makes a good checkpoint block? * + Is surrounded by blocks with reasonable timestamps @@ -165,7 +140,7 @@ public: base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container<std::vector<unsigned char> >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container<std::vector<unsigned char> >(); - convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main)); + vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); fRequireRPCPassword = true; fMiningRequiresPeers = true; @@ -221,7 +196,7 @@ public: base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >(); - convertSeed6(vFixedSeeds, pnSeed6_test, ARRAYLEN(pnSeed6_test)); + vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); fRequireRPCPassword = true; fMiningRequiresPeers = true; diff --git a/src/chainparams.h b/src/chainparams.h index 1b03900990..bfefe242b7 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -19,6 +19,12 @@ struct CDNSSeedData { CDNSSeedData(const std::string &strName, const std::string &strHost) : name(strName), host(strHost) {} }; +struct SeedSpec6 { + uint8_t addr[16]; + uint16_t port; +}; + + /** * CChainParams defines various tweakable parameters of a given instance of the * Bitcoin system. There are three: the main network on which people trade goods @@ -67,7 +73,7 @@ public: std::string NetworkIDString() const { return strNetworkID; } const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; } const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } - const std::vector<CAddress>& FixedSeeds() const { return vFixedSeeds; } + const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; } virtual const Checkpoints::CCheckpointData& Checkpoints() const = 0; protected: CChainParams() {} @@ -83,7 +89,7 @@ protected: std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES]; std::string strNetworkID; CBlock genesis; - std::vector<CAddress> vFixedSeeds; + std::vector<SeedSpec6> vFixedSeeds; bool fRequireRPCPassword; bool fMiningRequiresPeers; bool fDefaultConsistencyChecks; diff --git a/src/init.cpp b/src/init.cpp index 6f852fcaa5..f4caa4717f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -68,7 +68,7 @@ enum BindFlags { }; static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; -CClientUIInterface uiInterface; +CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h ////////////////////////////////////////////////////////////////////////////// // diff --git a/src/main.cpp b/src/main.cpp index 07156a9af2..7d7e670119 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3676,7 +3676,6 @@ bool static AlreadyHave(const CInv& inv) return true; } - void static ProcessGetData(CNode* pfrom) { std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin(); @@ -3704,11 +3703,13 @@ void static ProcessGetData(CNode* pfrom) if (chainActive.Contains(mi->second)) { send = true; } else { + static const int nOneMonth = 30 * 24 * 60 * 60; // To prevent fingerprinting attacks, only send blocks outside of the active - // chain if they are valid, and no more than a month older than the best header - // chain we know about. + // chain if they are valid, and no more than a month older (both in time, and in + // best equivalent proof of work) than the best header chain we know about. send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && - (mi->second->GetBlockTime() > pindexBestHeader->GetBlockTime() - 30 * 24 * 60 * 60); + (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && + (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth); if (!send) { LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); } @@ -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(); @@ -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) 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 45a06a105f..2de04fc574 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -142,6 +142,27 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer) return nBestScore >= 0; } +//! Convert the pnSeeds6 array into usable address objects. +static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn) +{ + // It'll only connect to one or two seed nodes because once it connects, + // it'll get a pile of addresses with newer timestamps. + // Seed nodes are given a random 'last seen time' of between one and two + // weeks ago. + const int64_t nOneWeek = 7*24*60*60; + std::vector<CAddress> vSeedsOut; + vSeedsOut.reserve(vSeedsIn.size()); + for (std::vector<SeedSpec6>::const_iterator i(vSeedsIn.begin()); i != vSeedsIn.end(); ++i) + { + struct in6_addr ip; + memcpy(&ip, i->addr, sizeof(ip)); + CAddress addr(CService(ip, i->port)); + addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek; + vSeedsOut.push_back(addr); + } + return vSeedsOut; +} + // get best local address for a particular peer as a CAddress // Otherwise, return the unroutable 0.0.0.0 but filled in with // the normal parameters, since the IP may be changed to a useful @@ -1195,7 +1216,7 @@ void ThreadOpenConnections() static bool done = false; if (!done) { LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); - addrman.Add(Params().FixedSeeds(), CNetAddr("127.0.0.1")); + addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1")); done = true; } } @@ -1884,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; @@ -1913,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; @@ -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/netbase.cpp b/src/netbase.cpp index 1837cfa9c3..2015d0271a 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -293,7 +293,7 @@ struct ProxyCredentials }; /** Connect using SOCKS5 (as described in RFC1928) */ -bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket) +static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket) { LogPrintf("SOCKS5 connecting %s\n", strDest); if (strDest.size() > 255) { @@ -558,7 +558,7 @@ bool IsProxy(const CNetAddr &addr) { return false; } -static bool ConnectThroughProxy(const proxyType &proxy, const std::string strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed) +static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed) { SOCKET hSocket = INVALID_SOCKET; // first connect to proxy server diff --git a/src/pow.cpp b/src/pow.cpp index fc6ed4f3d1..bb53ad204b 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -114,3 +114,20 @@ arith_uint256 GetBlockProof(const CBlockIndex& block) // or ~bnTarget / (nTarget+1) + 1. return (~bnTarget / (bnTarget + 1)) + 1; } + +int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params) +{ + arith_uint256 r; + int sign = 1; + if (to.nChainWork > from.nChainWork) { + r = to.nChainWork - from.nChainWork; + } else { + r = from.nChainWork - to.nChainWork; + sign = -1; + } + r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip); + if (r.bits() > 63) { + return sign * std::numeric_limits<int64_t>::max(); + } + return sign * r.GetLow64(); +} @@ -22,4 +22,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); arith_uint256 GetBlockProof(const CBlockIndex& block); +/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */ +int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&); + #endif // BITCOIN_POW_H diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 069601ab67..018169cfdc 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -532,7 +532,7 @@ int main(int argc, char *argv[]) // Now that QSettings are accessible, initialize translations QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); - uiInterface.Translate.connect(Translate); + translationInterface.Translate.connect(Translate); // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 7214249435..4fffd03adf 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -14,7 +14,6 @@ #include "main.h" #include "script/script.h" #include "timedata.h" -#include "ui_interface.h" #include "util.h" #include "wallet/db.h" #include "wallet/wallet.h" diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index ad676f9edc..4b576b3707 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -7,7 +7,6 @@ #include "rpcprotocol.h" #include "util.h" -#include "ui_interface.h" #include <set> #include <stdint.h> 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/data/script_invalid.json b/src/test/data/script_invalid.json index 271bc70f73..7afa2abf49 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -141,6 +141,8 @@ ["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled"], ["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled"], +["", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are no stack items"], +["0", "EQUAL NOT", "P2SH,STRICTENC", "EQUAL must error when there are not 2 stack items"], ["0 1","EQUAL", "P2SH,STRICTENC"], ["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC"], ["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC"], @@ -368,6 +370,16 @@ ["NOP", "HASH160 1", "P2SH,STRICTENC"], ["NOP", "HASH256 1", "P2SH,STRICTENC"], +["Increase CHECKSIG and CHECKMULTISIG negative test coverage"], +["", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are no stack items"], +["0", "CHECKSIG NOT", "STRICTENC", "CHECKSIG must error when there are not 2 stack items"], +["", "CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are no stack items"], +["", "-1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of pubkeys is negative"], +["", "1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough pubkeys on the stack"], +["", "-1 0 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when the specified number of signatures is negative"], +["", "1 'pk1' 1 CHECKMULTISIG NOT", "STRICTENC", "CHECKMULTISIG must error when there are not enough signatures on the stack"], +["", "'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF", "", "CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode"], + ["", "0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", "P2SH,STRICTENC", @@ -426,7 +438,7 @@ ["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"], -["0x4f 0x00100000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", +["0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"], @@ -780,6 +792,12 @@ "P2SH(P2PK) with non-push scriptSig" ], [ + "0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f", + "2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG", + "P2SH,STRICTENC", + "2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs" +], +[ "11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "CLEANSTACK,P2SH", 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/test/pow_tests.cpp b/src/test/pow_tests.cpp index 4ce1591c35..a436749287 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -69,4 +69,28 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00e1fd); } +BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + + std::vector<CBlockIndex> blocks(10000); + for (int i = 0; i < 10000; i++) { + blocks[i].pprev = i ? &blocks[i - 1] : NULL; + blocks[i].nHeight = i; + blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; + blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */ + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + } + + for (int j = 0; j < 1000; j++) { + CBlockIndex *p1 = &blocks[GetRand(10000)]; + CBlockIndex *p2 = &blocks[GetRand(10000)]; + CBlockIndex *p3 = &blocks[GetRand(10000)]; + + int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, params); + BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime()); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index a2cb78c989..4057eccbed 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -20,7 +20,7 @@ #include <boost/test/unit_test.hpp> #include <boost/thread.hpp> -CClientUIInterface uiInterface; +CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h CWallet* pwalletMain; extern bool fPrintToConsole; diff --git a/src/ui_interface.h b/src/ui_interface.h index 3f11a1ddab..32a92a4b81 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -78,9 +78,6 @@ public: /** Progress message during initialization. */ boost::signals2::signal<void (const std::string &message)> InitMessage; - /** Translate a message to the native language of the user. */ - boost::signals2::signal<std::string (const char* psz)> Translate; - /** Number of network connections changed. */ boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged; @@ -102,14 +99,4 @@ public: extern CClientUIInterface uiInterface; -/** - * Translation function: Call Translate signal on UI interface, which returns a boost::optional result. - * If no translation slot is registered, nothing is returned, and simply return the input. - */ -inline std::string _(const char* psz) -{ - boost::optional<std::string> rv = uiInterface.Translate(psz); - return rv ? (*rv) : psz; -} - #endif // BITCOIN_UI_INTERFACE_H diff --git a/src/util.cpp b/src/util.cpp index 1bb7df7085..c9e8242d47 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -7,7 +7,7 @@ #include "config/bitcoin-config.h" #endif -#if (defined(__FreeBSD__) || defined(__OpenBSD__)) +#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) #include <pthread.h> #include <pthread_np.h> #endif @@ -109,6 +109,7 @@ string strMiscWarning; bool fLogTimestamps = false; bool fLogIPs = false; volatile bool fReopenDebugLog = false; +CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ static CCriticalSection** ppmutexOpenSSL; @@ -712,7 +713,7 @@ void RenameThread(const char* name) #if defined(PR_SET_NAME) // Only the first 15 characters are used (16 - NUL terminator) ::prctl(PR_SET_NAME, name, 0, 0, 0); -#elif (defined(__FreeBSD__) || defined(__OpenBSD__)) +#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) pthread_set_name_np(pthread_self(), name); #elif defined(MAC_OSX) diff --git a/src/util.h b/src/util.h index 9b5a4153dd..483d9d7858 100644 --- a/src/util.h +++ b/src/util.h @@ -25,8 +25,17 @@ #include <vector> #include <boost/filesystem/path.hpp> +#include <boost/signals2/signal.hpp> #include <boost/thread/exceptions.hpp> +/** Signals for translation. */ +class CTranslationInterface +{ +public: + /** Translate a message to the native language of the user. */ + boost::signals2::signal<std::string (const char* psz)> Translate; +}; + extern std::map<std::string, std::string> mapArgs; extern std::map<std::string, std::vector<std::string> > mapMultiArgs; extern bool fDebug; @@ -37,6 +46,17 @@ extern std::string strMiscWarning; extern bool fLogTimestamps; extern bool fLogIPs; extern volatile bool fReopenDebugLog; +extern CTranslationInterface translationInterface; + +/** + * Translation function: Call Translate signal on UI interface, which returns a boost::optional result. + * If no translation slot is registered, nothing is returned, and simply return the input. + */ +inline std::string _(const char* psz) +{ + boost::optional<std::string> rv = translationInterface.Translate(psz); + return rv ? (*rv) : psz; +} void SetupEnvironment(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c31c09d922..dd5240e3c0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2330,7 +2330,7 @@ Value listunspent(const Array& params, bool fHelp) if (pk.IsPayToScriptHash()) { CTxDestination address; if (ExtractDestination(pk, address)) { - const CScriptID& hash = boost::get<const CScriptID&>(address); + const CScriptID& hash = boost::get<CScriptID>(address); CScript redeemScript; if (pwalletMain->GetCScript(hash, redeemScript)) entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b57955dae2..cb20998d26 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1101,6 +1101,9 @@ void CWallet::ReacceptWalletTransactions() if (!fBroadcastTransactions) return; LOCK2(cs_main, cs_wallet); + std::map<int64_t, CWalletTx*> mapSorted; + + // Sort pending wallet transactions based on their initial wallet insertion order BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) { const uint256& wtxid = item.first; @@ -1109,13 +1112,19 @@ void CWallet::ReacceptWalletTransactions() int nDepth = wtx.GetDepthInMainChain(); - if (!wtx.IsCoinBase() && nDepth < 0) - { - // Try to add to memory pool - LOCK(mempool.cs); - wtx.AcceptToMemoryPool(false); + if (!wtx.IsCoinBase() && nDepth < 0) { + mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); } } + + // Try to add wallet transactions to memory pool + BOOST_FOREACH(PAIRTYPE(const int64_t, CWalletTx*)& item, mapSorted) + { + CWalletTx& wtx = *(item.second); + + LOCK(mempool.cs); + wtx.AcceptToMemoryPool(false); + } } bool CWalletTx::RelayWalletTransaction() |