From ee9edc8829a707ebc4b6e195182e82f2098fbfea Mon Sep 17 00:00:00 2001 From: lateminer Date: Sun, 7 Jan 2018 19:17:53 +0300 Subject: [PATCH 001/110] Make Lore work on testnet, first attempt --- src/chainparams.cpp | 109 ++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0cc6cc8e5..cff842c91 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -20,22 +20,39 @@ using namespace std; static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { + // Genesis block - CMutableTransaction txNew; - txNew.nTime = 1393221600; - txNew.vin.resize(1); - txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 0 << CScriptNum(42) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); - txNew.vout[0].SetEmpty(); + // MainNet: - CBlock genesis; - genesis.vtx.push_back(txNew); - genesis.hashPrevBlock.SetNull(); - genesis.hashMerkleRoot = uint256S("12630d16a97f24b287c8c2594dda5fb98c9e6c70fc61d44191931ea2aa08dc90"); - genesis.nVersion = 1; - genesis.nTime = 1393221600; - genesis.nBits = 0x1e0fffff; - genesis.nNonce = 164482; + //CBlock(hash=000001faef25dec4fbcf906e6242621df2c183bf232f263d0ba5b101911e4563, ver=1, hashPrevBlock=0000000000000000000000000000000000000000000000000000000000000000, hashMerkleRoot=12630d16a97f24b287c8c2594dda5fb98c9e6c70fc61d44191931ea2aa08dc90, nTime=1393221600, nBits=1e0fffff, nNonce=164482, vtx=1, vchBlockSig=) + // Coinbase(hash=12630d16a9, nTime=1393221600, ver=1, vin.size=1, vout.size=1, nLockTime=0) + // CTxIn(COutPoint(0000000000, 4294967295), coinbase 00012a24323020466562203230313420426974636f696e2041544d7320636f6d6520746f20555341) + // CTxOut(empty) + // vMerkleTree: 12630d16a9 + + // TestNet: + + //CBlock(hash=0000724595fb3b9609d441cbfb9577615c292abf07d996d3edabc48de843642d, ver=1, hashPrevBlock=0000000000000000000000000000000000000000000000000000000000000000, hashMerkleRoot=12630d16a97f24b287c8c2594dda5fb98c9e6c70fc61d44191931ea2aa08dc90, nTime=1393221600, nBits=1f00ffff, nNonce=216178, vtx=1, vchBlockSig=) + // Coinbase(hash=12630d16a9, nTime=1393221600, ver=1, vin.size=1, vout.size=1, nLockTime=0) + // CTxIn(COutPoint(0000000000, 4294967295), coinbase 00012a24323020466562203230313420426974636f696e2041544d7320636f6d6520746f20555341) + // CTxOut(empty) + // vMerkleTree: 12630d16a9 + + CMutableTransaction txNew; + txNew.nTime = nTime; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 0 << CScriptNum(42) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].SetEmpty(); + + CBlock genesis; + genesis.vtx.push_back(txNew); + genesis.hashPrevBlock.SetNull(); + genesis.nVersion = nVersion; + genesis.nTime = nTime; + genesis.nBits = nBits; + genesis.nNonce = nNonce; + genesis.hashMerkleRoot = BlockMerkleRoot(genesis); return genesis; } @@ -43,12 +60,6 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi * 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=000001faef25dec4fbcf906e6242621df2c183bf232f263d0ba5b101911e4563, ver=1, hashPrevBlock=0000000000000000000000000000000000000000000000000000000000000000, hashMerkleRoot=12630d16a97f24b287c8c2594dda5fb98c9e6c70fc61d44191931ea2aa08dc90, nTime=1393221600, nBits=1e0fffff, nNonce=164482, vtx=1, vchBlockSig=) - * Coinbase(hash=12630d16a9, ver=1, nTime=1393221600, vin.size=1, vout.size=1, nLockTime=0) - * CTxIn(COutPoint(0000000000, 4294967295), coinbase 00012a24323020466562203230313420426974636f696e2041544d7320636f6d6520746f20555341) - * CTxOut(empty) - * vMerkleTree: 12630d16a9 */ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { @@ -82,8 +93,8 @@ public: consensus.nTargetTimespan = 16 * 60; // 16 mins consensus.nTargetSpacingV1 = 60; consensus.nTargetSpacing = 64; - consensus.BIP34Height = 227931; - consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); + consensus.BIP34Height = -1; + consensus.BIP34Hash = uint256(); consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 @@ -92,10 +103,10 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // Deployment of BIP68, BIP112, and BIP113. -// consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; -// consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 999999999999ULL; // never -// consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 0; // out of time +// Deployment of BIP68, BIP112, and BIP113. +// consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; +// consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 999999999999ULL; // never +// consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 0; // out of time consensus.nProtocolV1RetargetingFixedTime = 1395631999; consensus.nProtocolV2Time = 1407053625; @@ -120,17 +131,6 @@ public: nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 100000; - /** - * 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=000001faef25dec4fbcf906e6242621df2c183bf232f263d0ba5b101911e4563, ver=1, hashPrevBlock=0000000000000000000000000000000000000000000000000000000000000000, hashMerkleRoot=12630d16a97f24b287c8c2594dda5fb98c9e6c70fc61d44191931ea2aa08dc90, nTime=1393221600, nBits=1e0fffff, nNonce=164482, vtx=1, vchBlockSig=) - * Coinbase(hash=12630d16a9, ver=1, nTime=1393221600, vin.size=1, vout.size=1, nLockTime=0) - * CTxIn(COutPoint(0000000000, 4294967295), coinbase 00012a24323020466562203230313420426974636f696e2041544d7320636f6d6520746f20555341) - * CTxOut(empty) - * vMerkleTree: 12630d16a9 - */ const char* pszTimestamp = "20 Feb 2014 Bitcoin ATMs come to USA"; CMutableTransaction txNew; txNew.nTime = 1393221600; @@ -184,23 +184,36 @@ public: static CMainParams mainParams; /** - * Testnet (v3) + * Testnet */ class CTestNetParams : public CChainParams { public: CTestNetParams() { strNetworkID = "test"; + consensus.nMaxReorganizationDepth = 50; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 100; - consensus.BIP34Height = 21111; - consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.posLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.posLimitV2 = uint256S("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.nTargetTimespan = 16 * 60; // 16 mins + consensus.nTargetSpacingV1 = 60; + consensus.nTargetSpacing = 64; + consensus.BIP34Height = -1; + consensus.BIP34Hash = uint256(); consensus.fPowAllowMinDifficultyBlocks = true; - consensus.nProtocolV1RetargetingFixedTime = 0; - consensus.nProtocolV2Time = 0; - consensus.nProtocolV3Time = 0; + consensus.fPowNoRetargeting = false; + + consensus.nProtocolV1RetargetingFixedTime = 1395631999; + consensus.nProtocolV2Time = 1407053625; + consensus.nProtocolV3Time = 1444028400; consensus.nLastPOWBlock = 0x7fffffff; + consensus.nStakeTimestampMask = 0xf; // 15 + consensus.nCoinbaseMaturity = 50; + consensus.nStakeMinConfirmations = 50; + consensus.nStakeMinAge = 1 * 60 * 60; // 1 hour + pchMessageStart[0] = 0xcd; pchMessageStart[1] = 0xf2; pchMessageStart[2] = 0xc0; @@ -210,15 +223,13 @@ public: nMaxTipAge = 0x7fffffff; nPruneAfterHeight = 1000; - genesis = CreateGenesisBlock(1411111111, 216178, 0x1f00ffff, 2, 50 * COIN); + genesis = CreateGenesisBlock(1393221600, 216178, 0x1f00ffff, 1, 0); consensus.hashGenesisBlock = genesis.GetHash(); - + assert(consensus.hashGenesisBlock == uint256S("0x0000724595fb3b9609d441cbfb9577615c292abf07d996d3edabc48de843642d")); + assert(genesis.hashMerkleRoot == uint256S("0x12630d16a97f24b287c8c2594dda5fb98c9e6c70fc61d44191931ea2aa08dc90")); vFixedSeeds.clear(); vSeeds.clear(); - vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org")); - vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me")); - vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de")); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,111); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,196); @@ -236,7 +247,7 @@ public: checkpointData = (CCheckpointData) { boost::assign::map_list_of - ( 0, uint256S("0x0000724595fb3b9609d441cbfb9577615c292abf07d996d3edabc48de843642d")), + ( 0, uint256S("0x0000724595fb3b9609d441cbfb9577615c292abf07d996d3edabc48de843642d")), 0, 0, 0 From 6229258723c1d11eb61f2e4f1f99749804356461 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 5 Jan 2016 15:58:48 -0500 Subject: [PATCH 002/110] c++11: detect and correct for boost builds with an incompatible abi This is ugly, but temporary. boost::filesystem will likely be dropped soon after c++11 is enabled. Otherwise, we could simply roll our own copy_file. I've fixed this at the buildsystem level for now in order to avoid mixing in functional changes. Explanation: If boost (prior to 1.57) was built without c++11, it emulated scoped enums using c++98 constructs. Unfortunately, this implementation detail leaked into the abi. This was fixed in 1.57. When building against that installed version using c++11, the headers pick up on the native c++11 scoped enum support and enable it, however it will fail to link. This can be worked around by disabling c++11 scoped enums if linking will fail. Add an autoconf test to determine incompatibility. At build-time, if native enums are being used (a c++11 build), and force-disabling them causes a successful link, we can be sure that there's an incompatibility and enable the work-around. --- configure.ac | 25 +++++++++++++++++++++++++ src/wallet/walletdb.cpp | 6 ++++++ 2 files changed, 31 insertions(+) diff --git a/configure.ac b/configure.ac index 7731eaac5..de7ac947b 100644 --- a/configure.ac +++ b/configure.ac @@ -639,6 +639,31 @@ if test x$use_boost = xyes; then BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB" +TEMP_LIBS="$LIBS" +LIBS="$BOOST_LIBS $LIBS" +TEMP_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +AC_MSG_CHECKING([for mismatched boost c++11 scoped enums]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include "boost/config.hpp" + #include "boost/version.hpp" + #if !defined(BOOST_NO_SCOPED_ENUMS) && !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && BOOST_VERSION < 105700 + #define BOOST_NO_SCOPED_ENUMS + #define BOOST_NO_CXX11_SCOPED_ENUMS + #define CHECK + #endif + #include "boost/filesystem.hpp" + ]],[[ + #if defined(CHECK) + boost::filesystem::copy_file("foo", "bar"); + #else + choke; + #endif + ]])], + [AC_MSG_RESULT(mismatched); AC_DEFINE(FORCE_BOOST_EMULATED_SCOPED_ENUMS, 1, [Define this symbol if boost scoped enums are emulated])], [AC_MSG_RESULT(ok)]) +LIBS="$TEMP_LIBS" +CPPFLAGS="$TEMP_CPPFLAGS" + dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if dnl a working version is available, else fall back to sleep. sleep was removed diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index c739c5f9a..7be8d5bab 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -15,6 +15,12 @@ #include "utiltime.h" #include "wallet/wallet.h" +#if defined(FORCE_BOOST_EMULATED_SCOPED_ENUMS) +#define BOOST_NO_SCOPED_ENUMS +#define BOOST_NO_CXX11_SCOPED_ENUMS +#endif + +#include #include #include #include From 2579687f83363f3e1640bdd6671cad75c9e44b78 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 5 Jan 2016 16:10:13 -0500 Subject: [PATCH 003/110] c++11: don't throw from the reverselock destructor noexcept is default for destructors as of c++11. By throwing in reverselock's destructor if it's lock has been tampered with, the likely result is std::terminate being called. Indeed that happened before this change. Once reverselock has taken another lock (its ctor didn't throw), it makes no sense to try to grab or lock the parent lock. That is be broken/undefined behavior depending on the parent lock's implementation, but it shouldn't cause the reverselock to fail to re-lock when destroyed. To avoid those problems, simply swap the parent lock's contents with a dummy for the duration of the lock. That will ensure that any undefined behavior is caught at the call-site rather than the reverse lock's destruction. Barring a failed mutex unlock which would be indicative of a larger problem, the destructor should now never throw. --- src/reverselock.h | 5 ++++- src/test/reverselock_tests.cpp | 16 ++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/reverselock.h b/src/reverselock.h index 567636e16..fac1ccb79 100644 --- a/src/reverselock.h +++ b/src/reverselock.h @@ -15,10 +15,12 @@ public: explicit reverse_lock(Lock& lock) : lock(lock) { lock.unlock(); + lock.swap(templock); } ~reverse_lock() { - lock.lock(); + templock.lock(); + templock.swap(lock); } private: @@ -26,6 +28,7 @@ private: reverse_lock& operator=(reverse_lock const&); Lock& lock; + Lock templock; }; #endif // BITCOIN_REVERSELOCK_H diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index e7e627ae0..8bdff9700 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -42,22 +42,18 @@ BOOST_AUTO_TEST_CASE(reverselock_errors) BOOST_CHECK(failed); BOOST_CHECK(!lock.owns_lock()); - // Make sure trying to lock a lock after it has been reverse locked fails - failed = false; - bool locked = false; + // Locking the original lock after it has been taken by a reverse lock + // makes no sense. Ensure that the original lock no longer owns the lock + // after giving it to a reverse one. lock.lock(); BOOST_CHECK(lock.owns_lock()); - - try { + { reverse_lock > rlock(lock); - lock.lock(); - locked = true; - } catch(...) { - failed = true; + BOOST_CHECK(!lock.owns_lock()); } - BOOST_CHECK(locked && failed); + BOOST_CHECK(failed); BOOST_CHECK(lock.owns_lock()); } From e013f503975df66bd3b513f81ff3a5d7d54947d4 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 5 Jan 2016 16:25:42 -0500 Subject: [PATCH 004/110] c++11: CAccountingEntry must be defined before use in a list --- src/wallet/wallet.h | 163 ++++++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 83 deletions(-) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 159cb9806..21a1a3b69 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -68,7 +68,6 @@ static const bool DEFAULT_USE_HD_WALLET = true; extern const char * DEFAULT_WALLET_DAT; -class CAccountingEntry; class CBlockIndex; class CCoinControl; class COutput; @@ -466,6 +465,86 @@ public: } }; +/** + * Internal transfers. + * Database key is acentry. + */ +class CAccountingEntry +{ +public: + std::string strAccount; + CAmount nCreditDebit; + int64_t nTime; + std::string strOtherAccount; + std::string strComment; + mapValue_t mapValue; + int64_t nOrderPos; //! position in ordered transaction list + uint64_t nEntryNo; + + CAccountingEntry() + { + SetNull(); + } + + void SetNull() + { + nCreditDebit = 0; + nTime = 0; + strAccount.clear(); + strOtherAccount.clear(); + strComment.clear(); + nOrderPos = -1; + nEntryNo = 0; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + //! Note: strAccount is serialized as part of the key, not here. + READWRITE(nCreditDebit); + READWRITE(nTime); + READWRITE(LIMITED_STRING(strOtherAccount, 65536)); + + if (!ser_action.ForRead()) + { + WriteOrderPos(nOrderPos, mapValue); + + if (!(mapValue.empty() && _ssExtra.empty())) + { + CDataStream ss(nType, nVersion); + ss.insert(ss.begin(), '\0'); + ss << mapValue; + ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); + strComment.append(ss.str()); + } + } + + READWRITE(LIMITED_STRING(strComment, 65536)); + + size_t nSepPos = strComment.find("\0", 0, 1); + if (ser_action.ForRead()) + { + mapValue.clear(); + if (std::string::npos != nSepPos) + { + CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); + ss >> mapValue; + _ssExtra = std::vector(ss.begin(), ss.end()); + } + ReadOrderPos(nOrderPos, mapValue); + } + if (std::string::npos != nSepPos) + strComment.erase(nSepPos); + + mapValue.erase("n"); + } + +private: + std::vector _ssExtra; +}; /** @@ -907,87 +986,5 @@ public: } }; - - -/** - * Internal transfers. - * Database key is acentry. - */ -class CAccountingEntry -{ -public: - std::string strAccount; - CAmount nCreditDebit; - int64_t nTime; - std::string strOtherAccount; - std::string strComment; - mapValue_t mapValue; - int64_t nOrderPos; //! position in ordered transaction list - uint64_t nEntryNo; - - CAccountingEntry() - { - SetNull(); - } - - void SetNull() - { - nCreditDebit = 0; - nTime = 0; - strAccount.clear(); - strOtherAccount.clear(); - strComment.clear(); - nOrderPos = -1; - nEntryNo = 0; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - //! Note: strAccount is serialized as part of the key, not here. - READWRITE(nCreditDebit); - READWRITE(nTime); - READWRITE(LIMITED_STRING(strOtherAccount, 65536)); - - if (!ser_action.ForRead()) - { - WriteOrderPos(nOrderPos, mapValue); - - if (!(mapValue.empty() && _ssExtra.empty())) - { - CDataStream ss(nType, nVersion); - ss.insert(ss.begin(), '\0'); - ss << mapValue; - ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); - strComment.append(ss.str()); - } - } - - READWRITE(LIMITED_STRING(strComment, 65536)); - - size_t nSepPos = strComment.find("\0", 0, 1); - if (ser_action.ForRead()) - { - mapValue.clear(); - if (std::string::npos != nSepPos) - { - CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); - ss >> mapValue; - _ssExtra = std::vector(ss.begin(), ss.end()); - } - ReadOrderPos(nOrderPos, mapValue); - } - if (std::string::npos != nSepPos) - strComment.erase(nSepPos); - - mapValue.erase("n"); - } - -private: - std::vector _ssExtra; -}; bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, int64_t nTime, const COutPoint& prevout, int64_t* pBlockTime = NULL); #endif // BITCOIN_WALLET_WALLET_H From a5cb91308195e4fe9be2ce59ec7e1a76101d5c4e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 8 Jan 2016 13:31:55 -0500 Subject: [PATCH 005/110] c++11: add scoped enum fallbacks to CPPFLAGS rather than defining them locally Due to include ordering, defining in one place was not enough to ensure correct usage. Use global defines so that we don't have to worry abou this ordering. Also add a comment in configure about the test. --- configure.ac | 13 ++++++++++++- src/wallet/walletdb.cpp | 5 ----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index de7ac947b..b96feab3b 100644 --- a/configure.ac +++ b/configure.ac @@ -639,6 +639,17 @@ if test x$use_boost = xyes; then BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB" + +dnl If boost (prior to 1.57) was built without c++11, it emulated scoped enums +dnl using c++98 constructs. Unfortunately, this implementation detail leaked into +dnl the abi. This was fixed in 1.57. + +dnl When building against that installed version using c++11, the headers pick up +dnl on the native c++11 scoped enum support and enable it, however it will fail to +dnl link. This can be worked around by disabling c++11 scoped enums if linking will +dnl fail. +dnl BOOST_NO_SCOPED_ENUMS was changed to BOOST_NO_CXX11_SCOPED_ENUMS in 1.51. + TEMP_LIBS="$LIBS" LIBS="$BOOST_LIBS $LIBS" TEMP_CPPFLAGS="$CPPFLAGS" @@ -660,7 +671,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ choke; #endif ]])], - [AC_MSG_RESULT(mismatched); AC_DEFINE(FORCE_BOOST_EMULATED_SCOPED_ENUMS, 1, [Define this symbol if boost scoped enums are emulated])], [AC_MSG_RESULT(ok)]) + [AC_MSG_RESULT(mismatched); BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS"], [AC_MSG_RESULT(ok)]) LIBS="$TEMP_LIBS" CPPFLAGS="$TEMP_CPPFLAGS" diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7be8d5bab..b2e963263 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -15,11 +15,6 @@ #include "utiltime.h" #include "wallet/wallet.h" -#if defined(FORCE_BOOST_EMULATED_SCOPED_ENUMS) -#define BOOST_NO_SCOPED_ENUMS -#define BOOST_NO_CXX11_SCOPED_ENUMS -#endif - #include #include #include From 2bebba5a0e233480c693b42898883d5e583a3942 Mon Sep 17 00:00:00 2001 From: fanquake Date: Sat, 30 Jan 2016 10:10:11 +0800 Subject: [PATCH 006/110] Use Debian 8.3 in gitian build guide Add instructions to clone the gitian.sigs repo --- doc/gitian-building.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/gitian-building.md b/doc/gitian-building.md index e3fb94438..5ca91505e 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -74,11 +74,11 @@ In the VirtualBox GUI click "Create" and choose the following parameters in the - File location and size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side - Click `Create` -Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.2.0/amd64/iso-cd/debian-8.2.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). +Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.3.0/amd64/iso-cd/debian-8.3.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). This DVD image can be validated using a SHA256 hashing tool, for example on Unixy OSes by entering the following in a terminal: - echo "d393d17ac6b3113c81186e545c416a00f28ed6e05774284bb5e8f0df39fcbcb9 debian-8.2.0-amd64-netinst.iso" | sha256sum -c + echo "dd25bcdde3c6ea5703cc0f313cde621b13d42ff7d252e2538a11663c93bf8654 debian-8.3.0-amd64-netinst.iso" | sha256sum -c # (must return OK) After creating the VM, we need to configure it. @@ -305,6 +305,7 @@ Clone the git repositories for bitcoin and Gitian. ```bash git clone https://github.com/devrandom/gitian-builder.git git clone https://github.com/bitcoin/bitcoin +git clone https://github.com/bitcoin/gitian.sigs.git ``` Setting up the Gitian image From 6e4270f333cd30e16f0fb944274163c86e460bf4 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 15 Jan 2016 04:34:02 +0000 Subject: [PATCH 007/110] Bugfix: The var is LIBUNIVALUE,not LIBBITCOIN_UNIVALUE --- src/Makefile.bench.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index d660a3a74..00a80ae81 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -14,7 +14,7 @@ bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bench_bench_bitcoin_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UNIVALUE) \ + $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ From d4251e1075f65c02d108a5a0227f9bbc661618fa Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 14 Jan 2016 00:26:23 +0000 Subject: [PATCH 008/110] Build against system UniValue when available --- configure.ac | 50 ++++++++++++++++++++++++++++++++++++++- src/Makefile.am | 19 ++++++++++----- src/Makefile.test.include | 2 ++ 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index b96feab3b..e8155229a 100644 --- a/configure.ac +++ b/configure.ac @@ -165,6 +165,12 @@ AC_ARG_ENABLE([glibc-back-compat], [use_glibc_compat=$enableval], [use_glibc_compat=no]) +AC_ARG_WITH([system-univalue], + [AS_HELP_STRING([--without-system-univalue], + [Build with system UniValue (default is auto)])], + [system_univalue=$withval], + [system_univalue=auto] +) AC_ARG_ENABLE([zmq], [AS_HELP_STRING([--disable-zmq], [disable ZMQ notifications])], @@ -807,6 +813,44 @@ if test "x$use_zmq" = "xyes"; then fi fi +dnl univalue check + +if test x$system_univalue != xno ; then + found_univalue=no + if test x$use_pkgconfig = xyes; then + : #NOP + m4_ifdef( + [PKG_CHECK_MODULES], + [ + PKG_CHECK_MODULES([UNIVALUE],[libunivalue],[found_univalue=yes],[true]) + ] + ) + else + AC_CHECK_HEADER([univalue.h],[ + AC_CHECK_LIB([univalue], [main],[ + UNIVALUE_LIBS=-lunivalue + found_univalue=yes + ],[true]) + ],[true]) + fi + + if test x$found_univalue = xyes ; then + system_univalue=yes + elif test x$system_univalue = xyes ; then + AC_MSG_ERROR([univalue not found]) + else + system_univalue=no + fi +fi + +if test x$system_univalue = xno ; then + UNIVALUE_CFLAGS='-I$(srcdir)/univalue/include' + UNIVALUE_LIBS='univalue/libunivalue.la' +fi +AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$system_univalue = xno]) +AC_SUBST(UNIVALUE_CFLAGS) +AC_SUBST(UNIVALUE_LIBS) + CXXFLAGS_TEMP="$CXXFLAGS" LIBS_TEMP="$LIBS" CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" @@ -1022,8 +1066,12 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" +if test x$system_univalue = xno; then + AC_CONFIG_SUBDIRS([src/univalue]) +fi + ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" -AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) +AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 13e4e778a..138bd297f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,10 +1,21 @@ -DIST_SUBDIRS = secp256k1 univalue +DIST_SUBDIRS = secp256k1 AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(HARDENED_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = +if EMBEDDED_UNIVALUE +DIST_SUBDIRS += univalue + +LIBUNIVALUE = univalue/libunivalue.la + +$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +else +LIBUNIVALUE = $(UNIVALUE_LIBS) +endif + if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv @@ -24,7 +35,7 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include -BITCOIN_INCLUDES += -I$(srcdir)/univalue/include +BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) LIBBITCOIN_SERVER=libbitcoin_server.a @@ -34,7 +45,6 @@ LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBUNIVALUE=univalue/libunivalue.la if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a @@ -48,9 +58,6 @@ endif $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) - -$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 8e5e15e7b..6685e260c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -134,7 +134,9 @@ if ENABLE_WALLET $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/wallet-utility.py endif $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check +if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check +endif %.json.h: %.json @$(MKDIR_P) $(@D) From 473a292addda37c3518042ed9218f7e8706afe6d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 15 Jan 2016 02:19:28 +0000 Subject: [PATCH 009/110] doc: Add UniValue to build instructions --- doc/build-unix.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/build-unix.md b/doc/build-unix.md index 1da84dc2f..1d63fb008 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -46,6 +46,7 @@ Optional dependencies: qt | GUI | GUI toolkit (only needed when GUI enabled) protobuf | Payments in GUI | Data interchange format used for payment protocol (only needed when GUI enabled) libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled) + univalue | Utility | JSON parsing and encoding (if missing, bundled version will be used) libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.x) For the versions used in the release, see [release-process.md](release-process.md) under *Fetch and build inputs*. From 7ea8a49f711aab8f4425021b7e26f0f26f31132d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 28 Jan 2016 05:31:41 +0000 Subject: [PATCH 010/110] Change default configure option --with-system-univalue to "no" --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index e8155229a..8e727101b 100644 --- a/configure.ac +++ b/configure.ac @@ -166,10 +166,10 @@ AC_ARG_ENABLE([glibc-back-compat], [use_glibc_compat=no]) AC_ARG_WITH([system-univalue], - [AS_HELP_STRING([--without-system-univalue], - [Build with system UniValue (default is auto)])], + [AS_HELP_STRING([--with-system-univalue], + [Build with system UniValue (default is no)])], [system_univalue=$withval], - [system_univalue=auto] + [system_univalue=no] ) AC_ARG_ENABLE([zmq], [AS_HELP_STRING([--disable-zmq], From e5692bc4cbb3ba39b0bb42605f6cc8b93f959b5f Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sun, 31 Jan 2016 02:32:00 +0000 Subject: [PATCH 011/110] Bugfix: Always include univalue in DIST_SUBDIRS --- src/Makefile.am | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 138bd297f..2055249ee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -DIST_SUBDIRS = secp256k1 +DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(HARDENED_CXXFLAGS) @@ -6,8 +6,6 @@ AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = if EMBEDDED_UNIVALUE -DIST_SUBDIRS += univalue - LIBUNIVALUE = univalue/libunivalue.la $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) From 598c291182937932dd41b3276c5798bd4d1d6893 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sun, 31 Jan 2016 02:32:55 +0000 Subject: [PATCH 012/110] LDADD dependency order shuffling --- src/Makefile.bench.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 00a80ae81..7062dd62e 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -14,12 +14,12 @@ bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bench_bench_bitcoin_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ - $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ $(LIBMEMENV) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBUNIVALUE) if ENABLE_ZMQ bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) From 3d698b1f49469bf31a14fe172c2da621a477950a Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 1 Feb 2016 18:49:24 +0000 Subject: [PATCH 013/110] build-unix: Update UniValue build conditions --- doc/build-unix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build-unix.md b/doc/build-unix.md index 1d63fb008..d1e58f3be 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -46,7 +46,7 @@ Optional dependencies: qt | GUI | GUI toolkit (only needed when GUI enabled) protobuf | Payments in GUI | Data interchange format used for payment protocol (only needed when GUI enabled) libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled) - univalue | Utility | JSON parsing and encoding (if missing, bundled version will be used) + univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.x) For the versions used in the release, see [release-process.md](release-process.md) under *Fetch and build inputs*. From 429502e33423f914c258ccbbeeedaa48b957cb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20G=2E=20Aragoneses?= Date: Sat, 13 Feb 2016 04:44:42 +0800 Subject: [PATCH 014/110] autogen.sh: warn about needing autoconf if autoreconf is not found Changes the error message from: ./autogen.sh: 9: ./autogen.sh: autoreconf: not found To: configuration failed, please install autoconf first --- autogen.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/autogen.sh b/autogen.sh index 3e26a1830..46e36ff5b 100755 --- a/autogen.sh +++ b/autogen.sh @@ -6,4 +6,6 @@ if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then LIBTOOLIZE="${GLIBTOOLIZE}" export LIBTOOLIZE fi +which autoreconf >/dev/null || \ + (echo "configuration failed, please install autoconf first" && exit 1) autoreconf --install --force --warnings=all From 69a14ff63aaa64bbea748c101466371a1db8c153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Wed, 10 Feb 2016 21:03:51 +0100 Subject: [PATCH 015/110] make clean should clean .a files --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index 2055249ee..d25d04b8c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -485,6 +485,7 @@ CTAES_DIST += crypto/ctaes/README.md CTAES_DIST += crypto/ctaes/test.c CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a +CLEANFILES += $(EXTRA_LIBRARIES) CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno From 36362fecef2a412f249b679e4f99095b336e43e3 Mon Sep 17 00:00:00 2001 From: BtcDrak Date: Sat, 27 Feb 2016 21:06:21 +0000 Subject: [PATCH 016/110] Add missing sudo entry in gitian VM setup. [ci skip] --- doc/gitian-building.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 5ca91505e..77882a1b9 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -262,6 +262,7 @@ Then set up LXC and the rest with the following, which is a complex jumble of se # the version of lxc-start in Debian needs to run as root, so make sure # that the build script can execute it without providing a password echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-start" > /etc/sudoers.d/gitian-lxc +echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-execute" >> /etc/sudoers.d/gitian-lxc # make /etc/rc.local script that sets up bridge between guest and host echo '#!/bin/sh -e' > /etc/rc.local echo 'brctl addbr br0' >> /etc/rc.local From 929c0287d5ec8271534ac3dd4a1c2fd42349b839 Mon Sep 17 00:00:00 2001 From: BtcDrak Date: Wed, 9 Mar 2016 09:20:16 +0000 Subject: [PATCH 017/110] Add curl to Gitian setup instrustions curl is required to fetch dependencies [ci skip] --- doc/gitian-building.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 77882a1b9..54993d13a 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -252,7 +252,7 @@ First we need to log in as `root` to set up dependencies and make sure that our user can use the sudo command. Type/paste the following in the terminal: ```bash -apt-get install git ruby sudo apt-cacher-ng qemu-utils debootstrap lxc python-cheetah parted kpartx bridge-utils make ubuntu-archive-keyring +apt-get install git ruby sudo apt-cacher-ng qemu-utils debootstrap lxc python-cheetah parted kpartx bridge-utils make ubuntu-archive-keyring curl adduser debian sudo ``` From bc7543731f6496a8822c2ae09512e99ec746e411 Mon Sep 17 00:00:00 2001 From: fanquake Date: Sat, 19 Mar 2016 15:24:00 +0800 Subject: [PATCH 018/110] [build-aux] Update Boost & check macros to latest serials --- build-aux/m4/ax_boost_base.m4 | 20 +- build-aux/m4/ax_boost_program_options.m4 | 7 +- build-aux/m4/ax_boost_system.m4 | 5 +- build-aux/m4/ax_check_compile_flag.m4 | 12 +- build-aux/m4/ax_check_link_flag.m4 | 13 +- build-aux/m4/ax_check_preproc_flag.m4 | 12 +- build-aux/m4/ax_gcc_func_attribute.m4 | 8 +- build-aux/m4/ax_pthread.m4 | 505 +++++++++++++++-------- 8 files changed, 379 insertions(+), 203 deletions(-) diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 index 3f24d5ddc..45d948933 100644 --- a/build-aux/m4/ax_boost_base.m4 +++ b/build-aux/m4/ax_boost_base.m4 @@ -33,7 +33,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 23 +#serial 26 AC_DEFUN([AX_BOOST_BASE], [ @@ -95,8 +95,8 @@ if test "x$want_boost" = "xyes"; then x86_64) libsubdirs="lib64 libx32 lib lib64" ;; - ppc64|s390x|sparc64|aarch64) - libsubdirs="lib64 lib lib64" + ppc64|s390x|sparc64|aarch64|ppc64le) + libsubdirs="lib64 lib lib64 ppc64le" ;; esac @@ -170,7 +170,7 @@ if test "x$want_boost" = "xyes"; then AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) @@ -179,6 +179,10 @@ if test "x$want_boost" = "xyes"; then dnl if we found no boost with system layout we search for boost libraries dnl built and installed without the --layout=system option or for a staged(not installed) version if test "x$succeeded" != "xyes"; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + BOOST_LDFLAGS= _version=0 if test "$ac_boost_path" != ""; then if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then @@ -191,6 +195,12 @@ if test "x$want_boost" = "xyes"; then VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then + BOOST_CPPFLAGS="-I$ac_boost_path" + fi + fi fi else if test "$cross_compiling" != yes; then @@ -253,7 +263,7 @@ if test "x$want_boost" = "xyes"; then AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) fi diff --git a/build-aux/m4/ax_boost_program_options.m4 b/build-aux/m4/ax_boost_program_options.m4 index f59144185..2bdb59371 100644 --- a/build-aux/m4/ax_boost_program_options.m4 +++ b/build-aux/m4/ax_boost_program_options.m4 @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 22 +#serial 24 AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], [ @@ -63,9 +63,9 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_CACHE_CHECK([whether the Boost::Program_Options library is available], ax_cv_boost_program_options, [AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::program_options::options_description generic("Generic options"); + [[boost::program_options::error err("Error message"); return 0;]])], ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no) AC_LANG_POP([C++]) @@ -74,7 +74,6 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` if test "x$ax_boost_user_program_options_lib" = "x"; then - ax_lib= for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, diff --git a/build-aux/m4/ax_boost_system.m4 b/build-aux/m4/ax_boost_system.m4 index 9c78280fc..1c05450cb 100644 --- a/build-aux/m4/ax_boost_system.m4 +++ b/build-aux/m4/ax_boost_system.m4 @@ -31,7 +31,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 17 +#serial 18 AC_DEFUN([AX_BOOST_SYSTEM], [ @@ -68,9 +68,10 @@ AC_DEFUN([AX_BOOST_SYSTEM], ax_cv_boost_system, [AC_LANG_PUSH([C++]) CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS= AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::system::system_category]])], + [[boost::system::error_category *a = 0;]])], ax_cv_boost_system=yes, ax_cv_boost_system=no) CXXFLAGS=$CXXFLAGS_SAVE AC_LANG_POP([C++]) diff --git a/build-aux/m4/ax_check_compile_flag.m4 b/build-aux/m4/ax_check_compile_flag.m4 index c3a8d695a..ca3639715 100644 --- a/build-aux/m4/ax_check_compile_flag.m4 +++ b/build-aux/m4/ax_check_compile_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_COMPILE_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4 index e2d0d363e..eb01a6ce1 100644 --- a/build-aux/m4/ax_check_link_flag.m4 +++ b/build-aux/m4/ax_check_link_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # @@ -53,18 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_LINK_FLAG], -[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" - AC_LINK_IFELSE([AC_LANG_PROGRAM()], + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_preproc_flag.m4 b/build-aux/m4/ax_check_preproc_flag.m4 index b1cfef6b8..ca1d5ee2b 100644 --- a/build-aux/m4/ax_check_preproc_flag.m4 +++ b/build-aux/m4/ax_check_preproc_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # "CPPFLAGS EXTRA-FLAGS FLAG". This can for example be used to force the # preprocessor to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_PREPROC_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{COMPILE,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_PREPROC_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]cppflags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG preprocessor accepts $1], CACHEVAR, [ ax_check_save_flags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $4 $1" - AC_PREPROC_IFELSE([AC_LANG_PROGRAM()], + AC_PREPROC_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) CPPFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_gcc_func_attribute.m4 b/build-aux/m4/ax_gcc_func_attribute.m4 index 275ca63a2..c788ca9bd 100644 --- a/build-aux/m4/ax_gcc_func_attribute.m4 +++ b/build-aux/m4/ax_gcc_func_attribute.m4 @@ -31,6 +31,7 @@ # cold # const # constructor +# constructor_priority for constructor attribute with priority # deprecated # destructor # dllexport @@ -73,7 +74,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 2 +#serial 3 AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) @@ -103,6 +104,9 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [const], [ int foo( void ) __attribute__(($1)); ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], [constructor], [ int foo( void ) __attribute__(($1)); ], @@ -180,6 +184,8 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [visibility], [ int foo_def( void ) __attribute__(($1("default"))); int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); ], [warning], [ int foo( void ) __attribute__(($1(""))); diff --git a/build-aux/m4/ax_pthread.m4 b/build-aux/m4/ax_pthread.m4 index d383ad5c6..d218d1af7 100644 --- a/build-aux/m4/ax_pthread.m4 +++ b/build-aux/m4/ax_pthread.m4 @@ -19,10 +19,10 @@ # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, -# but also link it with them as well. e.g. you should link with +# but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # -# If you are only building threads programs, you may wish to use these +# If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" @@ -30,8 +30,8 @@ # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name -# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with @@ -82,35 +82,40 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 21 +#serial 22 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). +# requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test x"$ax_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -123,7 +128,7 @@ fi # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: @@ -132,186 +137,334 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case ${host_os} in - solaris*) +case $host_os in - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: + freebsd*) - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" - ;; + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) - darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; esac -# Clang doesn't consider unrecognized options an error unless we specify -# -Werror. We throw in some extra Clang-specific options to ensure that -# this doesn't happen for GCC, which also accepts -Werror. +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) -AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) -save_CFLAGS="$CFLAGS" -ax_pthread_extra_flags="-Werror" -CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], - [AC_MSG_RESULT([yes])], - [ax_pthread_extra_flags= - AC_MSG_RESULT([no])]) -CFLAGS="$save_CFLAGS" +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; + aix* | freebsd*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac +# Are we compiling with Clang? - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) +ax_pthread_clang_warning=no - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = xyes; then - break; - fi +if test "x$ax_pthread_clang" = "xyes"; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" done fi # Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $attr; return attr /* ; */])], - [attr_name=$attr; break], - []) - done - AC_MSG_RESULT([$attr_name]) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case ${host_os} in - aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; - osf* | hpux*) flag="-D_REENTRANT";; - solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - # TODO: What about Clang on Solaris? - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT([$flag]) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - # More AIX lossage: compile with *_r variant - if test "x$GCC" != xyes; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" @@ -321,12 +474,12 @@ AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : else - ax_pthread_ok=no - $2 + ax_pthread_ok=no + $2 fi AC_LANG_POP ])dnl AX_PTHREAD From 4e459ffc7b70eca8c7e681597bba00cf2628d0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Sat, 2 Apr 2016 16:32:42 +0200 Subject: [PATCH 019/110] Use relative paths instead of absolute paths --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index d25d04b8c..e0789d35a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -532,7 +532,7 @@ endif %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) - $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $( Date: Fri, 26 Feb 2016 00:04:48 +0000 Subject: [PATCH 020/110] build: Use PACKAGE_TARNAME and new bin names in NSIS script. Replaces the hardcoded string "bitcoin" with the autoconf variable PACKAGE_TARNAME; fixes #7265. Places where I chose not to replace: 1. bitcoin.ico wasn't replaced because it doesn't seem to be relevant to the build system and its filename never affects the end user. 2. InstallDir wasn't replaced because the current text has an uppercase B, and I'm not sure of a good way to capitalize the result of PACKAGE_TARNAME. 3. A comment in the Main Installer section wasn't replaced because comments don't ever face the end user. 4. The registry value "URL:Bitcoin" wasn't replaced for the same reason as InstallDir. 5. Startup shortcut wasn't replaced for the same reason as InstallDir. All other appearances of "bitcoin" were replaced with PACKAGE_TARNAME, except for the bin names, which were instead replaced with the new bin name autoconf variables. --- share/setup.nsi.in | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 62db88c27..62081b5b3 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -20,7 +20,7 @@ SetCompressor /SOLID lzma !define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY} !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup !define MUI_STARTMENUPAGE_DEFAULTFOLDER "@PACKAGE_NAME@" -!define MUI_FINISHPAGE_RUN $INSTDIR\bitcoin-qt.exe +!define MUI_FINISHPAGE_RUN $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" !define MUI_UNWELCOMEFINISHPAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp" !define MUI_UNFINISHPAGE_NOAUTOCLOSE @@ -48,7 +48,7 @@ Var StartMenuGroup !insertmacro MUI_LANGUAGE English # Installer attributes -OutFile @abs_top_srcdir@/bitcoin-${VERSION}-win@WINDOWS_BITS@-setup.exe +OutFile @abs_top_srcdir@/@PACKAGE_TARNAME@-${VERSION}-win@WINDOWS_BITS@-setup.exe !if "@WINDOWS_BITS@" == "64" InstallDir $PROGRAMFILES64\Bitcoin !else @@ -73,19 +73,19 @@ ShowUninstDetails show Section -Main SEC0000 SetOutPath $INSTDIR SetOverwrite on - File @abs_top_srcdir@/release/bitcoin-qt.exe + File @abs_top_srcdir@/release/@BITCOIN_GUI_NAME@@EXEEXT@ File /oname=COPYING.txt @abs_top_srcdir@/COPYING File /oname=readme.txt @abs_top_srcdir@/doc/README_windows.txt SetOutPath $INSTDIR\daemon - File @abs_top_srcdir@/release/bitcoind.exe - File @abs_top_srcdir@/release/bitcoin-cli.exe + File @abs_top_srcdir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@ + File @abs_top_srcdir@/release/@BITCOIN_CLI_NAME@@EXEEXT@ SetOutPath $INSTDIR\doc File /r @abs_top_srcdir@/doc\*.* SetOutPath $INSTDIR WriteRegStr HKCU "${REGKEY}\Components" Main 1 # Remove old wxwidgets-based-bitcoin executable and locales: - Delete /REBOOTOK $INSTDIR\bitcoin.exe + Delete /REBOOTOK $INSTDIR\@PACKAGE_TARNAME@.exe RMDir /r /REBOOTOK $INSTDIR\locale SectionEnd @@ -95,7 +95,7 @@ Section -post SEC0001 WriteUninstaller $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory $SMPROGRAMS\$StartMenuGroup - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\bitcoin-qt.exe + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_END WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" @@ -106,10 +106,10 @@ Section -post SEC0001 WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1 WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1 - WriteRegStr HKCR "bitcoin" "URL Protocol" "" - WriteRegStr HKCR "bitcoin" "" "URL:Bitcoin" - WriteRegStr HKCR "bitcoin\DefaultIcon" "" $INSTDIR\bitcoin-qt.exe - WriteRegStr HKCR "bitcoin\shell\open\command" "" '"$INSTDIR\bitcoin-qt.exe" "%1"' + WriteRegStr HKCR "@PACKAGE_TARNAME@" "URL Protocol" "" + WriteRegStr HKCR "@PACKAGE_TARNAME@" "" "URL:Bitcoin" + WriteRegStr HKCR "@PACKAGE_TARNAME@\DefaultIcon" "" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ + WriteRegStr HKCR "@PACKAGE_TARNAME@\shell\open\command" "" '"$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "%1"' SectionEnd # Macro for selecting uninstaller sections @@ -127,7 +127,7 @@ done${UNSECTION_ID}: # Uninstaller sections Section /o -un.Main UNSEC0000 - Delete /REBOOTOK $INSTDIR\bitcoin-qt.exe + Delete /REBOOTOK $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ Delete /REBOOTOK $INSTDIR\COPYING.txt Delete /REBOOTOK $INSTDIR\readme.txt RMDir /r /REBOOTOK $INSTDIR\daemon @@ -147,7 +147,7 @@ Section -un.post UNSEC0001 DeleteRegValue HKCU "${REGKEY}" Path DeleteRegKey /IfEmpty HKCU "${REGKEY}\Components" DeleteRegKey /IfEmpty HKCU "${REGKEY}" - DeleteRegKey HKCR "bitcoin" + DeleteRegKey HKCR "@PACKAGE_TARNAME@" RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup RmDir /REBOOTOK $INSTDIR Push $R0 From 471706588c0e84f9cf6cd2b13ef5659308c98194 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 1 Apr 2016 12:19:28 -0400 Subject: [PATCH 021/110] build: define base filenames for use elsewhere in the buildsystem --- Makefile.am | 6 +++--- configure.ac | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 643e048d0..5dacbab6b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,9 +9,9 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libbitcoinconsensus.pc endif -BITCOIND_BIN=$(top_builddir)/src/lored$(EXEEXT) -BITCOIN_QT_BIN=$(top_builddir)/src/qt/lore-qt$(EXEEXT) -BITCOIN_CLI_BIN=$(top_builddir)/src/lore-cli$(EXEEXT) +BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) +BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT) +BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) WALLET_UTILITY_BIN=$(top_builddir)/src/wallet-utility$(EXEEXT) BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) diff --git a/configure.ac b/configure.ac index 8e727101b..5a29d67c0 100644 --- a/configure.ac +++ b/configure.ac @@ -12,6 +12,11 @@ AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) +BITCOIN_DAEMON_NAME=lored +BITCOIN_GUI_NAME=lore-qt +BITCOIN_CLI_NAME=lore-cli +BITCOIN_TX_NAME=lore-tx + AC_CANONICAL_HOST AH_TOP([#ifndef BITCOIN_CONFIG_H]) @@ -1025,6 +1030,10 @@ AC_SUBST(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD) AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) +AC_SUBST(BITCOIN_DAEMON_NAME) +AC_SUBST(BITCOIN_GUI_NAME) +AC_SUBST(BITCOIN_CLI_NAME) +AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) AC_SUBST(HARDENED_CXXFLAGS) AC_SUBST(HARDENED_CPPFLAGS) From 92412d41bff459224077e71cb9b6ffbda025e856 Mon Sep 17 00:00:00 2001 From: JeremyRand Date: Sat, 19 Mar 2016 11:19:06 +0000 Subject: [PATCH 022/110] Remove wxwidgets references from NSIS script. The NSIS script tried to delete wxwidgets-based executables/locales. These files are ancient, and presumably no users have them anymore, so we can simplify the NSIS script by removing those lines. --- share/setup.nsi.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 62081b5b3..676ea3cda 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -83,10 +83,6 @@ Section -Main SEC0000 File /r @abs_top_srcdir@/doc\*.* SetOutPath $INSTDIR WriteRegStr HKCU "${REGKEY}\Components" Main 1 - - # Remove old wxwidgets-based-bitcoin executable and locales: - Delete /REBOOTOK $INSTDIR\@PACKAGE_TARNAME@.exe - RMDir /r /REBOOTOK $INSTDIR\locale SectionEnd Section -post SEC0001 From f508e91677a2507775a1073332a5febbc529fc1d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 18 Apr 2016 14:03:53 +0200 Subject: [PATCH 023/110] test: move accounting_tests and rpc_wallet_tests to wallet/test --- src/{ => wallet}/test/accounting_tests.cpp | 0 src/{ => wallet}/test/rpc_wallet_tests.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/{ => wallet}/test/accounting_tests.cpp (100%) rename src/{ => wallet}/test/rpc_wallet_tests.cpp (100%) diff --git a/src/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp similarity index 100% rename from src/test/accounting_tests.cpp rename to src/wallet/test/accounting_tests.cpp diff --git a/src/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp similarity index 100% rename from src/test/rpc_wallet_tests.cpp rename to src/wallet/test/rpc_wallet_tests.cpp From 4d9bacf1ae9eac3859d9d0fc083a5e2c51929384 Mon Sep 17 00:00:00 2001 From: lateminer Date: Wed, 10 Jan 2018 00:01:51 +0300 Subject: [PATCH 024/110] Fix: test: move accounting_tests and rpc_wallet_tests to wallet/test --- src/Makefile.test.include | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 6685e260c..eb1f797c2 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -88,10 +88,10 @@ BITCOIN_TESTS =\ if ENABLE_WALLET BITCOIN_TESTS += \ - test/accounting_tests.cpp \ + wallet/test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ - wallet/test/crypto_tests.cpp \ - test/rpc_wallet_tests.cpp + wallet/test/rpc_wallet_tests.cpp \ + wallet/test/crypto_tests.cpp endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) From 8a0a14b77b429b61af3042efcf9854653d621168 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 18 Apr 2016 14:54:57 +0200 Subject: [PATCH 025/110] test: Create test fixture for wallet Removes all the `#ifdef ENABLE_WALLET` from `test_bitcoin` by making the wallet tests use their own fixture. --- src/Makefile.test.include | 2 ++ src/test/test_bitcoin.cpp | 23 -------------------- src/test/test_bitcoin.h | 3 +-- src/wallet/test/accounting_tests.cpp | 4 ++-- src/wallet/test/rpc_wallet_tests.cpp | 4 ++-- src/wallet/test/wallet_test_fixture.cpp | 28 +++++++++++++++++++++++++ src/wallet/test/wallet_test_fixture.h | 18 ++++++++++++++++ src/wallet/test/wallet_tests.cpp | 4 ++-- 8 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 src/wallet/test/wallet_test_fixture.cpp create mode 100644 src/wallet/test/wallet_test_fixture.h diff --git a/src/Makefile.test.include b/src/Makefile.test.include index eb1f797c2..20ebd5c29 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -88,6 +88,8 @@ BITCOIN_TESTS =\ if ENABLE_WALLET BITCOIN_TESTS += \ + wallet/test/wallet_test_fixture.cpp \ + wallet/test/wallet_test_fixture.h \ wallet/test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ wallet/test/rpc_wallet_tests.cpp \ diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index ddc14d219..0e179f5e7 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -20,10 +20,6 @@ #include "util.h" #include "rpc/server.h" #include "rpc/register.h" -#ifdef ENABLE_WALLET -#include "wallet/db.h" -#include "wallet/wallet.h" -#endif #include #include @@ -54,10 +50,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha // Ideally we'd move all the RPC tests to the functional testing framework // instead of unit tests, but for now we need these here. RegisterAllCoreRPCCommands(tableRPC); -#ifdef ENABLE_WALLET - bitdb.MakeMock(); - RegisterWalletRPCCommands(tableRPC); -#endif ClearDatadirCache(); pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); boost::filesystem::create_directories(pathTemp); @@ -66,12 +58,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); InitBlockIndex(chainparams); -#ifdef ENABLE_WALLET - bool fFirstRun; - pwalletMain = new CWallet("wallet.dat"); - pwalletMain->LoadWallet(fFirstRun); - RegisterValidationInterface(pwalletMain); -#endif nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); @@ -83,19 +69,10 @@ TestingSetup::~TestingSetup() UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); -#ifdef ENABLE_WALLET - UnregisterValidationInterface(pwalletMain); - delete pwalletMain; - pwalletMain = NULL; -#endif UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; delete pblocktree; -#ifdef ENABLE_WALLET - bitdb.Flush(true); - bitdb.Reset(); -#endif boost::filesystem::remove_all(pathTemp); } diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 37bcb9b57..7ec0af709 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -21,8 +21,7 @@ struct BasicTestingSetup { }; /** Testing setup that configures a complete environment. - * Included are data directory, coins database, script check threads - * and wallet (if enabled) setup. + * Included are data directory, coins database, script check threads setup. */ struct TestingSetup: public BasicTestingSetup { CCoinsViewDB *pcoinsdbview; diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp index dad191c68..d075b2b64 100644 --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -5,7 +5,7 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" -#include "test/test_bitcoin.h" +#include "wallet/test/wallet_test_fixture.h" #include @@ -14,7 +14,7 @@ extern CWallet* pwalletMain; -BOOST_FIXTURE_TEST_SUITE(accounting_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup) static void GetResults(CWalletDB& walletdb, std::map& results) diff --git a/src/wallet/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp index 3443be209..4e7d177f5 100644 --- a/src/wallet/test/rpc_wallet_tests.cpp +++ b/src/wallet/test/rpc_wallet_tests.cpp @@ -9,7 +9,7 @@ #include "main.h" #include "wallet/wallet.h" -#include "test/test_bitcoin.h" +#include "wallet/test/wallet_test_fixture.h" #include #include @@ -23,7 +23,7 @@ extern UniValue CallRPC(string args); extern CWallet* pwalletMain; -BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, WalletTestingSetup) BOOST_AUTO_TEST_CASE(rpc_addmultisig) { diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp new file mode 100644 index 000000000..837030096 --- /dev/null +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -0,0 +1,28 @@ +#include "wallet/test/wallet_test_fixture.h" + +#include "rpc/server.h" +#include "wallet/db.h" +#include "wallet/wallet.h" + +WalletTestingSetup::WalletTestingSetup(const std::string& chainName): + TestingSetup(chainName) +{ + bitdb.MakeMock(); + + bool fFirstRun; + pwalletMain = new CWallet("wallet.dat"); + pwalletMain->LoadWallet(fFirstRun); + RegisterValidationInterface(pwalletMain); + + RegisterWalletRPCCommands(tableRPC); +} + +WalletTestingSetup::~WalletTestingSetup() +{ + UnregisterValidationInterface(pwalletMain); + delete pwalletMain; + pwalletMain = NULL; + + bitdb.Flush(true); + bitdb.Reset(); +} diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h new file mode 100644 index 000000000..97a6d9839 --- /dev/null +++ b/src/wallet/test/wallet_test_fixture.h @@ -0,0 +1,18 @@ +// Copyright (c) 2016 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_WALLET_TEST_FIXTURE_H +#define BITCOIN_WALLET_TEST_FIXTURE_H + +#include "test/test_bitcoin.h" + +/** Testing setup and teardown for wallet. + */ +struct WalletTestingSetup: public TestingSetup { + WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); + ~WalletTestingSetup(); +}; + +#endif + diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index daab216b0..9a91a31b9 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -9,7 +9,7 @@ #include #include -#include "test/test_bitcoin.h" +#include "wallet/test/wallet_test_fixture.h" #include #include @@ -27,7 +27,7 @@ std::vector> wtxn; typedef set > CoinSet; -BOOST_FIXTURE_TEST_SUITE(wallet_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup) static CWallet wallet; static vector vCoins; From a0bf1386b74d7af72feca8802d2afb61ca4fee30 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 18 Apr 2016 15:12:46 +0200 Subject: [PATCH 026/110] =?UTF-8?q?wallet=5Fismine.h=20=E2=86=92=20script/?= =?UTF-8?q?ismine.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/{wallet/wallet_ismine.cpp => script/ismine.cpp} | 2 +- src/{wallet/wallet_ismine.h => script/ismine.h} | 6 +++--- src/test/multisig_tests.cpp | 12 +----------- src/test/script_P2SH_tests.cpp | 9 +-------- src/wallet/wallet.h | 2 +- 5 files changed, 7 insertions(+), 24 deletions(-) rename src/{wallet/wallet_ismine.cpp => script/ismine.cpp} (99%) rename src/{wallet/wallet_ismine.h => script/ismine.h} (90%) diff --git a/src/wallet/wallet_ismine.cpp b/src/script/ismine.cpp similarity index 99% rename from src/wallet/wallet_ismine.cpp rename to src/script/ismine.cpp index ebda5cc53..535c56b57 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/script/ismine.cpp @@ -3,7 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "wallet_ismine.h" +#include "ismine.h" #include "key.h" #include "keystore.h" diff --git a/src/wallet/wallet_ismine.h b/src/script/ismine.h similarity index 90% rename from src/wallet/wallet_ismine.h rename to src/script/ismine.h index 93cdf6ab8..3b24aa99d 100644 --- a/src/wallet/wallet_ismine.h +++ b/src/script/ismine.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_WALLET_WALLET_ISMINE_H -#define BITCOIN_WALLET_WALLET_ISMINE_H +#ifndef BITCOIN_SCRIPT_ISMINE_H +#define BITCOIN_SCRIPT_ISMINE_H #include "script/standard.h" @@ -31,4 +31,4 @@ typedef uint8_t isminefilter; isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest); -#endif // BITCOIN_WALLET_WALLET_ISMINE_H +#endif // BITCOIN_SCRIPT_ISMINE_H diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index b65c299ad..3b0a460c9 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -9,12 +9,10 @@ #include "script/script_error.h" #include "script/interpreter.h" #include "script/sign.h" +#include "script/ismine.h" #include "uint256.h" #include "test/test_bitcoin.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet_ismine.h" -#endif #include #include @@ -210,10 +208,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); -#endif } { vector solutions; @@ -225,10 +221,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); -#endif } { vector solutions; @@ -239,11 +233,9 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK_EQUAL(solutions.size(), 4U); CTxDestination addr; BOOST_CHECK(!ExtractDestination(s, addr)); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); -#endif } { vector solutions; @@ -258,11 +250,9 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK(addrs[0] == keyaddr[0]); BOOST_CHECK(addrs[1] == keyaddr[1]); BOOST_CHECK(nRequired == 1); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); -#endif } { vector solutions; diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index a49ca2fbb..0fabef787 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -9,12 +9,9 @@ #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" +#include "script/ismine.h" #include "test/test_bitcoin.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet_ismine.h" -#endif - #include #include @@ -101,9 +98,7 @@ BOOST_AUTO_TEST_CASE(sign) txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1; -#ifdef ENABLE_WALLET BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); -#endif } for (int i = 0; i < 8; i++) { @@ -198,9 +193,7 @@ BOOST_AUTO_TEST_CASE(set) txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1*CENT; txTo[i].vout[0].scriptPubKey = inner[i]; -#ifdef ENABLE_WALLET BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); -#endif } for (int i = 0; i < 4; i++) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 21a1a3b69..aa03c10ab 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -12,8 +12,8 @@ #include "ui_interface.h" #include "utilstrencodings.h" #include "validationinterface.h" +#include "script/ismine.h" #include "wallet/crypter.h" -#include "wallet/wallet_ismine.h" #include "wallet/walletdb.h" #include "wallet/rpcwallet.h" From 897cef91cc74492a70bb39c1eaf2b8c48837fcee Mon Sep 17 00:00:00 2001 From: lateminer Date: Wed, 10 Jan 2018 00:03:40 +0300 Subject: [PATCH 027/110] =?UTF-8?q?Fix:=20wallet=5Fismine.h=20=E2=86=92=20?= =?UTF-8?q?script/ismine.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index e0789d35a..9a242de00 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -155,6 +155,7 @@ BITCOIN_CORE_H = \ script/sigcache.h \ script/sign.h \ script/standard.h \ + script/ismine.h \ serialize.h \ streams.h \ support/allocators/secure.h \ @@ -182,7 +183,6 @@ BITCOIN_CORE_H = \ wallet/db.h \ wallet/rpcwallet.h \ wallet/wallet.h \ - wallet/wallet_ismine.h \ wallet/walletdb.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h\ @@ -226,6 +226,7 @@ libbitcoin_server_a_SOURCES = \ rpc/rawtransaction.cpp \ rpc/server.cpp \ script/sigcache.cpp \ + script/ismine.cpp \ script/drivechain.cpp \ script/drivechain.h \ timedata.cpp \ @@ -257,7 +258,6 @@ libbitcoin_wallet_a_SOURCES = \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ - wallet/wallet_ismine.cpp \ wallet/walletdb.cpp \ policy/rbf.cpp \ $(BITCOIN_CORE_H) From 5acb13a540cb8b2dd430d069e7bc8370ef7bdc6c Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 18 Apr 2016 15:15:57 +0200 Subject: [PATCH 028/110] test: Rename wallet.dat to wallet_test.dat Indicate that the file name is not hardcoded, and a little bit of safety so that it never nukes the main wallet. Suggestion by Marco Falke. --- src/wallet/test/wallet_test_fixture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 837030096..9036ee26d 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -10,7 +10,7 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName): bitdb.MakeMock(); bool fFirstRun; - pwalletMain = new CWallet("wallet.dat"); + pwalletMain = new CWallet("wallet_test.dat"); pwalletMain->LoadWallet(fFirstRun); RegisterValidationInterface(pwalletMain); From 155af18074b0101479174f58419bdbe39c047eed Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 17 Feb 2016 14:35:35 -0500 Subject: [PATCH 029/110] leveldb: integrate leveldb into our buildsystem --- configure.ac | 22 ++++++++-- src/Makefile.am | 19 ++------- src/Makefile.leveldb.include | 81 ++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 18 deletions(-) create mode 100644 src/Makefile.leveldb.include diff --git a/configure.ac b/configure.ac index 5a29d67c0..056626362 100644 --- a/configure.ac +++ b/configure.ac @@ -273,7 +273,7 @@ case $host in fi CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB" - LEVELDB_TARGET_FLAGS="TARGET_OS=OS_WINDOWS_CROSSCOMPILE" + LEVELDB_TARGET_FLAGS="-DOS_WINDOWS" if test "x$CXXFLAGS_overridden" = "xno"; then CXXFLAGS="$CXXFLAGS -w" fi @@ -295,7 +295,7 @@ case $host in ;; *darwin*) TARGET_OS=darwin - LEVELDB_TARGET_FLAGS="TARGET_OS=Darwin" + LEVELDB_TARGET_FLAGS="-DOS_MACOSX" if test x$cross_compiling != xyes; then BUILD_OS=darwin AC_CHECK_PROG([PORT],port, port) @@ -357,9 +357,11 @@ case $host in OBJCXXFLAGS="-std=c++11 $CXXFLAGS" ;; *linux*) - TARGET_OS=linux + LEVELDB_TARGET_FLAGS="-DOS_LINUX" ;; *) + OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'` + LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}" ;; esac @@ -544,6 +546,18 @@ if test x$use_reduce_exports = xyes; then [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])]) fi +dnl This can go away when we require c++11 +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS -std=c++0x" +AC_MSG_CHECKING(for c++11 atomics) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[]])], + [ AC_MSG_RESULT(yes); LEVELDB_ATOMIC_CPPFLAGS="-DLEVELDB_ATOMIC_PRESENT"; LEVELDB_ATOMIC_CXXFLAGS="-std=c++0x"], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + LEVELDB_CPPFLAGS= LIBLEVELDB= LIBMEMENV= @@ -1048,6 +1062,8 @@ AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) AC_SUBST(MINIUPNPC_CPPFLAGS) AC_SUBST(MINIUPNPC_LIBS) +AC_SUBST(LEVELDB_ATOMIC_CPPFLAGS) +AC_SUBST(LEVELDB_ATOMIC_CXXFLAGS) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) diff --git a/src/Makefile.am b/src/Makefile.am index 9a242de00..abb2d8da1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,21 +14,6 @@ else LIBUNIVALUE = $(UNIVALUE_LIBS) endif -if EMBEDDED_LEVELDB -LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include -LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv -LIBLEVELDB += $(builddir)/leveldb/libleveldb.a -LIBMEMENV += $(builddir)/leveldb/libmemenv.a - -# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race -$(LIBLEVELDB): $(LIBMEMENV) - -$(LIBLEVELDB) $(LIBMEMENV): - @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ - CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" -endif - BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) @@ -534,6 +519,10 @@ endif @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$( Date: Tue, 26 Apr 2016 19:43:14 +1200 Subject: [PATCH 030/110] Re-instate TARGET_OS=linux in configure.ac. Removed by 351abf9e035. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 056626362..4984d8cf1 100644 --- a/configure.ac +++ b/configure.ac @@ -357,6 +357,7 @@ case $host in OBJCXXFLAGS="-std=c++11 $CXXFLAGS" ;; *linux*) + TARGET_OS=linux LEVELDB_TARGET_FLAGS="-DOS_LINUX" ;; *) From 0f461369998fe2c14901ca72be9489ed1477cc43 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 9 Mar 2016 16:45:58 -0500 Subject: [PATCH 031/110] build: quiet annoying warnings without adding new ones Disabling warnings can be tricky, because doing so can cause a different compiler to create new warnings about unsupported disable flags. Also, some warnings don't surface until they're paired with another warning (gcc). For example, adding "-Wno-foo" won't cause any trouble, but if there's a legitimate warning emitted, the "unknown option -Wno-foo" will show up as well. Work around this in 2 ways: 1. When checking to see if -Wno-foo is supported, check for "-Wfoo" instead. 2. Enable -Werror while checking 1. If "-Werror -Wfoo" compiles, "-Wno-foo" is almost guaranteed to be supported. -Werror itself is also checked. If that fails to compile by itself, it likely means that the user added a flag that adds a warning. In that case, -Werror won't be used while checking, and the build may be extra noisy. The user would need to fix the bad input flag. Also, silence 2 more additional warnings that can show up post-c++11. --- configure.ac | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 4984d8cf1..6781d602d 100644 --- a/configure.ac +++ b/configure.ac @@ -191,6 +191,9 @@ AC_ARG_ENABLE([debug], [enable_debug=$enableval], [enable_debug=no]) +AC_LANG_PUSH([C++]) +AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""]) + if test "x$enable_debug" = xyes; then CPPFLAGS="$CPPFLAGS -DDEBUG -DDEBUG_LOCKORDER" if test "x$GCC" = xyes; then @@ -202,11 +205,19 @@ if test "x$enable_debug" = xyes; then fi fi -## TODO: Remove these hard-coded paths and flags. They are here for the sake of -## compatibility with the legacy buildsystem. -## if test "x$CXXFLAGS_overridden" = "xno"; then - CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wno-self-assign" + AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS="$CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS="$CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) + + ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all + ## unknown options if any other warning is produced. Test the -Wfoo case, and + ## set the -Wno-foo case if it works. + AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[CXXFLAGS="$CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wself-assign],[CXXFLAGS="$CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) fi CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" @@ -228,8 +239,6 @@ AC_ARG_WITH([daemon], [build_bitcoind=$withval], [build_bitcoind=yes]) -AC_LANG_PUSH([C++]) - use_pkgconfig=yes case $host in *mingw*) From 6a8b389cde7fb6ea6915741ec547efd35d50aeed Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 28 Apr 2016 17:46:35 -0400 Subject: [PATCH 032/110] build: No need to check for leveldb atomics They're guaranteed with c++11 --- configure.ac | 14 -------------- src/Makefile.leveldb.include | 7 ++----- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/configure.ac b/configure.ac index 6781d602d..6baa4f0d9 100644 --- a/configure.ac +++ b/configure.ac @@ -556,18 +556,6 @@ if test x$use_reduce_exports = xyes; then [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])]) fi -dnl This can go away when we require c++11 -TEMP_CXXFLAGS="$CXXFLAGS" -CXXFLAGS="$CXXFLAGS -std=c++0x" -AC_MSG_CHECKING(for c++11 atomics) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include - ]],[[]])], - [ AC_MSG_RESULT(yes); LEVELDB_ATOMIC_CPPFLAGS="-DLEVELDB_ATOMIC_PRESENT"; LEVELDB_ATOMIC_CXXFLAGS="-std=c++0x"], - [ AC_MSG_RESULT(no)] -) -CXXFLAGS="$TEMP_CXXFLAGS" - LEVELDB_CPPFLAGS= LIBLEVELDB= LIBMEMENV= @@ -1072,8 +1060,6 @@ AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) AC_SUBST(MINIUPNPC_CPPFLAGS) AC_SUBST(MINIUPNPC_LIBS) -AC_SUBST(LEVELDB_ATOMIC_CPPFLAGS) -AC_SUBST(LEVELDB_ATOMIC_CXXFLAGS) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include index 36a6bc409..88bb0c193 100644 --- a/src/Makefile.leveldb.include +++ b/src/Makefile.leveldb.include @@ -13,7 +13,7 @@ LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv LEVELDB_CPPFLAGS_INT = LEVELDB_CPPFLAGS_INT += -I$(srcdir)/leveldb LEVELDB_CPPFLAGS_INT += $(LEVELDB_TARGET_FLAGS) -LEVELDB_CPPFLAGS_INT += $(LEVELDB_ATOMIC_CPPFLAGS) +LEVELDB_CPPFLAGS_INT += -DLEVELDB_ATOMIC_PRESENT LEVELDB_CPPFLAGS_INT += -D__STDC_LIMIT_MACROS if TARGET_WINDOWS @@ -22,11 +22,8 @@ else LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_POSIX endif -LEVELDB_CXXFLAGS_INT = -LEVELDB_CXXFLAGS_INT += $(LEVELDB_ATOMIC_CXXFLAGS) - leveldb_libleveldb_a_CPPFLAGS = $(AM_CPPFLAGS) $(LEVELDB_CPPFLAGS_INT) $(LEVELDB_CPPFLAGS) -leveldb_libleveldb_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(LEVELDB_CXXFLAGS_INT) +leveldb_libleveldb_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) leveldb_libleveldb_a_SOURCES= leveldb_libleveldb_a_SOURCES += leveldb/db/builder.cc From 85aaa0b0238b8622ecb498842c56150aab7252cc Mon Sep 17 00:00:00 2001 From: lateminer Date: Wed, 10 Jan 2018 20:32:50 +0300 Subject: [PATCH 033/110] Fix comparison between signed and unsigned int rpcwallet.cpp wallet.cpp --- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 11b054125..9715a36a3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2503,7 +2503,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) if (origTx.vout.size() == 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output"); - if (changePosition != -1 && (changePosition < 0 || changePosition > origTx.vout.size())) + if (changePosition != -1 && (changePosition < 0 || (unsigned int)changePosition > origTx.vout.size())) throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds"); CMutableTransaction tx(origTx); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bd8b19330..2549ee7fb 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2717,7 +2717,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt // Insert change txn at random position: nChangePosInOut = GetRandInt(txNew.vout.size()+1); } - else if (nChangePosInOut > txNew.vout.size()) + else if ((unsigned int)nChangePosInOut > txNew.vout.size()) { strFailReason = _("Change index out of range"); return false; From 72875a21160bef55b39a7420dc1462cba2de0ccb Mon Sep 17 00:00:00 2001 From: lateminer Date: Wed, 10 Jan 2018 21:52:38 +0300 Subject: [PATCH 034/110] Relay double-spends, subject to anti-DOS https://github.com/bitcoinxt/bitcoinxt/commit/cef37115001abc70094b0fccd649212f9c4c9efd#diff-7ec3c68a81efff79b6ca22ac1f1eabbaL929 --- src/init.cpp | 1 + src/main.cpp | 98 ++++++++++++++++++++++++++++------ src/main.h | 3 ++ src/primitives/transaction.cpp | 9 ++++ src/primitives/transaction.h | 3 ++ src/qt/transactionrecord.cpp | 4 +- src/txmempool.cpp | 1 - src/validationinterface.cpp | 8 +-- src/validationinterface.h | 8 +-- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 60 +++++++++++++-------- src/wallet/wallet.h | 9 ++-- 12 files changed, 150 insertions(+), 56 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 97b29a8fb..b362f1450 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1439,6 +1439,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); + InitRespendFilter(); StartNode(threadGroup, scheduler); // Monitor the chain, and alert if we get blocks much quicker or slower than expected diff --git a/src/main.cpp b/src/main.cpp index 3cf9db618..eae3b38a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -561,6 +561,14 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector= nLimit*10*1000) + return true; + dCount += nSize; + return false; +} + +static bool RespendRelayExceeded(const CTransaction& doubleSpend) +{ + // Apply an independent rate limit to double-spend relays + static double dRespendCount; + static int64_t nLastRespendTime; + static int64_t nRespendLimit = GetArg("-limitrespendrelay", 100); + unsigned int nSize = ::GetSerializeSize(doubleSpend, SER_NETWORK, PROTOCOL_VERSION); + + if (RateLimitExceeded(dRespendCount, nLastRespendTime, nRespendLimit, nSize)) + { + LogPrint("mempool", "Double-spend relay rejected by rate limiter\n"); + return true; + } + + LogPrint("mempool", "Rate limit dRespendCount: %g => %g\n", dRespendCount, dRespendCount+nSize); + + return false; +} + bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, std::vector& vHashTxnToUncache) @@ -1066,13 +1109,26 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool"); // Check for conflicts with in-memory transactions + bool fRespend = false; + COutPoint relayForOutpoint; + set setConflicts; { LOCK(pool.cs); // protect pool.mapNextTx BOOST_FOREACH(const CTxIn &txin, tx.vin) { + COutPoint outpoint = txin.prevout; + // A respend is a tx that conflicts with a member of the pool if (pool.mapNextTx.count(txin.prevout)) { + fRespend = true; + // Relay only one tx per respent outpoint, but not if tx is equivalent to pool member + if (!doubleSpendFilter.contains(outpoint) && !tx.IsEquivalentTo(*pool.mapNextTx[outpoint].ptx)) + { + relayForOutpoint = outpoint; + break; + } + /* const CTransaction *ptxConflicting = pool.mapNextTx[txin.prevout].ptx; if (!setConflicts.count(ptxConflicting->GetHash())) { @@ -1105,8 +1161,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C setConflicts.insert(ptxConflicting->GetHash()); } + */ + } } + if (fRespend && (relayForOutpoint.IsNull() || RespendRelayExceeded(tx))) + return false; } { @@ -1215,22 +1275,15 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // be annoying or make others' transactions take longer to confirm. if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) { - static CCriticalSection csFreeLimiter; static double dFreeCount; - static int64_t nLastTime; - int64_t nNow = GetTime(); + static int64_t nLastFreeTime; + static int64_t nFreeLimit = GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY); - LOCK(csFreeLimiter); - - // Use an exponentially decaying ~10-minute window: - dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); - nLastTime = nNow; // -limitfreerelay unit is thousand-bytes-per-minute // At default rate it would take over a month to fill 1GB - if (dFreeCount >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000) + if (RateLimitExceeded(dFreeCount, nLastFreeTime, nFreeLimit, nSize)) return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction"); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); - dFreeCount += nSize; } if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) @@ -1434,8 +1487,19 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C } pool.RemoveStaged(allConflicting); - // Store transaction in memory - pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); + if (fRespend) + { + // Clear the filter on average every MAX_DOUBLE_SPEND_BLOOM insertions + if (insecure_rand()%MAX_DOUBLESPEND_BLOOM == 0) + doubleSpendFilter.clear(); + doubleSpendFilter.insert(relayForOutpoint); + RelayTransaction(tx); + } + else + { + // Store transaction in memory + pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); + } // Add memory address index if (fAddressIndex) { @@ -1455,9 +1519,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C } } - SyncWithWallets(tx, NULL); + SyncWithWallets(tx, NULL, fRespend); - return true; + return !fRespend; } bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, @@ -3149,7 +3213,7 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: BOOST_FOREACH(const CTransaction &tx, block.vtx) { - SyncWithWallets(tx, NULL); + SyncWithWallets(tx, NULL, false); } return true; } @@ -3208,11 +3272,11 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, // Tell wallet about transactions that went from mempool // to conflicted: BOOST_FOREACH(const CTransaction &tx, txConflicted) { - SyncWithWallets(tx, NULL); + SyncWithWallets(tx, NULL, false); } // ... and about transactions that got confirmed: BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { - SyncWithWallets(tx, pblock); + SyncWithWallets(tx, pblock, false); } int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; diff --git a/src/main.h b/src/main.h index d2998c841..3438510a9 100644 --- a/src/main.h +++ b/src/main.h @@ -169,6 +169,9 @@ extern CBlockIndex *pindexBestHeader; /** Minimum disk space required - used in CheckDiskSpace() */ static const uint64_t nMinDiskSpace = 52428800; +/** Initialize respend bloom filter **/ +void InitRespendFilter(); + /** Pruning-related variables and constants */ /** True if any block files have ever been pruned. */ extern bool fHavePruned; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index a75c5f452..c3577dad4 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -89,6 +89,15 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) { return *this; } +bool CTransaction::IsEquivalentTo(const CTransaction& tx) const +{ + CMutableTransaction tx1 = *this; + CMutableTransaction tx2 = tx; + for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript(); + for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript(); + return CTransaction(tx1) == CTransaction(tx2); +} + CAmount CTransaction::GetValueOut() const { CAmount nValueOut = 0; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 9a71ff72e..50fdc0d6f 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -272,6 +272,9 @@ public: return hash; } + // True if only scriptSigs are different + bool IsEquivalentTo(const CTransaction& tx) const; + // Return sum of txouts. CAmount GetValueOut() const; // GetValueIn() is a method on CCoinsViewCache, because diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index f9626e2e9..041e93982 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -240,7 +240,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) if (status.depth < 0) { status.status = TransactionStatus::Conflicted; - status.hasConflicting = !(wtx.GetConflicts().empty()); + status.hasConflicting = !(wtx.GetConflicts(false).empty()); } else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) { @@ -249,7 +249,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) else if (status.depth == 0) { status.status = TransactionStatus::Unconfirmed; - status.hasConflicting = !(wtx.GetConflicts().empty()); + status.hasConflicting = !(wtx.GetConflicts(false).empty()); if (wtx.isAbandoned()) status.status = TransactionStatus::Abandoned; } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 97a335a99..8782678eb 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -684,7 +684,6 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem void CTxMemPool::removeConflicts(const CTransaction &tx, std::list& removed) { // Remove transactions which depend on inputs of tx, recursively - list result; LOCK(cs); BOOST_FOREACH(const CTxIn &txin, tx.vin) { std::map::iterator it = mapNextTx.find(txin.prevout); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 81f3b775f..7cc1b3ce3 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -14,7 +14,7 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); - g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); + g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); @@ -32,7 +32,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); + g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3)); g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); } @@ -48,6 +48,6 @@ void UnregisterAllValidationInterfaces() { g_signals.UpdatedBlockTip.disconnect_all_slots(); } -void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { - g_signals.SyncTransaction(tx, pblock); +void SyncWithWallets(const CTransaction &tx, const CBlock *pblock, bool fRespend) { + g_signals.SyncTransaction(tx, pblock, fRespend); } diff --git a/src/validationinterface.h b/src/validationinterface.h index 4da145473..211bcf0c7 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -27,12 +27,12 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); /** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); +void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fRespend = false); class CValidationInterface { protected: virtual void UpdatedBlockTip(const CBlockIndex *pindex) {} - virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} + virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock, bool fRespend) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} @@ -48,8 +48,8 @@ protected: struct CMainSignals { /** Notifies listeners of updated block chain tip */ boost::signals2::signal UpdatedBlockTip; - /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ - boost::signals2::signal SyncTransaction; + /** Notifies listeners of updated transaction data (transaction, optionally the block it is found in, and whether this is a known respend. */ + boost::signals2::signal SyncTransaction; /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a new active block chain. */ diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2a68252c5..b9d7ded1e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -95,7 +95,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) conflicts.push_back(conflict.GetHex()); entry.push_back(Pair("walletconflicts", conflicts)); UniValue respends; - BOOST_FOREACH(const uint256& respend, wtx.GetConflicts()) + BOOST_FOREACH(const uint256& respend, wtx.GetConflicts(false)) respends.push_back(respend.GetHex()); entry.push_back(Pair("respendsobserved", respends)); entry.push_back(Pair("time", wtx.GetTxTime())); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a56e99e5e..977346a42 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -391,7 +391,7 @@ bool CWallet::SetMaxVersion(int nVersion) return true; } -set CWallet::GetConflicts(const uint256& txid) const +set CWallet::GetConflicts(const uint256& txid, bool includeEquivalent) const { set result; AssertLockHeld(cs_wallet); @@ -409,7 +409,8 @@ set CWallet::GetConflicts(const uint256& txid) const continue; // No conflict if zero or one spends range = mapTxSpends.equal_range(txin.prevout); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) - result.insert(it->second); + if (includeEquivalent || !wtx.IsEquivalentTo(mapWallet.at(it->second))) + result.insert(it->second); } return result; } @@ -1237,7 +1238,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD * pblock is optional, but should be provided if the transaction is known to be in a block. * If fUpdate is true, existing transactions will be updated. */ -bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fRespend) { { AssertLockHeld(cs_wallet); @@ -1257,7 +1258,15 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) return false; - if (fExisted || IsMine(tx) || IsFromMe(tx)) + + bool fIsConflicting = IsConflicting(tx); + // Don't add respends that pay us, unless they conflict with us. Prevents resource exhaustion. + if (!fIsConflicting && fRespend) return false; + + if (fIsConflicting) + nConflictsReceived++; + + if (fExisted || IsMine(tx) || IsFromMe(tx) || fIsConflicting) { CWalletTx wtx(this,tx); @@ -1392,24 +1401,21 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) } } -void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) +void void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock, bool fRespend) { + LOCK2(cs_main, cs_wallet); + if (!pblock) { + // wallets need to refund inputs when disconnecting coinstake + if (tx.IsCoinStake()) { + if (IsFromMe(tx)) { + DisableTransaction(tx); + return; + } + } + } - - LOCK2(cs_main, cs_wallet); - - if (!pblock) { - // wallets need to refund inputs when disconnecting coinstake - if (tx.IsCoinStake()) { - if (IsFromMe(tx)) { - DisableTransaction(tx); - return; - } - } - } - - if (!AddToWalletIfInvolvingMe(tx, pblock, true)) + if (!AddToWalletIfInvolvingMe(tx, pblock, true, fRespend)) return; // Not one of ours // If a transaction changes 'conflicted' state, that changes the balance @@ -1438,6 +1444,14 @@ isminetype CWallet::IsMine(const CTxIn &txin) const return ISMINE_NO; } +bool CWallet::IsConflicting(const CTransaction& tx) const +{ + BOOST_FOREACH(const CTxIn& txin, tx.vin) + if (mapTxSpends.count(txin.prevout)) + return true; + return false; +} + CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const { { @@ -1774,7 +1788,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ReadBlockFromDisk(block, pindex, Params().GetConsensus()); BOOST_FOREACH(CTransaction& tx, block.vtx) { - if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) + if (AddToWalletIfInvolvingMe(tx, &block, fUpdate, false)) ret++; } pindex = chainActive.Next(pindex); @@ -1805,7 +1819,7 @@ void CWallet::ReacceptWalletTransactions() int nDepth = wtx.GetDepthInMainChain(); - if (!wtx.IsCoinBase() && !wtx.IsCoinStake() && (nDepth == 0 && !wtx.isAbandoned())) { + if (!wtx.IsCoinBase() && !wtx.IsCoinStake() && (nDepth == 0 && !wtx.isAbandoned() && (IsMine(wtx) || IsFromMe(wtx)))) { mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); } } @@ -1834,13 +1848,13 @@ bool CWalletTx::RelayWalletTransaction() return false; } -set CWalletTx::GetConflicts() const +set CWalletTx::GetConflicts(bool includeEquivalent) const { set result; if (pwallet != NULL) { uint256 myHash = GetHash(); - result = pwallet->GetConflicts(myHash); + result = pwallet->GetConflicts(myHash, includeEquivalent); result.erase(myHash); } return result; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f87feb20c..63ecbc7fd 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -414,7 +414,7 @@ public: bool RelayWalletTransaction(); - std::set GetConflicts() const; + std::set GetConflicts(bool includeEquivalent=true) const; }; @@ -668,8 +668,8 @@ public: void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); - void SyncTransaction(const CTransaction& tx, const CBlock* pblock); - bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); + void SyncTransaction(const CTransaction& tx, const CBlock* pblock, bool fRespend); + bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fRespend); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime); @@ -737,6 +737,7 @@ public: bool IsMine(const CTransaction& tx) const; /** should probably be renamed to IsRelevantToMe */ bool IsFromMe(const CTransaction& tx) const; + bool IsConflicting(const CTransaction& tx) const; CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetChange(const CTransaction& tx) const; @@ -789,7 +790,7 @@ public: void DisableTransaction(const CTransaction &tx); //! Get wallet transactions that conflict with given transaction (spend same outputs) - std::set GetConflicts(const uint256& txid) const; + std::set GetConflicts(const uint256& txid, bool includeEquivalent) const; //! Flush wallet (bitdb flush) void Flush(bool shutdown=false); From 72fb9f5567b32bb66bb477354996fd7a055b82a8 Mon Sep 17 00:00:00 2001 From: lateminer Date: Wed, 10 Jan 2018 22:12:18 +0300 Subject: [PATCH 035/110] Fix typo wallet.cpp --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 977346a42..91e55c43e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1401,7 +1401,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) } } -void void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock, bool fRespend) +void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock, bool fRespend) { LOCK2(cs_main, cs_wallet); From 7006f94a6bd05a75bb706be9367d69f7a390f541 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 25 Dec 2015 13:14:26 +0100 Subject: [PATCH 036/110] [gitian] Default reference_datetime to commit author date --- contrib/gitian-descriptors/gitian-linux.yml | 3 +-- contrib/gitian-descriptors/gitian-osx-signer.yml | 1 - contrib/gitian-descriptors/gitian-osx.yml | 3 +-- contrib/gitian-descriptors/gitian-win-signer.yml | 1 - contrib/gitian-descriptors/gitian-win.yml | 3 +-- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 120eb7481..ca8493eba 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -5,7 +5,7 @@ suites: - "trusty" architectures: - "amd64" -packages: +packages: - "curl" - "g++-multilib" - "git-core" @@ -18,7 +18,6 @@ packages: - "binutils-gold" - "ca-certificates" - "python" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index 4c4e3ff82..ad3884cfd 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -6,7 +6,6 @@ architectures: - "amd64" packages: - "faketime" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin-detached-sigs.git" "dir": "signature" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 7e9da9727..f8124643a 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -5,7 +5,7 @@ suites: - "trusty" architectures: - "amd64" -packages: +packages: - "curl" - "g++" - "git-core" @@ -21,7 +21,6 @@ packages: - "libbz2-dev" - "ca-certificates" - "python" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 27c4f01eb..6b53b89b6 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -7,7 +7,6 @@ architectures: packages: - "libssl-dev" - "autoconf" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin-detached-sigs.git" "dir": "signature" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index af7a80cec..54e65245d 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -5,7 +5,7 @@ suites: - "trusty" architectures: - "amd64" -packages: +packages: - "curl" - "g++" - "git-core" @@ -21,7 +21,6 @@ packages: - "zip" - "ca-certificates" - "python" -reference_datetime: "2016-01-01 00:00:00" remotes: - "url": "https://github.com/bitcoin/bitcoin.git" "dir": "bitcoin" From ed60218b70370160a92342cd1b37f02edbfa519a Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 5 Apr 2016 13:29:04 +0200 Subject: [PATCH 037/110] [gitian] hardcode datetime for depends --- contrib/gitian-descriptors/gitian-linux.yml | 19 ++++++++++++---- contrib/gitian-descriptors/gitian-osx.yml | 19 ++++++++++++---- contrib/gitian-descriptors/gitian-win.yml | 25 ++++++++++++++++----- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index ca8493eba..2fe6d31e7 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -41,29 +41,36 @@ script: | mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi - # Create global faketime wrappers + function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done + } - # Create per-host faketime wrappers + function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } + export PATH=${WRAP_DIR}:${PATH} + # Faketime for depends so intermediate results are comparable + create_global_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_faketime_wrappers "2000-01-01 12:00:00" + cd bitcoin BASEPREFIX=`pwd`/depends # Build dependencies for each host @@ -71,6 +78,10 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done + # Faketime for binaries + create_global_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + # Create the release tarball using (arbitrarily) the first host ./autogen.sh ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index f8124643a..5bdceb141 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -47,29 +47,36 @@ script: | export ZERO_AR_DATE=1 - # Create global faketime wrappers + function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done + } - # Create per-host faketime wrappers + function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } + export PATH=${WRAP_DIR}:${PATH} + # Faketime for depends so intermediate results are comparable + create_global_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_faketime_wrappers "2000-01-01 12:00:00" + cd bitcoin BASEPREFIX=`pwd`/depends @@ -81,6 +88,10 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done + # Faketime for binaries + create_global_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + # Create the release tarball using (arbitrarily) the first host ./autogen.sh ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 54e65245d..690132264 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -44,29 +44,31 @@ script: | mkdir -p ${BASE_CACHE} ${SOURCES_PATH} fi - # Create global faketime wrappers + function create_global_faketime_wrappers { for prog in ${FAKETIME_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${prog} echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} echo "\$REAL \$@" >> $WRAP_DIR/${prog} chmod +x ${WRAP_DIR}/${prog} done + } - # Create per-host faketime wrappers + function create_per-host_faketime_wrappers { for i in $HOSTS; do for prog in ${FAKETIME_HOST_PROGS}; do echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } - # Create per-host linker wrapper + function create_per-host_linker_wrapper { # This is only needed for trusty, as the mingw linker leaks a few bytes of # heap, causing non-determinism. See discussion in https://github.com/bitcoin/bitcoin/pull/6900 for i in $HOSTS; do @@ -82,15 +84,21 @@ script: | echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} - echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog} echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} chmod +x ${WRAP_DIR}/${i}-${prog} done done + } export PATH=${WRAP_DIR}:${PATH} + # Faketime for depends so intermediate results are comparable + create_global_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_linker_wrapper "2000-01-01 12:00:00" + cd bitcoin BASEPREFIX=`pwd`/depends # Build dependencies for each host @@ -98,6 +106,11 @@ script: | make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done + # Faketime for binaries + create_global_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_linker_wrapper "${REFERENCE_DATETIME}" + # Create the release tarball using (arbitrarily) the first host ./autogen.sh ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` From 3efa7adf3b0d1e3ed856547c23d83fb3470f7f5e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 1 Jun 2016 18:05:09 -0400 Subject: [PATCH 038/110] build: out-of-tree fixups Don't glob the leveldb for dist. That means we need to enumerate the headers. --- Makefile.am | 10 ------- src/Makefile.am | 7 ++--- src/Makefile.leveldb.include | 56 ++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/Makefile.am b/Makefile.am index 5dacbab6b..4b99dc5c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,18 +47,8 @@ COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info dist-hook: - -$(MAKE) -C $(top_distdir)/src/leveldb clean - -$(MAKE) -C $(top_distdir)/src/secp256k1 distclean -$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf - -distcheck-hook: - $(MKDIR_P) $(top_distdir)/_build/src/leveldb - cp -rf $(top_srcdir)/src/leveldb/* $(top_distdir)/_build/src/leveldb/ - -$(MAKE) -C $(top_distdir)/_build/src/leveldb clean - -distcleancheck: - @: - $(BITCOIN_WIN_INSTALLER): all-recursive $(MKDIR_P) $(top_builddir)/release STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release diff --git a/src/Makefile.am b/src/Makefile.am index abb2d8da1..20c1b3f06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -469,8 +469,8 @@ CTAES_DIST += crypto/ctaes/ctaes.h CTAES_DIST += crypto/ctaes/README.md CTAES_DIST += crypto/ctaes/test.c -CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a -CLEANFILES += $(EXTRA_LIBRARIES) +CLEANFILES = $(EXTRA_LIBRARIES) + CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno @@ -486,10 +486,9 @@ CLEANFILES += zmq/*.gcda zmq/*.gcno DISTCLEANFILES = obj/build.h -EXTRA_DIST = leveldb $(CTAES_DIST) +EXTRA_DIST = $(CTAES_DIST) clean-local: - -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include index 88bb0c193..4b3cd6364 100644 --- a/src/Makefile.leveldb.include +++ b/src/Makefile.leveldb.include @@ -26,6 +26,61 @@ leveldb_libleveldb_a_CPPFLAGS = $(AM_CPPFLAGS) $(LEVELDB_CPPFLAGS_INT) $(LEVELDB leveldb_libleveldb_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) leveldb_libleveldb_a_SOURCES= +leveldb_libleveldb_a_SOURCES += leveldb/port/atomic_pointer.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port_example.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port_posix.h +leveldb_libleveldb_a_SOURCES += leveldb/port/win/stdint.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port.h +leveldb_libleveldb_a_SOURCES += leveldb/port/port_win.h +leveldb_libleveldb_a_SOURCES += leveldb/port/thread_annotations.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/db.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/options.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/comparator.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/filter_policy.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/slice.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table_builder.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/env.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/c.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/iterator.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/cache.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/dumpfile.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/write_batch.h +leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/status.h +leveldb_libleveldb_a_SOURCES += leveldb/db/log_format.h +leveldb_libleveldb_a_SOURCES += leveldb/db/memtable.h +leveldb_libleveldb_a_SOURCES += leveldb/db/version_set.h +leveldb_libleveldb_a_SOURCES += leveldb/db/write_batch_internal.h +leveldb_libleveldb_a_SOURCES += leveldb/db/filename.h +leveldb_libleveldb_a_SOURCES += leveldb/db/version_edit.h +leveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.h +leveldb_libleveldb_a_SOURCES += leveldb/db/builder.h +leveldb_libleveldb_a_SOURCES += leveldb/db/log_writer.h +leveldb_libleveldb_a_SOURCES += leveldb/db/db_iter.h +leveldb_libleveldb_a_SOURCES += leveldb/db/skiplist.h +leveldb_libleveldb_a_SOURCES += leveldb/db/db_impl.h +leveldb_libleveldb_a_SOURCES += leveldb/db/table_cache.h +leveldb_libleveldb_a_SOURCES += leveldb/db/snapshot.h +leveldb_libleveldb_a_SOURCES += leveldb/db/log_reader.h +leveldb_libleveldb_a_SOURCES += leveldb/table/filter_block.h +leveldb_libleveldb_a_SOURCES += leveldb/table/block_builder.h +leveldb_libleveldb_a_SOURCES += leveldb/table/block.h +leveldb_libleveldb_a_SOURCES += leveldb/table/two_level_iterator.h +leveldb_libleveldb_a_SOURCES += leveldb/table/merger.h +leveldb_libleveldb_a_SOURCES += leveldb/table/format.h +leveldb_libleveldb_a_SOURCES += leveldb/table/iterator_wrapper.h +leveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.h +leveldb_libleveldb_a_SOURCES += leveldb/util/arena.h +leveldb_libleveldb_a_SOURCES += leveldb/util/random.h +leveldb_libleveldb_a_SOURCES += leveldb/util/posix_logger.h +leveldb_libleveldb_a_SOURCES += leveldb/util/hash.h +leveldb_libleveldb_a_SOURCES += leveldb/util/histogram.h +leveldb_libleveldb_a_SOURCES += leveldb/util/coding.h +leveldb_libleveldb_a_SOURCES += leveldb/util/testutil.h +leveldb_libleveldb_a_SOURCES += leveldb/util/mutexlock.h +leveldb_libleveldb_a_SOURCES += leveldb/util/logging.h +leveldb_libleveldb_a_SOURCES += leveldb/util/testharness.h + leveldb_libleveldb_a_SOURCES += leveldb/db/builder.cc leveldb_libleveldb_a_SOURCES += leveldb/db/c.cc leveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.cc @@ -76,3 +131,4 @@ endif leveldb_libmemenv_a_CPPFLAGS = $(leveldb_libleveldb_a_CPPFLAGS) leveldb_libmemenv_a_CXXFLAGS = $(leveldb_libleveldb_a_CXXFLAGS) leveldb_libmemenv_a_SOURCES = leveldb/helpers/memenv/memenv.cc +leveldb_libmemenv_a_SOURCES += leveldb/helpers/memenv/memenv.h From 9590ee0613c5c30d1a0b7b514c52602fd3f181f9 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 1 Jun 2016 18:06:40 -0400 Subject: [PATCH 039/110] build: more out-of-tree fixups - clear the __pycache__ during 'make clean' - Copy the qrc locale file to a temp location and remove it when finished (rcc expects everything to be in the same path) --- src/Makefile.am | 1 + src/Makefile.qt.include | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 20c1b3f06..5b4ec878d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -493,6 +493,7 @@ clean-local: -$(MAKE) -C univalue clean -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -f config.h + -rm -rf test/__pycache__ .rc.o: @test -f $(WINDRES) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 373b2ead7..8e1475679 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -410,9 +410,10 @@ translate: qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) @test -f $(RCC) - @test -f $(@D)/$( $@ + @rm $(@D)/temp_$( Date: Wed, 1 Jun 2016 18:47:21 -0400 Subject: [PATCH 040/110] build: a few ugly hacks to get the rpc tests working out-of-tree --- Makefile.am | 1 + configure.ac | 1 + qa/pull-tester/rpc-tests.py | 1 + qa/pull-tester/tests_config.py.in | 1 + 4 files changed, 4 insertions(+) diff --git a/Makefile.am b/Makefile.am index 4b99dc5c8..6e8a31516 100644 --- a/Makefile.am +++ b/Makefile.am @@ -219,3 +219,4 @@ CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) clean-local: rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ qa/tmp/ cache/ $(OSX_APP) + rm -rf qa/pull-tester/__pycache__ diff --git a/configure.ac b/configure.ac index 6baa4f0d9..b38f0feb5 100644 --- a/configure.ac +++ b/configure.ac @@ -1063,6 +1063,7 @@ AC_SUBST(MINIUPNPC_LIBS) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) +AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py]) dnl boost's m4 checks do something really nasty: they export these vars. As a dnl result, they leak into secp256k1's configure and crazy things happen. diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 796e5a3a5..dc175cfc2 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -29,6 +29,7 @@ import subprocess import tempfile import re +sys.path.append("qa/pull-tester/") from tests_config import * #If imported values are not defined then set to zero (or disabled) diff --git a/qa/pull-tester/tests_config.py.in b/qa/pull-tester/tests_config.py.in index 937b4231f..4e8a83654 100644 --- a/qa/pull-tester/tests_config.py.in +++ b/qa/pull-tester/tests_config.py.in @@ -3,6 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +SRCDIR="@abs_top_srcdir@" BUILDDIR="@abs_top_builddir@" EXEEXT="@EXEEXT@" From 861e43938ecafd953c725a054252713712a04d5d Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 1 Jun 2016 22:19:29 -0400 Subject: [PATCH 041/110] build: fix out-of-tree 'make deploy' for osx The plist is generated, lives in builddir. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6e8a31516..e21d69bd1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,7 @@ OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist OSX_BASE_LPROJ_DIR=$(top_srcdir)/contrib/macdeploy/Base.lproj/InfoPlist.strings OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns -OSX_PLIST=$(top_srcdir)/share/qt/Info.plist #not installed +OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) From 2672a5bba3fcc82760f1bb4d6f4ec8313119b56b Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 1 Jun 2016 19:24:29 -0400 Subject: [PATCH 042/110] travis: use out-of-tree build --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f2fb8a4fc..6718b0d16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,10 +69,8 @@ script: - BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" - depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh - - ./configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - - make distdir PACKAGE=bitcoin VERSION=$HOST - - cd bitcoin-$HOST - - ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) + - mkdir build && cd build + - ../configure $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - if [ "$RUN_TESTS" = "true" ]; then make check; fi From 0d2cf50377327764891aa60e86f73792ad68bf81 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 3 Jun 2016 14:00:38 -0400 Subject: [PATCH 043/110] build: add temporary fix for "bad magic number" error in out-of-tree builds This was caused by an pyc files hanging around from previous python2 invocations, when the matching .py missing from that path. This should not be a problem with python3's tagged caches. --- Makefile.am | 3 +++ src/Makefile.test.include | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Makefile.am b/Makefile.am index e21d69bd1..89148c823 100644 --- a/Makefile.am +++ b/Makefile.am @@ -215,6 +215,9 @@ EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc- CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) +# This file is problematic for out-of-tree builds if it exists. +DISTCLEANFILES = qa/pull-tester/tests_config.pyc + .INTERMEDIATE: $(COVERAGE_INFO) clean-local: diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 20ebd5c29..ce31db5b5 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -120,6 +120,9 @@ CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_TEST) +# This file is problematic for out-of-tree builds if it exists. +DISTCLEANFILES += test/buildenv.pyc + bitcoin_test: $(TEST_BINARY) bitcoin_test_check: $(TEST_BINARY) FORCE From 8da4c55c851960bb2ec243d1e8fa556522094862 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 9 Jun 2016 17:49:16 -0400 Subject: [PATCH 044/110] bulid: fix "make translate" when out-of-tree --- src/Makefile.qt.include | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 8e1475679..9e69bfb3f 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -400,13 +400,13 @@ QT_QM=$(QT_TS:.ts=.qm) SECONDARY: $(QT_QM) -qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) +$(srcdir)/qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) ../share/qt/extract_strings_qt.py $^ -translate: qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) +translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts qt/locale/bitcoin_en.ts + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts $(srcdir)/qt/locale/bitcoin_en.ts $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) @test -f $(RCC) From c896b9ed64170c4841d1837deedd8d946ec15ccf Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 12 Jun 2016 14:10:55 +0200 Subject: [PATCH 045/110] [gitian] set correct PATH for wrappers --- contrib/gitian-descriptors/gitian-linux.yml | 6 ++++-- contrib/gitian-descriptors/gitian-osx.yml | 6 ++++-- contrib/gitian-descriptors/gitian-win.yml | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 2fe6d31e7..c3dcab960 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -65,11 +65,11 @@ script: | done } - export PATH=${WRAP_DIR}:${PATH} - # Faketime for depends so intermediate results are comparable + export PATH_orig=${PATH} create_global_faketime_wrappers "2000-01-01 12:00:00" create_per-host_faketime_wrappers "2000-01-01 12:00:00" + export PATH=${WRAP_DIR}:${PATH} cd bitcoin BASEPREFIX=`pwd`/depends @@ -79,8 +79,10 @@ script: | done # Faketime for binaries + export PATH=${PATH_orig} create_global_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host ./autogen.sh diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 5bdceb141..2f9a1e0fb 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -71,11 +71,11 @@ script: | done } - export PATH=${WRAP_DIR}:${PATH} - # Faketime for depends so intermediate results are comparable + export PATH_orig=${PATH} create_global_faketime_wrappers "2000-01-01 12:00:00" create_per-host_faketime_wrappers "2000-01-01 12:00:00" + export PATH=${WRAP_DIR}:${PATH} cd bitcoin BASEPREFIX=`pwd`/depends @@ -89,8 +89,10 @@ script: | done # Faketime for binaries + export PATH=${PATH_orig} create_global_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host ./autogen.sh diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 690132264..9a09f637d 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -92,12 +92,12 @@ script: | done } - export PATH=${WRAP_DIR}:${PATH} - # Faketime for depends so intermediate results are comparable + export PATH_orig=${PATH} create_global_faketime_wrappers "2000-01-01 12:00:00" create_per-host_faketime_wrappers "2000-01-01 12:00:00" create_per-host_linker_wrapper "2000-01-01 12:00:00" + export PATH=${WRAP_DIR}:${PATH} cd bitcoin BASEPREFIX=`pwd`/depends @@ -107,9 +107,11 @@ script: | done # Faketime for binaries + export PATH=${PATH_orig} create_global_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" create_per-host_linker_wrapper "${REFERENCE_DATETIME}" + export PATH=${WRAP_DIR}:${PATH} # Create the release tarball using (arbitrarily) the first host ./autogen.sh From dc7486e015103eb9f75a8d773281fd6fa06e0f75 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 13 Jun 2016 19:33:02 +0800 Subject: [PATCH 046/110] [trivial] Sync ax_pthread with upstream draft --- build-aux/m4/ax_pthread.m4 | 506 ++++++++++++++++++------------------- 1 file changed, 253 insertions(+), 253 deletions(-) diff --git a/build-aux/m4/ax_pthread.m4 b/build-aux/m4/ax_pthread.m4 index d218d1af7..4c4051ea3 100644 --- a/build-aux/m4/ax_pthread.m4 +++ b/build-aux/m4/ax_pthread.m4 @@ -82,7 +82,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 22 +#serial 23 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ @@ -100,22 +100,22 @@ ax_pthread_ok=no # etcetera environment variables, and if threads linking works using # them: if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then - ax_pthread_save_CC="$CC" - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) - AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = "xno"; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - CC="$ax_pthread_save_CC" - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -152,50 +152,50 @@ ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread -- case $host_os in - freebsd*) + freebsd*) - # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) - # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) - ax_pthread_flags="-kthread lthread $ax_pthread_flags" - ;; + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; - hpux*) + hpux*) - # From the cc(1) man page: "[-mt] Sets various -D flags to enable - # multi-threading and also sets -lpthread." + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." - ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" - ;; + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; - openedition*) + openedition*) - # IBM z/OS requires a feature-test macro to be defined in order to - # enable POSIX threads at all, so give the user a hint if this is - # not set. (We don't define these ourselves, as they can affect - # other portions of the system API in unpredictable ways.) + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) - AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], - [ -# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) - AX_PTHREAD_ZOS_MISSING -# endif - ], - [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) - ;; + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; - solaris*) + solaris*) - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (N.B.: The stubs are missing - # pthread_cleanup_push, or rather a function called by this macro, - # so we could check for that, but who knows whether they'll stub - # that too in a future libc.) So we'll check first for the - # standard Solaris way of linking pthreads (-mt -lpthread). + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). - ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" - ;; + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; esac # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) @@ -208,17 +208,17 @@ AS_IF([test "x$GCC" = "xyes"], # correctly enabled case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) - ax_pthread_check_macro="_REENTRANT" - ;; + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; - aix* | freebsd*) - ax_pthread_check_macro="_THREAD_SAFE" - ;; + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; - *) - ax_pthread_check_macro="--" - ;; + *) + ax_pthread_check_macro="--" + ;; esac AS_IF([test "x$ax_pthread_check_macro" = "x--"], [ax_pthread_check_cond=0], @@ -231,13 +231,13 @@ AC_CACHE_CHECK([whether $CC is Clang], [ax_cv_PTHREAD_CLANG=no # Note that Autoconf sets GCC=yes for Clang as well as GCC if test "x$GCC" = "xyes"; then - AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], - [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ -# if defined(__clang__) && defined(__llvm__) - AX_PTHREAD_CC_IS_CLANG -# endif - ], - [ax_cv_PTHREAD_CLANG=yes]) + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) fi ]) ax_pthread_clang="$ax_cv_PTHREAD_CLANG" @@ -249,222 +249,222 @@ ax_pthread_clang_warning=no if test "x$ax_pthread_clang" = "xyes"; then - # Clang takes -pthread; it has never supported any other flag + # Clang takes -pthread; it has never supported any other flag - # (Note 1: This will need to be revisited if a system that Clang - # supports has POSIX threads in a separate library. This tends not - # to be the way of modern systems, but it's conceivable.) + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) - # (Note 2: On some systems, notably Darwin, -pthread is not needed - # to get POSIX threads support; the API is always present and - # active. We could reasonably leave PTHREAD_CFLAGS empty. But - # -pthread does define _REENTRANT, and while the Darwin headers - # ignore this macro, third-party headers might not.) + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) - PTHREAD_CFLAGS="-pthread" - PTHREAD_LIBS= + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= - ax_pthread_ok=yes + ax_pthread_ok=yes - # However, older versions of Clang make a point of warning the user - # that, in an invocation where only linking and no compilation is - # taking place, the -pthread option has no effect ("argument unused - # during compilation"). They expect -pthread to be passed in only - # when source code is being compiled. - # - # Problem is, this is at odds with the way Automake and most other - # C build frameworks function, which is that the same flags used in - # compilation (CFLAGS) are also used in linking. Many systems - # supported by AX_PTHREAD require exactly this for POSIX threads - # support, and in fact it is often not straightforward to specify a - # flag that is used only in the compilation phase and not in - # linking. Such a scenario is extremely rare in practice. - # - # Even though use of the -pthread flag in linking would only print - # a warning, this can be a nuisance for well-run software projects - # that build with -Werror. So if the active version of Clang has - # this misfeature, we search for an option to squash it. + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. - AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown - # Create an alternate version of $ac_link that compiles and - # links in two steps (.c -> .o, .o -> exe) instead of one - # (.c -> exe), because the warning occurs only in the second - # step - ax_pthread_save_ac_link="$ac_link" - ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' - ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` - ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" - ax_pthread_save_CFLAGS="$CFLAGS" - for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do - AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) - CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" - ac_link="$ax_pthread_save_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [ac_link="$ax_pthread_2step_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [break]) - ]) - done - ac_link="$ax_pthread_save_ac_link" - CFLAGS="$ax_pthread_save_CFLAGS" - AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) - ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" - ]) + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) - case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in - no | unknown) ;; - *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; - esac + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac fi # $ax_pthread_clang = yes if test "x$ax_pthread_ok" = "xno"; then for ax_pthread_try_flag in $ax_pthread_flags; do - case $ax_pthread_try_flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; - -mt,pthread) - AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) - PTHREAD_CFLAGS="-mt" - PTHREAD_LIBS="-lpthread" - ;; + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; - -*) - AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) - PTHREAD_CFLAGS="$ax_pthread_try_flag" - ;; + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; - *) - AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) - PTHREAD_LIBS="-l$ax_pthread_try_flag" - ;; - esac + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include -# if $ax_pthread_check_cond -# error "$ax_pthread_check_macro must be defined" -# endif - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - AC_MSG_RESULT([$ax_pthread_ok]) - AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = "xyes"; then - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_CACHE_CHECK([for joinable pthread attribute], - [ax_cv_PTHREAD_JOINABLE_ATTR], - [ax_cv_PTHREAD_JOINABLE_ATTR=unknown - for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $ax_pthread_attr; return attr /* ; */])], - [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], - []) - done - ]) - AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ - test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ - test "x$ax_pthread_joinable_attr_defined" != "xyes"], - [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], - [$ax_cv_PTHREAD_JOINABLE_ATTR], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - ax_pthread_joinable_attr_defined=yes - ]) + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) - AC_CACHE_CHECK([whether more special flags are required for pthreads], - [ax_cv_PTHREAD_SPECIAL_FLAGS], - [ax_cv_PTHREAD_SPECIAL_FLAGS=no - case $host_os in - solaris*) - ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" - ;; - esac - ]) - AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ - test "x$ax_pthread_special_flags_added" != "xyes"], - [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" - ax_pthread_special_flags_added=yes]) + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ - test "x$ax_pthread_prio_inherit_defined" != "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) - ax_pthread_prio_inherit_defined=yes - ]) + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - # More AIX lossage: compile with *_r variant - if test "x$GCC" != "xyes"; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" @@ -475,11 +475,11 @@ AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test "x$ax_pthread_ok" = "xyes"; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : else - ax_pthread_ok=no - $2 + ax_pthread_ok=no + $2 fi AC_LANG_POP ])dnl AX_PTHREAD From d730d69efd08d1f8ce9db34a0ad7abe727d47acf Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 29 Jun 2016 11:01:29 +0200 Subject: [PATCH 047/110] windows: Add testnet link to installer --- share/setup.nsi.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 676ea3cda..9b7966d08 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -92,6 +92,7 @@ Section -post SEC0001 !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory $SMPROGRAMS\$StartMenuGroup CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet, @WINDOWS_BITS@-bit).lnk" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "-testnet" CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_END WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" @@ -135,6 +136,7 @@ Section -un.post UNSEC0001 DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" + Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet, @WINDOWS_BITS@-bit).lnk" Delete /REBOOTOK "$SMSTARTUP\Bitcoin.lnk" Delete /REBOOTOK $INSTDIR\uninstall.exe Delete /REBOOTOK $INSTDIR\debug.log From 8b6c238f0d5ce48e450651e503ac631da53c6114 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 29 Jun 2016 13:06:28 +0200 Subject: [PATCH 048/110] windows: Add testnet icon for testnet link Overhauled testnet icon by Jonas Schnelli --- share/setup.nsi.in | 2 +- src/Makefile.qt.include | 1 + src/qt/res/bitcoin-qt-res.rc | 1 + src/qt/res/icons/bitcoin_testnet.ico | Bin 0 -> 57251 bytes 4 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/qt/res/icons/bitcoin_testnet.ico diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 9b7966d08..cdd7cac2d 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -92,7 +92,7 @@ Section -post SEC0001 !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory $SMPROGRAMS\$StartMenuGroup CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@ - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet, @WINDOWS_BITS@-bit).lnk" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "-testnet" + CreateShortcut "$SMPROGRAMS\$StartMenuGroup\@PACKAGE_NAME@ (testnet, @WINDOWS_BITS@-bit).lnk" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "-testnet" "$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" 1 CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe !insertmacro MUI_STARTMENU_WRITE_END WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 9e69bfb3f..242baf7ae 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -230,6 +230,7 @@ RES_ICONS = \ qt/res/icons/about.png \ qt/res/icons/about_qt.png \ qt/res/icons/bitcoin.ico \ + qt/res/icons/bitcoin_testnet.ico \ qt/res/icons/bitcoin.png \ qt/res/icons/chevron.png \ qt/res/icons/clock1.png \ diff --git a/src/qt/res/bitcoin-qt-res.rc b/src/qt/res/bitcoin-qt-res.rc index 1a3117a67..a5cd3e5f2 100644 --- a/src/qt/res/bitcoin-qt-res.rc +++ b/src/qt/res/bitcoin-qt-res.rc @@ -1,4 +1,5 @@ IDI_ICON1 ICON DISCARDABLE "icons/bitcoin.ico" +IDI_ICON2 ICON DISCARDABLE "icons/bitcoin_testnet.ico" #include // needed for VERSIONINFO #include "../../clientversion.h" // holds the needed client version information diff --git a/src/qt/res/icons/bitcoin_testnet.ico b/src/qt/res/icons/bitcoin_testnet.ico new file mode 100644 index 0000000000000000000000000000000000000000..909194ecd2e10985bbca35c3cd26fd1adb4730b8 GIT binary patch literal 57251 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 N250BL5H*Z+s*3%&l;+rD=4 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 Date: Wed, 6 Jul 2016 17:29:43 -0400 Subject: [PATCH 049/110] build: require boost for bench --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b38f0feb5..b50f4cc55 100644 --- a/configure.ac +++ b/configure.ac @@ -583,7 +583,7 @@ BITCOIN_QT_INIT dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt5]) -if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests = xnononono; then +if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then use_boost=no else use_boost=yes From 4cdc0c43cc89ec960fabbbf7dc79f9582b63faea Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 7 Jul 2016 13:47:54 -0400 Subject: [PATCH 050/110] build: fix Windows builds without pkg-config - guard PKG_PROG_PKG_CONFIG with an m4_ifdef. If not building for windows, require it - add nops as necessary in case the ifdef reduces the if/then to nothing - AC_SUBST some missing _LIBS. These were split out over time, but not all were properly substituted. They continued to work if pkg-config is installed because it does the AC_SUBST itself --- configure.ac | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index b50f4cc55..36e01e762 100644 --- a/configure.ac +++ b/configure.ac @@ -82,9 +82,6 @@ AC_PATH_PROG(HEXDUMP,hexdump) AC_PATH_TOOL(READELF, readelf) AC_PATH_TOOL(CPPFILT, c++filt) -dnl pkg-config check. -PKG_PROG_PKG_CONFIG - # Enable wallet AC_ARG_ENABLE([wallet], [AS_HELP_STRING([--disable-wallet], @@ -375,6 +372,16 @@ case $host in ;; esac +if test x$use_pkgconfig = xyes; then + m4_ifndef([PKG_PROG_PKG_CONFIG], [AC_MSG_ERROR(PKG_PROG_PKG_CONFIG macro not found. Please install pkg-config and re-run autogen.sh.)]) + m4_ifdef([PKG_PROG_PKG_CONFIG], [ + PKG_PROG_PKG_CONFIG + if test x"$PKG_CONFIG" = "x"; then + AC_MSG_ERROR(pkg-config not found.) + fi + ]) +fi + if test x$use_comparison_tool != xno; then AC_SUBST(JAVA_COMPARISON_TOOL, $use_comparison_tool) fi @@ -752,12 +759,7 @@ fi fi if test x$use_pkgconfig = xyes; then - - if test x"$PKG_CONFIG" = "x"; then - AC_MSG_ERROR(pkg-config not found.) - fi - - : #NOP + : dnl m4_ifdef( [PKG_CHECK_MODULES], [ @@ -1060,6 +1062,13 @@ AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) AC_SUBST(MINIUPNPC_CPPFLAGS) AC_SUBST(MINIUPNPC_LIBS) +AC_SUBST(CRYPTO_LIBS) +AC_SUBST(SSL_LIBS) +AC_SUBST(EVENT_LIBS) +AC_SUBST(EVENT_PTHREADS_LIBS) +AC_SUBST(ZMQ_LIBS) +AC_SUBST(PROTOBUF_LIBS) +AC_SUBST(QR_LIBS) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) From 6112e5877cec907a3fa53270d6a8d824146f4a46 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 30 Jun 2016 01:51:09 +0000 Subject: [PATCH 051/110] Bugfix: Allow building libbitcoinconsensus without any univalue --- configure.ac | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 36e01e762..b1390ac80 100644 --- a/configure.ac +++ b/configure.ac @@ -834,6 +834,12 @@ fi dnl univalue check +need_bundled_univalue=yes + +if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then + need_bundled_univalue=no +else + if test x$system_univalue != xno ; then found_univalue=no if test x$use_pkgconfig = xyes; then @@ -855,6 +861,7 @@ if test x$system_univalue != xno ; then if test x$found_univalue = xyes ; then system_univalue=yes + need_bundled_univalue=no elif test x$system_univalue = xyes ; then AC_MSG_ERROR([univalue not found]) else @@ -862,11 +869,14 @@ if test x$system_univalue != xno ; then fi fi -if test x$system_univalue = xno ; then +if test x$need_bundled_univalue = xyes ; then UNIVALUE_CFLAGS='-I$(srcdir)/univalue/include' UNIVALUE_LIBS='univalue/libunivalue.la' fi -AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$system_univalue = xno]) + +fi + +AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes]) AC_SUBST(UNIVALUE_CFLAGS) AC_SUBST(UNIVALUE_LIBS) @@ -1097,7 +1107,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" -if test x$system_univalue = xno; then +if test x$need_bundled_univalue = xyes; then AC_CONFIG_SUBDIRS([src/univalue]) fi From afc5e2c51d4a3fb84735b21889de42cafa88baab Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 9 Aug 2016 05:07:28 +0000 Subject: [PATCH 052/110] configure: Allow building bench_bitcoin by itself --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b1390ac80..7496385bf 100644 --- a/configure.ac +++ b/configure.ac @@ -1022,8 +1022,8 @@ else AC_MSG_RESULT([no]) fi -if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_tests = xnonononono; then - AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui or --enable-tests]) +if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnononononono; then + AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests]) fi AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) From 209a5f1a04652e0a687351d96f018b4840f0b960 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 16 Aug 2016 11:16:21 +0200 Subject: [PATCH 053/110] build: Remove check for `openssl/ec.h` We don't use any elliptic curves from OpenSSL anymore, nor include this header anywhere but optionally in the tests of secp256k1 (which has its own autoconf setup). Reported by sinetek on IRC. --- configure.ac | 8 -------- 1 file changed, 8 deletions(-) diff --git a/configure.ac b/configure.ac index 7496385bf..9db68a136 100644 --- a/configure.ac +++ b/configure.ac @@ -880,14 +880,6 @@ AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes]) AC_SUBST(UNIVALUE_CFLAGS) AC_SUBST(UNIVALUE_LIBS) -CXXFLAGS_TEMP="$CXXFLAGS" -LIBS_TEMP="$LIBS" -CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" -LIBS="$LIBS $SSL_LIBS $CRYPTO_LIBS" -AC_CHECK_HEADER([openssl/ec.h],, AC_MSG_ERROR(OpenSSL ec header missing),) -CXXFLAGS="$CXXFLAGS_TEMP" -LIBS="$LIBS_TEMP" - BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path) AC_MSG_CHECKING([whether to build bitcoind]) From 2f3208b448b1dd28919cd9b859754c5442b9969e Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 15 Nov 2016 16:12:17 -0500 Subject: [PATCH 054/110] build: fix qt5.7 build under macOS OBJCXX's std flags don't get defined by our cxx macro. Rather than hard-coding to c++11, just force OBJCXX to be the same as CXX unless the user specified otherwise. --- configure.ac | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index 9db68a136..88137bee5 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,15 @@ fi AC_PROG_OBJCXX ]) +dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures +dnl that we get the same -std flags for both. +m4_ifdef([AC_PROG_OBJCXX],[ +if test "x${OBJCXX+set}" = "x"; then + OBJCXX="${CXX}" +fi +AC_PROG_OBJCXX +]) + dnl Libtool init checks. LT_INIT([pic-only]) From ae3b2575d9e460cffd348791fcb1c5b9cc8ff89d Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 12 Dec 2016 08:10:27 +0000 Subject: [PATCH 055/110] Fix wallet/test/crypto_tests.cpp for OpenSSL 1.1 API. This avoids a compile failure on newly installed debian stretch systems. --- src/wallet/test/crypto_tests.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp index 05387f5f2..b235b9609 100644 --- a/src/wallet/test/crypto_tests.cpp +++ b/src/wallet/test/crypto_tests.cpp @@ -42,15 +42,19 @@ bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0; vchCiphertext = std::vector (nCLen); - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + if (!ctx) return false; bool fOk = true; - EVP_CIPHER_CTX_init(&ctx); - if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; - if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0; - if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0; - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_init(ctx); + if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; + if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0; + if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0; + EVP_CIPHER_CTX_cleanup(ctx); + + EVP_CIPHER_CTX_free(ctx); if (!fOk) return false; @@ -66,15 +70,19 @@ bool OldDecrypt(const std::vector& vchCiphertext, CKeyingMaterial vchPlaintext = CKeyingMaterial(nPLen); - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + if (!ctx) return false; bool fOk = true; - EVP_CIPHER_CTX_init(&ctx); - if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; - if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0; - if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0; - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_init(ctx); + if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; + if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0; + if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0; + EVP_CIPHER_CTX_cleanup(ctx); + + EVP_CIPHER_CTX_free(ctx); if (!fOk) return false; From 43f8575bc37b937b726ea0ab8fbefa2881c938f5 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 12 Dec 2016 18:45:56 +0000 Subject: [PATCH 056/110] Fix qt/paymentrequestplus.cpp for OpenSSL 1.1 API. This avoids a compile failure on newly installed debian stretch systems. --- src/qt/paymentrequestplus.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 20e1f79ff..82be4d831 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -159,14 +159,24 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c std::string data_to_verify; // Everything but the signature rcopy.SerializeToString(&data_to_verify); - EVP_MD_CTX ctx; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context."); +#else + EVP_MD_CTX _ctx; + EVP_MD_CTX *ctx; + ctx = &_ctx; +#endif EVP_PKEY *pubkey = X509_get_pubkey(signing_cert); - EVP_MD_CTX_init(&ctx); - if (!EVP_VerifyInit_ex(&ctx, digestAlgorithm, NULL) || - !EVP_VerifyUpdate(&ctx, data_to_verify.data(), data_to_verify.size()) || - !EVP_VerifyFinal(&ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) { + EVP_MD_CTX_init(ctx); + if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, NULL) || + !EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) || + !EVP_VerifyFinal(ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) { throw SSLVerifyError("Bad signature, invalid payment request."); } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_MD_CTX_free(ctx); +#endif // OpenSSL API for getting human printable strings from certs is baroque. int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, NULL, 0); From 33137dbc6d356cb91ce84b4ec4131a0e97771426 Mon Sep 17 00:00:00 2001 From: Ivo van der Sangen Date: Sun, 27 Nov 2016 12:08:39 +0100 Subject: [PATCH 057/110] Include select.h when WIN32 is not defined --- src/compat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compat.h b/src/compat.h index 1225ea18e..e8cdbdb4e 100644 --- a/src/compat.h +++ b/src/compat.h @@ -34,6 +34,7 @@ #else #include #include +#include #include #include #include From 602f3d2aaddfe933c81a8db7a9874e1c760fdf60 Mon Sep 17 00:00:00 2001 From: janko33bd Date: Wed, 10 Jan 2018 23:06:58 +0100 Subject: [PATCH 058/110] removing confusing tooltip --- src/qt/forms/askpassphrasedialog.ui | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui index 5b7223e4f..dce4b8883 100644 --- a/src/qt/forms/askpassphrasedialog.ui +++ b/src/qt/forms/askpassphrasedialog.ui @@ -117,9 +117,6 @@ - - Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. - * Tick for staking only From 714d2650b5fa0e1a5a0410a3795ca7417bf36033 Mon Sep 17 00:00:00 2001 From: janko33bd Date: Wed, 10 Jan 2018 23:13:59 +0100 Subject: [PATCH 059/110] added SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS --- src/script/interpreter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index a6f8fd0e1..e86bf4fc1 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -428,6 +428,10 @@ bool EvalScript(vector >& stack, const CScript& script, un case OP_COUNT_ACKS: { + if (SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); + } + // (secondary_chain_id ack_period liveness_period -- ) if (stack.size() < 3) From c4c9d818233f27d1309bcd6e8b500ce2049fad59 Mon Sep 17 00:00:00 2001 From: lateminer Date: Fri, 12 Jan 2018 07:34:45 +0300 Subject: [PATCH 060/110] Use std::shared_ptr instead of boost::shared_ptr --- src/miner.cpp | 2 +- src/rpc/mining.cpp | 3 +-- src/rpc/server.cpp | 5 ++--- src/validationinterface.h | 5 ++--- src/wallet/wallet.cpp | 4 ++-- src/wallet/wallet.h | 4 +--- 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 7a856ae29..543d3617b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -390,7 +390,7 @@ void static BitcoinMiner(const CChainParams& chainparams) unsigned int nExtraNonce = 0; - boost::shared_ptr coinbaseScript; + std::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); try { diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 254fbc300..fac37d340 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -28,7 +28,6 @@ #include #include -#include #include @@ -141,7 +140,7 @@ UniValue generate(const UniValue& params, bool fHelp) int nHeight = 0; int nGenerate = params[0].get_int(); - boost::shared_ptr coinbaseScript; + std::shared_ptr coinbaseScript; GetMainSignals().ScriptForMining(coinbaseScript); // If the keypool is exhausted, no script is returned at all. Catch this. diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 102c77631..dc0d8074d 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include // for to_upper() @@ -36,7 +35,7 @@ static CCriticalSection cs_rpcWarmup; static RPCTimerInterface* timerInterface = NULL; /* Map of name to timer. * @note Can be changed to std::unique_ptr when C++11 */ -static std::map > deadlineTimers; +static std::map > deadlineTimers; static struct CRPCSignals { @@ -492,7 +491,7 @@ void RPCRunLater(const std::string& name, boost::function func, int6 throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); deadlineTimers.erase(name); LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); - deadlineTimers.insert(std::make_pair(name, boost::shared_ptr(timerInterface->NewTimer(func, nSeconds*1000)))); + deadlineTimers.insert(std::make_pair(name, std::shared_ptr(timerInterface->NewTimer(func, nSeconds*1000)))); } CRPCTable tableRPC; diff --git a/src/validationinterface.h b/src/validationinterface.h index 211bcf0c7..df03388b0 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -7,7 +7,6 @@ #define BITCOIN_VALIDATIONINTERFACE_H #include -#include class CBlock; struct CBlockLocator; @@ -38,7 +37,7 @@ protected: virtual void Inventory(const uint256 &hash) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} - virtual void GetScriptForMining(boost::shared_ptr&) {}; + virtual void GetScriptForMining(std::shared_ptr&) {}; virtual void ResetRequestCount(const uint256 &hash) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); @@ -61,7 +60,7 @@ struct CMainSignals { /** Notifies listeners of a block validation result */ boost::signals2::signal BlockChecked; /** Notifies listeners that a key for mining is required (coinbase) */ - boost::signals2::signal&)> ScriptForMining; + boost::signals2::signal&)> ScriptForMining; /** Notifies listeners that a block has been successfully mined */ boost::signals2::signal BlockFound; }; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 91e55c43e..75fbcc98d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3473,9 +3473,9 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) } } -void CWallet::GetScriptForMining(boost::shared_ptr &script) +void CWallet::GetScriptForMining(std::shared_ptr &script) { - boost::shared_ptr rKey(new CReserveKey(this)); + std::shared_ptr rKey = std::make_shared(this); CPubKey pubkey; if (!rKey->GetReservedKey(pubkey)) return; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 63ecbc7fd..9b8125361 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -26,8 +26,6 @@ #include #include -#include - extern CWallet* pwalletMain; /** @@ -763,7 +761,7 @@ public: } } - void GetScriptForMining(boost::shared_ptr &script); + void GetScriptForMining(std::shared_ptr &script); void ResetRequestCount(const uint256 &hash) { LOCK(cs_wallet); From b1d5409eb85c0589eebe9d0793544883d132111b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 20 Mar 2016 17:51:52 +0000 Subject: [PATCH 061/110] build: python 3 compatibility --- Makefile.am | 7 +- configure.ac | 2 +- contrib/devtools/security-check.py | 34 +++---- contrib/devtools/symbol-check.py | 63 ++++++------- contrib/macdeploy/custom_dsstore.py | 60 ++++++++++++ contrib/macdeploy/macdeployqtplus | 136 ++++++++++++++-------------- share/qt/extract_strings_qt.py | 9 +- src/Makefile.qt.include | 2 +- src/Makefile.test.include | 4 +- src/test/bctest.py | 2 +- src/test/bitcoin-util-test.py | 2 +- 11 files changed, 194 insertions(+), 127 deletions(-) create mode 100755 contrib/macdeploy/custom_dsstore.py diff --git a/Makefile.am b/Makefile.am index 89148c823..ff82f89de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,6 +18,7 @@ BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EX OSX_APP=Lore-Qt.app OSX_DMG=Blackcoin-Lore.dmg OSX_BACKGROUND_IMAGE=background.tiff +OSX_DSSTORE_GEN=$(top_srcdir)/contrib/macdeploy/custom_dsstore.py OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist OSX_BASE_LPROJ_DIR=$(top_srcdir)/contrib/macdeploy/Base.lproj/InfoPlist.strings @@ -92,7 +93,7 @@ OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lp if BUILD_DARWIN $(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) - $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 + $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME) deploydir: $(OSX_DMG) else @@ -111,11 +112,11 @@ $(OSX_DMG): $(APP_DIST_EXTRAS) $(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) $(MKDIR_P) $(@D) $(INSTALL) $< $@ -$(APP_DIST_DIR)/.DS_Store: contrib/macdeploy/DS_Store +$(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN) $(INSTALL) $< $@ $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Lore-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) - INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 + INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 deploydir: $(APP_DIST_EXTRAS) endif diff --git a/configure.ac b/configure.ac index 88137bee5..f7a498801 100644 --- a/configure.ac +++ b/configure.ac @@ -82,7 +82,7 @@ AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) AC_PATH_PROG(JAVA, java) -AC_PATH_PROG(PYTHON, python) +AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 01586457d..d32c21e5d 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -5,7 +5,7 @@ Exit status will be 0 if succesful, and the program will be silent. Otherwise the exit status will be 1 and it will log which executables failed which checks. Needs `readelf` (for ELF) and `objdump` (for PE). ''' -from __future__ import division,print_function +from __future__ import division,print_function,unicode_literals import subprocess import sys import os @@ -23,9 +23,9 @@ def check_ELF_PIE(executable): raise IOError('Error opening file') ok = False - for line in stdout.split('\n'): + for line in stdout.split(b'\n'): line = line.split() - if len(line)>=2 and line[0] == 'Type:' and line[1] == 'DYN': + if len(line)>=2 and line[0] == b'Type:' and line[1] == b'DYN': ok = True return ok @@ -38,17 +38,17 @@ def get_ELF_program_headers(executable): in_headers = False count = 0 headers = [] - for line in stdout.split('\n'): - if line.startswith('Program Headers:'): + for line in stdout.split(b'\n'): + if line.startswith(b'Program Headers:'): in_headers = True - if line == '': + if line == b'': in_headers = False if in_headers: if count == 1: # header line - ofs_typ = line.find('Type') - ofs_offset = line.find('Offset') - ofs_flags = line.find('Flg') - ofs_align = line.find('Align') + ofs_typ = line.find(b'Type') + ofs_offset = line.find(b'Offset') + ofs_flags = line.find(b'Flg') + ofs_align = line.find(b'Align') if ofs_typ == -1 or ofs_offset == -1 or ofs_flags == -1 or ofs_align == -1: raise ValueError('Cannot parse elfread -lW output') elif count > 1: @@ -65,9 +65,9 @@ def check_ELF_NX(executable): have_wx = False have_gnu_stack = False for (typ, flags) in get_ELF_program_headers(executable): - if typ == 'GNU_STACK': + if typ == b'GNU_STACK': have_gnu_stack = True - if 'W' in flags and 'E' in flags: # section is both writable and executable + if b'W' in flags and b'E' in flags: # section is both writable and executable have_wx = True return have_gnu_stack and not have_wx @@ -84,7 +84,7 @@ def check_ELF_RELRO(executable): # However, the dynamic linker need to write to this area so these are RW. # Glibc itself takes care of mprotecting this area R after relocations are finished. # See also http://permalink.gmane.org/gmane.comp.gnu.binutils/71347 - if typ == 'GNU_RELRO': + if typ == b'GNU_RELRO': have_gnu_relro = True have_bindnow = False @@ -92,9 +92,9 @@ def check_ELF_RELRO(executable): (stdout, stderr) = p.communicate() if p.returncode: raise IOError('Error opening file') - for line in stdout.split('\n'): + for line in stdout.split(b'\n'): tokens = line.split() - if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2]): + if len(tokens)>1 and tokens[1] == b'(BIND_NOW)' or (len(tokens)>2 and tokens[1] == b'(FLAGS)' and b'BIND_NOW' in tokens[2]): have_bindnow = True return have_gnu_relro and have_bindnow @@ -107,8 +107,8 @@ def check_ELF_Canary(executable): if p.returncode: raise IOError('Error opening file') ok = False - for line in stdout.split('\n'): - if '__stack_chk_fail' in line: + for line in stdout.split(b'\n'): + if b'__stack_chk_fail' in line: ok = True return ok diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index 4ad5136f7..e26c0fbb9 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -11,7 +11,7 @@ Example usage: find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py ''' -from __future__ import division, print_function +from __future__ import division, print_function, unicode_literals import subprocess import re import sys @@ -47,28 +47,28 @@ MAX_VERSIONS = { # Ignore symbols that are exported as part of every executable IGNORE_EXPORTS = { -'_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used' +b'_edata', b'_end', b'_init', b'__bss_start', b'_fini', b'_IO_stdin_used' } READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') # Allowed NEEDED libraries ALLOWED_LIBRARIES = { # bitcoind and bitcoin-qt -'libgcc_s.so.1', # GCC base support -'libc.so.6', # C library -'libpthread.so.0', # threading -'libanl.so.1', # DNS resolve -'libm.so.6', # math library -'librt.so.1', # real-time (clock) -'ld-linux-x86-64.so.2', # 64-bit dynamic linker -'ld-linux.so.2', # 32-bit dynamic linker +b'libgcc_s.so.1', # GCC base support +b'libc.so.6', # C library +b'libpthread.so.0', # threading +b'libanl.so.1', # DNS resolve +b'libm.so.6', # math library +b'librt.so.1', # real-time (clock) +b'ld-linux-x86-64.so.2', # 64-bit dynamic linker +b'ld-linux.so.2', # 32-bit dynamic linker # bitcoin-qt only -'libX11-xcb.so.1', # part of X11 -'libX11.so.6', # part of X11 -'libxcb.so.1', # part of X11 -'libfontconfig.so.1', # font support -'libfreetype.so.6', # font parsing -'libdl.so.2' # programming interface to dynamic linker +b'libX11-xcb.so.1', # part of X11 +b'libX11.so.6', # part of X11 +b'libxcb.so.1', # part of X11 +b'libfontconfig.so.1', # font support +b'libfreetype.so.6', # font parsing +b'libdl.so.2' # programming interface to dynamic linker } class CPPFilt(object): @@ -81,7 +81,8 @@ class CPPFilt(object): self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE) def __call__(self, mangled): - self.proc.stdin.write(mangled + '\n') + self.proc.stdin.write(mangled + b'\n') + self.proc.stdin.flush() return self.proc.stdout.readline().rstrip() def close(self): @@ -99,24 +100,24 @@ def read_symbols(executable, imports=True): if p.returncode: raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip())) syms = [] - for line in stdout.split('\n'): + for line in stdout.split(b'\n'): line = line.split() - if len(line)>7 and re.match('[0-9]+:$', line[0]): - (sym, _, version) = line[7].partition('@') - is_import = line[6] == 'UND' - if version.startswith('@'): + if len(line)>7 and re.match(b'[0-9]+:$', line[0]): + (sym, _, version) = line[7].partition(b'@') + is_import = line[6] == b'UND' + if version.startswith(b'@'): version = version[1:] if is_import == imports: syms.append((sym, version)) return syms def check_version(max_versions, version): - if '_' in version: - (lib, _, ver) = version.rpartition('_') + if b'_' in version: + (lib, _, ver) = version.rpartition(b'_') else: lib = version ver = '0' - ver = tuple([int(x) for x in ver.split('.')]) + ver = tuple([int(x) for x in ver.split(b'.')]) if not lib in max_versions: return False return ver <= max_versions[lib] @@ -127,10 +128,10 @@ def read_libraries(filename): if p.returncode: raise IOError('Error opening file') libraries = [] - for line in stdout.split('\n'): + for line in stdout.split(b'\n'): tokens = line.split() - if len(tokens)>2 and tokens[1] == '(NEEDED)': - match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:])) + if len(tokens)>2 and tokens[1] == b'(NEEDED)': + match = re.match(b'^Shared library: \[(.*)\]$', b' '.join(tokens[2:])) if match: libraries.append(match.group(1)) else: @@ -144,18 +145,18 @@ if __name__ == '__main__': # Check imported symbols for sym,version in read_symbols(filename, True): if version and not check_version(MAX_VERSIONS, version): - print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version)) + print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym).decode('utf-8'), version.decode('utf-8'))) retval = 1 # Check exported symbols for sym,version in read_symbols(filename, False): if sym in IGNORE_EXPORTS: continue - print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym))) + print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym).decode('utf-8'))) retval = 1 # Check dependency libraries for library_name in read_libraries(filename): if library_name not in ALLOWED_LIBRARIES: - print('%s: NEEDED library %s is not allowed' % (filename, library_name)) + print('%s: NEEDED library %s is not allowed' % (filename, library_name.decode('utf-8'))) retval = 1 exit(retval) diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py new file mode 100755 index 000000000..03e2325fc --- /dev/null +++ b/contrib/macdeploy/custom_dsstore.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright (c) 2013-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. +from __future__ import division,print_function,unicode_literals +import biplist +from ds_store import DSStore +from mac_alias import Alias +import sys + +output_file = sys.argv[1] +package_name_ns = sys.argv[2] + +ds = DSStore.open(output_file, 'w+') +ds['.']['bwsp'] = { + 'ShowStatusBar': False, + 'WindowBounds': b'{{300, 280}, {500, 343}}', + 'ContainerShowSidebar': False, + 'SidebarWidth': 0, + 'ShowTabView': False, + 'PreviewPaneVisibility': False, + 'ShowToolbar': False, + 'ShowSidebar': False, + 'ShowPathbar': True +} + +icvp = { + 'gridOffsetX': 0.0, + 'textSize': 12.0, + 'viewOptionsVersion': 1, + 'backgroundImageAlias': b'\x00\x00\x00\x00\x02\x1e\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x94\\\xb0H+\x00\x05\x00\x00\x00\x98\x0fbackground.tiff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xd19\xb0\xf8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\r\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b.background\x00\x00\x10\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x11\x00\x08\x00\x00\xd19\xb0\xf8\x00\x00\x00\x01\x00\x04\x00\x00\x00\x98\x00\x0e\x00 \x00\x0f\x00b\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x00.\x00t\x00i\x00f\x00f\x00\x0f\x00\x02\x00\x00\x00\x12\x00\x1c/.background/background.tiff\x00\x14\x01\x06\x00\x00\x00\x00\x01\x06\x00\x02\x00\x00\x0cMacintosh HD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x97\xab\xc3H+\x00\x00\x01\x88[\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02u\xab\x8d\xd1\x94\\\xb0devrddsk\xff\xff\xff\xff\x00\x00\t \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07bitcoin\x00\x00\x10\x00\x08\x00\x00\xce\x97\xab\xc3\x00\x00\x00\x11\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x01\x00\x14\x01\x88[\x88\x00\x16\xa9\t\x00\x08\xfaR\x00\x08\xfaQ\x00\x02d\x8e\x00\x0e\x00\x02\x00\x00\x00\x0f\x00\x1a\x00\x0c\x00M\x00a\x00c\x00i\x00n\x00t\x00o\x00s\x00h\x00 \x00H\x00D\x00\x13\x00\x01/\x00\x00\x15\x00\x02\x00\x14\xff\xff\x00\x00\xff\xff\x00\x00', + 'backgroundColorBlue': 1.0, + 'iconSize': 96.0, + 'backgroundColorGreen': 1.0, + 'arrangeBy': 'none', + 'showIconPreview': True, + 'gridSpacing': 100.0, + 'gridOffsetY': 0.0, + 'showItemInfo': False, + 'labelOnBottom': True, + 'backgroundType': 2, + 'backgroundColorRed': 1.0 +} +alias = Alias.from_bytes(icvp['backgroundImageAlias']) +alias.volume.name = package_name_ns +alias.volume.posix_path = '/Volumes/' + package_name_ns +alias.volume.disk_image_alias.target.filename = package_name_ns + '.temp.dmg' +alias.volume.disk_image_alias.target.carbon_path = 'Macintosh HD:Users:\x00bitcoinuser:\x00Documents:\x00bitcoin:\x00bitcoin:\x00' + package_name_ns + '.temp.dmg' +alias.volume.disk_image_alias.target.posix_path = 'Users/bitcoinuser/Documents/bitcoin/bitcoin/' + package_name_ns + '.temp.dmg' +alias.target.carbon_path = package_name_ns + ':.background:\x00background.tiff' +icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes()) +ds['.']['icvp'] = icvp + +ds['.']['vSrn'] = ('long', 1) + +ds['Applications']['Iloc'] = (370, 156) +ds['Bitcoin-Qt.app']['Iloc'] = (128, 156) + +ds.flush() +ds.close() diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 2253c40af..c51130077 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -1,5 +1,5 @@ #!/usr/bin/env python - +from __future__ import division, print_function, unicode_literals # # Copyright (C) 2011 Patrick "p2k" Schneider # @@ -201,7 +201,7 @@ class DeploymentInfo(object): def getFrameworks(binaryPath, verbose): if verbose >= 3: - print "Inspecting with otool: " + binaryPath + print("Inspecting with otool: " + binaryPath) otoolbin=os.getenv("OTOOL", "otool") otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) o_stdout, o_stderr = otool.communicate() @@ -222,8 +222,8 @@ def getFrameworks(binaryPath, verbose): info = FrameworkInfo.fromOtoolLibraryLine(line.strip()) if info is not None: if verbose >= 3: - print "Found framework:" - print info + print("Found framework:") + print(info) libraries.append(info) return libraries @@ -234,24 +234,24 @@ def runInstallNameTool(action, *args): def changeInstallName(oldName, newName, binaryPath, verbose): if verbose >= 3: - print "Using install_name_tool:" - print " in", binaryPath - print " change reference", oldName - print " to", newName + print("Using install_name_tool:") + print(" in", binaryPath) + print(" change reference", oldName) + print(" to", newName) runInstallNameTool("change", oldName, newName, binaryPath) def changeIdentification(id, binaryPath, verbose): if verbose >= 3: - print "Using install_name_tool:" - print " change identification in", binaryPath - print " to", id + print("Using install_name_tool:") + print(" change identification in", binaryPath) + print(" to", id) runInstallNameTool("id", id, binaryPath) def runStrip(binaryPath, verbose): stripbin=os.getenv("STRIP", "strip") if verbose >= 3: - print "Using strip:" - print " stripped", binaryPath + print("Using strip:") + print(" stripped", binaryPath) subprocess.check_call([stripbin, "-x", binaryPath]) def copyFramework(framework, path, verbose): @@ -274,8 +274,8 @@ def copyFramework(framework, path, verbose): shutil.copy2(fromPath, toPath) if verbose >= 3: - print "Copied:", fromPath - print " to:", toPath + print("Copied:", fromPath) + print(" to:", toPath) permissions = os.stat(toPath) if not permissions.st_mode & stat.S_IWRITE: @@ -288,14 +288,14 @@ def copyFramework(framework, path, verbose): if not os.path.exists(linkfrom): os.symlink(linkto, linkfrom) if verbose >= 2: - print "Linked:", linkfrom, "->", linkto + print("Linked:", linkfrom, "->", linkto) fromResourcesDir = framework.sourceResourcesDirectory if os.path.exists(fromResourcesDir): toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory) shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True) if verbose >= 3: - print "Copied resources:", fromResourcesDir - print " to:", toResourcesDir + print("Copied resources:", fromResourcesDir) + print(" to:", toResourcesDir) fromContentsDir = framework.sourceVersionContentsDirectory if not os.path.exists(fromContentsDir): fromContentsDir = framework.sourceContentsDirectory @@ -304,16 +304,16 @@ def copyFramework(framework, path, verbose): shutil.copytree(fromContentsDir, toContentsDir, symlinks=True) contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory) if verbose >= 3: - print "Copied Contents:", fromContentsDir - print " to:", toContentsDir + print("Copied Contents:", fromContentsDir) + print(" to:", toContentsDir) elif framework.frameworkName.startswith("libQtGui"): # Copy qt_menu.nib (applies to non-framework layout) qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib") qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib") if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath): shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True) if verbose >= 3: - print "Copied for libQtGui:", qtMenuNibSourcePath - print " to:", qtMenuNibDestinationPath + print("Copied for libQtGui:", qtMenuNibSourcePath) + print(" to:", qtMenuNibDestinationPath) return toPath @@ -326,7 +326,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym deploymentInfo.deployedFrameworks.append(framework.frameworkName) if verbose >= 2: - print "Processing", framework.frameworkName, "..." + print("Processing", framework.frameworkName, "...") # Get the Qt path from one of the Qt frameworks if deploymentInfo.qtPath is None and framework.isQtFramework(): @@ -334,7 +334,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym if framework.installName.startswith("@executable_path") or framework.installName.startswith(bundlePath): if verbose >= 2: - print framework.frameworkName, "already deployed, skipping." + print(framework.frameworkName, "already deployed, skipping.") continue # install_name_tool the new id into the binary @@ -366,7 +366,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym def deployFrameworksForAppBundle(applicationBundle, strip, verbose): frameworks = getFrameworks(applicationBundle.binaryPath, verbose) if len(frameworks) == 0 and verbose >= 1: - print "Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path) + print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path)) return DeploymentInfo() else: return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose) @@ -444,7 +444,7 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): for pluginDirectory, pluginName in plugins: if verbose >= 2: - print "Processing plugin", os.path.join(pluginDirectory, pluginName), "..." + print("Processing plugin", os.path.join(pluginDirectory, pluginName), "...") sourcePath = os.path.join(deploymentInfo.pluginPath, pluginDirectory, pluginName) destinationDirectory = os.path.join(appBundleInfo.pluginPath, pluginDirectory) @@ -454,8 +454,8 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): destinationPath = os.path.join(destinationDirectory, pluginName) shutil.copy2(sourcePath, destinationPath) if verbose >= 3: - print "Copied:", sourcePath - print " to:", destinationPath + print("Copied:", sourcePath) + print(" to:", destinationPath) if strip: runStrip(destinationPath, verbose) @@ -524,7 +524,7 @@ if config.translations_dir and config.translations_dir[0]: for p in config.add_resources: if verbose >= 3: - print "Checking for \"%s\"..." % p + print("Checking for \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p)) @@ -534,7 +534,7 @@ for p in config.add_resources: if len(config.fancy) == 1: if verbose >= 3: - print "Fancy: Importing plistlib..." + print("Fancy: Importing plistlib...") try: import plistlib except ImportError: @@ -544,7 +544,7 @@ if len(config.fancy) == 1: p = config.fancy[0] if verbose >= 3: - print "Fancy: Loading \"%s\"..." % p + print("Fancy: Loading \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p)) @@ -558,23 +558,23 @@ if len(config.fancy) == 1: sys.exit(1) try: - assert not fancy.has_key("window_bounds") or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4) - assert not fancy.has_key("background_picture") or isinstance(fancy["background_picture"], str) - assert not fancy.has_key("icon_size") or isinstance(fancy["icon_size"], int) - assert not fancy.has_key("applications_symlink") or isinstance(fancy["applications_symlink"], bool) - if fancy.has_key("items_position"): + assert "window_bounds" not in fancy or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4) + assert "background_picture" not in fancy or isinstance(fancy["background_picture"], str) + assert "icon_size" not in fancy or isinstance(fancy["icon_size"], int) + assert "applications_symlink" not in fancy or isinstance(fancy["applications_symlink"], bool) + if "items_position" in fancy: assert isinstance(fancy["items_position"], dict) - for key, value in fancy["items_position"].iteritems(): + for key, value in fancy["items_position"].items(): assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int) except: if verbose >= 1: sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p)) sys.exit(1) - if fancy.has_key("background_picture"): + if "background_picture" in fancy: bp = fancy["background_picture"] if verbose >= 3: - print "Fancy: Resolving background picture \"%s\"..." % bp + print("Fancy: Resolving background picture \"%s\"..." % bp) if not os.path.exists(bp): bp = os.path.join(os.path.dirname(p), bp) if not os.path.exists(bp): @@ -590,7 +590,7 @@ else: if os.path.exists("dist"): if verbose >= 2: - print "+ Removing old dist folder +" + print("+ Removing old dist folder +") shutil.rmtree("dist") @@ -599,9 +599,9 @@ if os.path.exists("dist"): target = os.path.join("dist", "Bitcoin-Qt.app") if verbose >= 2: - print "+ Copying source bundle +" + print("+ Copying source bundle +") if verbose >= 3: - print app_bundle, "->", target + print(app_bundle, "->", target) os.mkdir("dist") shutil.copytree(app_bundle, target, symlinks=True) @@ -611,7 +611,7 @@ applicationBundle = ApplicationBundleInfo(target) # ------------------------------------------------ if verbose >= 2: - print "+ Deploying frameworks +" + print("+ Deploying frameworks +") try: deploymentInfo = deployFrameworksForAppBundle(applicationBundle, config.strip, verbose) @@ -630,7 +630,7 @@ except RuntimeError as e: if config.plugins: if verbose >= 2: - print "+ Deploying plugins +" + print("+ Deploying plugins +") try: deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose) @@ -656,7 +656,7 @@ else: for lng_file in add_qt_tr: p = os.path.join(qt_tr_dir, lng_file) if verbose >= 3: - print "Checking for \"%s\"..." % p + print("Checking for \"%s\"..." % p) if not os.path.exists(p): if verbose >= 1: sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file)) @@ -665,7 +665,7 @@ else: # ------------------------------------------------ if verbose >= 2: - print "+ Installing qt.conf +" + print("+ Installing qt.conf +") f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") f.write(qt_conf) @@ -674,22 +674,22 @@ f.close() # ------------------------------------------------ if len(add_qt_tr) > 0 and verbose >= 2: - print "+ Adding Qt translations +" + print("+ Adding Qt translations +") for lng_file in add_qt_tr: if verbose >= 3: - print os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file) + print(os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file)) shutil.copy2(os.path.join(qt_tr_dir, lng_file), os.path.join(applicationBundle.resourcesPath, lng_file)) # ------------------------------------------------ if len(config.add_resources) > 0 and verbose >= 2: - print "+ Adding additional resources +" + print("+ Adding additional resources +") for p in config.add_resources: t = os.path.join(applicationBundle.resourcesPath, os.path.basename(p)) if verbose >= 3: - print p, "->", t + print(p, "->", t) if os.path.isdir(p): shutil.copytree(p, t, symlinks=True) else: @@ -698,10 +698,10 @@ for p in config.add_resources: # ------------------------------------------------ if config.sign and 'CODESIGNARGS' not in os.environ: - print "You must set the CODESIGNARGS environment variable. Skipping signing." + print("You must set the CODESIGNARGS environment variable. Skipping signing.") elif config.sign: if verbose >= 1: - print "Code-signing app bundle %s"%(target,) + print("Code-signing app bundle %s"%(target,)) subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True) # ------------------------------------------------ @@ -726,7 +726,7 @@ if config.dmg is not None: def runHDIUtil(verb, image_basename, **kwargs): hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] - if kwargs.has_key("capture_stdout"): + if "capture_stdout" in kwargs: del kwargs["capture_stdout"] run = subprocess.check_output else: @@ -736,7 +736,7 @@ if config.dmg is not None: hdiutil_args.append("-verbose") run = subprocess.check_call - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): hdiutil_args.append("-" + key) if not value is True: hdiutil_args.append(str(value)) @@ -745,9 +745,9 @@ if config.dmg is not None: if verbose >= 2: if fancy is None: - print "+ Creating .dmg disk image +" + print("+ Creating .dmg disk image +") else: - print "+ Preparing .dmg disk image +" + print("+ Preparing .dmg disk image +") if config.dmg != "": dmg_name = config.dmg @@ -762,7 +762,7 @@ if config.dmg is not None: sys.exit(e.returncode) else: if verbose >= 3: - print "Determining size of \"dist\"..." + print("Determining size of \"dist\"...") size = 0 for path, dirs, files in os.walk("dist"): for file in files: @@ -770,14 +770,14 @@ if config.dmg is not None: size += int(size * 0.15) if verbose >= 3: - print "Creating temp image for modification..." + print("Creating temp image for modification...") try: runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname="Bitcoin-Core", ov=True) except subprocess.CalledProcessError as e: sys.exit(e.returncode) if verbose >= 3: - print "Attaching temp image..." + print("Attaching temp image...") try: output = runHDIUtil("attach", dmg_name + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True) except subprocess.CalledProcessError as e: @@ -788,13 +788,13 @@ if config.dmg is not None: disk_name = m.group(1) if verbose >= 2: - print "+ Applying fancy settings +" + print("+ Applying fancy settings +") - if fancy.has_key("background_picture"): + if "background_picture" in fancy: bg_path = os.path.join(disk_root, ".background", os.path.basename(fancy["background_picture"])) os.mkdir(os.path.dirname(bg_path)) if verbose >= 3: - print fancy["background_picture"], "->", bg_path + print(fancy["background_picture"], "->", bg_path) shutil.copy2(fancy["background_picture"], bg_path) else: bg_path = None @@ -831,8 +831,8 @@ if config.dmg is not None: itemscript = Template('set position of item "${item}" of container window to {${position}}') items_positions = [] - if fancy.has_key("items_position"): - for name, position in fancy["items_position"].iteritems(): + if "items_position" in fancy: + for name, position in fancy["items_position"].items(): params = { "item" : name, "position" : ",".join([str(p) for p in position]) } items_positions.append(itemscript.substitute(params)) @@ -843,9 +843,9 @@ if config.dmg is not None: "background_commands" : "", "items_positions" : "\n ".join(items_positions) } - if fancy.has_key("window_bounds"): + if "window_bounds" in fancy: params["window.bounds"] = ",".join([str(p) for p in fancy["window_bounds"]]) - if fancy.has_key("icon_size"): + if "icon_size" in fancy: params["icon_size"] = str(fancy["icon_size"]) if bg_path is not None: # Set background file, then call SetFile to make it invisible. @@ -865,7 +865,7 @@ if config.dmg is not None: print("Error running osascript.") if verbose >= 2: - print "+ Finalizing .dmg disk image +" + print("+ Finalizing .dmg disk image +") time.sleep(5) try: @@ -878,6 +878,6 @@ if config.dmg is not None: # ------------------------------------------------ if verbose >= 2: - print "+ Done +" + print("+ Done +") sys.exit(0) diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py index d4bd58513..a270926e1 100755 --- a/share/qt/extract_strings_qt.py +++ b/share/qt/extract_strings_qt.py @@ -1,8 +1,9 @@ #!/usr/bin/python ''' -Extract _("...") strings for translation and convert to Qt4 stringdefs so that +Extract _("...") strings for translation and convert to Qt stringdefs so that they can be picked up by Qt linguist. ''' +from __future__ import division,print_function,unicode_literals from subprocess import Popen, PIPE import glob import operator @@ -52,10 +53,14 @@ files = sys.argv[1:] # xgettext -n --keyword=_ $FILES XGETTEXT=os.getenv('XGETTEXT', 'xgettext') +if not XGETTEXT: + print('Cannot extract strings: xgettext utility is not installed or not configured.',file=sys.stderr) + print('Please install package "gettext" and re-run \'./configure\'.',file=sys.stderr) + exit(1) child = Popen([XGETTEXT,'--output=-','-n','--keyword=_'] + files, stdout=PIPE) (out, err) = child.communicate() -messages = parse_po(out) +messages = parse_po(out.decode('utf-8')) f = open(OUT_CPP, 'w') f.write(""" diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 242baf7ae..c04adb184 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -403,7 +403,7 @@ SECONDARY: $(QT_QM) $(srcdir)/qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" - $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) ../share/qt/extract_strings_qt.py $^ + $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) $(PYTHON) ../share/qt/extract_strings_qt.py $^ translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" diff --git a/src/Makefile.test.include b/src/Makefile.test.include index ce31db5b5..8a8f05be3 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -133,10 +133,10 @@ bitcoin_test_clean : FORCE check-local: @echo "Running test/bitcoin-util-test.py..." - $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py + $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/bitcoin-util-test.py if ENABLE_WALLET @echo "Running test/wallet-utility.py..." - $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/wallet-utility.py + $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/wallet-utility.py endif $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE diff --git a/src/test/bctest.py b/src/test/bctest.py index 3a8d0ea51..8105b87ff 100644 --- a/src/test/bctest.py +++ b/src/test/bctest.py @@ -1,7 +1,7 @@ # Copyright 2014 BitPay, Inc. # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. - +from __future__ import division,print_function,unicode_literals import subprocess import os import json diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py index 20afb16a9..95dd3e81b 100755 --- a/src/test/bitcoin-util-test.py +++ b/src/test/bitcoin-util-test.py @@ -2,7 +2,7 @@ # Copyright 2014 BitPay, Inc. # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. - +from __future__ import division,print_function,unicode_literals import os import bctest import buildenv From f6d63b9123c5beb4c8489443a0002f9cb246d475 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 2 Apr 2016 16:45:26 +0200 Subject: [PATCH 062/110] depends: mac deploy Py3 compatibility This fixes the gitian MacOSX build, it was broken in #7723. The patch to `native_mac_alias` should probably make it upstream. --- contrib/macdeploy/macdeployqtplus | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index c51130077..5fbabdcda 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -210,8 +210,8 @@ def getFrameworks(binaryPath, verbose): sys.stderr.write(o_stderr) sys.stderr.flush() raise RuntimeError("otool failed with return code %d" % otool.returncode) - - otoolLines = o_stdout.split("\n") + + otoolLines = o_stdout.decode().split("\n") otoolLines.pop(0) # First line is the inspected binary if ".framework" in binaryPath or binaryPath.endswith(".dylib"): otoolLines.pop(0) # Frameworks and dylibs list themselves as a dependency. @@ -668,7 +668,7 @@ if verbose >= 2: print("+ Installing qt.conf +") f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") -f.write(qt_conf) +f.write(qt_conf.encode()) f.close() # ------------------------------------------------ From ed3c825a9afcaa553409f2179a783d35f017baee Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 7 Jun 2016 14:51:51 -0400 Subject: [PATCH 063/110] gitian: use CONFIG_SITE rather than hijacking the prefix --- contrib/gitian-descriptors/gitian-linux.yml | 6 +++--- contrib/gitian-descriptors/gitian-osx.yml | 6 +++--- contrib/gitian-descriptors/gitian-win.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index c3dcab960..921f5452a 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -86,7 +86,7 @@ script: | # Create the release tarball using (arbitrarily) the first host ./autogen.sh - ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` + CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` @@ -107,11 +107,11 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security make ${MAKEOPTS} -C src check-symbols - make install-strip + make install-strip DESTDIR=${INSTALLPATH} cd installed find . -name "lib*.la" -delete find . -name "lib*.a" -delete diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 2f9a1e0fb..1bfa13e9d 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -96,7 +96,7 @@ script: | # Create the release tarball using (arbitrarily) the first host ./autogen.sh - ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` + CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` @@ -118,9 +118,9 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} - make install-strip + make install-strip DESTDIR=${INSTALLPATH} make deploydir mkdir -p unsigned-app-${i} diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 9a09f637d..b9202e2b3 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -115,7 +115,7 @@ script: | # Create the release tarball using (arbitrarily) the first host ./autogen.sh - ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` + CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist SOURCEDIST=`echo bitcoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` @@ -139,11 +139,11 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security make deploy - make install-strip + make install-strip DESTDIR=${INSTALLPATH} cp -f bitcoin-*setup*.exe $OUTDIR/ cd installed mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ From f41be6dbfb64e6750c4e930bf70651cff0ef1e7f Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 7 Jun 2016 22:09:28 -0400 Subject: [PATCH 064/110] gitian: create debug packages for linux/windows --- contrib/gitian-descriptors/gitian-linux.yml | 21 +++++++++++++++------ contrib/gitian-descriptors/gitian-win.yml | 20 ++++++++++++++------ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 921f5452a..a189e321b 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -24,10 +24,13 @@ remotes: files: [] script: | WRAP_DIR=$HOME/wrapped - HOSTS="i686-pc-linux-gnu x86_64-unknown-linux-gnu" - CONFIGFLAGS="--enable-upnp-default --enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests LDFLAGS=-static-libstdc++" + HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu" + CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests" FAKETIME_HOST_PROGS="" - FAKETIME_PROGS="date ar ranlib nm strip" + FAKETIME_PROGS="date ar ranlib nm" + HOST_CFLAGS="-O2 -g" + HOST_CXXFLAGS="-O2 -g" + HOST_LDFLAGS=-static-libstdc++ export QT_RCC_TEST=1 export GZIP="-9n" @@ -107,20 +110,26 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security make ${MAKEOPTS} -C src check-symbols - make install-strip DESTDIR=${INSTALLPATH} + make install DESTDIR=${INSTALLPATH} cd installed find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig - find ${DISTNAME} | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz + find ${DISTNAME}/bin -type f -executable -exec objcopy --only-keep-debug {} {}.dbg \; -exec strip -s {} \; -exec objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME}/lib -type f -exec objcopy --only-keep-debug {} {}.dbg \; -exec strip -s {} \; -exec objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz + find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz cd ../../ + rm -rf distsrc-${i} done mkdir -p $OUTDIR/src mv $SOURCEDIST $OUTDIR/src + mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.tar.gz ${OUTDIR}/${DISTNAME}-linux64-debug.tar.gz + mv ${OUTDIR}/${DISTNAME}-i686-*-debug.tar.gz ${OUTDIR}/${DISTNAME}-linux32-debug.tar.gz mv ${OUTDIR}/${DISTNAME}-x86_64-*.tar.gz ${OUTDIR}/${DISTNAME}-linux64.tar.gz mv ${OUTDIR}/${DISTNAME}-i686-*.tar.gz ${OUTDIR}/${DISTNAME}-linux32.tar.gz diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index b9202e2b3..f16532e0f 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -28,9 +28,11 @@ files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-w64-mingw32 i686-w64-mingw32" - CONFIGFLAGS="--enable-upnp-default --enable-reduce-exports --disable-gui-tests" - FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip" + CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests" + FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip objcopy" FAKETIME_PROGS="date makensis zip" + HOST_CFLAGS="-O2 -g" + HOST_CXXFLAGS="-O2 -g" export QT_RCC_TEST=1 export GZIP="-9n" @@ -139,22 +141,28 @@ script: | mkdir -p ${INSTALLPATH} tar --strip-components=1 -xf ../$SOURCEDIST - CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" make ${MAKEOPTS} make ${MAKEOPTS} -C src check-security make deploy - make install-strip DESTDIR=${INSTALLPATH} + make install DESTDIR=${INSTALLPATH} cp -f bitcoin-*setup*.exe $OUTDIR/ cd installed mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig - find ${DISTNAME} -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip - cd ../.. + find ${DISTNAME}/bin -type f -executable -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; + find ${DISTNAME} -not -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip + find ${DISTNAME} -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}-debug.zip + cd ../../ + rm -rf distsrc-${i} done cd $OUTDIR rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe find . -name "*-setup-unsigned.exe" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz + mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip + mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip mv ${OUTDIR}/${DISTNAME}-i686-*.zip ${OUTDIR}/${DISTNAME}-win32.zip From 2ac25f14eab34be462ce2870e1c689156d0b2163 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 7 Jul 2016 20:09:55 -0400 Subject: [PATCH 065/110] gitian: use a wrapped gcc/g++ to avoid the need for a system change --- contrib/gitian-descriptors/gitian-linux.yml | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index a189e321b..38034c5b2 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -74,11 +74,45 @@ script: | create_per-host_faketime_wrappers "2000-01-01 12:00:00" export PATH=${WRAP_DIR}:${PATH} + EXTRA_INCLUDES_BASE=$WRAP_DIR/extra_includes + mkdir -p $EXTRA_INCLUDES_BASE + + # x86 needs /usr/include/i386-linux-gnu/asm pointed to /usr/include/x86_64-linux-gnu/asm, + # but we can't write there. Instead, create a link here and force it to be included in the + # search paths by wrapping gcc/g++. + + mkdir -p $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu + rm -f $WRAP_DIR/extra_includes/i686-pc-linux-gnu/asm + ln -s /usr/include/x86_64-linux-gnu/asm $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu/asm + + for prog in gcc g++; do + rm -f ${WRAP_DIR}/${prog} + cat << EOF > ${WRAP_DIR}/${prog} + #!/bin/bash + REAL="`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1`" + for var in "\$@" + do + if [ "\$var" = "-m32" ]; then + export C_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu" + export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu" + break + fi + done + \$REAL \$@ + EOF + chmod +x ${WRAP_DIR}/${prog} + done + cd bitcoin BASEPREFIX=`pwd`/depends # Build dependencies for each host for i in $HOSTS; do + EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i" + if [ -d "$EXTRA_INCLUDES" ]; then + export HOST_ID_SALT="$EXTRA_INCLUDES" + fi make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" + unset HOST_ID_SALT done # Faketime for binaries From a4dc487b0e0b480cc922f0e95bcf0478fd040d93 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Thu, 12 Nov 2015 16:57:03 -0500 Subject: [PATCH 066/110] Save the last unnecessary database read It's possible coins with the same hash exist when you create a duplicate coinbase, so previously we were reading from the database to make sure we had the old coins cached so if we were to spend the new ones, the old ones would also be spent. This pull instead just marks the new coins as not fresh if they are from a coinbase, so if they are spent they will be written all the way down to the database anyway overwriting any duplicates. --- src/coins.cpp | 10 ++++++++-- src/coins.h | 2 +- src/main.cpp | 12 ++---------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index 3b354b1ca..20045466f 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -117,11 +117,17 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { return CCoinsModifier(*this, ret.first, cachedCoinUsage); } -CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid) { +// ModifyNewCoins has to know whether the new outputs its creating are for a +// coinbase or not. If they are for a coinbase, it can not mark them as fresh. +// This is to ensure that the historical duplicate coinbases before BIP30 was +// in effect will still be properly overwritten when spent. +CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) { assert(!hasModifier); std::pair ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); ret.first->second.coins.Clear(); - ret.first->second.flags = CCoinsCacheEntry::FRESH; + if (!coinbase) { + ret.first->second.flags = CCoinsCacheEntry::FRESH; + } ret.first->second.flags |= CCoinsCacheEntry::DIRTY; return CCoinsModifier(*this, ret.first, 0); } diff --git a/src/coins.h b/src/coins.h index 3bab34ad0..ac308423e 100644 --- a/src/coins.h +++ b/src/coins.h @@ -469,7 +469,7 @@ public: * would not properly overwrite the first coinbase of the pair. Simultaneous modifications * are not allowed. */ - CCoinsModifier ModifyNewCoins(const uint256 &txid); + CCoinsModifier ModifyNewCoins(const uint256 &txid, bool coinbase); /** * Push the modifications applied to this cache to its base. diff --git a/src/main.cpp b/src/main.cpp index eae3b38a8..28f6c05b4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1932,17 +1932,9 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach undo.nTime = coins->nTime; } } - // add outputs - inputs.ModifyNewCoins(tx.GetHash())->FromTx(tx, nHeight); - } - else { - // add outputs for coinbase tx - // In this case call the full ModifyCoins which will do a database - // lookup to be sure the coins do not already exist otherwise we do not - // know whether to mark them fresh or not. We want the duplicate coinbases - // before BIP30 to still be properly overwritten. - inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); } + // add outputs + inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight); } void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight) From 3d26f43eb0a943d5792d92343db4598c1cb56136 Mon Sep 17 00:00:00 2001 From: lateminer Date: Sat, 13 Jan 2018 01:30:21 +0300 Subject: [PATCH 067/110] mempool: Replace maxFeeRate of 10000*minRelayTxFee with maxTxFee https://github.com/bitcoin/bitcoin/pull/7084/commits/fa331db68bcc68e4c93fb45aaa30f911b0ecfe1a --- src/main.cpp | 6 +++--- src/main.h | 5 +++++ src/wallet/wallet.cpp | 1 - src/wallet/wallet.h | 4 +--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 28f6c05b4..1ae584992 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -92,8 +92,8 @@ uint64_t nPruneTarget = 0; bool fAlerts = DEFAULT_ALERTS; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; -/** Fees smaller than this (in satoshi) are considered zero fee (for relaying, mining and transaction creation) */ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); +CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; CTxMemPool mempool(::minRelayTxFee); @@ -1286,10 +1286,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); } - if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) + if (fRejectAbsurdFee && nFees > maxTxFee) return state.Invalid(false, REJECT_HIGHFEE, "absurdly-high-fee", - strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000)); + strprintf("%d > %d", nFees, maxTxFee)); // Calculate in-mempool ancestors, up to a limit. CTxMemPool::setEntries setAncestors; diff --git a/src/main.h b/src/main.h index 3438510a9..ff3cf033a 100644 --- a/src/main.h +++ b/src/main.h @@ -53,6 +53,8 @@ static const bool DEFAULT_WHITELISTRELAY = true; static const bool DEFAULT_WHITELISTFORCERELAY = true; /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 10000; +//! -maxtxfee default +static const CAmount DEFAULT_TRANSACTION_MAXFEE = 1 * COIN; //! Discourage users to set fees higher than this amount (in satoshis) per kB static const CAmount HIGH_TX_FEE_PER_KB = 0.1 * COIN; //! -maxtxfee will warn if called with a higher fee than this amount (in satoshis) @@ -158,7 +160,10 @@ extern unsigned int nBytesPerSigOp; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; extern size_t nCoinCacheUsage; +/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */ extern CFeeRate minRelayTxFee; +/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */ +extern CAmount maxTxFee; extern bool fAlerts; extern bool fEnableReplacement; extern int64_t nLastCoinStakeSearchInterval; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0080d9bf7..727562976 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -38,7 +38,6 @@ using namespace std; CWallet* pwalletMain = NULL; /** Transaction fee set by the user */ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); -CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 9bb06bd45..9da3f39a7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -32,7 +32,6 @@ extern CWallet* pwalletMain; * Settings */ extern CFeeRate payTxFee; -extern CAmount maxTxFee; extern CAmount nReserveBalance; extern CAmount nMinimumInputValue; extern unsigned int nTxConfirmTarget; @@ -47,8 +46,6 @@ static const CAmount DEFAULT_TRANSACTION_FEE = 10000; static const CAmount DEFAULT_FALLBACK_FEE = 10000; //! -mintxfee default static const CAmount DEFAULT_TRANSACTION_MINFEE = 10000; -//! -maxtxfee default -static const CAmount DEFAULT_TRANSACTION_MAXFEE = 1 * COIN; //! minimum change amount static const CAmount MIN_CHANGE = CENT; //! Default for -spendzeroconfchange @@ -215,6 +212,7 @@ public: int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; } int GetBlocksToMaturity() const; + /** Pass this transaction to the mempool. Fails if absolute fee exceeds maxTxFee. */ bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true); bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); } bool isAbandoned() const { return (hashBlock == ABANDON_HASH); } From 1e0ba49e26b1e8c1a46d659a2e52088e7863071c Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 16 Feb 2016 12:10:12 -0500 Subject: [PATCH 068/110] Add tags to mempool's mapTx indices --- src/miner.cpp | 4 ++-- src/test/mempool_tests.cpp | 22 +++++++++++----------- src/txmempool.cpp | 6 +++--- src/txmempool.h | 8 ++++++++ 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 543d3617b..19fb0034d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -184,10 +184,10 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); } - CTxMemPool::indexed_transaction_set::nth_index<3>::type::iterator mi = mempool.mapTx.get<3>().begin(); + CTxMemPool::indexed_transaction_set::index::type::iterator mi = mempool.mapTx.get().begin(); CTxMemPool::txiter iter; - while (mi != mempool.mapTx.get<3>().end() || !clearedTxs.empty()) + while (mi != mempool.mapTx.get().end() || !clearedTxs.empty()) { bool priorityTx = false; if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 1347d2365..fa352ace8 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -102,13 +102,13 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) removed.clear(); } -template +template void CheckSort(CTxMemPool &pool, std::vector &sortedOrder) { BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size()); - typename CTxMemPool::indexed_transaction_set::nth_index::type::iterator it = pool.mapTx.get().begin(); + typename CTxMemPool::indexed_transaction_set::index::type::iterator it = pool.mapTx.get().begin(); int count=0; - for (; it != pool.mapTx.get().end(); ++it, ++count) { + for (; it != pool.mapTx.get().end(); ++it, ++count) { BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]); } } @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder[2] = tx1.GetHash().ToString(); // 10000 sortedOrder[3] = tx4.GetHash().ToString(); // 15000 sortedOrder[4] = tx2.GetHash().ToString(); // 20000 - CheckSort<1>(pool, sortedOrder); + CheckSort(pool, sortedOrder); /* low fee but with high fee child */ /* tx6 -> tx7 -> tx8, tx9 -> tx10 */ @@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_CHECK_EQUAL(pool.size(), 6); // Check that at this point, tx6 is sorted low sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort(pool, sortedOrder); CTxMemPool::setEntries setAncestors; setAncestors.insert(pool.mapTx.find(tx6.GetHash())); @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder.erase(sortedOrder.begin()); sortedOrder.push_back(tx6.GetHash().ToString()); sortedOrder.push_back(tx7.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx8 = CMutableTransaction(); @@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) // Now tx8 should be sorted low, but tx6/tx both high sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx9 = CMutableTransaction(); @@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9); sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString()); - CheckSort<1>(pool, sortedOrder); + CheckSort(pool, sortedOrder); std::vector snapshotOrder = sortedOrder; @@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString()); sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString()); sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6 - CheckSort<1>(pool, sortedOrder); + CheckSort(pool, sortedOrder); // there should be 10 transactions in the mempool BOOST_CHECK_EQUAL(pool.size(), 10); @@ -282,7 +282,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) // Now try removing tx10 and verify the sort order returns to normal std::list removed; pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true); - CheckSort<1>(pool, snapshotOrder); + CheckSort(pool, snapshotOrder); pool.remove(pool.mapTx.find(tx9.GetHash())->GetTx(), removed, true); pool.remove(pool.mapTx.find(tx8.GetHash())->GetTx(), removed, true); @@ -314,7 +314,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) sortedOrder.push_back(tx3.GetHash().ToString()); sortedOrder.push_back(tx6.GetHash().ToString()); } - CheckSort<3>(pool, sortedOrder); + CheckSort(pool, sortedOrder); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 8782678eb..d87a72f99 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1011,9 +1011,9 @@ void CTxMemPool::RemoveStaged(setEntries &stage) { int CTxMemPool::Expire(int64_t time) { LOCK(cs); - indexed_transaction_set::nth_index<2>::type::iterator it = mapTx.get<2>().begin(); + indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); setEntries toremove; - while (it != mapTx.get<2>().end() && it->GetTime() < time) { + while (it != mapTx.get().end() && it->GetTime() < time) { toremove.insert(mapTx.project<0>(it)); it++; } @@ -1109,7 +1109,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe unsigned nTxnRemoved = 0; CFeeRate maxFeeRateRemoved(0); while (DynamicMemoryUsage() > sizelimit) { - indexed_transaction_set::nth_index<1>::type::iterator it = mapTx.get<1>().begin(); + indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); // We set the new mempool min fee to the feerate of the removed set, plus the // "minimum reasonable fee rate" (ie some value under which we consider txn diff --git a/src/txmempool.h b/src/txmempool.h index a94ff607b..f91790d47 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -260,6 +260,11 @@ public: } }; +// Multi_index tag names +struct descendant_score {}; +struct entry_time {}; +struct mining_score {}; + class CBlockPolicyEstimator; /** An inpoint - a combination of a transaction and an index n into its vin */ @@ -382,16 +387,19 @@ public: boost::multi_index::ordered_unique, // sorted by fee rate boost::multi_index::ordered_non_unique< + boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByDescendantScore >, // sorted by entry time boost::multi_index::ordered_non_unique< + boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByEntryTime >, // sorted by score (for mining prioritization) boost::multi_index::ordered_unique< + boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByScore > From fefec9de84001d5a5160e9b2fa83afb57417b18f Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 24 Feb 2016 18:34:37 +0100 Subject: [PATCH 069/110] mempool: Re-remove ERROR logging for mempool rejects --- src/main.cpp | 57 +++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1ae584992..c549cb614 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1069,7 +1069,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C *pfMissingInputs = false; if (!CheckTransaction(tx, state)) - return false; + return false; // state filled in by CheckTransaction // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) @@ -1311,10 +1311,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C const uint256 &hashAncestor = ancestorIt->GetTx().GetHash(); if (setConflicts.count(hashAncestor)) { - return state.DoS(10, error("AcceptToMemoryPool: %s spends conflicting transaction %s", + return state.DoS(10, false, + REJECT_INVALID, "bad-txns-spends-conflicting-tx", false, + strprintf("%s spends conflicting transaction %s", hash.ToString(), - hashAncestor.ToString()), - REJECT_INVALID, "bad-txns-spends-conflicting-tx"); + hashAncestor.ToString())); } } @@ -1351,11 +1352,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // that we don't spend too much time walking descendants. // This should be rare. if (mi->IsDirty()) { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; cannot replace tx %s with untracked descendants", + return state.DoS(0, false, + REJECT_NONSTANDARD, "too many potential replacements", false, + strprintf("too many potential replacements: rejecting replacement %s; cannot replace tx %s with untracked descendants", hash.ToString(), - mi->GetTx().GetHash().ToString()), - REJECT_NONSTANDARD, "too many potential replacements"); + mi->GetTx().GetHash().ToString())); } // Don't allow the replacement to reduce the feerate of the @@ -1377,12 +1378,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize()); if (newFeeRate <= oldFeeRate) { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; new feerate %s <= old feerate %s", + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s; new feerate %s <= old feerate %s", hash.ToString(), newFeeRate.ToString(), - oldFeeRate.ToString()), - REJECT_INSUFFICIENTFEE, "insufficient fee"); + oldFeeRate.ToString())); } BOOST_FOREACH(const CTxIn &txin, mi->GetTx().vin) @@ -1406,12 +1407,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C nConflictingSize += it->GetTxSize(); } } else { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; too many potential replacements (%d > %d)\n", + return state.DoS(0, false, + REJECT_NONSTANDARD, "too many potential replacements", false, + strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n", hash.ToString(), nConflictingCount, - maxDescendantsToVisit), - REJECT_NONSTANDARD, "too many potential replacements"); + maxDescendantsToVisit)); } for (unsigned int j = 0; j < tx.vin.size(); j++) @@ -1426,9 +1427,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // it's cheaper to just check if the new input refers to a // tx that's in the mempool. if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end()) - return state.DoS(0, error("AcceptToMemoryPool: replacement %s adds unconfirmed input, idx %d", - hash.ToString(), j), - REJECT_NONSTANDARD, "replacement-adds-unconfirmed"); + return state.DoS(0, false, + REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false, + strprintf("replacement %s adds unconfirmed input, idx %d", + hash.ToString(), j)); } } @@ -1437,9 +1439,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // transactions would not be paid for. if (nModifiedFees < nConflictingFees) { - return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s", - hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)), - REJECT_INSUFFICIENTFEE, "insufficient fee"); + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s", + hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees))); } // Finally in addition to paying more fees than the conflicts the @@ -1447,19 +1450,19 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C CAmount nDeltaFees = nModifiedFees - nConflictingFees; if (nDeltaFees < ::minRelayTxFee.GetFee(nSize)) { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s, not enough additional fees to relay; %s < %s", + return state.DoS(0, false, + REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s", hash.ToString(), FormatMoney(nDeltaFees), - FormatMoney(::minRelayTxFee.GetFee(nSize))), - REJECT_INSUFFICIENTFEE, "insufficient fee"); + FormatMoney(::minRelayTxFee.GetFee(nSize)))); } } // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) - return false; + return false; // state filled in by CheckInputs // Check again against just the consensus-critical mandatory script // verification flags, in case of bugs in the standard flags that cause From ff1f0ead66d6aff950b06dd28641498314f19a1b Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 12:42:42 -0400 Subject: [PATCH 070/110] CTxMemPool::removeForBlock now uses RemoveStaged --- src/txmempool.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index d87a72f99..f6b7e6dcb 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -716,8 +716,12 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i } BOOST_FOREACH(const CTransaction& tx, vtx) { - std::list dummy; - remove(tx, dummy, false); + txiter it = mapTx.find(tx.GetHash()); + if (it != mapTx.end()) { + setEntries stage; + stage.insert(it); + RemoveStaged(stage); + } removeConflicts(tx, conflicts); ClearPrioritisation(tx.GetHash()); } From e001fd3ea4992f6ad33cafcad50ec88c826558ef Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 12:43:38 -0400 Subject: [PATCH 071/110] Rename CTxMemPool::remove -> removeRecursive --- src/main.cpp | 2 +- src/test/mempool_tests.cpp | 20 ++++++++++---------- src/txmempool.cpp | 18 +++++++----------- src/txmempool.h | 2 +- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c549cb614..51411964b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3192,7 +3192,7 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons list removed; CValidationState stateDummy; if (tx.IsCoinBase() || tx.IsCoinStake() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { - mempool.remove(tx, removed, true); + mempool.removeRecursive(tx, removed); } else if (mempool.exists(tx.GetHash())) { vHashUpdate.push_back(tx.GetHash()); } diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index fa352ace8..ebdf7dbaa 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -57,12 +57,12 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) std::list removed; // Nothing in pool, remove should do nothing: - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 0); // Just the parent: testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 1); removed.clear(); @@ -74,16 +74,16 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } // Remove Child[0], GrandChild[0] should be removed: - testPool.remove(txChild[0], removed, true); + testPool.removeRecursive(txChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 2); removed.clear(); // ... make sure grandchild and child are gone: - testPool.remove(txGrandChild[0], removed, true); + testPool.removeRecursive(txGrandChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 0); - testPool.remove(txChild[0], removed, true); + testPool.removeRecursive(txChild[0], removed); BOOST_CHECK_EQUAL(removed.size(), 0); // Remove parent, all children/grandchildren should go: - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 5); BOOST_CHECK_EQUAL(testPool.size(), 0); removed.clear(); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) } // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be // put into the mempool (maybe because it is non-standard): - testPool.remove(txParent, removed, true); + testPool.removeRecursive(txParent, removed); BOOST_CHECK_EQUAL(removed.size(), 6); BOOST_CHECK_EQUAL(testPool.size(), 0); removed.clear(); @@ -281,11 +281,11 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) // Now try removing tx10 and verify the sort order returns to normal std::list removed; - pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true); + pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), removed); CheckSort(pool, snapshotOrder); - pool.remove(pool.mapTx.find(tx9.GetHash())->GetTx(), removed, true); - pool.remove(pool.mapTx.find(tx8.GetHash())->GetTx(), removed, true); + pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), removed); + pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), removed); /* Now check the sort on the mining score index. * Final order should be: * diff --git a/src/txmempool.cpp b/src/txmempool.cpp index f6b7e6dcb..5ab1d5f37 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -607,7 +607,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::remove(const CTransaction &origTx, std::list& removed, bool fRecursive) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list& removed) { // Remove transaction from memory pool { @@ -616,8 +616,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txiter origit = mapTx.find(origTx.GetHash()); if (origit != mapTx.end()) { txToRemove.insert(origit); - } else if (fRecursive) { - // If recursively removing but origTx isn't in the mempool + } else { + // When recursively removing but origTx isn't in the mempool // be sure to remove any children that are in the pool. This can // happen during chain re-orgs if origTx isn't re-accepted into // the mempool for any reason. @@ -631,12 +631,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem } } setEntries setAllRemoves; - if (fRecursive) { - BOOST_FOREACH(txiter it, txToRemove) { - CalculateDescendants(it, setAllRemoves); - } - } else { - setAllRemoves.swap(txToRemove); + BOOST_FOREACH(txiter it, txToRemove) { + CalculateDescendants(it, setAllRemoves); } BOOST_FOREACH(txiter it, setAllRemoves) { removed.push_back(it->GetTx()); @@ -677,7 +673,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem } BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { list removed; - remove(tx, removed, true); + removeRecursive(tx, removed); } } @@ -691,7 +687,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list const CTransaction &txConflict = *it->second.ptx; if (txConflict != tx) { - remove(txConflict, removed, true); + removeRecursive(txConflict, removed); ClearPrioritisation(txConflict.GetHash()); } } diff --git a/src/txmempool.h b/src/txmempool.h index f91790d47..d3e72b3ac 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -481,7 +481,7 @@ public: bool getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); bool removeSpentIndex(const uint256 txhash); - void remove(const CTransaction &tx, std::list& removed, bool fRecursive = false); + void removeRecursive(const CTransaction &tx, std::list& removed); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); void removeConflicts(const CTransaction &tx, std::list& removed); void removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, From 83568275f1be1aa837c4f541d8efa82a8f3f16b6 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 21 Oct 2015 10:18:24 -0400 Subject: [PATCH 072/110] Remove work limit in UpdateForDescendants() The work limit served to prevent the descendant walking algorithm from doing too much work by marking the parent transaction as dirty. However to implement ancestor tracking, it's not possible to similarly mark those descendant transactions as dirty without having to calculate them to begin with. This commit removes the work limit altogether. With appropriate chain limits (-limitdescendantcount) the concern about doing too much work inside this function should be mitigated. --- src/main.cpp | 14 ----------- src/txmempool.cpp | 59 +++++++++-------------------------------------- src/txmempool.h | 19 +-------------- 3 files changed, 12 insertions(+), 80 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 51411964b..993198b83 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1345,20 +1345,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // Save these to avoid repeated lookups setIterConflicting.insert(mi); - // If this entry is "dirty", then we don't have descendant - // state for this transaction, which means we probably have - // lots of in-mempool descendants. - // Don't allow replacements of dirty transactions, to ensure - // that we don't spend too much time walking descendants. - // This should be rare. - if (mi->IsDirty()) { - return state.DoS(0, false, - REJECT_NONSTANDARD, "too many potential replacements", false, - strprintf("too many potential replacements: rejecting replacement %s; cannot replace tx %s with untracked descendants", - hash.ToString(), - mi->GetTx().GetHash().ToString())); - } - // Don't allow the replacement to reduce the feerate of the // mempool. // diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5ab1d5f37..ce41f6e4c 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -69,21 +69,13 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. -bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set &setExclude) +void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set &setExclude) { - // Track the number of entries (outside setExclude) that we'd need to visit - // (will bail out if it exceeds maxDescendantsToVisit) - int nChildrenToVisit = 0; - setEntries stageEntries, setAllDescendants; stageEntries = GetMemPoolChildren(updateIt); while (!stageEntries.empty()) { const txiter cit = *stageEntries.begin(); - if (cit->IsDirty()) { - // Don't consider any more children if any descendant is dirty - return false; - } setAllDescendants.insert(cit); stageEntries.erase(cit); const setEntries &setChildren = GetMemPoolChildren(cit); @@ -93,22 +85,11 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit // We've already calculated this one, just add the entries for this set // but don't traverse again. BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) { - // update visit count only for new child transactions - // (outside of setExclude and stageEntries) - if (setAllDescendants.insert(cacheEntry).second && - !setExclude.count(cacheEntry->GetTx().GetHash()) && - !stageEntries.count(cacheEntry)) { - nChildrenToVisit++; - } + setAllDescendants.insert(cacheEntry); } } else if (!setAllDescendants.count(childEntry)) { - // Schedule for later processing and update our visit count - if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) { - nChildrenToVisit++; - } - } - if (nChildrenToVisit > maxDescendantsToVisit) { - return false; + // Schedule for later processing + stageEntries.insert(childEntry); } } } @@ -126,7 +107,6 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); - return true; } // vHashesToUpdate is the set of transaction hashes from a disconnected block @@ -172,10 +152,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes UpdateParent(childIter, it, true); } } - if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) { - // Mark as dirty if we can't do the calculation. - mapTx.modify(it, set_dirty()); - } + UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded); } } @@ -306,22 +283,13 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) } } -void CTxMemPoolEntry::SetDirty() -{ - nCountWithDescendants = 0; - nSizeWithDescendants = nTxSize; - nModFeesWithDescendants = GetModifiedFee(); -} - void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) { - if (!IsDirty()) { - nSizeWithDescendants += modifySize; - assert(int64_t(nSizeWithDescendants) > 0); - nModFeesWithDescendants += modifyFee; - nCountWithDescendants += modifyCount; - assert(int64_t(nCountWithDescendants) > 0); - } + nSizeWithDescendants += modifySize; + assert(int64_t(nSizeWithDescendants) > 0); + nModFeesWithDescendants += modifyFee; + nCountWithDescendants += modifyCount; + assert(int64_t(nCountWithDescendants) > 0); } CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : @@ -810,12 +778,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(setChildrenCheck == GetMemPoolChildren(it)); // Also check to make sure size is greater than sum with immediate children. // just a sanity check, not definitive that this calc is correct... - if (!it->IsDirty()) { - assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); - } else { - assert(it->GetSizeWithDescendants() == it->GetTxSize()); - assert(it->GetModFeesWithDescendants() == it->GetModifiedFee()); - } + assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); if (fDependsWait) waitingOnDependants.push_back(&(*it)); diff --git a/src/txmempool.h b/src/txmempool.h index d3e72b3ac..4a463b520 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -130,13 +130,6 @@ public: // Update the LockPoints after a reorg void UpdateLockPoints(const LockPoints& lp); - /** We can set the entry to be dirty if doing the full calculation of in- - * mempool descendants will be too expensive, which can potentially happen - * when re-adding transactions from a block back to the mempool. - */ - void SetDirty(); - bool IsDirty() const { return nCountWithDescendants == 0; } - uint64_t GetCountWithDescendants() const { return nCountWithDescendants; } uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; } CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } @@ -160,12 +153,6 @@ struct update_descendant_state int64_t modifyCount; }; -struct set_dirty -{ - void operator() (CTxMemPoolEntry &e) - { e.SetDirty(); } -}; - struct update_fee_delta { update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { } @@ -608,15 +595,11 @@ private: * updated and hence their state is already reflected in the parent * state). * - * If updating an entry requires looking at more than maxDescendantsToVisit - * transactions, outside of the ones in setExclude, then give up. - * * cachedDescendants will be updated with the descendants of the transaction * being updated, so that future invocations don't need to walk the * same transaction again, if encountered in another transaction chain. */ - bool UpdateForDescendants(txiter updateIt, - int maxDescendantsToVisit, + void UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set &setExclude); /** Update ancestors of hash to add/remove it as a descendant transaction. */ From dcb944110557311484a7739f656ac0296f87a069 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 10:54:28 -0400 Subject: [PATCH 073/110] Add ancestor tracking to mempool This implements caching of ancestor state to each mempool entry, similar to descendant tracking, but also including caching sigops-with-ancestors (as that metric will be helpful to future code that implements better transaction selection in CreatenewBlock). --- src/main.cpp | 2 +- src/txmempool.cpp | 88 +++++++++++++++++++++++++++++++++++++++-------- src/txmempool.h | 49 ++++++++++++++++++++++---- 3 files changed, 117 insertions(+), 22 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 993198b83..2079cd268 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1474,7 +1474,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C FormatMoney(nModifiedFees - nConflictingFees), (int)nSize - (int)nConflictingSize); } - pool.RemoveStaged(allConflicting); + pool.RemoveStaged(allConflicting, false); if (fRespend) { diff --git a/src/txmempool.cpp b/src/txmempool.cpp index ce41f6e4c..0546f7f15 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -38,6 +38,11 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, assert(inChainInputValue <= nValueIn); feeDelta = 0; + + nCountWithAncestors = 1; + nSizeWithAncestors = nTxSize; + nModFeesWithAncestors = nFee; + nSigOpCountWithAncestors = sigOpCount; } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -58,6 +63,7 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) { nModFeesWithDescendants += newFeeDelta - feeDelta; + nModFeesWithAncestors += newFeeDelta - feeDelta; feeDelta = newFeeDelta; } @@ -104,6 +110,8 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan modifyFee += cit->GetModifiedFee(); modifyCount++; cachedDescendants[updateIt].insert(cit); + // Update ancestor state for each descendant + mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount())); } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); @@ -113,6 +121,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan // which has been re-added to the mempool. // for each entry, look for descendants that are outside hashesToUpdate, and // add fee/size information for such descendants to the parent. +// for each such descendant, also update the ancestor state to include the parent. void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashesToUpdate) { LOCK(cs); @@ -233,6 +242,20 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors } } +void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) +{ + int64_t updateCount = setAncestors.size(); + int64_t updateSize = 0; + CAmount updateFee = 0; + int updateSigOps = 0; + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + updateSize += ancestorIt->GetTxSize(); + updateFee += ancestorIt->GetModifiedFee(); + updateSigOps += ancestorIt->GetSigOpCount(); + } + mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOps)); +} + void CTxMemPool::UpdateChildrenForRemoval(txiter it) { const setEntries &setMemPoolChildren = GetMemPoolChildren(it); @@ -241,11 +264,30 @@ void CTxMemPool::UpdateChildrenForRemoval(txiter it) } } -void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) +void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) { // For each entry, walk back all ancestors and decrement size associated with this // transaction const uint64_t nNoLimit = std::numeric_limits::max(); + if (updateDescendants) { + // updateDescendants should be true whenever we're not recursively + // removing a tx and all its descendants, eg when a transaction is + // confirmed in a block. + // Here we only update statistics and not data in mapLinks (which + // we need to preserve until we're finished with all operations that + // need to traverse the mempool). + BOOST_FOREACH(txiter removeIt, entriesToRemove) { + setEntries setDescendants; + CalculateDescendants(removeIt, setDescendants); + setDescendants.erase(removeIt); // don't update state for self + int64_t modifySize = -((int64_t)removeIt->GetTxSize()); + CAmount modifyFee = -removeIt->GetModifiedFee(); + int modifySigOps = -removeIt->GetSigOpCount(); + BOOST_FOREACH(txiter dit, setDescendants) { + mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps)); + } + } + } BOOST_FOREACH(txiter removeIt, entriesToRemove) { setEntries setAncestors; const CTxMemPoolEntry &entry = *removeIt; @@ -269,10 +311,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) // transactions as the set of things to update for removal. CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); // Note that UpdateAncestorsOf severs the child links that point to - // removeIt in the entries for the parents of removeIt. This is - // fine since we don't need to use the mempool children of any entries - // to walk back over our ancestors (but we do need the mempool - // parents!) + // removeIt in the entries for the parents of removeIt. UpdateAncestorsOf(false, removeIt, setAncestors); } // After updating all the ancestor sizes, we can now sever the link between each @@ -283,7 +322,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) } } -void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) +void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) { nSizeWithDescendants += modifySize; assert(int64_t(nSizeWithDescendants) > 0); @@ -292,6 +331,17 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t assert(int64_t(nCountWithDescendants) > 0); } +void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps) +{ + nSizeWithAncestors += modifySize; + assert(int64_t(nSizeWithAncestors) > 0); + nModFeesWithAncestors += modifyFee; + nCountWithAncestors += modifyCount; + assert(int64_t(nCountWithAncestors) > 0); + nSigOpCountWithAncestors += modifySigOps; + assert(int(nSigOpCountWithAncestors) >= 0); +} + CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) : nTransactionsUpdated(0) { @@ -382,6 +432,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, } } UpdateAncestorsOf(true, newit, setAncestors); + UpdateEntryForAncestors(newit, setAncestors); nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); @@ -605,7 +656,7 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::listGetTx()); } - RemoveStaged(setAllRemoves); + RemoveStaged(setAllRemoves, false); } } @@ -684,7 +735,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i if (it != mapTx.end()) { setEntries stage; stage.insert(it); - RemoveStaged(stage); + RemoveStaged(stage, true); } removeConflicts(tx, conflicts); ClearPrioritisation(tx.GetHash()); @@ -742,6 +793,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; setEntries setParentCheck; + int64_t parentSizes = 0; + unsigned int parentSigOpCount = 0; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -749,7 +802,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; - setParentCheck.insert(it2); + if (setParentCheck.insert(it2).second) { + parentSizes += it2->GetTxSize(); + parentSigOpCount += it2->GetSigOpCount(); + } } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); assert(coins && coins->IsAvailable(txin.prevout.n)); @@ -762,17 +818,19 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } assert(setParentCheck == GetMemPoolParents(it)); + // Also check to make sure ancestor size/sigops are >= sum with immediate + // parents. + assert(it->GetSizeWithAncestors() >= parentSizes + it->GetTxSize()); + assert(it->GetSigOpCountWithAncestors() >= parentSigOpCount + it->GetSigOpCount()); // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 0; - CAmount childModFee = 0; for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) { txiter childit = mapTx.find(iter->second.ptx->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); - childModFee += childit->GetModifiedFee(); } } assert(setChildrenCheck == GetMemPoolChildren(it)); @@ -964,9 +1022,9 @@ size_t CTxMemPool::DynamicMemoryUsage() const { return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 12 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; } -void CTxMemPool::RemoveStaged(setEntries &stage) { +void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { AssertLockHeld(cs); - UpdateForRemoveFromMempool(stage); + UpdateForRemoveFromMempool(stage, updateDescendants); BOOST_FOREACH(const txiter& it, stage) { removeUnchecked(it); } @@ -984,7 +1042,7 @@ int CTxMemPool::Expire(int64_t time) { BOOST_FOREACH(txiter removeit, toremove) { CalculateDescendants(removeit, stage); } - RemoveStaged(stage); + RemoveStaged(stage, false); return stage.size(); } @@ -1093,7 +1151,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe BOOST_FOREACH(txiter it, stage) txn.push_back(it->GetTx()); } - RemoveStaged(stage); + RemoveStaged(stage, false); if (pvNoSpendsRemaining) { BOOST_FOREACH(const CTransaction& tx, txn) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { diff --git a/src/txmempool.h b/src/txmempool.h index 4a463b520..405fe9d23 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -99,6 +99,12 @@ private: uint64_t nSizeWithDescendants; //! ... and size CAmount nModFeesWithDescendants; //! ... and total fees (all including us) + // Analogous statistics for ancestor transactions + uint64_t nCountWithAncestors; + uint64_t nSizeWithAncestors; + CAmount nModFeesWithAncestors; + unsigned int nSigOpCountWithAncestors; + public: CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, @@ -123,7 +129,9 @@ public: const LockPoints& GetLockPoints() const { return lockPoints; } // Adjusts the descendant state, if this entry is not dirty. - void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount); + void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount); + // Adjusts the ancestor state + void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps); // Updates the fee delta used for mining priority score, and the // modified fees with descendants. void UpdateFeeDelta(int64_t feeDelta); @@ -135,6 +143,11 @@ public: CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } bool GetSpendsCoinbase() const { return spendsCoinbase; } + + uint64_t GetCountWithAncestors() const { return nCountWithAncestors; } + uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } + CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } + unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; } }; // Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index. @@ -145,7 +158,7 @@ struct update_descendant_state {} void operator() (CTxMemPoolEntry &e) - { e.UpdateState(modifySize, modifyFee, modifyCount); } + { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); } private: int64_t modifySize; @@ -153,6 +166,22 @@ struct update_descendant_state int64_t modifyCount; }; +struct update_ancestor_state +{ + update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int _modifySigOps) : + modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOps(_modifySigOps) + {} + + void operator() (CTxMemPoolEntry &e) + { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOps); } + + private: + int64_t modifySize; + CAmount modifyFee; + int64_t modifyCount; + int modifySigOps; +}; + struct update_fee_delta { update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { } @@ -493,8 +522,12 @@ public: public: /** Remove a set of transactions from the mempool. * If a transaction is in this set, then all in-mempool descendants must - * also be in the set.*/ - void RemoveStaged(setEntries &stage); + * also be in the set, unless this transaction is being removed for being + * in a block. + * Set updateDescendants to true when removing a tx that was in a block, so + * that any in-mempool descendants have their ancestor state updated. + */ + void RemoveStaged(setEntries &stage, bool updateDescendants); /** When adding transactions from a disconnected block back to the mempool, * new mempool entries may have children in the mempool (which is generally @@ -604,8 +637,12 @@ private: const std::set &setExclude); /** Update ancestors of hash to add/remove it as a descendant transaction. */ void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors); - /** For each transaction being removed, update ancestors and any direct children. */ - void UpdateForRemoveFromMempool(const setEntries &entriesToRemove); + /** Set ancestor state for an entry */ + void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors); + /** For each transaction being removed, update ancestors and any direct children. + * If updateDescendants is true, then also update in-mempool descendants' + * ancestor state. */ + void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants); /** Sever link between specified transaction and direct children. */ void UpdateChildrenForRemoval(txiter entry); From b02423bdb50baccb9e0cffcaaac03a34c01c9901 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 19 Oct 2015 15:15:12 -0400 Subject: [PATCH 074/110] Add ancestor feerate index to mempool --- src/test/mempool_tests.cpp | 104 +++++++++++++++++++++++++++++++++++++ src/txmempool.cpp | 4 +- src/txmempool.h | 32 +++++++++++- 3 files changed, 137 insertions(+), 3 deletions(-) diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index ebdf7dbaa..c8b43df26 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -317,6 +317,110 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) CheckSort(pool, sortedOrder); } +BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) +{ + CTxMemPool pool(CFeeRate(0)); + TestMemPoolEntryHelper entry; + entry.hadNoDependencies = true; + + /* 3rd highest fee */ + CMutableTransaction tx1 = CMutableTransaction(); + tx1.vout.resize(1); + tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx1.vout[0].nValue = 10 * COIN; + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); + + /* highest fee */ + CMutableTransaction tx2 = CMutableTransaction(); + tx2.vout.resize(1); + tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx2.vout[0].nValue = 2 * COIN; + pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); + uint64_t tx2Size = ::GetSerializeSize(tx2, SER_NETWORK, PROTOCOL_VERSION); + + /* lowest fee */ + CMutableTransaction tx3 = CMutableTransaction(); + tx3.vout.resize(1); + tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx3.vout[0].nValue = 5 * COIN; + pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); + + /* 2nd highest fee */ + CMutableTransaction tx4 = CMutableTransaction(); + tx4.vout.resize(1); + tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx4.vout[0].nValue = 6 * COIN; + pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); + + /* equal fee rate to tx1, but newer */ + CMutableTransaction tx5 = CMutableTransaction(); + tx5.vout.resize(1); + tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx5.vout[0].nValue = 11 * COIN; + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + BOOST_CHECK_EQUAL(pool.size(), 5); + + std::vector sortedOrder; + sortedOrder.resize(5); + sortedOrder[0] = tx2.GetHash().ToString(); // 20000 + sortedOrder[1] = tx4.GetHash().ToString(); // 15000 + // tx1 and tx5 are both 10000 + // Ties are broken by hash, not timestamp, so determine which + // hash comes first. + if (tx1.GetHash() < tx5.GetHash()) { + sortedOrder[2] = tx1.GetHash().ToString(); + sortedOrder[3] = tx5.GetHash().ToString(); + } else { + sortedOrder[2] = tx5.GetHash().ToString(); + sortedOrder[3] = tx1.GetHash().ToString(); + } + sortedOrder[4] = tx3.GetHash().ToString(); // 0 + + CheckSort(pool, sortedOrder); + + /* low fee parent with high fee child */ + /* tx6 (0) -> tx7 (high) */ + CMutableTransaction tx6 = CMutableTransaction(); + tx6.vout.resize(1); + tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx6.vout[0].nValue = 20 * COIN; + uint64_t tx6Size = ::GetSerializeSize(tx6, SER_NETWORK, PROTOCOL_VERSION); + + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + BOOST_CHECK_EQUAL(pool.size(), 6); + sortedOrder.push_back(tx6.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + CMutableTransaction tx7 = CMutableTransaction(); + tx7.vin.resize(1); + tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0); + tx7.vin[0].scriptSig = CScript() << OP_11; + tx7.vout.resize(1); + tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + tx7.vout[0].nValue = 10 * COIN; + uint64_t tx7Size = ::GetSerializeSize(tx7, SER_NETWORK, PROTOCOL_VERSION); + + /* set the fee to just below tx2's feerate when including ancestor */ + CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1; + + //CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); + pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7)); + BOOST_CHECK_EQUAL(pool.size(), 7); + sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString()); + CheckSort(pool, sortedOrder); + + /* after tx6 is mined, tx7 should move up in the sort */ + std::vector vtx; + vtx.push_back(tx6); + std::list dummy; + pool.removeForBlock(vtx, 1, dummy, false); + + sortedOrder.erase(sortedOrder.begin()+1); + sortedOrder.pop_back(); + sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString()); + CheckSort(pool, sortedOrder); +} + BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) { diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0546f7f15..856f20b4c 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1018,8 +1018,8 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); - // Estimate the overhead of mapTx to be 12 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. - return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 12 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; + // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage; } void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) { diff --git a/src/txmempool.h b/src/txmempool.h index 405fe9d23..a34e3abf5 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -276,10 +276,34 @@ public: } }; +class CompareTxMemPoolEntryByAncestorFee +{ +public: + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + { + double aFees = a.GetModFeesWithAncestors(); + double aSize = a.GetSizeWithAncestors(); + + double bFees = b.GetModFeesWithAncestors(); + double bSize = b.GetSizeWithAncestors(); + + // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). + double f1 = aFees * bSize; + double f2 = aSize * bFees; + + if (f1 == f2) { + return a.GetTx().GetHash() < b.GetTx().GetHash(); + } + + return f1 > f2; + } +}; + // Multi_index tag names struct descendant_score {}; struct entry_time {}; struct mining_score {}; +struct ancestor_score {}; class CBlockPolicyEstimator; @@ -412,12 +436,18 @@ public: boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByEntryTime - >, + >, // sorted by score (for mining prioritization) boost::multi_index::ordered_unique< boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByScore + >, + // sorted by fee rate with ancestors + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::identity, + CompareTxMemPoolEntryByAncestorFee > > > indexed_transaction_set; From 26475e2de4ea910aaf8bbd2610330bba458723d1 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 8 Mar 2016 15:49:26 -0500 Subject: [PATCH 075/110] Check all ancestor state in CTxMemPool::check() --- src/txmempool.cpp | 27 ++++++++++++++++++++++----- src/txmempool.h | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 856f20b4c..c93e15c26 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -165,7 +165,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes } } -bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) +bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const { setEntries parentHashes; const CTransaction &tx = entry.GetTx(); @@ -818,10 +818,27 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } assert(setParentCheck == GetMemPoolParents(it)); - // Also check to make sure ancestor size/sigops are >= sum with immediate - // parents. - assert(it->GetSizeWithAncestors() >= parentSizes + it->GetTxSize()); - assert(it->GetSigOpCountWithAncestors() >= parentSigOpCount + it->GetSigOpCount()); + // Verify ancestor state is correct. + setEntries setAncestors; + uint64_t nNoLimit = std::numeric_limits::max(); + std::string dummy; + CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); + uint64_t nCountCheck = setAncestors.size() + 1; + uint64_t nSizeCheck = it->GetTxSize(); + CAmount nFeesCheck = it->GetModifiedFee(); + unsigned int nSigOpCheck = it->GetSigOpCount(); + + BOOST_FOREACH(txiter ancestorIt, setAncestors) { + nSizeCheck += ancestorIt->GetTxSize(); + nFeesCheck += ancestorIt->GetModifiedFee(); + nSigOpCheck += ancestorIt->GetSigOpCount(); + } + + assert(it->GetCountWithAncestors() == nCountCheck); + assert(it->GetSizeWithAncestors() == nSizeCheck); + assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); + assert(it->GetModFeesWithAncestors() == nFeesCheck); + // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); diff --git a/src/txmempool.h b/src/txmempool.h index a34e3abf5..533fbe949 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -580,7 +580,7 @@ public: * fSearchForParents = whether to search a tx's vin for in-mempool parents, or * look up parents from mapLinks. Must be true for entries not in the mempool */ - bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true); + bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true) const; /** Populate setDescendants with all in-mempool descendants of hash. * Assumes that setDescendants includes all in-mempool descendants of anything From 17d8ea7041debb4006a48ece688c253200148ca6 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 18 Apr 2016 12:05:32 +0200 Subject: [PATCH 076/110] txdb: Fix assert crash in new UTXO set cursor Remove the mistaken assumption that GetKey returning false signifies an internal database issue. It will return false when the key cannot be deserialized into the (char,uint256) stanza, which indicates that the cursor has reached a different kind of key. Fixes bug #7890 introduced in #7756. --- src/txdb.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/txdb.cpp b/src/txdb.cpp index 7bbbb4f44..dfd4504f3 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -139,12 +139,8 @@ bool CCoinsViewDBCursor::Valid() const void CCoinsViewDBCursor::Next() { pcursor->Next(); - if (pcursor->Valid()) { - bool ok = pcursor->GetKey(keyTmp); - assert(ok); // If GetKey fails here something must be wrong with underlying database, we cannot handle that here - } else { + if (!pcursor->Valid() || !pcursor->GetKey(keyTmp)) keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false - } } bool CBlockTreeDB::WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo) { From ca67fc240709edcf421c0b38fe8ba4901e5f095f Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Apr 2016 09:05:12 +0200 Subject: [PATCH 077/110] dbwrapper: Remove throw keywords in function signatures Using throw() specifications in function signatures is not only not required in C++, it is considered deprecated for [various reasons](https://stackoverflow.com/questions/1055387/throw-keyword-in-functions-signature). It is not implemented by any of the common C++ compilers. The usage is also inconsistent with the rest of the source code. --- src/dbwrapper.cpp | 4 ++-- src/dbwrapper.h | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 5f1f175b8..2498b34d9 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -15,7 +15,7 @@ #include #include -void HandleError(const leveldb::Status& status) throw(dbwrapper_error) +void HandleError(const leveldb::Status& status) { if (status.ok()) return; @@ -102,7 +102,7 @@ CDBWrapper::~CDBWrapper() options.env = NULL; } -bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error) +bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) { leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); HandleError(status); diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 2acd5fc05..9520ba7a8 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -23,7 +23,7 @@ public: dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {} }; -void HandleError(const leveldb::Status& status) throw(dbwrapper_error); +void HandleError(const leveldb::Status& status); /** Batch of changes queued to be written to a CDBWrapper */ class CDBBatch @@ -182,7 +182,7 @@ public: ~CDBWrapper(); template - bool Read(const K& key, V& value) const throw(dbwrapper_error) + bool Read(const K& key, V& value) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); @@ -208,7 +208,7 @@ public: } template - bool Write(const K& key, const V& value, bool fSync = false) throw(dbwrapper_error) + bool Write(const K& key, const V& value, bool fSync = false) { CDBBatch batch(&obfuscate_key); batch.Write(key, value); @@ -216,7 +216,7 @@ public: } template - bool Exists(const K& key) const throw(dbwrapper_error) + bool Exists(const K& key) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(ssKey.GetSerializeSize(key)); @@ -235,14 +235,14 @@ public: } template - bool Erase(const K& key, bool fSync = false) throw(dbwrapper_error) + bool Erase(const K& key, bool fSync = false) { CDBBatch batch(&obfuscate_key); batch.Erase(key); return WriteBatch(batch, fSync); } - bool WriteBatch(CDBBatch& batch, bool fSync = false) throw(dbwrapper_error); + bool WriteBatch(CDBBatch& batch, bool fSync = false); // not available for LevelDB; provide for compatibility with BDB bool Flush() @@ -250,7 +250,7 @@ public: return true; } - bool Sync() throw(dbwrapper_error) + bool Sync() { CDBBatch batch(&obfuscate_key); return WriteBatch(batch, true); From dacaf6a61c89a5d366a297b0b50320a814bc6f51 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Apr 2016 09:08:45 +0200 Subject: [PATCH 078/110] dbwrapper: Remove CDBWrapper::GetObfuscateKeyHex It is an unnecessary method as it is used only two times and only internally, and the whole implementation is HexStr(obfuscate_key). --- src/dbwrapper.cpp | 9 ++------- src/dbwrapper.h | 6 ------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 2498b34d9..cf0aea9d1 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -84,10 +84,10 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b Write(OBFUSCATE_KEY_KEY, new_key); obfuscate_key = new_key; - LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), GetObfuscateKeyHex()); + LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key)); } - LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex()); + LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key)); } CDBWrapper::~CDBWrapper() @@ -141,11 +141,6 @@ const std::vector& CDBWrapper::GetObfuscateKey() const return obfuscate_key; } -std::string CDBWrapper::GetObfuscateKeyHex() const -{ - return HexStr(obfuscate_key); -} - CDBIterator::~CDBIterator() { delete piter; } bool CDBIterator::Valid() { return piter->Valid(); } void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 9520ba7a8..ad6e39ae4 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -270,12 +270,6 @@ public: * Accessor for obfuscate_key. */ const std::vector& GetObfuscateKey() const; - - /** - * Return the obfuscate_key as a hex-formatted string. - */ - std::string GetObfuscateKeyHex() const; - }; #endif // BITCOIN_DBWRAPPER_H From b2c1789e61a8536c8607ed39a27cfaa791d2c5b9 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Apr 2016 11:46:01 +0200 Subject: [PATCH 079/110] dbwrapper: Pass parent CDBWrapper into CDBBatch and CDBIterator Pass parent wrapper directly instead of obfuscation key. This makes it possible for other databases which re-use this code to use other properties from the database. Add a namespace dbwrapper_private for private functions to be used only in dbwrapper.h/cpp and dbwrapper_tests. --- src/dbwrapper.cpp | 14 +++++++---- src/dbwrapper.h | 46 ++++++++++++++++++++++-------------- src/test/dbwrapper_tests.cpp | 8 +++---- src/txdb.cpp | 6 ++--- 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index cf0aea9d1..ff440ac13 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -136,12 +136,16 @@ bool CDBWrapper::IsEmpty() return !(it->Valid()); } -const std::vector& CDBWrapper::GetObfuscateKey() const -{ - return obfuscate_key; -} - CDBIterator::~CDBIterator() { delete piter; } bool CDBIterator::Valid() { return piter->Valid(); } void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } void CDBIterator::Next() { piter->Next(); } + +namespace dbwrapper_private { + +const std::vector& GetObfuscateKey(const CDBWrapper &w) +{ + return w.obfuscate_key; +} + +}; diff --git a/src/dbwrapper.h b/src/dbwrapper.h index ad6e39ae4..66e80a5de 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -25,20 +25,34 @@ public: void HandleError(const leveldb::Status& status); +class CDBWrapper; + +/** These should be considered an implementation detail of the specific database. + */ +namespace dbwrapper_private { + +/** Work around circular dependency, as well as for testing in dbwrapper_tests. + * Database obfuscation should be considered an implementation detail of the + * specific database. + */ +const std::vector& GetObfuscateKey(const CDBWrapper &w); + +}; + /** Batch of changes queued to be written to a CDBWrapper */ class CDBBatch { friend class CDBWrapper; private: + const CDBWrapper &parent; leveldb::WriteBatch batch; - const std::vector *obfuscate_key; public: /** - * @param[in] obfuscate_key If passed, XOR data with this key. + * @param[in] parent CDBWrapper that this batch is to be submitted to */ - CDBBatch(const std::vector *obfuscate_key) : obfuscate_key(obfuscate_key) { }; + CDBBatch(const CDBWrapper &parent) : parent(parent) { }; template void Write(const K& key, const V& value) @@ -51,7 +65,7 @@ public: CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.reserve(ssValue.GetSerializeSize(value)); ssValue << value; - ssValue.Xor(*obfuscate_key); + ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); leveldb::Slice slValue(&ssValue[0], ssValue.size()); batch.Put(slKey, slValue); @@ -72,17 +86,17 @@ public: class CDBIterator { private: + const CDBWrapper &parent; leveldb::Iterator *piter; - const std::vector *obfuscate_key; public: /** + * @param[in] parent Parent CDBWrapper instance. * @param[in] piterIn The original leveldb iterator. - * @param[in] obfuscate_key If passed, XOR data with this key. */ - CDBIterator(leveldb::Iterator *piterIn, const std::vector* obfuscate_key) : - piter(piterIn), obfuscate_key(obfuscate_key) { }; + CDBIterator(const CDBWrapper &parent, leveldb::Iterator *piterIn) : + parent(parent), piter(piterIn) { }; ~CDBIterator(); bool Valid(); @@ -118,7 +132,7 @@ public: leveldb::Slice slValue = piter->value(); try { CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); - ssValue.Xor(*obfuscate_key); + ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); ssValue >> value; } catch (const std::exception&) { return false; @@ -134,6 +148,7 @@ public: class CDBWrapper { + friend const std::vector& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w); private: //! custom environment this database is using (may be NULL in case of default environment) leveldb::Env* penv; @@ -210,7 +225,7 @@ public: template bool Write(const K& key, const V& value, bool fSync = false) { - CDBBatch batch(&obfuscate_key); + CDBBatch batch(*this); batch.Write(key, value); return WriteBatch(batch, fSync); } @@ -237,7 +252,7 @@ public: template bool Erase(const K& key, bool fSync = false) { - CDBBatch batch(&obfuscate_key); + CDBBatch batch(*this); batch.Erase(key); return WriteBatch(batch, fSync); } @@ -252,24 +267,19 @@ public: bool Sync() { - CDBBatch batch(&obfuscate_key); + CDBBatch batch(*this); return WriteBatch(batch, true); } CDBIterator *NewIterator() { - return new CDBIterator(pdb->NewIterator(iteroptions), &obfuscate_key); + return new CDBIterator(*this, pdb->NewIterator(iteroptions)); } /** * Return true if the database managed by this class contains no entries. */ bool IsEmpty(); - - /** - * Accessor for obfuscate_key. - */ - const std::vector& GetObfuscateKey() const; }; #endif // BITCOIN_DBWRAPPER_H diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 466a0f4de..10db482e5 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) uint256 res; // Ensure that we're doing real obfuscation when obfuscate=true - BOOST_CHECK(obfuscate != is_null_key(dbw.GetObfuscateKey())); + BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw))); BOOST_CHECK(dbw.Write(key, in)); BOOST_CHECK(dbw.Read(key, res)); @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) uint256 in3 = GetRandHash(); uint256 res; - CDBBatch batch(&dbw.GetObfuscateKey()); + CDBBatch batch(dbw); batch.Write(key, in); batch.Write(key2, in2); @@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) BOOST_CHECK_EQUAL(res2.ToString(), in.ToString()); BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data - BOOST_CHECK(is_null_key(odbw.GetObfuscateKey())); // The key should be an empty string + BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string uint256 in2 = GetRandHash(); uint256 res3; @@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) // Check that the key/val we wrote with unobfuscated wrapper doesn't exist uint256 res2; BOOST_CHECK(!odbw.Read(key, res2)); - BOOST_CHECK(!is_null_key(odbw.GetObfuscateKey())); + BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); uint256 in2 = GetRandHash(); uint256 res3; diff --git a/src/txdb.cpp b/src/txdb.cpp index dfd4504f3..c9c03eb46 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -54,7 +54,7 @@ uint256 CCoinsViewDB::GetBestBlock() const { } bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { - CDBBatch batch(&db.GetObfuscateKey()); + CDBBatch batch(db); size_t count = 0; size_t changed = 0; for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { @@ -144,7 +144,7 @@ void CCoinsViewDBCursor::Next() } bool CBlockTreeDB::WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); for (std::vector >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second); } @@ -160,7 +160,7 @@ bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { } bool CBlockTreeDB::WriteTxIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) batch.Write(make_pair(DB_TXINDEX, it->first), it->second); return WriteBatch(batch); From 584c3d088e1fc4c99383b7d9ed2f49b34d0a67cb Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 20 Apr 2016 11:48:57 +0200 Subject: [PATCH 080/110] dbwrapper: Move `HandleError` to `dbwrapper_private` --- src/dbwrapper.cpp | 34 +++++++++++++++++----------------- src/dbwrapper.h | 10 ++++++---- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index ff440ac13..74d9c7bbe 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -15,20 +15,6 @@ #include #include -void HandleError(const leveldb::Status& status) -{ - if (status.ok()) - return; - LogPrintf("%s\n", status.ToString()); - if (status.IsCorruption()) - throw dbwrapper_error("Database corrupted"); - if (status.IsIOError()) - throw dbwrapper_error("Database I/O error"); - if (status.IsNotFound()) - throw dbwrapper_error("Database entry missing"); - throw dbwrapper_error("Unknown database error"); -} - static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxOpenFiles) { leveldb::Options options; @@ -61,13 +47,13 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b if (fWipe) { LogPrintf("Wiping LevelDB in %s\n", path.string()); leveldb::Status result = leveldb::DestroyDB(path.string(), options); - HandleError(result); + dbwrapper_private::HandleError(result); } TryCreateDirectory(path); LogPrintf("Opening LevelDB in %s\n", path.string()); } leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb); - HandleError(status); + dbwrapper_private::HandleError(status); LogPrintf("Opened LevelDB successfully\n"); // The base-case obfuscation key, which is a noop. @@ -105,7 +91,7 @@ CDBWrapper::~CDBWrapper() bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) { leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); - HandleError(status); + dbwrapper_private::HandleError(status); return true; } @@ -143,6 +129,20 @@ void CDBIterator::Next() { piter->Next(); } namespace dbwrapper_private { +void HandleError(const leveldb::Status& status) +{ + if (status.ok()) + return; + LogPrintf("%s\n", status.ToString()); + if (status.IsCorruption()) + throw dbwrapper_error("Database corrupted"); + if (status.IsIOError()) + throw dbwrapper_error("Database I/O error"); + if (status.IsNotFound()) + throw dbwrapper_error("Database entry missing"); + throw dbwrapper_error("Unknown database error"); +} + const std::vector& GetObfuscateKey(const CDBWrapper &w) { return w.obfuscate_key; diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 66e80a5de..20b5f849e 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -23,14 +23,16 @@ public: dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {} }; -void HandleError(const leveldb::Status& status); - class CDBWrapper; /** These should be considered an implementation detail of the specific database. */ namespace dbwrapper_private { +/** Handle database error by throwing dbwrapper_error exception. + */ +void HandleError(const leveldb::Status& status); + /** Work around circular dependency, as well as for testing in dbwrapper_tests. * Database obfuscation should be considered an implementation detail of the * specific database. @@ -210,7 +212,7 @@ public: if (status.IsNotFound()) return false; LogPrintf("LevelDB read failure: %s\n", status.ToString()); - HandleError(status); + dbwrapper_private::HandleError(status); } try { CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); @@ -244,7 +246,7 @@ public: if (status.IsNotFound()) return false; LogPrintf("LevelDB read failure: %s\n", status.ToString()); - HandleError(status); + dbwrapper_private::HandleError(status); } return true; } From 96a96215344f77b194a64c2721d9bad531afbda7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 25 Apr 2016 12:31:45 +0200 Subject: [PATCH 081/110] Introduce constant for maximum CScript length --- src/script/interpreter.cpp | 2 +- src/script/script.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index e86bf4fc1..ac0caec03 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -263,7 +263,7 @@ bool EvalScript(vector >& stack, const CScript& script, un vector vfExec; vector altstack; set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); - if (script.size() > 10000) + if (script.size() > MAX_SCRIPT_SIZE) return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; diff --git a/src/script/script.h b/src/script/script.h index 3c294f82d..76bc844af 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -27,6 +27,9 @@ static const int MAX_OPS_PER_SCRIPT = 201; // Maximum number of public keys per multisig static const int MAX_PUBKEYS_PER_MULTISIG = 20; +// Maximum script length in bytes +static const int MAX_SCRIPT_SIZE = 10000; + // Threshold for nLockTime: below this value it is interpreted as block number, // otherwise as UNIX timestamp. static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC From 622fa5bb1965500e8a60447af3e18016456a9aa7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 25 Apr 2016 12:32:01 +0200 Subject: [PATCH 082/110] Treat overly long scriptPubKeys as unspendable --- src/script/script.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/script.h b/src/script/script.h index 76bc844af..4d816f891 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -637,7 +637,7 @@ public: bool IsUnspendable() const { - return (size() > 0 && *begin() == OP_RETURN); + return (size() > 0 && *begin() == OP_RETURN) || (size() > MAX_SCRIPT_SIZE); } void clear() From 12751d523a57216549883dfb52052d97d4baf3a6 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 24 Apr 2016 16:21:44 +0200 Subject: [PATCH 083/110] Fix OOM bug: UTXO entries with invalid script length --- src/compressor.h | 10 ++++++++-- src/streams.h | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/compressor.h b/src/compressor.h index 4a7209083..fa702f0df 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -86,8 +86,14 @@ public: return; } nSize -= nSpecialScripts; - script.resize(nSize); - s >> REF(CFlatData(script)); + if (nSize > MAX_SCRIPT_SIZE) { + // Overly long script, replace with a short invalid one + script << OP_RETURN; + s.ignore(nSize); + } else { + script.resize(nSize); + s >> REF(CFlatData(script)); + } } }; diff --git a/src/streams.h b/src/streams.h index 0fc6135a6..8b839b70a 100644 --- a/src/streams.h +++ b/src/streams.h @@ -404,6 +404,20 @@ public: return (*this); } + CAutoFile& ignore(size_t nSize) + { + if (!file) + throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL"); + unsigned char data[4096]; + while (nSize > 0) { + size_t nNow = std::min(nSize, sizeof(data)); + if (fread(data, 1, nNow, file) != nNow) + throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed"); + nSize -= nNow; + } + return (*this); + } + CAutoFile& write(const char* pch, size_t nSize) { if (!file) From 7132135a12c92b37f4053e99903fc921e6faf4d1 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Sun, 24 Apr 2016 21:59:46 -0700 Subject: [PATCH 084/110] CDataStream::ignore Throw exception instead of assert on negative nSize. Previously disk corruption would cause an assert instead of an exception. --- src/streams.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/streams.h b/src/streams.h index 8b839b70a..ed14f3f41 100644 --- a/src/streams.h +++ b/src/streams.h @@ -240,7 +240,9 @@ public: CDataStream& ignore(int nSize) { // Ignore from the beginning of the buffer - assert(nSize >= 0); + if (nSize < 0) { + throw std::ios_base::failure("CDataStream::ignore(): nSize negative"); + } unsigned int nReadPosNext = nReadPos + nSize; if (nReadPosNext >= vch.size()) { From 010816786613c90ecf24c97010b9801c881ae2f7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 25 Apr 2016 14:05:36 +0200 Subject: [PATCH 085/110] Add tests for CCoins deserialization --- src/test/coins_tests.cpp | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 48e3c8ed8..129ce04e0 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -4,7 +4,9 @@ #include "coins.h" #include "random.h" +#include "script/standard.h" #include "uint256.h" +#include "utilstrencodings.h" #include "test/test_bitcoin.h" #include "main.h" #include "consensus/validation.h" @@ -345,4 +347,73 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) BOOST_CHECK(spent_a_duplicate_coinbase); } +BOOST_AUTO_TEST_CASE(ccoins_serialization) +{ + // Good example + CDataStream ss1(ParseHex("0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e"), SER_DISK, CLIENT_VERSION); + CCoins cc1; + ss1 >> cc1; + BOOST_CHECK_EQUAL(cc1.nVersion, 1); + BOOST_CHECK_EQUAL(cc1.fCoinBase, false); + BOOST_CHECK_EQUAL(cc1.nHeight, 203998); + BOOST_CHECK_EQUAL(cc1.vout.size(), 2); + BOOST_CHECK_EQUAL(cc1.IsAvailable(0), false); + BOOST_CHECK_EQUAL(cc1.IsAvailable(1), true); + BOOST_CHECK_EQUAL(cc1.vout[1].nValue, 60000000000ULL); + BOOST_CHECK_EQUAL(HexStr(cc1.vout[1].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); + + // Good example + CDataStream ss2(ParseHex("0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b"), SER_DISK, CLIENT_VERSION); + CCoins cc2; + ss2 >> cc2; + BOOST_CHECK_EQUAL(cc2.nVersion, 1); + BOOST_CHECK_EQUAL(cc2.fCoinBase, true); + BOOST_CHECK_EQUAL(cc2.nHeight, 120891); + BOOST_CHECK_EQUAL(cc2.vout.size(), 17); + for (int i = 0; i < 17; i++) { + BOOST_CHECK_EQUAL(cc2.IsAvailable(i), i == 4 || i == 16); + } + BOOST_CHECK_EQUAL(cc2.vout[4].nValue, 234925952); + BOOST_CHECK_EQUAL(HexStr(cc2.vout[4].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("61b01caab50f1b8e9c50a5057eb43c2d9563a4ee")))))); + BOOST_CHECK_EQUAL(cc2.vout[16].nValue, 110397); + BOOST_CHECK_EQUAL(HexStr(cc2.vout[16].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); + + // Smallest possible example + CDataStream ssx(SER_DISK, CLIENT_VERSION); + BOOST_CHECK_EQUAL(HexStr(ssx.begin(), ssx.end()), ""); + + CDataStream ss3(ParseHex("0002000600"), SER_DISK, CLIENT_VERSION); + CCoins cc3; + ss3 >> cc3; + BOOST_CHECK_EQUAL(cc3.nVersion, 0); + BOOST_CHECK_EQUAL(cc3.fCoinBase, false); + BOOST_CHECK_EQUAL(cc3.nHeight, 0); + BOOST_CHECK_EQUAL(cc3.vout.size(), 1); + BOOST_CHECK_EQUAL(cc3.IsAvailable(0), true); + BOOST_CHECK_EQUAL(cc3.vout[0].nValue, 0); + BOOST_CHECK_EQUAL(cc3.vout[0].scriptPubKey.size(), 0); + + // scriptPubKey that ends beyond the end of the stream + CDataStream ss4(ParseHex("0002000800"), SER_DISK, CLIENT_VERSION); + try { + CCoins cc4; + ss4 >> cc4; + BOOST_CHECK_MESSAGE(false, "We should have thrown"); + } catch (const std::ios_base::failure& e) { + } + + // Very large scriptPubKey (3*10^9 bytes) past the end of the stream + CDataStream tmp(SER_DISK, CLIENT_VERSION); + uint64_t x = 3000000000ULL; + tmp << VARINT(x); + BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00"); + CDataStream ss5(ParseHex("0002008a95c0bb0000"), SER_DISK, CLIENT_VERSION); + try { + CCoins cc5; + ss5 >> cc5; + BOOST_CHECK_MESSAGE(false, "We should have thrown"); + } catch (const std::ios_base::failure& e) { + } +} + BOOST_AUTO_TEST_SUITE_END() From 3806509c82dd528438c4a61c113731e3cbbd469a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 6 May 2016 20:41:28 +0200 Subject: [PATCH 086/110] Add SipHash-2-4 primitives to hash --- src/hash.cpp | 94 +++++++++++++++++++++++++++++++++++++++++ src/hash.h | 15 +++++++ src/test/hash_tests.cpp | 20 +++++++++ src/uint256.h | 13 ++++++ 4 files changed, 142 insertions(+) diff --git a/src/hash.cpp b/src/hash.cpp index 7f3cf1a1f..a518314a5 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -81,3 +81,97 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he num[3] = (nChild >> 0) & 0xFF; CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output); } + +#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define SIPROUND do { \ + v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \ + v0 = ROTL(v0, 32); \ + v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \ + v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \ + v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \ + v2 = ROTL(v2, 32); \ +} while (0) + +CSipHasher::CSipHasher(uint64_t k0, uint64_t k1) +{ + v[0] = 0x736f6d6570736575ULL ^ k0; + v[1] = 0x646f72616e646f6dULL ^ k1; + v[2] = 0x6c7967656e657261ULL ^ k0; + v[3] = 0x7465646279746573ULL ^ k1; + count = 0; +} + +CSipHasher& CSipHasher::Write(uint64_t data) +{ + uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + + v3 ^= data; + SIPROUND; + SIPROUND; + v0 ^= data; + + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; + + count++; + return *this; +} + +uint64_t CSipHasher::Finalize() const +{ + uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + + v3 ^= ((uint64_t)count) << 59; + SIPROUND; + SIPROUND; + v0 ^= ((uint64_t)count) << 59; + v2 ^= 0xFF; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + return v0 ^ v1 ^ v2 ^ v3; +} + +uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val) +{ + /* Specialized implementation for efficiency */ + uint64_t d = val.GetUint64(0); + + uint64_t v0 = 0x736f6d6570736575ULL ^ k0; + uint64_t v1 = 0x646f72616e646f6dULL ^ k1; + uint64_t v2 = 0x6c7967656e657261ULL ^ k0; + uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d; + + SIPROUND; + SIPROUND; + v0 ^= d; + d = val.GetUint64(1); + v3 ^= d; + SIPROUND; + SIPROUND; + v0 ^= d; + d = val.GetUint64(2); + v3 ^= d; + SIPROUND; + SIPROUND; + v0 ^= d; + d = val.GetUint64(3); + v3 ^= d; + SIPROUND; + SIPROUND; + v0 ^= d; + v3 ^= ((uint64_t)4) << 59; + SIPROUND; + SIPROUND; + v0 ^= ((uint64_t)4) << 59; + v2 ^= 0xFF; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + return v0 ^ v1 ^ v2 ^ v3; +} diff --git a/src/hash.h b/src/hash.h index 97955c8d5..600dabec5 100644 --- a/src/hash.h +++ b/src/hash.h @@ -171,4 +171,19 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector void Serialize(Stream& s, int nType, int nVersion) const { From c4641ab5886b7a892d8a8f2abb42da9ede9430c5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 6 May 2016 20:47:12 +0200 Subject: [PATCH 087/110] Use SipHash-2-4 for CCoinsCache index --- src/coins.cpp | 6 ++++- src/coins.h | 14 ++++++----- src/uint256.cpp | 64 ------------------------------------------------- src/uint256.h | 4 ---- 4 files changed, 13 insertions(+), 75 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index 20045466f..74429d05a 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -56,7 +56,11 @@ void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); } -CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} +SaltedTxidHasher::SaltedTxidHasher() +{ + GetRandBytes((unsigned char*)&k0, sizeof(k0)); + GetRandBytes((unsigned char*)&k1, sizeof(k1)); +} CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { } diff --git a/src/coins.h b/src/coins.h index ac308423e..eb55d9135 100644 --- a/src/coins.h +++ b/src/coins.h @@ -9,6 +9,7 @@ #include "compressor.h" #include "core_memusage.h" +#include "hash.h" #include "memusage.h" #include "serialize.h" #include "uint256.h" @@ -291,21 +292,22 @@ public: } }; -class CCoinsKeyHasher +class SaltedTxidHasher { private: - uint256 salt; + /** Salt */ + uint64_t k0, k1; public: - CCoinsKeyHasher(); + SaltedTxidHasher(); /** * This *must* return size_t. With Boost 1.46 on 32-bit systems the * unordered_map will behave unpredictably if the custom hasher returns a * uint64_t, resulting in failures when syncing the chain (#4634). */ - size_t operator()(const uint256& key) const { - return key.GetHash(salt); + size_t operator()(const uint256& txid) const { + return SipHashUint256(k0, k1, txid); } }; @@ -322,7 +324,7 @@ struct CCoinsCacheEntry CCoinsCacheEntry() : coins(), flags(0) {} }; -typedef boost::unordered_map CCoinsMap; +typedef boost::unordered_map CCoinsMap; /** Cursor for iterating over CoinsView state */ class CCoinsViewCursor diff --git a/src/uint256.cpp b/src/uint256.cpp index 75294474b..56b4da69b 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -81,70 +81,6 @@ template std::string base_blob<256>::ToString() const; template void base_blob<256>::SetHex(const char*); template void base_blob<256>::SetHex(const std::string&); -static void inline HashMix(uint32_t& a, uint32_t& b, uint32_t& c) -{ - // Taken from lookup3, by Bob Jenkins. - a -= c; - a ^= ((c << 4) | (c >> 28)); - c += b; - b -= a; - b ^= ((a << 6) | (a >> 26)); - a += c; - c -= b; - c ^= ((b << 8) | (b >> 24)); - b += a; - a -= c; - a ^= ((c << 16) | (c >> 16)); - c += b; - b -= a; - b ^= ((a << 19) | (a >> 13)); - a += c; - c -= b; - c ^= ((b << 4) | (b >> 28)); - b += a; -} - -static void inline HashFinal(uint32_t& a, uint32_t& b, uint32_t& c) -{ - // Taken from lookup3, by Bob Jenkins. - c ^= b; - c -= ((b << 14) | (b >> 18)); - a ^= c; - a -= ((c << 11) | (c >> 21)); - b ^= a; - b -= ((a << 25) | (a >> 7)); - c ^= b; - c -= ((b << 16) | (b >> 16)); - a ^= c; - a -= ((c << 4) | (c >> 28)); - b ^= a; - b -= ((a << 14) | (a >> 18)); - c ^= b; - c -= ((b << 24) | (b >> 8)); -} - -uint64_t uint256::GetHash(const uint256& salt) const -{ - uint32_t a, b, c; - const uint32_t *pn = (const uint32_t*)data; - const uint32_t *salt_pn = (const uint32_t*)salt.data; - a = b = c = 0xdeadbeef + WIDTH; - - a += pn[0] ^ salt_pn[0]; - b += pn[1] ^ salt_pn[1]; - c += pn[2] ^ salt_pn[2]; - HashMix(a, b, c); - a += pn[3] ^ salt_pn[3]; - b += pn[4] ^ salt_pn[4]; - c += pn[5] ^ salt_pn[5]; - HashMix(a, b, c); - a += pn[6] ^ salt_pn[6]; - b += pn[7] ^ salt_pn[7]; - HashFinal(a, b, c); - - return ((((uint64_t)b) << 32) | c); -} - uint64_t uint256::GetLow64() const { assert(sizeof(data) >= 2); diff --git a/src/uint256.h b/src/uint256.h index 457a544d3..4ce062e7e 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -139,10 +139,6 @@ public: return ReadLE64(data); } - /** A more secure, salted hash function. - * @note This hash is not stable between little and big endian. - */ - uint64_t GetHash(const uint256& salt) const; uint64_t GetLow64() const; }; From cae6dbb6ab98ebe25b78ebfd368511d09481836c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 6 May 2016 21:36:36 +0200 Subject: [PATCH 088/110] Switch CTxMempool::mapTx to use a hash index for txids --- src/txmempool.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/txmempool.h b/src/txmempool.h index 533fbe949..864a0c97e 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -19,6 +19,7 @@ #undef foreach #include "boost/multi_index_container.hpp" #include "boost/multi_index/ordered_index.hpp" +#include "boost/multi_index/hashed_index.hpp" class CAutoFile; class CBlockIndex; @@ -424,7 +425,7 @@ public: CTxMemPoolEntry, boost::multi_index::indexed_by< // sorted by txid - boost::multi_index::ordered_unique, + boost::multi_index::hashed_unique, // sorted by fee rate boost::multi_index::ordered_non_unique< boost::multi_index::tag, From 458cfffcd01cd114977b5701627894f4187587e4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 6 May 2016 21:53:38 +0200 Subject: [PATCH 089/110] Use SipHash-2-4 for address relay selection --- src/main.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2079cd268..14419189b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5467,25 +5467,23 @@ 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 addrKnowns of the chosen nodes prevent repeats - static uint256 hashSalt; - if (hashSalt.IsNull()) - hashSalt = GetRandHash(); + static uint64_t salt0 = 0, salt1 = 0; + while (salt0 == 0 && salt1 == 0) { + GetRandBytes((unsigned char*)&salt0, sizeof(salt0)); + GetRandBytes((unsigned char*)&salt1, sizeof(salt1)); + } uint64_t hashAddr = addr.GetHash(); - uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60))); - hashRand = Hash(BEGIN(hashRand), END(hashRand)); - multimap mapMix; + multimap mapMix; + const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); BOOST_FOREACH(CNode* pnode, vNodes) { if (pnode->nVersion < CADDR_TIME_VERSION) continue; - unsigned int nPointer; - memcpy(&nPointer, &pnode, sizeof(nPointer)); - uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer); - hashKey = Hash(BEGIN(hashKey), END(hashKey)); + uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize(); mapMix.insert(make_pair(hashKey, pnode)); } int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) - for (multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) + for (multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) ((*mi).second)->PushAddress(addr); } } From 4366ce4fa0fcdbaaa4d85aae86a8bf7c1af5dc7a Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Fri, 20 May 2016 04:59:57 -0400 Subject: [PATCH 090/110] VerifyDB: don't check blocks that have been pruned --- src/init.cpp | 4 ++-- src/main.cpp | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index b362f1450..5dff5e707 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1302,8 +1302,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) uiInterface.InitMessage(_("Verifying blocks...")); if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { - LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n", - MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", DEFAULT_CHECKBLOCKS)); + LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks", + MIN_BLOCKS_TO_KEEP); } { diff --git a/src/main.cpp b/src/main.cpp index 14419189b..2cf1d8dd0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4565,6 +4565,11 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); if (pindex->nHeight < chainActive.Height()-nCheckDepth) break; + if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) { + // If pruning, only go back as far as we have data. + LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight); + break; + } CBlock block; // check level 0: read from disk if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) From 52680318bb236225fac561339510596c98f66a08 Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Sat, 30 Apr 2016 21:45:26 -0700 Subject: [PATCH 091/110] mapNextTx: use pointer as key, simplify value --- src/Makefile.am | 1 + src/indirectmap.h | 52 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 5 +++-- src/memusage.h | 16 +++++++++++++++ src/txmempool.cpp | 46 ++++++++++++++++++++--------------------- src/txmempool.h | 17 ++-------------- 6 files changed, 96 insertions(+), 41 deletions(-) create mode 100644 src/indirectmap.h diff --git a/src/Makefile.am b/src/Makefile.am index 5b4ec878d..e0a118991 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,6 +105,7 @@ BITCOIN_CORE_H = \ hash.h \ httprpc.h \ httpserver.h \ + indirectmap.h \ init.h \ key.h \ keystore.h \ diff --git a/src/indirectmap.h b/src/indirectmap.h new file mode 100644 index 000000000..28e1e8ded --- /dev/null +++ b/src/indirectmap.h @@ -0,0 +1,52 @@ +#ifndef BITCOIN_INDIRECTMAP_H +#define BITCOIN_INDIRECTMAP_H + +template +struct DereferencingComparator { bool operator()(const T a, const T b) const { return *a < *b; } }; + +/* Map whose keys are pointers, but are compared by their dereferenced values. + * + * Differs from a plain std::map > in + * that methods that take a key for comparison take a K rather than taking a K* + * (taking a K* would be confusing, since it's the value rather than the address + * of the object for comparison that matters due to the dereferencing comparator). + * + * Objects pointed to by keys must not be modified in any way that changes the + * result of DereferencingComparator. + */ +template +class indirectmap { +private: + typedef std::map > base; + base m; +public: + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + typedef typename base::size_type size_type; + typedef typename base::value_type value_type; + + // passthrough (pointer interface) + std::pair insert(const value_type& value) { return m.insert(value); } + + // pass address (value interface) + iterator find(const K& key) { return m.find(&key); } + const_iterator find(const K& key) const { return m.find(&key); } + iterator lower_bound(const K& key) { return m.lower_bound(&key); } + const_iterator lower_bound(const K& key) const { return m.lower_bound(&key); } + size_type erase(const K& key) { return m.erase(&key); } + size_type count(const K& key) const { return m.count(&key); } + + // passthrough + bool empty() const { return m.empty(); } + size_type size() const { return m.size(); } + size_type max_size() const { return m.max_size(); } + void clear() { m.clear(); } + iterator begin() { return m.begin(); } + iterator end() { return m.end(); } + const_iterator begin() const { return m.begin(); } + const_iterator end() const { return m.end(); } + const_iterator cbegin() const { return m.cbegin(); } + const_iterator cend() const { return m.cend(); } +}; + +#endif // BITCOIN_INDIRECTMAP_H diff --git a/src/main.cpp b/src/main.cpp index 2cf1d8dd0..8ecfabba5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1119,7 +1119,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C { COutPoint outpoint = txin.prevout; // A respend is a tx that conflicts with a member of the pool - if (pool.mapNextTx.count(txin.prevout)) + auto itConflicting = pool.mapNextTx.find(txin.prevout); + if (itConflicting != pool.mapNextTx.end()) { fRespend = true; // Relay only one tx per respent outpoint, but not if tx is equivalent to pool member @@ -1129,7 +1130,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C break; } /* - const CTransaction *ptxConflicting = pool.mapNextTx[txin.prevout].ptx; + const CTransaction *ptxConflicting = itConflicting->second; if (!setConflicts.count(ptxConflicting->GetHash())) { // Allow opt-out of transaction replacement by setting diff --git a/src/memusage.h b/src/memusage.h index 49760e64c..9c98e5c2c 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_MEMUSAGE_H #define BITCOIN_MEMUSAGE_H +#include "indirectmap.h" + #include #include @@ -106,6 +108,20 @@ static inline size_t IncrementalDynamicUsage(const std::map& m) return MallocUsage(sizeof(stl_tree_node >)); } +// indirectmap has underlying map with pointer as key + +template +static inline size_t DynamicUsage(const indirectmap& m) +{ + return MallocUsage(sizeof(stl_tree_node >)) * m.size(); +} + +template +static inline size_t IncrementalDynamicUsage(const indirectmap& m) +{ + return MallocUsage(sizeof(stl_tree_node >)); +} + // Boost data structures template diff --git a/src/txmempool.cpp b/src/txmempool.cpp index c93e15c26..58c66ae45 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -147,11 +147,11 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes if (it == mapTx.end()) { continue; } - std::map::iterator iter = mapNextTx.lower_bound(COutPoint(hash, 0)); + auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); // First calculate the children, and update setMemPoolChildren to // include them, and update their setMemPoolParents to include this tx. - for (; iter != mapNextTx.end() && iter->first.hash == hash; ++iter) { - const uint256 &childHash = iter->second.ptx->GetHash(); + for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { + const uint256 &childHash = iter->second->GetHash(); txiter childIter = mapTx.find(childHash); assert(childIter != mapTx.end()); // We can skip updating entries we've encountered before or that @@ -365,11 +365,11 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) { LOCK(cs); - std::map::iterator it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); + auto it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); // iterate over all COutPoints in mapNextTx whose hash equals the provided hashTx - while (it != mapNextTx.end() && it->first.hash == hashTx) { - coins.Spend(it->first.n); // and remove those outputs from coins + while (it != mapNextTx.end() && it->first->hash == hashTx) { + coins.Spend(it->first->n); // and remove those outputs from coins it++; } } @@ -414,7 +414,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, const CTransaction& tx = newit->GetTx(); std::set setParentTransactions; for (unsigned int i = 0; i < tx.vin.size(); i++) { - mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); + mapNextTx.insert(std::make_pair(&tx.vin[i].prevout, &tx)); setParentTransactions.insert(tx.vin[i].prevout.hash); } // Don't bother worrying about child transactions of this one. @@ -641,10 +641,10 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); + auto it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); if (it == mapNextTx.end()) continue; - txiter nextit = mapTx.find(it->second.ptx->GetHash()); + txiter nextit = mapTx.find(it->second->GetHash()); assert(nextit != mapTx.end()); txToRemove.insert(nextit); } @@ -701,9 +701,9 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list // Remove transactions which depend on inputs of tx, recursively LOCK(cs); BOOST_FOREACH(const CTxIn &txin, tx.vin) { - std::map::iterator it = mapNextTx.find(txin.prevout); + auto it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { - const CTransaction &txConflict = *it->second.ptx; + const CTransaction &txConflict = *it->second; if (txConflict != tx) { removeRecursive(txConflict, removed); @@ -811,10 +811,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(coins && coins->IsAvailable(txin.prevout.n)); } // Check whether its inputs are marked in mapNextTx. - std::map::const_iterator it3 = mapNextTx.find(txin.prevout); + auto it3 = mapNextTx.find(txin.prevout); assert(it3 != mapNextTx.end()); - assert(it3->second.ptx == &tx); - assert(it3->second.n == i); + assert(it3->first == &txin.prevout); + assert(it3->second == &tx); i++; } assert(setParentCheck == GetMemPoolParents(it)); @@ -841,10 +841,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; - std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); + auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 0; - for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) { - txiter childit = mapTx.find(iter->second.ptx->GetHash()); + for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) { + txiter childit = mapTx.find(iter->second->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); @@ -878,14 +878,12 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const stepsSinceLastRemove = 0; } } - for (std::map::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { - uint256 hash = it->second.ptx->GetHash(); + for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { + uint256 hash = it->second->GetHash(); indexed_transaction_set::const_iterator it2 = mapTx.find(hash); const CTransaction& tx = it2->GetTx(); assert(it2 != mapTx.end()); - assert(&tx == it->second.ptx); - assert(tx.vin.size() > it->second.n); - assert(it->first == it->second.ptx->vin[it->second.n].prevout); + assert(&tx == it->second); } assert(totalTxSize == checkTotal); @@ -1174,8 +1172,8 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe BOOST_FOREACH(const CTxIn& txin, tx.vin) { if (exists(txin.prevout.hash)) continue; - std::map::iterator it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); - if (it == mapNextTx.end() || it->first.hash != txin.prevout.hash) + auto it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); + if (it == mapNextTx.end() || it->first->hash != txin.prevout.hash) pvNoSpendsRemaining->push_back(txin.prevout.hash); } } diff --git a/src/txmempool.h b/src/txmempool.h index 864a0c97e..a59cea1e2 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -13,6 +13,7 @@ #include "spentindex.h" #include "amount.h" #include "coins.h" +#include "indirectmap.h" #include "primitives/transaction.h" #include "sync.h" @@ -308,20 +309,6 @@ struct ancestor_score {}; class CBlockPolicyEstimator; -/** An inpoint - a combination of a transaction and an index n into its vin */ -class CInPoint -{ -public: - const CTransaction* ptx; - uint32_t n; - - CInPoint() { SetNull(); } - CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; } - void SetNull() { ptx = NULL; n = (uint32_t) -1; } - bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); } - size_t DynamicMemoryUsage() const { return 0; } -}; - /** * CTxMemPool stores valid-according-to-the-current-best-chain * transactions that may be included in the next block. @@ -492,7 +479,7 @@ private: void UpdateChild(txiter entry, txiter child, bool add); public: - std::map mapNextTx; + indirectmap mapNextTx; std::map > mapDeltas; /** Create a new CTxMemPool. From 09ddb265d608c185b9564ee59a6150714615c17a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 18 Jun 2016 18:16:36 +0200 Subject: [PATCH 092/110] Stop trimming when mapTx is empty --- src/txmempool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 58c66ae45..be8b2c206 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1144,7 +1144,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe unsigned nTxnRemoved = 0; CFeeRate maxFeeRateRemoved(0); - while (DynamicMemoryUsage() > sizelimit) { + while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) { indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); // We set the new mempool min fee to the feerate of the removed set, plus the From e46145b8500df5282f532e1ce2198a377800b72e Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 17 Dec 2015 13:45:33 -0500 Subject: [PATCH 093/110] Eliminate unnecessary call to CheckBlock --- src/main.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8ecfabba5..8bafdfb6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4177,22 +4177,17 @@ bool static IsCanonicalBlockSignature(const CBlock* pblock) bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp, const uint256& hash) { - if (!IsCanonicalBlockSignature(pblock)) { - if (pfrom && pfrom->nVersion >= CANONICAL_BLOCK_SIG_VERSION) - return state.DoS(100, error("ProcessNewBlock(): bad block signature encoding"), - REJECT_INVALID, "bad-block-signature-encoding"); - return false; - } - // Preliminary checks - bool checked = CheckBlock(*pblock, state, hash); + if (!IsCanonicalBlockSignature(pblock)) { + if (pfrom && pfrom->nVersion >= CANONICAL_BLOCK_SIG_VERSION) + return state.DoS(100, error("ProcessNewBlock(): bad block signature encoding"), + REJECT_INVALID, "bad-block-signature-encoding"); + return false; + } { LOCK(cs_main); bool fRequested = MarkBlockAsReceived(hash); fRequested |= fForceProcessing; - if (!checked) { - return error("%s: CheckBlock FAILED", __func__); - } // Store to disk CBlockIndex *pindex = NULL; From 87ea7318b3f9323b4e45b2b02a110dd8bada7077 Mon Sep 17 00:00:00 2001 From: lateminer Date: Sat, 13 Jan 2018 02:38:07 +0300 Subject: [PATCH 094/110] Fix: dbwrapper: Pass parent CDBWrapper into CDBBatch and CDBIterator --- src/txdb.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/txdb.cpp b/src/txdb.cpp index c9c03eb46..0689ac1f4 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -171,7 +171,7 @@ bool CBlockTreeDB::ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) } bool CBlockTreeDB::UpdateSpentIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) { if (it->second.IsNull()) { batch.Erase(make_pair(DB_SPENTINDEX, it->first)); @@ -183,7 +183,7 @@ bool CBlockTreeDB::UpdateSpentIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) { if (it->second.IsNull()) { batch.Erase(make_pair(DB_ADDRESSUNSPENTINDEX, it->first)); @@ -220,14 +220,14 @@ bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type, } bool CBlockTreeDB::WriteAddressIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) batch.Write(make_pair(DB_ADDRESSINDEX, it->first), it->second); return WriteBatch(batch); } bool CBlockTreeDB::EraseAddressIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) batch.Erase(make_pair(DB_ADDRESSINDEX, it->first)); return WriteBatch(batch); @@ -268,7 +268,7 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, } bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey ×tampIndex) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0); return WriteBatch(batch); } @@ -301,7 +301,7 @@ bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned i } bool CBlockTreeDB::WriteTimestampBlockIndex(const CTimestampBlockIndexKey &blockhashIndex, const CTimestampBlockIndexValue &logicalts) { - CDBBatch batch(&GetObfuscateKey()); + CDBBatch batch(*this); batch.Write(make_pair(DB_BLOCKHASHINDEX, blockhashIndex), logicalts); return WriteBatch(batch); } From c946ec9d9e988be05b7ef08e521de058d2ad91a4 Mon Sep 17 00:00:00 2001 From: lateminer Date: Sat, 13 Jan 2018 02:44:28 +0300 Subject: [PATCH 095/110] Revert "mapNextTx: use pointer as key, simplify value" This reverts commit 52680318bb236225fac561339510596c98f66a08. --- src/Makefile.am | 1 - src/indirectmap.h | 52 ----------------------------------------------- src/main.cpp | 5 ++--- src/memusage.h | 16 --------------- src/txmempool.cpp | 46 +++++++++++++++++++++-------------------- src/txmempool.h | 17 ++++++++++++++-- 6 files changed, 41 insertions(+), 96 deletions(-) delete mode 100644 src/indirectmap.h diff --git a/src/Makefile.am b/src/Makefile.am index e0a118991..5b4ec878d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,7 +105,6 @@ BITCOIN_CORE_H = \ hash.h \ httprpc.h \ httpserver.h \ - indirectmap.h \ init.h \ key.h \ keystore.h \ diff --git a/src/indirectmap.h b/src/indirectmap.h deleted file mode 100644 index 28e1e8ded..000000000 --- a/src/indirectmap.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef BITCOIN_INDIRECTMAP_H -#define BITCOIN_INDIRECTMAP_H - -template -struct DereferencingComparator { bool operator()(const T a, const T b) const { return *a < *b; } }; - -/* Map whose keys are pointers, but are compared by their dereferenced values. - * - * Differs from a plain std::map > in - * that methods that take a key for comparison take a K rather than taking a K* - * (taking a K* would be confusing, since it's the value rather than the address - * of the object for comparison that matters due to the dereferencing comparator). - * - * Objects pointed to by keys must not be modified in any way that changes the - * result of DereferencingComparator. - */ -template -class indirectmap { -private: - typedef std::map > base; - base m; -public: - typedef typename base::iterator iterator; - typedef typename base::const_iterator const_iterator; - typedef typename base::size_type size_type; - typedef typename base::value_type value_type; - - // passthrough (pointer interface) - std::pair insert(const value_type& value) { return m.insert(value); } - - // pass address (value interface) - iterator find(const K& key) { return m.find(&key); } - const_iterator find(const K& key) const { return m.find(&key); } - iterator lower_bound(const K& key) { return m.lower_bound(&key); } - const_iterator lower_bound(const K& key) const { return m.lower_bound(&key); } - size_type erase(const K& key) { return m.erase(&key); } - size_type count(const K& key) const { return m.count(&key); } - - // passthrough - bool empty() const { return m.empty(); } - size_type size() const { return m.size(); } - size_type max_size() const { return m.max_size(); } - void clear() { m.clear(); } - iterator begin() { return m.begin(); } - iterator end() { return m.end(); } - const_iterator begin() const { return m.begin(); } - const_iterator end() const { return m.end(); } - const_iterator cbegin() const { return m.cbegin(); } - const_iterator cend() const { return m.cend(); } -}; - -#endif // BITCOIN_INDIRECTMAP_H diff --git a/src/main.cpp b/src/main.cpp index 8bafdfb6a..a05aba09a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1119,8 +1119,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C { COutPoint outpoint = txin.prevout; // A respend is a tx that conflicts with a member of the pool - auto itConflicting = pool.mapNextTx.find(txin.prevout); - if (itConflicting != pool.mapNextTx.end()) + if (pool.mapNextTx.count(txin.prevout)) { fRespend = true; // Relay only one tx per respent outpoint, but not if tx is equivalent to pool member @@ -1130,7 +1129,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C break; } /* - const CTransaction *ptxConflicting = itConflicting->second; + const CTransaction *ptxConflicting = pool.mapNextTx[txin.prevout].ptx; if (!setConflicts.count(ptxConflicting->GetHash())) { // Allow opt-out of transaction replacement by setting diff --git a/src/memusage.h b/src/memusage.h index 9c98e5c2c..49760e64c 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -5,8 +5,6 @@ #ifndef BITCOIN_MEMUSAGE_H #define BITCOIN_MEMUSAGE_H -#include "indirectmap.h" - #include #include @@ -108,20 +106,6 @@ static inline size_t IncrementalDynamicUsage(const std::map& m) return MallocUsage(sizeof(stl_tree_node >)); } -// indirectmap has underlying map with pointer as key - -template -static inline size_t DynamicUsage(const indirectmap& m) -{ - return MallocUsage(sizeof(stl_tree_node >)) * m.size(); -} - -template -static inline size_t IncrementalDynamicUsage(const indirectmap& m) -{ - return MallocUsage(sizeof(stl_tree_node >)); -} - // Boost data structures template diff --git a/src/txmempool.cpp b/src/txmempool.cpp index be8b2c206..9e3b21778 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -147,11 +147,11 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector &vHashes if (it == mapTx.end()) { continue; } - auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); + std::map::iterator iter = mapNextTx.lower_bound(COutPoint(hash, 0)); // First calculate the children, and update setMemPoolChildren to // include them, and update their setMemPoolParents to include this tx. - for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { - const uint256 &childHash = iter->second->GetHash(); + for (; iter != mapNextTx.end() && iter->first.hash == hash; ++iter) { + const uint256 &childHash = iter->second.ptx->GetHash(); txiter childIter = mapTx.find(childHash); assert(childIter != mapTx.end()); // We can skip updating entries we've encountered before or that @@ -365,11 +365,11 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) { LOCK(cs); - auto it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); + std::map::iterator it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); // iterate over all COutPoints in mapNextTx whose hash equals the provided hashTx - while (it != mapNextTx.end() && it->first->hash == hashTx) { - coins.Spend(it->first->n); // and remove those outputs from coins + while (it != mapNextTx.end() && it->first.hash == hashTx) { + coins.Spend(it->first.n); // and remove those outputs from coins it++; } } @@ -414,7 +414,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, const CTransaction& tx = newit->GetTx(); std::set setParentTransactions; for (unsigned int i = 0; i < tx.vin.size(); i++) { - mapNextTx.insert(std::make_pair(&tx.vin[i].prevout, &tx)); + mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); setParentTransactions.insert(tx.vin[i].prevout.hash); } // Don't bother worrying about child transactions of this one. @@ -641,10 +641,10 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); if (it == mapNextTx.end()) continue; - txiter nextit = mapTx.find(it->second->GetHash()); + txiter nextit = mapTx.find(it->second.ptx->GetHash()); assert(nextit != mapTx.end()); txToRemove.insert(nextit); } @@ -701,9 +701,9 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list // Remove transactions which depend on inputs of tx, recursively LOCK(cs); BOOST_FOREACH(const CTxIn &txin, tx.vin) { - auto it = mapNextTx.find(txin.prevout); + std::map::iterator it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { - const CTransaction &txConflict = *it->second; + const CTransaction &txConflict = *it->second.ptx; if (txConflict != tx) { removeRecursive(txConflict, removed); @@ -811,10 +811,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(coins && coins->IsAvailable(txin.prevout.n)); } // Check whether its inputs are marked in mapNextTx. - auto it3 = mapNextTx.find(txin.prevout); + std::map::const_iterator it3 = mapNextTx.find(txin.prevout); assert(it3 != mapNextTx.end()); - assert(it3->first == &txin.prevout); - assert(it3->second == &tx); + assert(it3->second.ptx == &tx); + assert(it3->second.n == i); i++; } assert(setParentCheck == GetMemPoolParents(it)); @@ -841,10 +841,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; - auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); + std::map::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); int64_t childSizes = 0; - for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) { - txiter childit = mapTx.find(iter->second->GetHash()); + for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) { + txiter childit = mapTx.find(iter->second.ptx->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); @@ -878,12 +878,14 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const stepsSinceLastRemove = 0; } } - for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { - uint256 hash = it->second->GetHash(); + for (std::map::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { + uint256 hash = it->second.ptx->GetHash(); indexed_transaction_set::const_iterator it2 = mapTx.find(hash); const CTransaction& tx = it2->GetTx(); assert(it2 != mapTx.end()); - assert(&tx == it->second); + assert(&tx == it->second.ptx); + assert(tx.vin.size() > it->second.n); + assert(it->first == it->second.ptx->vin[it->second.n].prevout); } assert(totalTxSize == checkTotal); @@ -1172,8 +1174,8 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe BOOST_FOREACH(const CTxIn& txin, tx.vin) { if (exists(txin.prevout.hash)) continue; - auto it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); - if (it == mapNextTx.end() || it->first->hash != txin.prevout.hash) + std::map::iterator it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0)); + if (it == mapNextTx.end() || it->first.hash != txin.prevout.hash) pvNoSpendsRemaining->push_back(txin.prevout.hash); } } diff --git a/src/txmempool.h b/src/txmempool.h index a59cea1e2..864a0c97e 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -13,7 +13,6 @@ #include "spentindex.h" #include "amount.h" #include "coins.h" -#include "indirectmap.h" #include "primitives/transaction.h" #include "sync.h" @@ -309,6 +308,20 @@ struct ancestor_score {}; class CBlockPolicyEstimator; +/** An inpoint - a combination of a transaction and an index n into its vin */ +class CInPoint +{ +public: + const CTransaction* ptx; + uint32_t n; + + CInPoint() { SetNull(); } + CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; } + void SetNull() { ptx = NULL; n = (uint32_t) -1; } + bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); } + size_t DynamicMemoryUsage() const { return 0; } +}; + /** * CTxMemPool stores valid-according-to-the-current-best-chain * transactions that may be included in the next block. @@ -479,7 +492,7 @@ private: void UpdateChild(txiter entry, txiter child, bool add); public: - indirectmap mapNextTx; + std::map mapNextTx; std::map > mapDeltas; /** Create a new CTxMemPool. From 64f04a5405a95dc3e1abc1093c2d0ab29ae1f726 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Tue, 19 Apr 2016 13:07:16 -0700 Subject: [PATCH 096/110] Replace memcmp with std::equal in CScript::FindAndDelete Function is stl; std::equal just makes more sense. --- src/script/script.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/script.h b/src/script/script.h index 4d816f891..62aaa1e19 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -590,7 +590,7 @@ public: opcodetype opcode; do { - while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0) + while (end() - pc >= (long)b.size() && std::equal(b.begin(), b.end(), pc)) { pc = erase(pc, pc + b.size()); ++nFound; From e9acefb94bc2c9fcb964b2b54a9c3d87fcc33e1f Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Tue, 19 Apr 2016 13:13:46 -0700 Subject: [PATCH 097/110] Replace c-style cast with c++ style static_cast. --- src/script/script.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/script.h b/src/script/script.h index 62aaa1e19..7590e669d 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -590,7 +590,7 @@ public: opcodetype opcode; do { - while (end() - pc >= (long)b.size() && std::equal(b.begin(), b.end(), pc)) + while (static_cast(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { pc = erase(pc, pc + b.size()); ++nFound; From 5cb65440931f1a10f441bb2540152ccb8ca401ef Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Wed, 3 Feb 2016 16:15:18 -0500 Subject: [PATCH 098/110] Unit test for CScript::FindAndDelete --- src/test/script_tests.cpp | 117 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index f370a4aa2..620f39ea3 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1013,4 +1013,121 @@ BOOST_AUTO_TEST_CASE(script_GetScriptAsm) BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); } +static CScript +ScriptFromHex(const char* hex) +{ + std::vector data = ParseHex(hex); + return CScript(data.begin(), data.end()); +} + + +BOOST_AUTO_TEST_CASE(script_FindAndDelete) +{ + // Exercise the FindAndDelete functionality + CScript s; + CScript d; + CScript expect; + + s = CScript() << OP_1 << OP_2; + d = CScript(); // delete nothing should be a no-op + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + s = CScript() << OP_1 << OP_2 << OP_3; + d = CScript() << OP_2; + expect = CScript() << OP_1 << OP_3; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3; + d = CScript() << OP_3; + expect = CScript() << OP_1 << OP_4; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack + d = ScriptFromHex("0302ff03"); + expect = CScript(); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03 + d = ScriptFromHex("0302ff03"); + expect = CScript(); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff030302ff03"); + d = ScriptFromHex("02"); + expect = s; // FindAndDelete matches entire opcodes + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0302ff030302ff03"); + d = ScriptFromHex("ff"); + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + // This is an odd edge case: strip of the push-three-bytes + // prefix, leaving 02ff03 which is push-two-bytes: + s = ScriptFromHex("0302ff030302ff03"); + d = ScriptFromHex("03"); + expect = CScript() << ParseHex("ff03") << ParseHex("ff03"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); + BOOST_CHECK(s == expect); + + // Byte sequence that spans multiple opcodes: + s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY + d = ScriptFromHex("feed51"); + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes + BOOST_CHECK(s == expect); + + s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY + d = ScriptFromHex("02feed51"); + expect = ScriptFromHex("69"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("516902feed5169"); + d = ScriptFromHex("feed51"); + expect = s; + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("516902feed5169"); + d = ScriptFromHex("02feed51"); + expect = ScriptFromHex("516969"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = CScript() << OP_0 << OP_0 << OP_1 << OP_1; + d = CScript() << OP_0 << OP_1; + expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1; + d = CScript() << OP_0 << OP_1; + expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); + BOOST_CHECK(s == expect); + + // Another weird edge case: + // End with invalid push (not enough data)... + s = ScriptFromHex("0003feed"); + d = ScriptFromHex("03feed"); // ... can remove the invalid push + expect = ScriptFromHex("00"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); + + s = ScriptFromHex("0003feed"); + d = ScriptFromHex("00"); + expect = ScriptFromHex("03feed"); + BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); + BOOST_CHECK(s == expect); +} + BOOST_AUTO_TEST_SUITE_END() From a1c72cf46121d6c18ba0cbd33f2d20cc58eb21bd Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Tue, 19 Apr 2016 13:17:38 -0700 Subject: [PATCH 099/110] Improve worst-case behavior of CScript::FindAndDelete Thanks to Sergio Lerner for identifying this issue and suggesting this kind of solution. --- src/script/script.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/script/script.h b/src/script/script.h index 7590e669d..b24da9c47 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -586,17 +586,26 @@ public: int nFound = 0; if (b.empty()) return nFound; - iterator pc = begin(); + CScript result; + iterator pc = begin(), pc2 = begin(); opcodetype opcode; do { + result.insert(result.end(), pc2, pc); while (static_cast(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc)) { - pc = erase(pc, pc + b.size()); + pc = pc + b.size(); ++nFound; } + pc2 = pc; } while (GetOp(pc, opcode)); + + if (nFound > 0) { + result.insert(result.end(), pc2, end()); + *this = result; + } + return nFound; } int Find(opcodetype op) const From 1ab443eec77088e099fc5617464c50d703ce2847 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 29 Mar 2016 16:46:20 +0200 Subject: [PATCH 100/110] Reformat version in UpdateTip and other messages --- src/main.cpp | 4 ++-- src/primitives/block.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a05aba09a..f8de1c788 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3101,8 +3101,8 @@ void static UpdateTip(CBlockIndex *pindexNew) { nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, + LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 09560a269..d5f825d43 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -28,7 +28,7 @@ uint256 CBlockHeader::GetPoWHash() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u, vchBlockSig=%s)\n", + s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u, vchBlockSig=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), From 722169b74db49b0a47ae33d62d6b5b74665e40cc Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 20 Apr 2016 14:53:36 +0200 Subject: [PATCH 101/110] Make ProcessNewBlock dbp const and update comment --- src/main.cpp | 4 ++-- src/main.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f8de1c788..6a019dac5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4090,7 +4090,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state } /** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ -static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp, const uint256& hash) +static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, const uint256& hash) { AssertLockHeld(cs_main); @@ -4174,7 +4174,7 @@ bool static IsCanonicalBlockSignature(const CBlock* pblock) return IsLowDERSignature(pblock->vchBlockSig, NULL, false); } -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp, const uint256& hash) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, const uint256& hash) { if (!IsCanonicalBlockSignature(pblock)) { if (pfrom && pfrom->nVersion >= CANONICAL_BLOCK_SIG_VERSION) diff --git a/src/main.h b/src/main.h index ff3cf033a..7e833b706 100644 --- a/src/main.h +++ b/src/main.h @@ -214,10 +214,10 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. * @param[in] pblock The block we want to process. * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. - * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. + * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp, const uint256& hash); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, const uint256& hash); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ From 26d85443144261947fdc986ddf1c93a717adaaf3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 20 Apr 2016 15:45:41 +0200 Subject: [PATCH 102/110] Switch reindexing to AcceptBlock in-loop and ActivateBestChain afterwards --- src/init.cpp | 20 ++++++++++---------- src/main.cpp | 15 +++++++++------ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 5dff5e707..30164076b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -406,7 +406,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitdescendantcount=", strprintf("Do not accept transactions if any ancestor would have or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT)); strUsage += HelpMessageOpt("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent, tor, zmq"; // Don't translate these and qt below + string debugCategories = "addrman, alert, bench, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + @@ -566,9 +566,10 @@ void ThreadImport(std::vector vImportFiles) { const CChainParams& chainparams = Params(); RenameThread("bitcoin-loadblk"); + CImportingNow imp; + // -reindex if (fReindex) { - CImportingNow imp; int nFile = 0; while (true) { CDiskBlockPos pos(nFile, 0); @@ -593,7 +594,6 @@ void ThreadImport(std::vector vImportFiles) if (boost::filesystem::exists(pathBootstrap)) { FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); if (file) { - CImportingNow imp; boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); LoadExternalBlockFile(chainparams, file); @@ -607,7 +607,6 @@ void ThreadImport(std::vector vImportFiles) BOOST_FOREACH(const boost::filesystem::path& path, vImportFiles) { FILE *file = fopen(path.string().c_str(), "rb"); if (file) { - CImportingNow imp; LogPrintf("Importing blocks file %s...\n", path.string()); LoadExternalBlockFile(chainparams, file); } else { @@ -615,6 +614,13 @@ void ThreadImport(std::vector vImportFiles) } } + // scan for better chains in the block chain database, that are not yet connected in the active best chain + CValidationState state; + if (!ActivateBestChain(state, chainparams)) { + LogPrintf("Failed to connect best block"); + StartShutdown(); + } + if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); StartShutdown(); @@ -1400,12 +1406,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); - uiInterface.InitMessage(_("Activating best chain...")); - // scan for better chains in the block chain database, that are not yet connected in the active best chain - CValidationState state; - if (!ActivateBestChain(state, chainparams)) - strErrors << "Failed to connect best block"; - std::vector vImportFiles; if (mapArgs.count("-loadblock")) { diff --git a/src/main.cpp b/src/main.cpp index 6a019dac5..ec08c2110 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4094,7 +4094,8 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha { AssertLockHeld(cs_main); - CBlockIndex *&pindex = *ppindex; + CBlockIndex *pindexDummy = NULL; + CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy; if (!AcceptBlockHeader(block, state, hash, chainparams, &pindex)) return false; @@ -4775,13 +4776,14 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB // process in case the block isn't known yet if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { + LOCK(cs_main); CValidationState state; - if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp, hash)) + if (AcceptBlock(block, state, chainparams, NULL, true, dbp, hash)) nLoaded++; if (state.IsError()) break; } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { - LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); + LogPrint("reindex", "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } // Recursively process earlier encountered successors of this block @@ -4795,11 +4797,12 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB std::multimap::iterator it = range.first; if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus())) { - uint256 hash = block.GetHash(); - LogPrintf("%s: Processing out of order child %s of %s\n", __func__, hash.ToString(), + uint256 hash = block.GetHash(); + LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, hash.ToString(), head.ToString()); + LOCK(cs_main); CValidationState dummy; - if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second, hash)) + if (AcceptBlock(block, dummy, chainparams, NULL, true, &it->second, hash)) { nLoaded++; queue.push_back(block.GetHash()); From c72b2908788f69eb7403b113922f6e0ee74db267 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 20 Apr 2016 16:02:19 +0200 Subject: [PATCH 103/110] Optimize ActivateBestChain for long chains --- src/main.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ec08c2110..eb0423236 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3340,10 +3340,9 @@ static void PruneBlockIndexCandidates() { * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock) +static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound) { AssertLockHeld(cs_main); - bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); @@ -3431,16 +3430,23 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, { LOCK(cs_main); CBlockIndex *pindexOldTip = chainActive.Tip(); - pindexMostWork = FindMostWorkChain(); + if (pindexMostWork == NULL) { + pindexMostWork = FindMostWorkChain(); + } // Whether we have anything to do at all. if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) return true; - if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && (*phash) == pindexMostWork->GetBlockHash() ? pblock : NULL)) - return false; + bool fInvalidFound = false; + if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && (*phash) == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound)) + return false; - pindexNewTip = chainActive.Tip(); + if (fInvalidFound) { + // Wipe cache, we may need another branch now. + pindexMostWork = NULL; + } + pindexNewTip = chainActive.Tip(); pindexFork = chainActive.FindFork(pindexOldTip); fInitialDownload = IsInitialBlockDownload(); } From 2cc8c4ace9916838c06504238e0ec51f9cd124c7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 21 Apr 2016 14:14:37 +0200 Subject: [PATCH 104/110] Add -reindex-chainstate that does not rebuild block index --- qa/rpc-tests/reindex.py | 17 ++++++++++++----- src/init.cpp | 8 +++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py index 321c2fe42..e246cbde3 100755 --- a/qa/rpc-tests/reindex.py +++ b/qa/rpc-tests/reindex.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -# Test -reindex with CheckBlockIndex +# Test -reindex and -reindex-chainstate with CheckBlockIndex # from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * @@ -20,13 +20,20 @@ class ReindexTest(BitcoinTestFramework): self.is_network_split = False self.nodes.append(start_node(0, self.options.tmpdir)) - def run_test(self): + def reindex(self, justchainstate=False): self.nodes[0].generate(3) + blockcount = self.nodes[0].getblockcount() stop_node(self.nodes[0], 0) wait_bitcoinds() - self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1"]) - assert_equal(self.nodes[0].getblockcount(), 3) - print "Success" + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]) + assert_equal(self.nodes[0].getblockcount(), blockcount) + print("Success") + + def run_test(self): + self.reindex(False) + self.reindex(True) + self.reindex(False) + self.reindex(True) if __name__ == '__main__': ReindexTest().main() diff --git a/src/init.cpp b/src/init.cpp index 30164076b..ca11177fe 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -324,7 +324,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " "(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); - strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files on startup")); + strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks")); + strUsage += HelpMessageOpt("-reindex", _("Rebuild chain state and block index from the blk*.dat files on disk")); #ifndef WIN32 strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif @@ -1190,6 +1191,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 7: load block chain fReindex = GetBoolArg("-reindex", false); + bool fReindexChainState = GetBoolArg("-reindex-chainstate", false); // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/ boost::filesystem::path blocksDir = GetDataDir() / "blocks"; @@ -1266,7 +1268,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) delete pblocktree; pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles); - pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); + pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); pcoinsTip = new CCoinsViewCache(pcoinscatcher); @@ -1295,7 +1297,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Check for changed -txindex state if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); + strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex"); break; } From bba401c69361e07c2cd57dc26425f76024fe63d9 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 28 Apr 2016 16:18:45 +0200 Subject: [PATCH 105/110] Report reindexing progress in GUI --- qa/rpc-tests/reindex.py | 3 +++ src/main.cpp | 39 ++++++++++++++++++++++++++++++++++++++ src/qt/bitcoingui.cpp | 18 ++++++++++++++---- src/qt/bitcoingui.h | 2 +- src/qt/clientmodel.cpp | 18 ++++++++++++------ src/qt/clientmodel.h | 2 +- src/qt/rpcconsole.cpp | 12 +++++++----- src/qt/rpcconsole.h | 2 +- src/qt/sendcoinsdialog.cpp | 2 +- src/ui_interface.h | 3 +++ 10 files changed, 82 insertions(+), 19 deletions(-) diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py index e246cbde3..4f875972c 100755 --- a/qa/rpc-tests/reindex.py +++ b/qa/rpc-tests/reindex.py @@ -8,6 +8,7 @@ # from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * +import time class ReindexTest(BitcoinTestFramework): @@ -26,6 +27,8 @@ class ReindexTest(BitcoinTestFramework): stop_node(self.nodes[0], 0) wait_bitcoinds() self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]) + while self.nodes[0].getblockcount() < blockcount: + time.sleep(0.1) assert_equal(self.nodes[0].getblockcount(), blockcount) print("Success") diff --git a/src/main.cpp b/src/main.cpp index eb0423236..3cc191347 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3412,6 +3412,28 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c return true; } +static void NotifyHeaderTip() { + bool fNotify = false; + bool fInitialBlockDownload = false; + static CBlockIndex* pindexHeaderOld = NULL; + CBlockIndex* pindexHeader = NULL; + { + LOCK(cs_main); + if (!setBlockIndexCandidates.empty()) { + pindexHeader = *setBlockIndexCandidates.rbegin(); + } + if (pindexHeader != pindexHeaderOld) { + fNotify = true; + fInitialBlockDownload = IsInitialBlockDownload(); + pindexHeaderOld = pindexHeader; + } + } + // Send block tip changed notifications without cs_main + if (fNotify) { + uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader); + } +} + /** * Make the best chain active, in multiple steps. The result is either failure * or an activated best chain. pblock is either NULL or a pointer to a block @@ -4206,6 +4228,8 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c return error("%s: AcceptBlock FAILED", __func__); } + NotifyHeaderTip(); + if (!ActivateBestChain(state, chainparams, pblock, &hash)) return error("%s: ActivateBestChain failed", __func__); @@ -4792,6 +4816,16 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB LogPrint("reindex", "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } + // Activate the genesis block so normal node progress can continue + if (hash == chainparams.GetConsensus().hashGenesisBlock) { + CValidationState state; + if (!ActivateBestChain(state, chainparams)) { + break; + } + } + + NotifyHeaderTip(); + // Recursively process earlier encountered successors of this block deque queue; queue.push_back(hash); @@ -4816,6 +4850,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB } range.first++; mapBlocksUnknownParent.erase(it); + NotifyHeaderTip(); } } } catch (const std::exception& e) { @@ -5858,6 +5893,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, ReadCompactSize(vRecv); // ignore block sig; assume it is 0. } + { LOCK(cs_main); if (nCount == 0) { @@ -5942,6 +5978,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } CheckBlockIndex(chainparams.GetConsensus()); + } + + NotifyHeaderTip(); } else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 29a05fdd2..8773ba29a 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -487,8 +487,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) setNumConnections(clientModel->getNumConnections()); connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL)); - connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double))); + setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL), false); + connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); // Receive and report messages from client model connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); @@ -727,7 +727,7 @@ void BitcoinGUI::setNumConnections(int count) labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count)); } -void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress) +void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header) { if(!clientModel) return; @@ -739,15 +739,25 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer enum BlockSource blockSource = clientModel->getBlockSource(); switch (blockSource) { case BLOCK_SOURCE_NETWORK: + if (header) { + return; + } progressBarLabel->setText(tr("Synchronizing with network...")); break; case BLOCK_SOURCE_DISK: - progressBarLabel->setText(tr("Importing blocks from disk...")); + if (header) { + progressBarLabel->setText(tr("Indexing blocks on disk...")); + } else { + progressBarLabel->setText(tr("Processing blocks on disk...")); + } break; case BLOCK_SOURCE_REINDEX: progressBarLabel->setText(tr("Reindexing blocks on disk...")); break; case BLOCK_SOURCE_NONE: + if (header) { + return; + } // Case: not Importing, not Reindexing and no network connection progressBarLabel->setText(tr("No block source available...")); break; diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index b8276a9a3..a58ec5574 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -157,7 +157,7 @@ public Q_SLOTS: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks and last block date shown in the UI */ - void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress); + void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers); /** Notify the user of an event from the core network or transaction handling code. @param[in] title the message box / notification title diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 47ef29862..33173209a 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -26,6 +26,7 @@ class CBlockIndex; static const int64_t nClientStartupTime = GetTime(); +static int64_t nLastHeaderTipUpdateNotification = 0; static int64_t nLastBlockTipUpdateNotification = 0; ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : @@ -237,7 +238,7 @@ static void BannedListChanged(ClientModel *clientmodel) QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection); } -static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex) +static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex, bool fHeader) { // lock free async UI updates in case we have a new block tip // during initial sync, only update the UI if the last update @@ -246,14 +247,17 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB if (initialSync) now = GetTimeMillis(); + int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; + // if we are in-sync, update the UI regardless of last update time - if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) { + if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { //pass a async signal to the UI thread QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection, Q_ARG(int, pIndex->nHeight), Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())), - Q_ARG(double, clientmodel->getVerificationProgress(pIndex))); - nLastBlockTipUpdateNotification = now; + Q_ARG(double, clientmodel->getVerificationProgress(pIndex)), + Q_ARG(bool, fHeader)); + nLastUpdateNotification = now; } } @@ -264,7 +268,8 @@ void ClientModel::subscribeToCoreSignals() uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); + uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2, false)); + uiInterface.NotifyHeaderTip.connect(boost::bind(BlockTipChanged, this, _1, _2, true)); } void ClientModel::unsubscribeFromCoreSignals() @@ -274,5 +279,6 @@ void ClientModel::unsubscribeFromCoreSignals() uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); + uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, false)); + uiInterface.NotifyHeaderTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, true)); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 518e7032a..7640739a5 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -88,7 +88,7 @@ private: Q_SIGNALS: void numConnectionsChanged(int count); - void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress); + void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header); void mempoolSizeChanged(long count, size_t mempoolSizeInBytes); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a1999bf4c..1773c9630 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -355,8 +355,8 @@ void RPCConsole::setClientModel(ClientModel *model) setNumConnections(model->getNumConnections()); connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL)); - connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double))); + setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL), false); + connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent()); connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64))); @@ -584,10 +584,12 @@ void RPCConsole::setNumConnections(int count) ui->numberOfConnections->setText(connections); } -void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress) +void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers) { - ui->numberOfBlocks->setText(QString::number(count)); - ui->lastBlockTime->setText(blockDate.toString()); + if (!headers) { + ui->numberOfBlocks->setText(QString::number(count)); + ui->lastBlockTime->setText(blockDate.toString()); + } } void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 2923587bc..28affa954 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -87,7 +87,7 @@ public Q_SLOTS: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks and last block date shown in the UI */ - void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress); + void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers); /** Set size (number of transactions and memory usage) of the mempool in the UI */ void setMempoolSize(long numberOfTxs, size_t dynUsage); /** Go forward or back in history */ diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 19ad78b5f..4ec02393c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -124,7 +124,7 @@ void SendCoinsDialog::setClientModel(ClientModel *clientModel) this->clientModel = clientModel; if (clientModel) { - connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(updateSmartFeeLabel())); + connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel())); } } diff --git a/src/ui_interface.h b/src/ui_interface.h index a7628ca0f..2bbe0730e 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -101,6 +101,9 @@ public: /** New block has been accepted */ boost::signals2::signal NotifyBlockTip; + /** Best header has changed */ + boost::signals2::signal NotifyHeaderTip; + /** Banlist did change. */ boost::signals2::signal BannedListChanged; }; From 1506d6b0ae0c13cf62b767da25b31b1b637c03e2 Mon Sep 17 00:00:00 2001 From: lateminer Date: Sat, 13 Jan 2018 13:26:20 +0300 Subject: [PATCH 106/110] Add policy: null signature for failed CHECK(MULTI)SIG https://github.com/bitcoin/bitcoin/pull/8634/commits/e41bd449ab2b8d01260795383af2c40b659d8587 --- src/policy/policy.h | 1 + src/script/interpreter.cpp | 14 +++++++++++++- src/script/interpreter.h | 4 ++++ src/script/script_error.cpp | 2 ++ src/script/script_error.h | 1 + 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/policy/policy.h b/src/policy/policy.h index 7832b027a..d2fb6b570 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -37,6 +37,7 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | SCRIPT_VERIFY_CLEANSTACK | + SCRIPT_VERIFY_NULLFAIL | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; /** For convenience, standard but not mandatory verify flags. */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index ac0caec03..5c6d46c88 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -930,6 +930,9 @@ bool EvalScript(vector >& stack, const CScript& script, un } bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode); + if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) + return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); @@ -959,6 +962,9 @@ bool EvalScript(vector >& stack, const CScript& script, un if (nOpCount > MAX_OPS_PER_SCRIPT) return set_error(serror, SCRIPT_ERR_OP_COUNT); int ikey = ++i; + // ikey2 is the position of last non-signature item in the stack. Top stack item = 1. + // With SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if operation fails. + int ikey2 = nKeysCount + 2; i += nKeysCount; if ((int)stack.size() < i) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); @@ -1013,8 +1019,14 @@ bool EvalScript(vector >& stack, const CScript& script, un } // Clean up stack of actual arguments - while (i-- > 1) + while (i-- > 1) { + // If the operation failed, we require that all signatures must be empty vector + if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && !ikey2 && stacktop(-1).size()) + return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + if (ikey2 > 0) + ikey2--; popstack(stack); + } // A bug causes CHECKMULTISIG to consume one extra argument // whose contents were not checked in any way. diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 500c768f1..79a7b093e 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -90,6 +90,10 @@ enum // // See BIP112 for details SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), + + // Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed + // + SCRIPT_VERIFY_NULLFAIL = (1U << 14), }; bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError* serror); diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index f1aa1fb40..c06bce023 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -63,6 +63,8 @@ const char* ScriptErrorString(const ScriptError serror) return "Non-canonical signature: S value is unnecessarily high"; case SCRIPT_ERR_SIG_NULLDUMMY: return "Dummy CHECKMULTISIG argument must be zero"; + case SCRIPT_ERR_SIG_NULLFAIL: + return "Signature must be zero for failed CHECK(MULTI)SIG operation"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS: return "NOPx reserved for soft-fork upgrades"; case SCRIPT_ERR_PUBKEYTYPE: diff --git a/src/script/script_error.h b/src/script/script_error.h index d9c88a809..c3a31cb33 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -48,6 +48,7 @@ typedef enum ScriptError_t SCRIPT_ERR_SIG_NULLDUMMY, SCRIPT_ERR_PUBKEYTYPE, SCRIPT_ERR_CLEANSTACK, + SCRIPT_ERR_SIG_NULLFAIL, /* softfork safeness */ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, From 9bb6d44326682d8c1a7998491fddb845be554901 Mon Sep 17 00:00:00 2001 From: maiiz Date: Mon, 18 Jul 2016 15:01:34 +0800 Subject: [PATCH 107/110] Fix relaypriority calculation error --- src/coins.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coins.cpp b/src/coins.cpp index 74429d05a..8ef6e7d49 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -279,7 +279,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount assert(coins); if (!coins->IsAvailable(txin.prevout.n)) continue; if (coins->nHeight <= nHeight) { - dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight); + dResult += (double)(coins->vout[txin.prevout.n].nValue) * (nHeight-coins->nHeight); inChainInputValue += coins->vout[txin.prevout.n].nValue; } } From 092922c063ae33d816c816f94cf0384d8c1c017b Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Tue, 29 Nov 2016 12:18:44 -0500 Subject: [PATCH 108/110] Disable fee estimates for a confirm target of 1 block Backport of #9239 without GUI changes and fixing conflicts in tests. --- src/policy/fees.cpp | 7 ++++++- src/rpc/mining.cpp | 2 ++ src/test/policyestimator_tests.cpp | 30 ++++++++++++++++++++++-------- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 980ecf10d..d949ca3b1 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -494,7 +494,8 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) { // Return failure if trying to analyze a target we're not tracking - if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) + // It's not possible to get reasonable estimates for confTarget of 1 + if (confTarget <= 1 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) return CFeeRate(0); double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); @@ -513,6 +514,10 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) return CFeeRate(0); + // It's not possible to get reasonable estimates for confTarget of 1 + if (confTarget == 1) + confTarget = 2; + double median = -1; while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) { median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index fac37d340..6ca239323 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -727,6 +727,8 @@ UniValue estimatefee(const UniValue& params, bool fHelp) "\n" "A negative value is returned if not enough transactions and blocks\n" "have been observed to make an estimate.\n" + "-1 is always returned for nblocks == 1 as it is impossible to calculate\n" + "a fee that is high enough to get reliably included in the next block.\n" "\nExample:\n" + HelpExampleCli("estimatefee", "6") ); diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 644c3da21..59c5c2b8c 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -104,19 +104,26 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // Highest feerate is 10*baseRate and gets in all blocks, // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, - // so estimateFee(1) should return 10*baseRate. + // so estimateFee(1) would return 10*baseRate but is hardcoded to return failure // Second highest feerate has 100% chance of being included by 2 blocks, // so estimateFee(2) should return 9*baseRate etc... for (int i = 1; i < 10;i++) { origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK()); origPriEst.push_back(mpool.estimatePriority(i)); if (i > 1) { // Fee estimates should be monotonically decreasing - BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); + if (i > 2) { + BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); + } BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]); } int mult = 11-i; - BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); - BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); + if (i > 1) { + BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); + } + else { + BOOST_CHECK(origFeeEst[i-1] == CFeeRate(0).GetFeePerK()); + } BOOST_CHECK(origPriEst[i-1] < pow(10,mult) * basepri + deltaPri); BOOST_CHECK(origPriEst[i-1] > pow(10,mult) * basepri - deltaPri); } @@ -126,9 +133,12 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) while (blocknum < 250) mpool.removeForBlock(block, ++blocknum, dummyConflicted); + BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); for (int i = 1; i < 10;i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee); - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + if (i > 1) { + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee); + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + } BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri); BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); } @@ -168,8 +178,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) } mpool.removeForBlock(block, 265, dummyConflicted); block.clear(); + BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); for (int i = 1; i < 10;i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + if (i > 1) + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); } @@ -189,8 +201,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) mpool.removeForBlock(block, ++blocknum, dummyConflicted); block.clear(); } + BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); for (int i = 1; i < 10; i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); + if (i > 1) + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri); } From 67c3960ddbebe0b0318aeb6ca9bbb99e7b1c2151 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Tue, 25 Oct 2016 15:30:55 -0400 Subject: [PATCH 109/110] Send tip change notification from invalidateblock This change is needed to prevent sync_blocks timeouts in the mempool_reorg test after the sync_blocks update in the upcoming commit "[qa] Change sync_blocks to pick smarter maxheight". This change was initially suggested by Suhas Daftuar in https://github.com/bitcoin/bitcoin/pull/8680#r78209060 --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 3cc191347..ba5435999 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3559,6 +3559,7 @@ bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensus InvalidChainFound(pindex); mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); return true; } From 20938be16fc8cee93c80713e1bc0d10bc7a05845 Mon Sep 17 00:00:00 2001 From: lateminer Date: Sat, 13 Jan 2018 14:27:47 +0300 Subject: [PATCH 110/110] Fix: Reformat version in UpdateTip and other messages --- src/main.cpp | 2 +- src/primitives/block.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ba5435999..01ca26435 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3101,7 +3101,7 @@ void static UpdateTip(CBlockIndex *pindexNew) { nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, + LogPrintf("%s: new best=%s height=%d version=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index d5f825d43..09560a269 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -28,7 +28,7 @@ uint256 CBlockHeader::GetPoWHash() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u, vchBlockSig=%s)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u, vchBlockSig=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(),