diff options
Diffstat (limited to 'src')
167 files changed, 2692 insertions, 1154 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 59618c4940..cc8dded413 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,6 +94,7 @@ BITCOIN_CORE_H = \ consensus/params.h \ consensus/validation.h \ core_io.h \ + core_memusage.h \ eccryptoverify.h \ ecwrapper.h \ hash.h \ @@ -111,6 +112,7 @@ BITCOIN_CORE_H = \ netbase.h \ noui.h \ policy/fees.h \ + policy/policy.h \ pow.h \ primitives/block.h \ primitives/transaction.h \ @@ -176,6 +178,7 @@ libbitcoin_server_a_SOURCES = \ net.cpp \ noui.cpp \ policy/fees.cpp \ + policy/policy.cpp \ pow.cpp \ rest.cpp \ rpcblockchain.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 6b7c42285d..748f2b14d5 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -185,13 +185,13 @@ BITCOIN_QT_H = \ qt/paymentrequestplus.h \ qt/paymentserver.h \ qt/peertablemodel.h \ + qt/platformstyle.h \ qt/qvalidatedlineedit.h \ qt/qvaluecombobox.h \ qt/receivecoinsdialog.h \ qt/receiverequestdialog.h \ qt/recentrequeststablemodel.h \ qt/rpcconsole.h \ - qt/scicon.h \ qt/sendcoinsdialog.h \ qt/sendcoinsentry.h \ qt/signverifymessagedialog.h \ @@ -273,10 +273,10 @@ BITCOIN_QT_CPP = \ qt/optionsdialog.cpp \ qt/optionsmodel.cpp \ qt/peertablemodel.cpp \ + qt/platformstyle.cpp \ qt/qvalidatedlineedit.cpp \ qt/qvaluecombobox.cpp \ qt/rpcconsole.cpp \ - qt/scicon.cpp \ qt/splashscreen.cpp \ qt/trafficgraphwidget.cpp \ qt/utilitydialog.cpp @@ -322,7 +322,7 @@ RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png) BITCOIN_RC = qt/res/bitcoin-qt-res.rc BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \ - -I$(builddir)/qt/forms + -I$(builddir)/qt/forms -DQT_NO_KEYWORDS qt_libbitcoinqt_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 0997148117..f9384a09a4 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -73,6 +73,7 @@ BITCOIN_TESTS =\ test/test_bitcoin.h \ test/timedata_tests.cpp \ test/transaction_tests.cpp \ + test/txvalidationcache_tests.cpp \ test/uint256_tests.cpp \ test/univalue_tests.cpp \ test/util_tests.cpp diff --git a/src/alert.cpp b/src/alert.cpp index ad81e74226..91e54a9178 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -11,6 +11,7 @@ #include "timedata.h" #include "ui_interface.h" #include "util.h" +#include "utilstrencodings.h" #include <stdint.h> #include <algorithm> diff --git a/src/base58.h b/src/base58.h index 787979c827..90014b9496 100644 --- a/src/base58.h +++ b/src/base58.h @@ -146,7 +146,10 @@ public: K GetKey() { K ret; - ret.Decode(&vchData[0], &vchData[Size]); + if (vchData.size() == Size) { + //if base58 encouded data not holds a ext key, return a !IsValid() key + ret.Decode(&vchData[0]); + } return ret; } @@ -154,6 +157,10 @@ public: SetKey(key); } + CBitcoinExtKeyBase(const std::string& strBase58c) { + SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size()); + } + CBitcoinExtKeyBase() {} }; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index d451720141..1c5a312874 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -97,12 +97,6 @@ static bool AppInitRPC(int argc, char* argv[]) UniValue CallRPC(const string& strMethod, const UniValue& params) { - if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") - throw runtime_error(strprintf( - _("You must set rpcpassword=<password> in the configuration file:\n%s\n" - "If the file does not exist, create it with owner-readable-only file permissions."), - GetConfigFile().string().c_str())); - // Connect to localhost bool fUseSSL = GetBoolArg("-rpcssl", false); boost::asio::io_service io_service; @@ -116,10 +110,24 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) if (!fConnected) throw CConnectionFailed("couldn't connect to server"); + // Find credentials to use + std::string strRPCUserColonPass; + if (mapArgs["-rpcpassword"] == "") { + // Try fall back to cookie-based authentication if no password is provided + if (!GetAuthCookie(&strRPCUserColonPass)) { + throw runtime_error(strprintf( + _("You must set rpcpassword=<password> in the configuration file:\n%s\n" + "If the file does not exist, create it with owner-readable-only file permissions."), + GetConfigFile().string().c_str())); + + } + } else { + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + } + // HTTP basic authentication - string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]); map<string, string> mapRequestHeaders; - mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64; + mapRequestHeaders["Authorization"] = string("Basic ") + EncodeBase64(strRPCUserColonPass); // Send request string strRequest = JSONRPCRequest(strMethod, params, 1); @@ -190,6 +198,15 @@ int CommandLineRPC(int argc, char *argv[]) throw CConnectionFailed("server in warmup"); strPrint = "error: " + error.write(); nRet = abs(code); + if (error.isObject()) + { + UniValue errCode = find_value(error, "code"); + UniValue errMsg = find_value(error, "message"); + strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n"; + + if (errMsg.isStr()) + strPrint += "error message:\n"+errMsg.get_str(); + } } else { // Result if (result.isNull()) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 45990f6bd8..e389d51a73 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -8,6 +8,7 @@ #include "consensus/consensus.h" #include "core_io.h" #include "keystore.h" +#include "policy/policy.h" #include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" @@ -142,13 +143,14 @@ static void RegisterLoad(const string& strInput) valStr.insert(valStr.size(), buf, bread); } - if (ferror(f)) { + int error = ferror(f); + fclose(f); + + if (error) { string strErr = "Error reading file " + filename; throw runtime_error(strErr); } - fclose(f); - // evaluate as JSON buffer register RegisterSetJson(key, valStr); } diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index cce687ac98..39bb301f44 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -3,10 +3,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" #include "clientversion.h" #include "rpcserver.h" #include "init.h" -#include "main.h" #include "noui.h" #include "scheduler.h" #include "util.h" diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7785417518..623104690a 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -16,6 +16,45 @@ using namespace std; #include "chainparamsseeds.h" +static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) +{ + CMutableTransaction txNew; + txNew.nVersion = 1; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].nValue = genesisReward; + txNew.vout[0].scriptPubKey = genesisOutputScript; + + CBlock genesis; + genesis.nTime = nTime; + genesis.nBits = nBits; + genesis.nNonce = nNonce; + genesis.nVersion = nVersion; + genesis.vtx.push_back(txNew); + genesis.hashPrevBlock.SetNull(); + genesis.hashMerkleRoot = genesis.BuildMerkleTree(); + return genesis; +} + +/** + * Build the genesis block. Note that the output of its generation + * transaction cannot be spent since it did not originally exist in the + * database. + * + * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) + * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) + * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) + * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) + * vMerkleTree: 4a5e1e + */ +static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) +{ + const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; + const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; + return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward); +} + /** * Main network */ @@ -50,36 +89,9 @@ public: pchMessageStart[3] = 0xd9; vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); nDefaultPort = 8333; - nMinerThreads = 0; 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=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) - * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) - * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) - * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) - * vMerkleTree: 4a5e1e - */ - const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; - CMutableTransaction txNew; - txNew.nVersion = 1; - txNew.vin.resize(1); - txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); - txNew.vout[0].nValue = 50 * COIN; - txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; - genesis.vtx.push_back(txNew); - genesis.hashPrevBlock.SetNull(); - genesis.hashMerkleRoot = genesis.BuildMerkleTree(); - genesis.nVersion = 1; - genesis.nTime = 1231006505; - genesis.nBits = 0x1d00ffff; - genesis.nNonce = 2083236893; - + genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); @@ -99,7 +111,6 @@ public: vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); - fRequireRPCPassword = true; fMiningRequiresPeers = true; fDefaultConsistencyChecks = false; fRequireStandard = true; @@ -133,13 +144,17 @@ static CMainParams mainParams; /** * Testnet (v3) */ -class CTestNetParams : public CMainParams { +class CTestNetParams : public CChainParams { public: CTestNetParams() { strNetworkID = "test"; + consensus.nSubsidyHalvingInterval = 210000; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 100; + consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks + consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -147,14 +162,12 @@ public: pchMessageStart[3] = 0x07; vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); nDefaultPort = 18333; - nMinerThreads = 0; nPruneAfterHeight = 1000; - //! Modify the testnet genesis block so the timestamp is valid for a later start. - genesis.nTime = 1296688602; - genesis.nNonce = 414098458; + genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); + assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); vFixedSeeds.clear(); vSeeds.clear(); @@ -171,7 +184,6 @@ public: vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); - fRequireRPCPassword = true; fMiningRequiresPeers = true; fDefaultConsistencyChecks = false; fRequireStandard = false; @@ -193,7 +205,7 @@ static CTestNetParams testNetParams; /** * Regression test */ -class CRegTestParams : public CTestNetParams { +class CRegTestParams : public CChainParams { public: CRegTestParams() { strNetworkID = "regtest"; @@ -202,23 +214,25 @@ public: consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks + consensus.nPowTargetSpacing = 10 * 60; + consensus.fPowAllowMinDifficultyBlocks = true; + pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; pchMessageStart[3] = 0xda; - nMinerThreads = 1; - genesis.nTime = 1296688602; - genesis.nBits = 0x207fffff; - genesis.nNonce = 2; - consensus.hashGenesisBlock = genesis.GetHash(); nDefaultPort = 18444; - assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); nPruneAfterHeight = 1000; + genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN); + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); + assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. - fRequireRPCPassword = false; fMiningRequiresPeers = false; fDefaultConsistencyChecks = true; fRequireStandard = false; @@ -232,6 +246,11 @@ public: 0, 0 }; + base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111); + base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196); + base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239); + base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >(); + base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >(); } }; static CRegTestParams regTestParams; diff --git a/src/chainparams.h b/src/chainparams.h index 8044b553e1..66d865b620 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -50,10 +50,7 @@ public: const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } - /** Used if GenerateBitcoins is called with a negative number of threads */ - int DefaultMinerThreads() const { return nMinerThreads; } const CBlock& GenesisBlock() const { return genesis; } - bool RequireRPCPassword() const { return fRequireRPCPassword; } /** Make miner wait to have peers to avoid wasting work */ bool MiningRequiresPeers() const { return fMiningRequiresPeers; } /** Default value for -checkmempool and -checkblockindex argument */ @@ -79,14 +76,12 @@ protected: //! Raw pub key bytes for the broadcast alert signing key. std::vector<unsigned char> vAlertPubKey; int nDefaultPort; - int nMinerThreads; uint64_t nPruneAfterHeight; std::vector<CDNSSeedData> vSeeds; std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES]; std::string strNetworkID; CBlock genesis; std::vector<SeedSpec6> vFixedSeeds; - bool fRequireRPCPassword; bool fMiningRequiresPeers; bool fDefaultConsistencyChecks; bool fRequireStandard; diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 7d82d689ec..9c87bf2154 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -25,7 +25,7 @@ static CBaseMainParams mainParams; /** * Testnet (v3) */ -class CBaseTestNetParams : public CBaseMainParams +class CBaseTestNetParams : public CBaseChainParams { public: CBaseTestNetParams() @@ -39,11 +39,12 @@ static CBaseTestNetParams testNetParams; /* * Regression test */ -class CBaseRegTestParams : public CBaseTestNetParams +class CBaseRegTestParams : public CBaseChainParams { public: CBaseRegTestParams() { + nRPCPort = 18332; strDataDir = "regtest"; } }; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 87f4ad7f2e..a9822eed89 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -4,6 +4,7 @@ #include "checkpoints.h" +#include "chain.h" #include "chainparams.h" #include "main.h" #include "uint256.h" diff --git a/src/coins.cpp b/src/coins.cpp index a41d5a310d..f02949de53 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -83,7 +83,7 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const // version as fresh. ret->second.flags = CCoinsCacheEntry::FRESH; } - cachedCoinsUsage += memusage::DynamicUsage(ret->second.coins); + cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage(); return ret; } @@ -110,7 +110,7 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { ret.first->second.flags = CCoinsCacheEntry::FRESH; } } else { - cachedCoinUsage = memusage::DynamicUsage(ret.first->second.coins); + cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage(); } // Assume that whenever ModifyCoins is called, the entry will be modified. ret.first->second.flags |= CCoinsCacheEntry::DIRTY; @@ -159,7 +159,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn assert(it->second.flags & CCoinsCacheEntry::FRESH); CCoinsCacheEntry& entry = cacheCoins[it->first]; entry.coins.swap(it->second.coins); - cachedCoinsUsage += memusage::DynamicUsage(entry.coins); + cachedCoinsUsage += entry.coins.DynamicMemoryUsage(); entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH; } } else { @@ -167,13 +167,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn // The grandparent does not have an entry, and the child is // modified and being pruned. This means we can just delete // it from the parent. - cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coins); + cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage(); cacheCoins.erase(itUs); } else { // A normal modification. - cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coins); + cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage(); itUs->second.coins.swap(it->second.coins); - cachedCoinsUsage += memusage::DynamicUsage(itUs->second.coins); + cachedCoinsUsage += itUs->second.coins.DynamicMemoryUsage(); itUs->second.flags |= CCoinsCacheEntry::DIRTY; } } @@ -261,6 +261,6 @@ CCoinsModifier::~CCoinsModifier() cache.cacheCoins.erase(it); } else { // If the coin still exists after the modification, add the new usage - cache.cachedCoinsUsage += memusage::DynamicUsage(it->second.coins); + cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage(); } } diff --git a/src/coins.h b/src/coins.h index a4671645df..bf4a777b8a 100644 --- a/src/coins.h +++ b/src/coins.h @@ -7,6 +7,7 @@ #define BITCOIN_COINS_H #include "compressor.h" +#include "core_memusage.h" #include "memusage.h" #include "serialize.h" #include "uint256.h" @@ -257,8 +258,7 @@ public: size_t DynamicMemoryUsage() const { size_t ret = memusage::DynamicUsage(vout); BOOST_FOREACH(const CTxOut &out, vout) { - const std::vector<unsigned char> *script = &out.scriptPubKey; - ret += memusage::DynamicUsage(*script); + ret += RecursiveDynamicUsage(out.scriptPubKey); } return ret; } diff --git a/src/compat.h b/src/compat.h index 7a5438a11e..5378c2c761 100644 --- a/src/compat.h +++ b/src/compat.h @@ -92,4 +92,12 @@ typedef u_int SOCKET; size_t strnlen( const char *start, size_t max_len); #endif // HAVE_DECL_STRNLEN +bool static inline IsSelectableSocket(SOCKET s) { +#ifdef WIN32 + return true; +#else + return (s < FD_SETSIZE); +#endif +} + #endif // BITCOIN_COMPAT_H diff --git a/src/core_memusage.h b/src/core_memusage.h new file mode 100644 index 0000000000..711135bb44 --- /dev/null +++ b/src/core_memusage.h @@ -0,0 +1,62 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CORE_MEMUSAGE_H +#define BITCOIN_CORE_MEMUSAGE_H + +#include "primitives/transaction.h" +#include "primitives/block.h" +#include "memusage.h" + +static inline size_t RecursiveDynamicUsage(const CScript& script) { + return memusage::DynamicUsage(*static_cast<const std::vector<unsigned char>*>(&script)); +} + +static inline size_t RecursiveDynamicUsage(const COutPoint& out) { + return 0; +} + +static inline size_t RecursiveDynamicUsage(const CTxIn& in) { + return RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout); +} + +static inline size_t RecursiveDynamicUsage(const CTxOut& out) { + return RecursiveDynamicUsage(out.scriptPubKey); +} + +static inline size_t RecursiveDynamicUsage(const CTransaction& tx) { + size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout); + for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) { + mem += RecursiveDynamicUsage(*it); + } + for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) { + mem += RecursiveDynamicUsage(*it); + } + return mem; +} + +static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) { + size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout); + for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) { + mem += RecursiveDynamicUsage(*it); + } + for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) { + mem += RecursiveDynamicUsage(*it); + } + return mem; +} + +static inline size_t RecursiveDynamicUsage(const CBlock& block) { + size_t mem = memusage::DynamicUsage(block.vtx) + memusage::DynamicUsage(block.vMerkleTree); + for (std::vector<CTransaction>::const_iterator it = block.vtx.begin(); it != block.vtx.end(); it++) { + mem += RecursiveDynamicUsage(*it); + } + return mem; +} + +static inline size_t RecursiveDynamicUsage(const CBlockLocator& locator) { + return memusage::DynamicUsage(locator.vHave); +} + +#endif // BITCOIN_CORE_MEMUSAGE_H diff --git a/src/init.cpp b/src/init.cpp index 6c9c1214f0..6bea42a20e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -11,6 +11,8 @@ #include "addrman.h" #include "amount.h" +#include "chain.h" +#include "chainparams.h" #include "checkpoints.h" #include "compat/sanity.h" #include "consensus/validation.h" @@ -18,15 +20,19 @@ #include "main.h" #include "miner.h" #include "net.h" +#include "policy/policy.h" #include "rpcserver.h" #include "script/standard.h" #include "scheduler.h" #include "txdb.h" +#include "txmempool.h" #include "ui_interface.h" #include "util.h" #include "utilmoneystr.h" +#include "utilstrencodings.h" #include "validationinterface.h" #ifdef ENABLE_WALLET +#include "wallet/db.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" #endif @@ -156,8 +162,8 @@ void Shutdown() #ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->Flush(false); - GenerateBitcoins(false, NULL, 0); #endif + GenerateBitcoins(false, 0, Params()); StopNode(); UnregisterNodeSignals(GetNodeSignals()); @@ -283,7 +289,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), - -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); + -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef WIN32 strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "bitcoind.pid")); #endif @@ -329,6 +335,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6")); strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") + " " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway")); + strUsage += HelpMessageOpt("-whiteconnections=<n>", strprintf(_("Reserve this many inbound connections for whitelisted peers (default: %d)"), 0)); #ifdef ENABLE_WALLET strUsage += HelpMessageGroup(_("Wallet options:")); @@ -370,10 +377,8 @@ std::string HelpMessage(HelpMessageMode mode) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " + _("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + "."); -#ifdef ENABLE_WALLET strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0)); strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1)); -#endif strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0)); strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1)); @@ -396,6 +401,8 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-testnet", _("Use the test network")); strUsage += HelpMessageGroup(_("Node relay options:")); + if (showDebug) + strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), 1)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); @@ -434,6 +441,9 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-min", _("Start minimized")); strUsage += HelpMessageOpt("-rootcertificates=<file>", _("Set SSL root certificates for payment request (default: -system-)")); strUsage += HelpMessageOpt("-splash", _("Show splash screen on startup (default: 1)")); + if (showDebug) { + strUsage += HelpMessageOpt("-uiplatform", "Select platform to customize UI for (one of windows, macosx, other; default: platform compiled on)"); + } } return strUsage; @@ -666,6 +676,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fLogTimestamps = GetBoolArg("-logtimestamps", true); fLogIPs = GetBoolArg("-logips", false); + LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); + // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified if (mapArgs.count("-bind")) { @@ -724,16 +737,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__); } - // Make sure enough file descriptors are available - int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); - nMaxConnections = GetArg("-maxconnections", 125); - nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); - int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); - if (nFD < MIN_CORE_FILEDESCRIPTORS) - return InitError(_("Not enough file descriptors available.")); - if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) - nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS; - // if using block pruning, then disable txindex if (GetArg("-prune", 0)) { if (GetBoolArg("-txindex", false)) @@ -744,6 +747,47 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif } + + // Make sure enough file descriptors are available + int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); + int nUserMaxConnections = GetArg("-maxconnections", 125); + nMaxConnections = std::max(nUserMaxConnections, 0); + int nUserWhiteConnections = GetArg("-whiteconnections", 0); + nWhiteConnections = std::max(nUserWhiteConnections, 0); + + if ((mapArgs.count("-whitelist")) || (mapArgs.count("-whitebind"))) { + if (!(mapArgs.count("-maxconnections"))) { + // User is using whitelist feature, + // but did not specify -maxconnections parameter. + // Silently increase the default to compensate, + // so that the whitelist connection reservation feature + // does not inadvertently reduce the default + // inbound connection capacity of the network. + nMaxConnections += nWhiteConnections; + } + } else { + // User not using whitelist feature. + // Silently disable connection reservation, + // for the same reason as above. + nWhiteConnections = 0; + } + + // Trim requested connection counts, to fit into system limitations + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); + int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + if (nFD < MIN_CORE_FILEDESCRIPTORS) + return InitError(_("Not enough file descriptors available.")); + nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections); + + if (nMaxConnections < nUserMaxConnections) + InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); + + // Connection capacity is prioritized in this order: + // outbound connections (hardcoded to 8), + // then whitelisted connections, + // then non-whitelisted connections get whatever's left (if any). + if ((nWhiteConnections > 0) && (nWhiteConnections >= (nMaxConnections - 8))) + InitWarning(strprintf(_("All non-whitelisted incoming connections will be dropped, because -whiteconnections is %d and -maxconnections is only %d."), nWhiteConnections, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags @@ -774,7 +818,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); if (nScriptCheckThreads <= 0) - nScriptCheckThreads += boost::thread::hardware_concurrency(); + nScriptCheckThreads += GetNumCores(); if (nScriptCheckThreads <= 1) nScriptCheckThreads = 0; else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) @@ -819,6 +863,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"])); } + fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard()); + if (Params().RequireStandard() && !fRequireStandard) + return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString())); + #ifdef ENABLE_WALLET if (mapArgs.count("-mintxfee")) { @@ -904,8 +952,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); - LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); + + if (fPrintToDebugLog) + OpenDebugLog(); + LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); #ifdef ENABLE_WALLET LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); @@ -916,6 +966,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Using data directory %s\n", strDataDir); LogPrintf("Using config file %s\n", GetConfigFile().string()); LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); + if (nWhiteConnections > 0) + LogPrintf("Reserving %i of these connections for whitelisted inbound peers\n", nWhiteConnections); std::ostringstream strErrors; LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); @@ -1444,11 +1496,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); scheduler.scheduleEvery(f, nPowTargetSpacing); -#ifdef ENABLE_WALLET // Generate coins in the background - if (pwalletMain) - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1)); -#endif + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); // ********************************************************* Step 11: finished diff --git a/src/main.cpp b/src/main.cpp index 6c4cfe75aa..fa12281655 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,17 +11,27 @@ #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" +#include "consensus/consensus.h" #include "consensus/validation.h" +#include "hash.h" #include "init.h" #include "merkleblock.h" #include "net.h" +#include "policy/policy.h" #include "pow.h" +#include "primitives/block.h" +#include "primitives/transaction.h" +#include "script/script.h" +#include "script/sigcache.h" +#include "script/standard.h" +#include "tinyformat.h" #include "txdb.h" #include "txmempool.h" #include "ui_interface.h" #include "undo.h" #include "util.h" #include "utilmoneystr.h" +#include "utilstrencodings.h" #include "validationinterface.h" #include <sstream> @@ -57,6 +67,7 @@ bool fTxIndex = false; bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = true; +bool fRequireStandard = true; bool fCheckBlockIndex = false; bool fCheckpointsEnabled = true; size_t nCoinCacheUsage = 5000 * 300; @@ -72,9 +83,9 @@ struct COrphanTx { CTransaction tx; NodeId fromPeer; }; -map<uint256, COrphanTx> mapOrphanTransactions; -map<uint256, set<uint256> > mapOrphanTransactionsByPrev; -void EraseOrphansFor(NodeId peer); +map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);; +map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);; +void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** * Returns true if there are nRequired or more blocks of minVersion or above @@ -524,7 +535,7 @@ CBlockTreeDB *pblocktree = NULL; // mapOrphanTransactions // -bool AddOrphanTx(const CTransaction& tx, NodeId peer) +bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { uint256 hash = tx.GetHash(); if (mapOrphanTransactions.count(hash)) @@ -554,7 +565,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) return true; } -void static EraseOrphanTx(uint256 hash) +void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) @@ -588,7 +599,7 @@ void EraseOrphansFor(NodeId peer) } -unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) +unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { unsigned int nEvicted = 0; while (mapOrphanTransactions.size() > nMaxOrphans) @@ -604,76 +615,6 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) return nEvicted; } - - - - - - -bool IsStandardTx(const CTransaction& tx, string& reason) -{ - if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { - reason = "version"; - return false; - } - - // Extremely large transactions with lots of inputs can cost the network - // almost as much to process as they cost the sender in fees, because - // computing signature hashes is O(ninputs*txsize). Limiting transactions - // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. - unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); - if (sz >= MAX_STANDARD_TX_SIZE) { - reason = "tx-size"; - return false; - } - - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed - // keys. (remember the 520 byte limit on redeemScript size) That works - // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 - // bytes of scriptSig, which we round off to 1650 bytes for some minor - // future-proofing. That's also enough to spend a 20-of-20 - // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not - // considered standard) - if (txin.scriptSig.size() > 1650) { - reason = "scriptsig-size"; - return false; - } - if (!txin.scriptSig.IsPushOnly()) { - reason = "scriptsig-not-pushonly"; - return false; - } - } - - unsigned int nDataOut = 0; - txnouttype whichType; - BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (!::IsStandard(txout.scriptPubKey, whichType)) { - reason = "scriptpubkey"; - return false; - } - - if (whichType == TX_NULL_DATA) - nDataOut++; - else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) { - reason = "bare-multisig"; - return false; - } else if (txout.IsDust(::minRelayTxFee)) { - reason = "dust"; - return false; - } - } - - // only one OP_RETURN txout is permitted - if (nDataOut > 1) { - reason = "multi-op-return"; - return false; - } - - return true; -} - bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) { if (tx.nLockTime == 0) @@ -692,74 +633,6 @@ bool CheckFinalTx(const CTransaction &tx) return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime()); } -/** - * Check transaction inputs to mitigate two - * potential denial-of-service attacks: - * - * 1. scriptSigs with extra data stuffed into them, - * not consumed by scriptPubKey (or P2SH script) - * 2. P2SH scripts with a crazy number of expensive - * CHECKSIG/CHECKMULTISIG operations - */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) -{ - if (tx.IsCoinBase()) - return true; // Coinbases don't use vin normally - - for (unsigned int i = 0; i < tx.vin.size(); i++) - { - const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]); - - vector<vector<unsigned char> > vSolutions; - txnouttype whichType; - // get the scriptPubKey corresponding to this input: - const CScript& prevScript = prev.scriptPubKey; - if (!Solver(prevScript, whichType, vSolutions)) - return false; - int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); - if (nArgsExpected < 0) - return false; - - // Transactions with extra stuff in their scriptSigs are - // non-standard. Note that this EvalScript() call will - // be quick, because if there are any operations - // beside "push data" in the scriptSig - // IsStandardTx() will have already returned false - // and this method isn't called. - vector<vector<unsigned char> > stack; - if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker())) - return false; - - if (whichType == TX_SCRIPTHASH) - { - if (stack.empty()) - return false; - CScript subscript(stack.back().begin(), stack.back().end()); - vector<vector<unsigned char> > vSolutions2; - txnouttype whichType2; - if (Solver(subscript, whichType2, vSolutions2)) - { - int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2); - if (tmpExpected < 0) - return false; - nArgsExpected += tmpExpected; - } - else - { - // Any other Script with less than 15 sigops OK: - unsigned int sigops = subscript.GetSigOpCount(true); - // ... extra data left on the stack after execution is OK, too: - return (sigops <= MAX_P2SH_SIGOPS); - } - } - - if (stack.size() != (unsigned int)nArgsExpected) - return false; - } - - return true; -} - unsigned int GetLegacySigOpCount(const CTransaction& tx) { unsigned int nSigOps = 0; @@ -900,7 +773,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; - if (Params().RequireStandard() && !IsStandardTx(tx, reason)) + if (fRequireStandard && !IsStandardTx(tx, reason)) return state.DoS(0, error("AcceptToMemoryPool: nonstandard transaction: %s", reason), REJECT_NONSTANDARD, reason); @@ -971,7 +844,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } // Check for non-standard pay-to-script-hash in inputs - if (Params().RequireStandard() && !AreInputsStandard(tx, view)) + if (fRequireStandard && !AreInputsStandard(tx, view)) return error("AcceptToMemoryPool: nonstandard transaction input"); // Check that the transaction doesn't have an excessive number of @@ -2194,7 +2067,6 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { CCoinsViewCache view(pcoinsTip); - CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); bool rv = ConnectBlock(*pblock, state, pindexNew, view); GetMainSignals().BlockChecked(*pblock, state); if (!rv) { @@ -2202,7 +2074,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * InvalidBlockFound(pindexNew, state); return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); } - mapBlockSource.erase(inv.hash); + mapBlockSource.erase(pindexNew->GetBlockHash()); nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001); assert(view.Flush()); @@ -2862,9 +2734,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, // Try to process all requested blocks that we don't have, but only // process an unrequested block if it's new and has enough work to - // advance our tip. + // advance our tip, and isn't too many blocks ahead. bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true); + // Blocks that are too out-of-order needlessly limit the effectiveness of + // pruning, because pruning will not delete block files that contain any + // blocks which are too close in height to the tip. Apply this test + // regardless of whether pruning is enabled; it should generally be safe to + // not process unrequested blocks. + bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); // TODO: deal better with return value and error conditions for duplicate // and unrequested blocks. @@ -2872,6 +2750,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, if (!fRequested) { // If we didn't ask for it: if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned if (!fHasMoreWork) return true; // Don't process less-work chains + if (fTooFarAhead) return true; // Block height is too high } if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { @@ -3519,7 +3398,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } } } catch (const std::exception& e) { - LogPrintf("%s: Deserialize or I/O error - %s", __func__, e.what()); + LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what()); } } } catch (const std::runtime_error& e) { @@ -3785,7 +3664,7 @@ std::string GetWarnings(const std::string& strFor) // -bool static AlreadyHave(const CInv& inv) +bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { switch (inv.type) { @@ -4496,8 +4375,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->AddInventoryKnown(inv); CValidationState state; - // Process all blocks from whitelisted peers, even if not requested. - ProcessNewBlock(state, pfrom, &block, pfrom->fWhitelisted, NULL); + // Process all blocks from whitelisted peers, even if not requested, + // unless we're still syncing with the network. + // Such an unrequested block may still be processed, subject to the + // conditions in AcceptBlock(). + bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); + ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), @@ -4959,7 +4842,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); else { - CNode::Ban(pto->addr); + CNode::Ban(pto->addr, BanReasonNodeMisbehaving); } } state.fShouldBan = false; diff --git a/src/main.h b/src/main.h index 4e2efaada0..96ad54cda6 100644 --- a/src/main.h +++ b/src/main.h @@ -12,19 +12,10 @@ #include "amount.h" #include "chain.h" -#include "chainparams.h" #include "coins.h" -#include "consensus/consensus.h" #include "net.h" -#include "primitives/block.h" -#include "primitives/transaction.h" -#include "script/script.h" -#include "script/sigcache.h" -#include "script/standard.h" +#include "script/script_error.h" #include "sync.h" -#include "tinyformat.h" -#include "txmempool.h" -#include "uint256.h" #include <algorithm> #include <exception> @@ -42,24 +33,14 @@ class CBlockTreeDB; class CBloomFilter; class CInv; class CScriptCheck; +class CTxMemPool; class CValidationInterface; class CValidationState; struct CNodeStateStats; -/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/ -static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; -static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; -/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ -static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; /** Default for accepting alerts from the P2P network. */ static const bool DEFAULT_ALERTS = true; -/** The maximum size for transactions we're willing to relay/mine */ -static const unsigned int MAX_STANDARD_TX_SIZE = 100000; -/** Maximum number of signature check operations in an IsStandard() P2SH script */ -static const unsigned int MAX_P2SH_SIGOPS = 15; -/** The maximum number of sigops we're willing to relay/mine in a single tx */ -static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** The maximum size of a blk?????.dat file (since 0.8) */ @@ -111,6 +92,7 @@ extern bool fReindex; extern int nScriptCheckThreads; extern bool fTxIndex; extern bool fIsBareMultisigStd; +extern bool fRequireStandard; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; extern size_t nCoinCacheUsage; @@ -131,7 +113,7 @@ extern bool fPruneMode; /** Number of MiB of block files that we're trying to stay below. */ extern uint64_t nPruneTarget; /** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ -static const signed int MIN_BLOCKS_TO_KEEP = 288; +static const unsigned int MIN_BLOCKS_TO_KEEP = 288; // Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) // At 1MB per block, 288 blocks = 288MB. @@ -141,7 +123,7 @@ static const signed int MIN_BLOCKS_TO_KEEP = 288; // full block file chunks, we need the high water mark which triggers the prune to be // one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB // Setting the target to > than 550MB will make it likely we can respect the target. -static const signed int MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; +static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); @@ -273,25 +255,6 @@ struct CDiskTxPos : public CDiskBlockPos CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree); -/** - * Check transaction inputs, and make sure any - * pay-to-script-hash transactions are evaluating IsStandard scripts - * - * Why bother? To avoid denial-of-service attacks; an attacker - * can submit a standard HASH... OP_EQUAL transaction, - * which will get accepted into blocks. The redemption - * script can be anything; an attacker could use a very - * expensive-to-check-upon-redemption script like: - * DUP CHECKSIG DROP ... repeated 100 times... OP_1 - */ - -/** - * Check for standard transaction types - * @param[in] mapInputs Map of previous transactions that have outputs we're spending - * @return True if all inputs (scriptSigs) use only standard transaction forms - */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); - /** * Count ECDSA signature operations the old-fashioned (pre-0.6) way * @return number of sigops this transaction's outputs will produce when spent @@ -323,11 +286,6 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach /** Context-independent validity checks */ bool CheckTransaction(const CTransaction& tx, CValidationState& state); -/** Check for standard transaction types - * @return True if all outputs (scriptPubKeys) use only standard transaction forms - */ -bool IsStandardTx(const CTransaction& tx, std::string& reason); - /** * Check if transaction is final and can be included in a block with the * specified height and time. Consensus critical. diff --git a/src/memusage.h b/src/memusage.h index 9f7de9e2e1..be3964df1b 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -11,6 +11,7 @@ #include <set> #include <vector> +#include <boost/foreach.hpp> #include <boost/unordered_set.hpp> #include <boost/unordered_map.hpp> @@ -20,19 +21,27 @@ namespace memusage /** Compute the total memory used by allocating alloc bytes. */ static size_t MallocUsage(size_t alloc); +/** Dynamic memory usage for built-in types is zero. */ +static inline size_t DynamicUsage(const int8_t& v) { return 0; } +static inline size_t DynamicUsage(const uint8_t& v) { return 0; } +static inline size_t DynamicUsage(const int16_t& v) { return 0; } +static inline size_t DynamicUsage(const uint16_t& v) { return 0; } +static inline size_t DynamicUsage(const int32_t& v) { return 0; } +static inline size_t DynamicUsage(const uint32_t& v) { return 0; } +static inline size_t DynamicUsage(const int64_t& v) { return 0; } +static inline size_t DynamicUsage(const uint64_t& v) { return 0; } +static inline size_t DynamicUsage(const float& v) { return 0; } +static inline size_t DynamicUsage(const double& v) { return 0; } +template<typename X> static inline size_t DynamicUsage(X * const &v) { return 0; } +template<typename X> static inline size_t DynamicUsage(const X * const &v) { return 0; } + /** Compute the memory used for dynamically allocated but owned data structures. * For generic data types, this is *not* recursive. DynamicUsage(vector<vector<int> >) * will compute the memory used for the vector<int>'s, but not for the ints inside. * This is for efficiency reasons, as these functions are intended to be fast. If * application data structures require more accurate inner accounting, they should - * do the recursion themselves, or use more efficient caching + updating on modification. + * iterate themselves, or use more efficient caching + updating on modification. */ -template<typename X> static size_t DynamicUsage(const std::vector<X>& v); -template<typename X> static size_t DynamicUsage(const std::set<X>& s); -template<typename X, typename Y> static size_t DynamicUsage(const std::map<X, Y>& m); -template<typename X, typename Y> static size_t DynamicUsage(const boost::unordered_set<X, Y>& s); -template<typename X, typename Y, typename Z> static size_t DynamicUsage(const boost::unordered_map<X, Y, Z>& s); -template<typename X> static size_t DynamicUsage(const X& x); static inline size_t MallocUsage(size_t alloc) { @@ -98,14 +107,6 @@ static inline size_t DynamicUsage(const boost::unordered_map<X, Y, Z>& m) return MallocUsage(sizeof(boost_unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count()); } -// Dispatch to class method as fallback - -template<typename X> -static inline size_t DynamicUsage(const X& x) -{ - return x.DynamicMemoryUsage(); -} - } #endif diff --git a/src/miner.cpp b/src/miner.cpp index f5919ca3af..e44f3392c8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -6,20 +6,23 @@ #include "miner.h" #include "amount.h" +#include "chain.h" #include "chainparams.h" +#include "coins.h" #include "consensus/consensus.h" #include "consensus/validation.h" #include "hash.h" #include "main.h" #include "net.h" +#include "policy/policy.h" #include "pow.h" #include "primitives/transaction.h" +#include "script/standard.h" #include "timedata.h" +#include "txmempool.h" #include "util.h" #include "utilmoneystr.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif +#include "validationinterface.h" #include <boost/thread.hpp> #include <boost/tuple/tuple.hpp> @@ -362,7 +365,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& pblock->hashMerkleRoot = pblock->BuildMerkleTree(); } -#ifdef ENABLE_WALLET ////////////////////////////////////////////////////////////////////////////// // // Internal miner @@ -401,17 +403,7 @@ bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phas } } -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) -{ - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) - return NULL; - - CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; - return CreateNewBlock(scriptPubKey); -} - -static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) +static bool ProcessBlockFound(CBlock* pblock, const CChainParams& chainparams) { LogPrintf("%s\n", pblock->ToString()); LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); @@ -423,14 +415,8 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese return error("BitcoinMiner: generated block is stale"); } - // Remove key from key pool - reservekey.KeepKey(); - - // Track how many getdata requests this block gets - { - LOCK(wallet.cs_wallet); - wallet.mapRequestCount[pblock->GetHash()] = 0; - } + // Inform about the new block + GetMainSignals().BlockFound(pblock->GetHash()); // Process this block the same as if we had received it from another node CValidationState state; @@ -440,18 +426,22 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese return true; } -void static BitcoinMiner(CWallet *pwallet) +void static BitcoinMiner(const CChainParams& chainparams) { LogPrintf("BitcoinMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("bitcoin-miner"); - const CChainParams& chainparams = Params(); - // Each thread has its own key and counter - CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; + boost::shared_ptr<CReserveScript> coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + try { + //throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw std::runtime_error("No coinbase script available (mining requires a wallet)"); + while (true) { if (chainparams.MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining @@ -474,7 +464,7 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey)); + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); @@ -506,8 +496,9 @@ void static BitcoinMiner(CWallet *pwallet) SetThreadPriority(THREAD_PRIORITY_NORMAL); LogPrintf("BitcoinMiner:\n"); LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, *pwallet, reservekey); + ProcessBlockFound(pblock, chainparams); SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); // In regression test mode, stop mining after a block is found. if (chainparams.MineBlocksOnDemand()) @@ -551,17 +542,12 @@ void static BitcoinMiner(CWallet *pwallet) } } -void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) +void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams) { static boost::thread_group* minerThreads = NULL; - if (nThreads < 0) { - // In regtest threads defaults to 1 - if (Params().DefaultMinerThreads()) - nThreads = Params().DefaultMinerThreads(); - else - nThreads = boost::thread::hardware_concurrency(); - } + if (nThreads < 0) + nThreads = GetNumCores(); if (minerThreads != NULL) { @@ -575,7 +561,5 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) minerThreads = new boost::thread_group(); for (int i = 0; i < nThreads; i++) - minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); + minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams))); } - -#endif // ENABLE_WALLET diff --git a/src/miner.h b/src/miner.h index 96a6b70ecd..777a091967 100644 --- a/src/miner.h +++ b/src/miner.h @@ -11,6 +11,7 @@ #include <stdint.h> class CBlockIndex; +class CChainParams; class CReserveKey; class CScript; class CWallet; @@ -24,10 +25,9 @@ struct CBlockTemplate }; /** Run the miner threads */ -void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); +void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); diff --git a/src/net.cpp b/src/net.cpp index 0511256e55..3cece520de 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -12,10 +12,12 @@ #include "addrman.h" #include "chainparams.h" #include "clientversion.h" +#include "crypto/common.h" +#include "hash.h" #include "primitives/transaction.h" #include "scheduler.h" #include "ui_interface.h" -#include "crypto/common.h" +#include "utilstrencodings.h" #ifdef WIN32 #include <string.h> @@ -79,6 +81,7 @@ uint64_t nLocalHostNonce = 0; static std::vector<ListenSocket> vhListenSocket; CAddrMan addrman; int nMaxConnections = 125; +int nWhiteConnections = 0; bool fAddressesInitialized = false; vector<CNode*> vNodes; @@ -385,6 +388,12 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) : ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed)) { + if (!IsSelectableSocket(hSocket)) { + LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n"); + CloseSocket(hSocket); + return NULL; + } + addrman.Attempt(addrConnect); // Add node @@ -443,13 +452,15 @@ void CNode::PushVersion() -std::map<CSubNet, int64_t> CNode::setBanned; +banmap_t CNode::setBanned; CCriticalSection CNode::cs_setBanned; +bool CNode::setBannedIsDirty; void CNode::ClearBanned() { LOCK(cs_setBanned); setBanned.clear(); + setBannedIsDirty = true; } bool CNode::IsBanned(CNetAddr ip) @@ -457,12 +468,12 @@ bool CNode::IsBanned(CNetAddr ip) bool fResult = false; { LOCK(cs_setBanned); - for (std::map<CSubNet, int64_t>::iterator it = setBanned.begin(); it != setBanned.end(); it++) + for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++) { CSubNet subNet = (*it).first; - int64_t t = (*it).second; + CBanEntry banEntry = (*it).second; - if(subNet.Match(ip) && GetTime() < t) + if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil) fResult = true; } } @@ -474,50 +485,99 @@ bool CNode::IsBanned(CSubNet subnet) bool fResult = false; { LOCK(cs_setBanned); - std::map<CSubNet, int64_t>::iterator i = setBanned.find(subnet); + banmap_t::iterator i = setBanned.find(subnet); if (i != setBanned.end()) { - int64_t t = (*i).second; - if (GetTime() < t) + CBanEntry banEntry = (*i).second; + if (GetTime() < banEntry.nBanUntil) fResult = true; } } return fResult; } -void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset, bool sinceUnixEpoch) { - CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); - Ban(subNet, bantimeoffset, sinceUnixEpoch); +void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { + CSubNet subNet(addr); + Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch); } -void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoch) { - int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban - if (bantimeoffset > 0) - banTime = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; +void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) { + CBanEntry banEntry(GetTime()); + banEntry.banReason = banReason; + if (bantimeoffset <= 0) + { + bantimeoffset = GetArg("-bantime", 60*60*24); // Default 24-hour ban + sinceUnixEpoch = false; + } + banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset; + LOCK(cs_setBanned); - if (setBanned[subNet] < banTime) - setBanned[subNet] = banTime; + if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) + setBanned[subNet] = banEntry; + + setBannedIsDirty = true; } bool CNode::Unban(const CNetAddr &addr) { - CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128")); + CSubNet subNet(addr); return Unban(subNet); } bool CNode::Unban(const CSubNet &subNet) { LOCK(cs_setBanned); if (setBanned.erase(subNet)) + { + setBannedIsDirty = true; return true; + } return false; } -void CNode::GetBanned(std::map<CSubNet, int64_t> &banMap) +void CNode::GetBanned(banmap_t &banMap) { LOCK(cs_setBanned); banMap = setBanned; //create a thread safe copy } +void CNode::SetBanned(const banmap_t &banMap) +{ + LOCK(cs_setBanned); + setBanned = banMap; + setBannedIsDirty = true; +} + +void CNode::SweepBanned() +{ + int64_t now = GetTime(); + + LOCK(cs_setBanned); + banmap_t::iterator it = setBanned.begin(); + while(it != setBanned.end()) + { + CBanEntry banEntry = (*it).second; + if(now > banEntry.nBanUntil) + { + setBanned.erase(it++); + setBannedIsDirty = true; + } + else + ++it; + } +} + +bool CNode::BannedSetIsDirty() +{ + LOCK(cs_setBanned); + return setBannedIsDirty; +} + +void CNode::SetBannedSetDirty(bool dirty) +{ + LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag + setBannedIsDirty = dirty; +} + std::vector<CSubNet> CNode::vWhitelistedRange; CCriticalSection CNode::cs_vWhitelistedRange; @@ -877,6 +937,7 @@ void ThreadSocketHandler() SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; + int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS; if (hSocket != INVALID_SOCKET) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) @@ -896,8 +957,19 @@ void ThreadSocketHandler() if (nErr != WSAEWOULDBLOCK) LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); } - else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) + else if (!IsSelectableSocket(hSocket)) + { + LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); + CloseSocket(hSocket); + } + else if (nInbound >= nMaxInbound) { + LogPrint("net", "connection from %s dropped (full)\n", addr.ToString()); + CloseSocket(hSocket); + } + else if (!whitelisted && (nInbound >= (nMaxInbound - nWhiteConnections))) + { + LogPrint("net", "connection from %s dropped (non-whitelisted)\n", addr.ToString()); CloseSocket(hSocket); } else if (CNode::IsBanned(addr) && !whitelisted) @@ -911,6 +983,8 @@ void ThreadSocketHandler() pnode->AddRef(); pnode->fWhitelisted = whitelisted; + LogPrint("net", "connection from %s accepted\n", addr.ToString()); + { LOCK(cs_vNodes); vNodes.push_back(pnode); @@ -1212,6 +1286,17 @@ void DumpAddresses() addrman.size(), GetTimeMillis() - nStart); } +void DumpData() +{ + DumpAddresses(); + + if (CNode::BannedSetIsDirty()) + { + DumpBanlist(); + CNode::SetBannedSetDirty(false); + } +} + void static ProcessOneShot() { string strDest; @@ -1525,6 +1610,13 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste LogPrintf("%s\n", strError); return false; } + if (!IsSelectableSocket(hListenSocket)) + { + strError = "Error: Couldn't create a listenable socket for incoming connections"; + LogPrintf("%s\n", strError); + return false; + } + #ifndef WIN32 #ifdef SO_NOSIGPIPE @@ -1650,6 +1742,17 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (!adb.Read(addrman)) LogPrintf("Invalid or missing peers.dat; recreating\n"); } + + //try to read stored banlist + CBanDB bandb; + banmap_t banmap; + if (!bandb.Read(banmap)) + LogPrintf("Invalid or missing banlist.dat; recreating\n"); + + CNode::SetBanned(banmap); //thread save setter + CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data + CNode::SweepBanned(); //sweap out unused entries + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); fAddressesInitialized = true; @@ -1690,7 +1793,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler)); // Dump network addresses - scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL); + scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL); } bool StopNode() @@ -1703,7 +1806,7 @@ bool StopNode() if (fAddressesInitialized) { - DumpAddresses(); + DumpData(); fAddressesInitialized = false; } @@ -1907,11 +2010,11 @@ bool CAddrDB::Read(CAddrMan& addr) return error("%s: Failed to open file %s", __func__, pathAddr.string()); // use file size to size memory buffer - int fileSize = boost::filesystem::file_size(pathAddr); - int dataSize = fileSize - sizeof(uint256); + uint64_t fileSize = boost::filesystem::file_size(pathAddr); + uint64_t dataSize = 0; // Don't try to resize to a negative number if file is small - if (dataSize < 0) - dataSize = 0; + if (fileSize >= sizeof(uint256)) + dataSize = fileSize - sizeof(uint256); vector<unsigned char> vchData; vchData.resize(dataSize); uint256 hashIn; @@ -2082,8 +2185,10 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) Fuzz(GetArg("-fuzzmessagestest", 10)); if (ssSend.size() == 0) + { + LEAVE_CRITICAL_SECTION(cs_vSend); return; - + } // Set the size unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); @@ -2107,3 +2212,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) LEAVE_CRITICAL_SECTION(cs_vSend); } + +// +// CBanDB +// + +CBanDB::CBanDB() +{ + pathBanlist = GetDataDir() / "banlist.dat"; +} + +bool CBanDB::Write(const banmap_t& banSet) +{ + // Generate random temporary filename + unsigned short randv = 0; + GetRandBytes((unsigned char*)&randv, sizeof(randv)); + std::string tmpfn = strprintf("banlist.dat.%04x", randv); + + // serialize banlist, checksum data up to that point, then append csum + CDataStream ssBanlist(SER_DISK, CLIENT_VERSION); + ssBanlist << FLATDATA(Params().MessageStart()); + ssBanlist << banSet; + uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end()); + ssBanlist << hash; + + // open temp output file, and associate with CAutoFile + boost::filesystem::path pathTmp = GetDataDir() / tmpfn; + FILE *file = fopen(pathTmp.string().c_str(), "wb"); + CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: Failed to open file %s", __func__, pathTmp.string()); + + // Write and commit header, data + try { + fileout << ssBanlist; + } + catch (const std::exception& e) { + return error("%s: Serialize or I/O error - %s", __func__, e.what()); + } + FileCommit(fileout.Get()); + fileout.fclose(); + + // replace existing banlist.dat, if any, with new banlist.dat.XXXX + if (!RenameOver(pathTmp, pathBanlist)) + return error("%s: Rename-into-place failed", __func__); + + return true; +} + +bool CBanDB::Read(banmap_t& banSet) +{ + // open input file, and associate with CAutoFile + FILE *file = fopen(pathBanlist.string().c_str(), "rb"); + CAutoFile filein(file, SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: Failed to open file %s", __func__, pathBanlist.string()); + + // use file size to size memory buffer + uint64_t fileSize = boost::filesystem::file_size(pathBanlist); + uint64_t dataSize = 0; + // Don't try to resize to a negative number if file is small + if (fileSize >= sizeof(uint256)) + dataSize = fileSize - sizeof(uint256); + vector<unsigned char> vchData; + vchData.resize(dataSize); + uint256 hashIn; + + // read data and checksum from file + try { + filein.read((char *)&vchData[0], dataSize); + filein >> hashIn; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + filein.fclose(); + + CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION); + + // verify stored checksum matches input data + uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end()); + if (hashIn != hashTmp) + return error("%s: Checksum mismatch, data corrupted", __func__); + + unsigned char pchMsgTmp[4]; + try { + // de-serialize file header (network specific magic number) and .. + ssBanlist >> FLATDATA(pchMsgTmp); + + // ... verify the network matches ours + if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) + return error("%s: Invalid network magic number", __func__); + + // de-serialize address data into one CAddrMan object + ssBanlist >> banSet; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + + return true; +} + +void DumpBanlist() +{ + int64_t nStart = GetTimeMillis(); + + CNode::SweepBanned(); //clean unused entires (if bantime has expired) + + CBanDB bandb; + banmap_t banmap; + CNode::GetBanned(banmap); + bandb.Write(banmap); + + LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - nStart); +} @@ -8,7 +8,6 @@ #include "bloom.h" #include "compat.h" -#include "hash.h" #include "limitedmap.h" #include "mruset.h" #include "netbase.h" @@ -17,7 +16,6 @@ #include "streams.h" #include "sync.h" #include "uint256.h" -#include "utilstrencodings.h" #include <deque> #include <stdint.h> @@ -31,7 +29,6 @@ #include <boost/signals2/signal.hpp> class CAddrMan; -class CBlockIndex; class CScheduler; class CNode; @@ -141,7 +138,20 @@ extern bool fListen; extern uint64_t nLocalServices; extern uint64_t nLocalHostNonce; extern CAddrMan addrman; + +// The allocation of connections against the maximum allowed (nMaxConnections) +// is prioritized as follows: +// 1st: Outbound connections (MAX_OUTBOUND_CONNECTIONS) +// 2nd: Inbound connections from whitelisted peers (nWhiteConnections) +// 3rd: Inbound connections from non-whitelisted peers +// Thus, the number of connection slots for the general public to use is: +// nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + nWhiteConnections) +// Any additional inbound connections beyond limits will be immediately closed + +/** Maximum number of connections to simultaneously allow (aka connection slots) */ extern int nMaxConnections; +/** Number of connection slots to reserve for inbound from whitelisted peers */ +extern int nWhiteConnections; extern std::vector<CNode*> vNodes; extern CCriticalSection cs_vNodes; @@ -228,8 +238,66 @@ public: }; +typedef enum BanReason +{ + BanReasonUnknown = 0, + BanReasonNodeMisbehaving = 1, + BanReasonManuallyAdded = 2 +} BanReason; + +class CBanEntry +{ +public: + static const int CURRENT_VERSION=1; + int nVersion; + int64_t nCreateTime; + int64_t nBanUntil; + uint8_t banReason; + + CBanEntry() + { + SetNull(); + } + + CBanEntry(int64_t nCreateTimeIn) + { + SetNull(); + nCreateTime = nCreateTimeIn; + } + + ADD_SERIALIZE_METHODS; + + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(nCreateTime); + READWRITE(nBanUntil); + READWRITE(banReason); + } + + void SetNull() + { + nVersion = CBanEntry::CURRENT_VERSION; + nCreateTime = 0; + nBanUntil = 0; + banReason = BanReasonUnknown; + } + std::string banReasonToString() + { + switch (banReason) { + case BanReasonNodeMisbehaving: + return "node misbehabing"; + case BanReasonManuallyAdded: + return "manually added"; + default: + return "unknown"; + } + } +}; +typedef std::map<CSubNet, CBanEntry> banmap_t; /** Information about a peer */ class CNode @@ -285,8 +353,9 @@ protected: // Denial-of-service detection/prevention // Key is IP address, value is banned-until-time - static std::map<CSubNet, int64_t> setBanned; + static banmap_t setBanned; static CCriticalSection cs_setBanned; + static bool setBannedIsDirty; // Whitelisted ranges. Any node connecting from these is automatically // whitelisted (as well as those connecting to whitelisted binds). @@ -608,11 +677,19 @@ public: static void ClearBanned(); // needed for unit testing static bool IsBanned(CNetAddr ip); static bool IsBanned(CSubNet subnet); - static void Ban(const CNetAddr &ip, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); - static void Ban(const CSubNet &subNet, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); + static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false); static bool Unban(const CNetAddr &ip); static bool Unban(const CSubNet &ip); - static void GetBanned(std::map<CSubNet, int64_t> &banmap); + static void GetBanned(banmap_t &banmap); + static void SetBanned(const banmap_t &banmap); + + //!check is the banlist has unwritten changes + static bool BannedSetIsDirty(); + //!set the "dirty" flag for the banlist + static void SetBannedSetDirty(bool dirty=true); + //!clean unused entires (if bantime has expired) + static void SweepBanned(); void copyStats(CNodeStats &stats); @@ -644,4 +721,17 @@ public: bool Read(CAddrMan& addr); }; +/** Access to the banlist database (banlist.dat) */ +class CBanDB +{ +private: + boost::filesystem::path pathBanlist; +public: + CBanDB(); + bool Write(const banmap_t& banSet); + bool Read(banmap_t& banSet); +}; + +void DumpBanlist(); + #endif // BITCOIN_NET_H diff --git a/src/netbase.cpp b/src/netbase.cpp index adac5c2d07..b7e2e57917 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -266,6 +266,9 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock } else { // Other error or blocking int nErr = WSAGetLastError(); if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { + if (!IsSelectableSocket(hSocket)) { + return false; + } struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); fd_set fdset; FD_ZERO(&fdset); @@ -1291,6 +1294,13 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup) network.ip[x] &= netmask[x]; } +CSubNet::CSubNet(const CNetAddr &addr): + valid(addr.IsValid()) +{ + memset(netmask, 255, sizeof(netmask)); + network = addr; +} + bool CSubNet::Match(const CNetAddr &addr) const { if (!valid || !addr.IsValid()) diff --git a/src/netbase.h b/src/netbase.h index 27f0eac2a2..6f8882b852 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -118,6 +118,9 @@ class CSubNet CSubNet(); explicit CSubNet(const std::string &strSubnet, bool fAllowLookup = false); + //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128) + explicit CSubNet(const CNetAddr &addr); + bool Match(const CNetAddr &addr) const; std::string ToString() const; @@ -126,6 +129,15 @@ class CSubNet friend bool operator==(const CSubNet& a, const CSubNet& b); friend bool operator!=(const CSubNet& a, const CSubNet& b); friend bool operator<(const CSubNet& a, const CSubNet& b); + + ADD_SERIALIZE_METHODS; + + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(network); + READWRITE(FLATDATA(netmask)); + READWRITE(FLATDATA(valid)); + } }; /** A combination of a network address (CNetAddr) and a (TCP) port */ diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index b1491cec01..cdee541d2f 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -249,7 +249,7 @@ unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val) unsigned int bucketindex = bucketMap.lower_bound(val)->second; unsigned int blockIndex = nBlockHeight % unconfTxs.size(); unconfTxs[blockIndex][bucketindex]++; - LogPrint("estimatefee", "adding to %s\n", dataTypeString); + LogPrint("estimatefee", "adding to %s", dataTypeString); return bucketindex; } @@ -390,8 +390,9 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK()); } else { - LogPrint("estimatefee", "not adding\n"); + LogPrint("estimatefee", "not adding"); } + LogPrint("estimatefee", "\n"); } void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp new file mode 100644 index 0000000000..169fef4af4 --- /dev/null +++ b/src/policy/policy.cpp @@ -0,0 +1,178 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic + +#include "policy/policy.h" + +#include "main.h" +#include "tinyformat.h" +#include "util.h" +#include "utilstrencodings.h" + +#include <boost/foreach.hpp> + + /** + * Check transaction inputs to mitigate two + * potential denial-of-service attacks: + * + * 1. scriptSigs with extra data stuffed into them, + * not consumed by scriptPubKey (or P2SH script) + * 2. P2SH scripts with a crazy number of expensive + * CHECKSIG/CHECKMULTISIG operations + * + * Check transaction inputs, and make sure any + * pay-to-script-hash transactions are evaluating IsStandard scripts + * + * Why bother? To avoid denial-of-service attacks; an attacker + * can submit a standard HASH... OP_EQUAL transaction, + * which will get accepted into blocks. The redemption + * script can be anything; an attacker could use a very + * expensive-to-check-upon-redemption script like: + * DUP CHECKSIG DROP ... repeated 100 times... OP_1 + */ + +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) +{ + std::vector<std::vector<unsigned char> > vSolutions; + if (!Solver(scriptPubKey, whichType, vSolutions)) + return false; + + if (whichType == TX_MULTISIG) + { + unsigned char m = vSolutions.front()[0]; + unsigned char n = vSolutions.back()[0]; + // Support up to x-of-3 multisig txns as standard + if (n < 1 || n > 3) + return false; + if (m < 1 || m > n) + return false; + } + + return whichType != TX_NONSTANDARD; +} + +bool IsStandardTx(const CTransaction& tx, std::string& reason) +{ + if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { + reason = "version"; + return false; + } + + // Extremely large transactions with lots of inputs can cost the network + // almost as much to process as they cost the sender in fees, because + // computing signature hashes is O(ninputs*txsize). Limiting transactions + // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. + unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + if (sz >= MAX_STANDARD_TX_SIZE) { + reason = "tx-size"; + return false; + } + + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed + // keys. (remember the 520 byte limit on redeemScript size) That works + // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 + // bytes of scriptSig, which we round off to 1650 bytes for some minor + // future-proofing. That's also enough to spend a 20-of-20 + // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not + // considered standard) + if (txin.scriptSig.size() > 1650) { + reason = "scriptsig-size"; + return false; + } + if (!txin.scriptSig.IsPushOnly()) { + reason = "scriptsig-not-pushonly"; + return false; + } + } + + unsigned int nDataOut = 0; + txnouttype whichType; + BOOST_FOREACH(const CTxOut& txout, tx.vout) { + if (!::IsStandard(txout.scriptPubKey, whichType)) { + reason = "scriptpubkey"; + return false; + } + + if (whichType == TX_NULL_DATA) + nDataOut++; + else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) { + reason = "bare-multisig"; + return false; + } else if (txout.IsDust(::minRelayTxFee)) { + reason = "dust"; + return false; + } + } + + // only one OP_RETURN txout is permitted + if (nDataOut > 1) { + reason = "multi-op-return"; + return false; + } + + return true; +} + +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) +{ + if (tx.IsCoinBase()) + return true; // Coinbases don't use vin normally + + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]); + + std::vector<std::vector<unsigned char> > vSolutions; + txnouttype whichType; + // get the scriptPubKey corresponding to this input: + const CScript& prevScript = prev.scriptPubKey; + if (!Solver(prevScript, whichType, vSolutions)) + return false; + int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); + if (nArgsExpected < 0) + return false; + + // Transactions with extra stuff in their scriptSigs are + // non-standard. Note that this EvalScript() call will + // be quick, because if there are any operations + // beside "push data" in the scriptSig + // IsStandardTx() will have already returned false + // and this method isn't called. + std::vector<std::vector<unsigned char> > stack; + if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker())) + return false; + + if (whichType == TX_SCRIPTHASH) + { + if (stack.empty()) + return false; + CScript subscript(stack.back().begin(), stack.back().end()); + std::vector<std::vector<unsigned char> > vSolutions2; + txnouttype whichType2; + if (Solver(subscript, whichType2, vSolutions2)) + { + int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2); + if (tmpExpected < 0) + return false; + nArgsExpected += tmpExpected; + } + else + { + // Any other Script with less than 15 sigops OK: + unsigned int sigops = subscript.GetSigOpCount(true); + // ... extra data left on the stack after execution is OK, too: + return (sigops <= MAX_P2SH_SIGOPS); + } + } + + if (stack.size() != (unsigned int)nArgsExpected) + return false; + } + + return true; +} diff --git a/src/policy/policy.h b/src/policy/policy.h new file mode 100644 index 0000000000..1551aecde8 --- /dev/null +++ b/src/policy/policy.h @@ -0,0 +1,58 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_POLICY_H +#define BITCOIN_POLICY_H + +#include "consensus/consensus.h" +#include "script/interpreter.h" +#include "script/standard.h" + +#include <string> + +class CCoinsViewCache; + +/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/ +static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; +static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; +/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ +static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; +/** The maximum size for transactions we're willing to relay/mine */ +static const unsigned int MAX_STANDARD_TX_SIZE = 100000; +/** Maximum number of signature check operations in an IsStandard() P2SH script */ +static const unsigned int MAX_P2SH_SIGOPS = 15; +/** The maximum number of sigops we're willing to relay/mine in a single tx */ +static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; +/** + * Standard script verification flags that standard transactions will comply + * with. However scripts violating these flags may still be present in valid + * blocks and we must accept those blocks. + */ +static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | + SCRIPT_VERIFY_DERSIG | + SCRIPT_VERIFY_STRICTENC | + SCRIPT_VERIFY_MINIMALDATA | + SCRIPT_VERIFY_NULLDUMMY | + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | + SCRIPT_VERIFY_CLEANSTACK | + SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + +/** For convenience, standard but not mandatory verify flags. */ +static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; + +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); + /** + * Check for standard transaction types + * @return True if all outputs (scriptPubKeys) use only standard transaction forms + */ +bool IsStandardTx(const CTransaction& tx, std::string& reason); + /** + * Check for standard transaction types + * @param[in] mapInputs Map of previous transactions that have outputs we're spending + * @return True if all inputs (scriptSigs) use only standard transaction forms + */ +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); + +#endif // BITCOIN_POLICY_H diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 6cfd93a9a1..2a457cdae7 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -141,10 +141,13 @@ public: // which has units satoshis-per-kilobyte. // If you'd pay more than 1/3 in fees // to spend something, then we consider it dust. - // A typical txout is 34 bytes big, and will + // A typical spendable txout is 34 bytes big, and will // need a CTxIn of at least 148 bytes to spend: - // so dust is a txout less than 546 satoshis + // so dust is a spendable txout less than 546 satoshis // with default minRelayTxFee. + if (scriptPubKey.IsUnspendable()) + return 0; + size_t nSize = GetSerializeSize(SER_DISK,0)+148u; return 3*minRelayTxFee.GetFee(nSize); } diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 5485d89f3e..8bd1586446 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -14,14 +14,14 @@ #include "csvmodelwriter.h" #include "editaddressdialog.h" #include "guiutil.h" -#include "scicon.h" +#include "platformstyle.h" #include <QIcon> #include <QMenu> #include <QMessageBox> #include <QSortFilterProxyModel> -AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : +AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent) : QDialog(parent), ui(new Ui::AddressBookPage), model(0), @@ -30,17 +30,17 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : { ui->setupUi(this); -#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac - ui->newAddress->setIcon(QIcon()); - ui->copyAddress->setIcon(QIcon()); - ui->deleteAddress->setIcon(QIcon()); - ui->exportButton->setIcon(QIcon()); -#else - ui->newAddress->setIcon(SingleColorIcon(":/icons/add")); - ui->copyAddress->setIcon(SingleColorIcon(":/icons/editcopy")); - ui->deleteAddress->setIcon(SingleColorIcon(":/icons/remove")); - ui->exportButton->setIcon(SingleColorIcon(":/icons/export")); -#endif + if (!platformStyle->getImagesOnButtons()) { + ui->newAddress->setIcon(QIcon()); + ui->copyAddress->setIcon(QIcon()); + ui->deleteAddress->setIcon(QIcon()); + ui->exportButton->setIcon(QIcon()); + } else { + ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add")); + ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy")); + ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export")); + } switch(mode) { @@ -254,8 +254,7 @@ void AddressBookPage::done(int retval) // Figure out which address was selected, and return it QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - foreach (QModelIndex index, indexes) - { + Q_FOREACH (const QModelIndex& index, indexes) { QVariant address = table->model()->data(index); returnValue = address.toString(); } diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 5105f09ced..92e6cab9ac 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -9,6 +9,7 @@ class AddressTableModel; class OptionsModel; +class PlatformStyle; namespace Ui { class AddressBookPage; @@ -39,13 +40,13 @@ public: ForEditing /**< Open address book for editing */ }; - explicit AddressBookPage(Mode mode, Tabs tab, QWidget *parent); + explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent); ~AddressBookPage(); void setModel(AddressTableModel *model); const QString &getReturnValue() const { return returnValue; } -public slots: +public Q_SLOTS: void done(int retval); private: @@ -59,7 +60,7 @@ private: QAction *deleteAction; // to be able to explicitly disable it QString newAddressToSelect; -private slots: +private Q_SLOTS: /** Delete currently selected address entry */ void on_deleteAddress_clicked(); /** Create a new address for receiving coins and / or add a new address book entry */ @@ -80,7 +81,7 @@ private slots: /** New entry/entries were added to address table */ void selectNewAddress(const QModelIndex &parent, int begin, int /*end*/); -signals: +Q_SIGNALS: void sendCoins(QString addr); }; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 8e20836c65..c5ac07cfc2 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -450,5 +450,5 @@ int AddressTableModel::lookupAddress(const QString &address) const void AddressTableModel::emitDataChanged(int idx) { - emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex())); + Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex())); } diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 6b34b2eac2..2b7475c4e2 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -84,7 +84,7 @@ private: /** Notify listeners that data changed. */ void emitDataChanged(int index); -public slots: +public Q_SLOTS: /* Update address list from core. */ void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index 74d54d18f7..d4d832825a 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -40,7 +40,7 @@ private: WalletModel *model; bool fCapsLock; -private slots: +private Q_SLOTS: void textChanged(); protected: diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 8740b98b70..1da2d3e344 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -8,12 +8,14 @@ #include "bitcoingui.h" +#include "chainparams.h" #include "clientmodel.h" #include "guiconstants.h" #include "guiutil.h" #include "intro.h" #include "networkstyle.h" #include "optionsmodel.h" +#include "platformstyle.h" #include "splashscreen.h" #include "utilitydialog.h" #include "winshutdownmonitor.h" @@ -24,7 +26,6 @@ #endif #include "init.h" -#include "main.h" #include "rpcserver.h" #include "scheduler.h" #include "ui_interface.h" @@ -48,6 +49,7 @@ #include <QThread> #include <QTimer> #include <QTranslator> +#include <QSslConfiguration> #if defined(QT_STATICPLUGIN) #include <QtPlugin> @@ -58,7 +60,9 @@ Q_IMPORT_PLUGIN(qtwcodecs) Q_IMPORT_PLUGIN(qkrcodecs) Q_IMPORT_PLUGIN(qtaccessiblewidgets) #else +#if QT_VERSION < 0x050400 Q_IMPORT_PLUGIN(AccessibleFactory) +#endif #if defined(QT_QPA_PLATFORM_XCB) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_WINDOWS) @@ -168,11 +172,11 @@ class BitcoinCore: public QObject public: explicit BitcoinCore(); -public slots: +public Q_SLOTS: void initialize(); void shutdown(); -signals: +Q_SIGNALS: void initializeResult(int retval); void shutdownResult(int retval); void runawayException(const QString &message); @@ -215,13 +219,13 @@ public: /// Get window identifier of QMainWindow (BitcoinGUI) WId getMainWinId() const; -public slots: +public Q_SLOTS: void initializeResult(int retval); void shutdownResult(int retval); /// Handle runaway exceptions. Shows a message box with the problem and quits the program. void handleRunawayException(const QString &message); -signals: +Q_SIGNALS: void requestedInitialize(); void requestedShutdown(); void stopThread(); @@ -238,6 +242,7 @@ private: WalletModel *walletModel; #endif int returnValue; + const PlatformStyle *platformStyle; void startThread(); }; @@ -252,7 +257,7 @@ BitcoinCore::BitcoinCore(): void BitcoinCore::handleRunawayException(const std::exception *e) { PrintExceptionContinue(e, "Runaway exception"); - emit runawayException(QString::fromStdString(strMiscWarning)); + Q_EMIT runawayException(QString::fromStdString(strMiscWarning)); } void BitcoinCore::initialize() @@ -268,7 +273,7 @@ void BitcoinCore::initialize() */ StartDummyRPCThread(); } - emit initializeResult(rv); + Q_EMIT initializeResult(rv); } catch (const std::exception& e) { handleRunawayException(&e); } catch (...) { @@ -285,7 +290,7 @@ void BitcoinCore::shutdown() threadGroup.join_all(); Shutdown(); qDebug() << __func__ << ": Shutdown finished"; - emit shutdownResult(1); + Q_EMIT shutdownResult(1); } catch (const std::exception& e) { handleRunawayException(&e); } catch (...) { @@ -307,6 +312,22 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv): returnValue(0) { setQuitOnLastWindowClosed(false); + + // UI per-platform customization + // This must be done inside the BitcoinApplication constructor, or after it, because + // PlatformStyle::instantiate requires a QApplication +#if defined(Q_OS_MAC) + std::string platformName = "macosx"; +#elif defined(Q_OS_WIN) + std::string platformName = "windows"; +#else + std::string platformName = "other"; +#endif + platformName = GetArg("-uiplatform", platformName); + platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName)); + if (!platformStyle) // Fall back to "other" if specified name not found + platformStyle = PlatformStyle::instantiate("other"); + assert(platformStyle); } BitcoinApplication::~BitcoinApplication() @@ -314,7 +335,7 @@ BitcoinApplication::~BitcoinApplication() if(coreThread) { qDebug() << __func__ << ": Stopping thread"; - emit stopThread(); + Q_EMIT stopThread(); coreThread->wait(); qDebug() << __func__ << ": Stopped thread"; } @@ -327,6 +348,8 @@ BitcoinApplication::~BitcoinApplication() #endif delete optionsModel; optionsModel = 0; + delete platformStyle; + platformStyle = 0; } #ifdef ENABLE_WALLET @@ -343,7 +366,7 @@ void BitcoinApplication::createOptionsModel() void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) { - window = new BitcoinGUI(networkStyle, 0); + window = new BitcoinGUI(platformStyle, networkStyle, 0); pollShutdownTimer = new QTimer(window); connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown())); @@ -385,7 +408,7 @@ void BitcoinApplication::requestInitialize() { qDebug() << __func__ << ": Requesting initialize"; startThread(); - emit requestedInitialize(); + Q_EMIT requestedInitialize(); } void BitcoinApplication::requestShutdown() @@ -408,7 +431,7 @@ void BitcoinApplication::requestShutdown() ShutdownWindow::showShutdownWindow(window); // Request shutdown from core thread - emit requestedShutdown(); + Q_EMIT requestedShutdown(); } void BitcoinApplication::initializeResult(int retval) @@ -418,6 +441,8 @@ void BitcoinApplication::initializeResult(int retval) returnValue = retval ? 0 : 1; if(retval) { + // Log this only after AppInit2 finishes, as then logging setup is guaranteed complete + qWarning() << "Platform customization:" << platformStyle->getName(); #ifdef ENABLE_WALLET PaymentServer::LoadRootCAs(); paymentServer->setOptionsModel(optionsModel); @@ -429,7 +454,7 @@ void BitcoinApplication::initializeResult(int retval) #ifdef ENABLE_WALLET if(pwalletMain) { - walletModel = new WalletModel(pwalletMain, optionsModel); + walletModel = new WalletModel(platformStyle, pwalletMain, optionsModel); window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel); window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET); @@ -448,7 +473,7 @@ void BitcoinApplication::initializeResult(int retval) { window->show(); } - emit splashFinished(window); + Q_EMIT splashFinished(window); #ifdef ENABLE_WALLET // Now that initialization/startup is done, process any command-line @@ -515,6 +540,13 @@ int main(int argc, char *argv[]) #ifdef Q_OS_MAC QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); #endif +#if QT_VERSION >= 0x050500 + // Because of the POODLE attack it is recommended to disable SSLv3 (https://disablessl3.com/), + // so set SSL protocols to TLS1.0+. + QSslConfiguration sslconf = QSslConfiguration::defaultConfiguration(); + sslconf.setProtocol(QSsl::TlsV1_0OrLater); + QSslConfiguration::setDefaultConfiguration(sslconf); +#endif // Register meta types used for QMetaObject::invokeMethod qRegisterMetaType< bool* >(); diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index d31a1e018b..d19b9fd4af 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -61,7 +61,7 @@ public: void setValue(const CAmount& value) { lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways)); - emit valueChanged(); + Q_EMIT valueChanged(); } void stepBy(int steps) @@ -184,7 +184,7 @@ protected: return rv; } -signals: +Q_SIGNALS: void valueChanged(); }; diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index b047e6c51a..3703b1f8d7 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -56,7 +56,7 @@ public: */ QWidget *setupTabChain(QWidget *prev); -signals: +Q_SIGNALS: void valueChanged(); protected: @@ -67,7 +67,7 @@ private: AmountSpinBox *amount; QValueComboBox *unit; -private slots: +private Q_SLOTS: void unitChanged(int idx); }; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index efba0f5e18..1d3f7762ab 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -13,8 +13,8 @@ #include "openuridialog.h" #include "optionsdialog.h" #include "optionsmodel.h" +#include "platformstyle.h" #include "rpcconsole.h" -#include "scicon.h" #include "utilitydialog.h" #ifdef ENABLE_WALLET @@ -60,7 +60,7 @@ const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; -BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : +BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), clientModel(0), walletFrame(0), @@ -98,7 +98,8 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : notificator(0), rpcConsole(0), prevBlocks(0), - spinnerFrame(0) + spinnerFrame(0), + platformStyle(platformStyle) { GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this); @@ -130,12 +131,12 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : setUnifiedTitleAndToolBarOnMac(true); #endif - rpcConsole = new RPCConsole(0); + rpcConsole = new RPCConsole(platformStyle, 0); #ifdef ENABLE_WALLET if(enableWallet) { /** Create wallet frame and make it the central widget */ - walletFrame = new WalletFrame(this); + walletFrame = new WalletFrame(platformStyle, this); setCentralWidget(walletFrame); } else #endif // ENABLE_WALLET @@ -175,7 +176,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks); frameBlocksLayout->setContentsMargins(3,0,3,0); frameBlocksLayout->setSpacing(3); - unitDisplayControl = new UnitDisplayStatusBarControl(); + unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle); labelEncryptionIcon = new QLabel(); labelConnectionsIcon = new QLabel(); labelBlocksIcon = new QLabel(); @@ -247,36 +248,36 @@ void BitcoinGUI::createActions() { QActionGroup *tabGroup = new QActionGroup(this); - overviewAction = new QAction(SingleColorIcon(":/icons/overview"), tr("&Overview"), this); + overviewAction = new QAction(platformStyle->SingleColorIcon(":/icons/overview"), tr("&Overview"), this); overviewAction->setStatusTip(tr("Show general overview of wallet")); overviewAction->setToolTip(overviewAction->statusTip()); overviewAction->setCheckable(true); overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1)); tabGroup->addAction(overviewAction); - sendCoinsAction = new QAction(SingleColorIcon(":/icons/send"), tr("&Send"), this); + sendCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/send"), tr("&Send"), this); sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address")); sendCoinsAction->setToolTip(sendCoinsAction->statusTip()); sendCoinsAction->setCheckable(true); sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); tabGroup->addAction(sendCoinsAction); - sendCoinsMenuAction = new QAction(TextColorIcon(":/icons/send"), sendCoinsAction->text(), this); + sendCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/send"), sendCoinsAction->text(), this); sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip()); sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip()); - receiveCoinsAction = new QAction(SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this); + receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this); receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)")); receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip()); receiveCoinsAction->setCheckable(true); receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); tabGroup->addAction(receiveCoinsAction); - receiveCoinsMenuAction = new QAction(TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this); + receiveCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this); receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip()); receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip()); - historyAction = new QAction(SingleColorIcon(":/icons/history"), tr("&Transactions"), this); + historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this); historyAction->setStatusTip(tr("Browse transaction history")); historyAction->setToolTip(historyAction->statusTip()); historyAction->setCheckable(true); @@ -300,46 +301,46 @@ void BitcoinGUI::createActions() connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); #endif // ENABLE_WALLET - quitAction = new QAction(TextColorIcon(":/icons/quit"), tr("E&xit"), this); + quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this); quitAction->setStatusTip(tr("Quit application")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); quitAction->setMenuRole(QAction::QuitRole); - aboutAction = new QAction(TextColorIcon(":/icons/about"), tr("&About Bitcoin Core"), this); + aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About Bitcoin Core"), this); aboutAction->setStatusTip(tr("Show information about Bitcoin Core")); aboutAction->setMenuRole(QAction::AboutRole); - aboutQtAction = new QAction(TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this); + aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this); aboutQtAction->setStatusTip(tr("Show information about Qt")); aboutQtAction->setMenuRole(QAction::AboutQtRole); - optionsAction = new QAction(TextColorIcon(":/icons/options"), tr("&Options..."), this); + optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this); optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin Core")); optionsAction->setMenuRole(QAction::PreferencesRole); - toggleHideAction = new QAction(TextColorIcon(":/icons/about"), tr("&Show / Hide"), this); + toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this); toggleHideAction->setStatusTip(tr("Show or hide the main Window")); - encryptWalletAction = new QAction(TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this); + encryptWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this); encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet")); encryptWalletAction->setCheckable(true); - backupWalletAction = new QAction(TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this); + backupWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this); backupWalletAction->setStatusTip(tr("Backup wallet to another location")); - changePassphraseAction = new QAction(TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this); + changePassphraseAction = new QAction(platformStyle->TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this); changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption")); - signMessageAction = new QAction(TextColorIcon(":/icons/edit"), tr("Sign &message..."), this); + signMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/edit"), tr("Sign &message..."), this); signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them")); - verifyMessageAction = new QAction(TextColorIcon(":/icons/verify"), tr("&Verify message..."), this); + verifyMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/verify"), tr("&Verify message..."), this); verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses")); - openRPCConsoleAction = new QAction(TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this); + openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this); openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console")); - usedSendingAddressesAction = new QAction(TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this); + usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this); usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels")); - usedReceivingAddressesAction = new QAction(TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this); + usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this); usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels")); - openAction = new QAction(TextColorIcon(":/icons/open"), tr("Open &URI..."), this); + openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a bitcoin: URI or payment request")); - showHelpMessageAction = new QAction(TextColorIcon(":/icons/info"), tr("&Command-line options"), this); + showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options")); @@ -600,7 +601,7 @@ void BitcoinGUI::openClicked() OpenURIDialog dlg(this); if(dlg.exec()) { - emit receivedURI(dlg.getURI()); + Q_EMIT receivedURI(dlg.getURI()); } } @@ -650,7 +651,7 @@ void BitcoinGUI::setNumConnections(int count) case 7: case 8: case 9: icon = ":/icons/connect_3"; break; default: icon = ":/icons/connect_4"; break; } - labelConnectionsIcon->setPixmap(SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelConnectionsIcon->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count)); } @@ -691,7 +692,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate) if(secs < 90*60) { tooltip = tr("Up to date") + QString(".<br>") + tooltip; - labelBlocksIcon->setPixmap(SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); #ifdef ENABLE_WALLET if(walletFrame) @@ -737,7 +738,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate) tooltip = tr("Catching up...") + QString("<br>") + tooltip; if(count != prevBlocks) { - labelBlocksIcon->setPixmap(SingleColorIcon(QString( + labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(QString( ":/movies/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0'))) .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES; @@ -886,9 +887,9 @@ void BitcoinGUI::dropEvent(QDropEvent *event) { if(event->mimeData()->hasUrls()) { - foreach(const QUrl &uri, event->mimeData()->urls()) + Q_FOREACH(const QUrl &uri, event->mimeData()->urls()) { - emit receivedURI(uri.toString()); + Q_EMIT receivedURI(uri.toString()); } } event->acceptProposedAction(); @@ -931,7 +932,7 @@ void BitcoinGUI::setEncryptionStatus(int status) break; case WalletModel::Unlocked: labelEncryptionIcon->show(); - labelEncryptionIcon->setPixmap(SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>")); encryptWalletAction->setChecked(true); changePassphraseAction->setEnabled(true); @@ -939,7 +940,7 @@ void BitcoinGUI::setEncryptionStatus(int status) break; case WalletModel::Locked: labelEncryptionIcon->show(); - labelEncryptionIcon->setPixmap(SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>")); encryptWalletAction->setChecked(true); changePassphraseAction->setEnabled(true); @@ -1041,7 +1042,7 @@ void BitcoinGUI::unsubscribeFromCoreSignals() uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); } -UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() : +UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) : optionsModel(0), menu(0) { @@ -1050,13 +1051,13 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() : QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits(); int max_width = 0; const QFontMetrics fm(font()); - foreach (const BitcoinUnits::Unit unit, units) + Q_FOREACH (const BitcoinUnits::Unit unit, units) { max_width = qMax(max_width, fm.width(BitcoinUnits::name(unit))); } setMinimumSize(max_width, 0); setAlignment(Qt::AlignRight | Qt::AlignVCenter); - setStyleSheet(QString("QLabel { color : %1 }").arg(SingleColor().name())); + setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle->SingleColor().name())); } /** So that it responds to button clicks */ @@ -1069,7 +1070,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(); - foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) + Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) { QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this); menuAction->setData(QVariant(u)); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 494541f002..dd0d4bb0e2 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -22,6 +22,7 @@ class ClientModel; class NetworkStyle; class Notificator; class OptionsModel; +class PlatformStyle; class RPCConsole; class SendCoinsRecipient; class UnitDisplayStatusBarControl; @@ -47,7 +48,7 @@ class BitcoinGUI : public QMainWindow public: static const QString DEFAULT_WALLET; - explicit BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent = 0); + explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0); ~BitcoinGUI(); /** Set the client model. @@ -117,6 +118,8 @@ private: int prevBlocks; int spinnerFrame; + const PlatformStyle *platformStyle; + /** Create the main UI actions. */ void createActions(); /** Create the menu bar and sub-menus. */ @@ -136,11 +139,11 @@ private: /** Disconnect core signals from GUI client */ void unsubscribeFromCoreSignals(); -signals: +Q_SIGNALS: /** Signal raised when a URI was entered or dragged to the GUI */ void receivedURI(const QString &uri); -public slots: +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 */ @@ -168,7 +171,7 @@ public slots: void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); #endif // ENABLE_WALLET -private slots: +private Q_SLOTS: #ifdef ENABLE_WALLET /** Switch to overview (home) page */ void gotoOverviewPage(); @@ -215,7 +218,7 @@ class UnitDisplayStatusBarControl : public QLabel Q_OBJECT public: - explicit UnitDisplayStatusBarControl(); + explicit UnitDisplayStatusBarControl(const PlatformStyle *platformStyle); /** Lets the control know about the Options Model (and its signals) */ void setOptionsModel(OptionsModel *optionsModel); @@ -232,7 +235,7 @@ private: /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */ void createContextMenu(); -private slots: +private Q_SLOTS: /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */ void updateDisplayUnit(int newUnits); /** Tells underlying optionsModel to update its current display unit. */ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 8e29cdeb06..41dc2ea77e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -11,7 +11,6 @@ #include "chainparams.h" #include "checkpoints.h" #include "clientversion.h" -#include "main.h" #include "net.h" #include "ui_interface.h" #include "util.h" @@ -53,9 +52,9 @@ int ClientModel::getNumConnections(unsigned int flags) const return vNodes.size(); int nNum = 0; - BOOST_FOREACH(CNode* pnode, vNodes) - if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) - nNum++; + BOOST_FOREACH(const CNode* pnode, vNodes) + if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) + nNum++; return nNum; } @@ -117,15 +116,15 @@ void ClientModel::updateTimer() cachedReindexing = fReindex; cachedImporting = fImporting; - emit numBlocksChanged(newNumBlocks, newBlockDate); + Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate); } - emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); + Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); } void ClientModel::updateNumConnections(int numConnections) { - emit numConnectionsChanged(numConnections); + Q_EMIT numConnectionsChanged(numConnections); } void ClientModel::updateAlert(const QString &hash, int status) @@ -138,11 +137,11 @@ void ClientModel::updateAlert(const QString &hash, int status) CAlert alert = CAlert::getAlertByHash(hash_256); if(!alert.IsNull()) { - emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); + Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); } } - emit alertsChanged(getStatusBarWarnings()); + Q_EMIT alertsChanged(getStatusBarWarnings()); } bool ClientModel::inInitialBlockDownload() const diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 214701810c..68434f404c 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -82,7 +82,7 @@ private: void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); -signals: +Q_SIGNALS: void numConnectionsChanged(int count); void numBlocksChanged(int count, const QDateTime& blockDate); void alertsChanged(const QString &warnings); @@ -94,7 +94,7 @@ signals: // Show progress dialog e.g. for verifychain void showProgress(const QString &title, int nProgress); -public slots: +public Q_SLOTS: void updateTimer(); void updateNumConnections(int numConnections); void updateAlert(const QString &hash, int status); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 7531fbddcb..51008ad2de 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -9,12 +9,13 @@ #include "bitcoinunits.h" #include "guiutil.h" #include "optionsmodel.h" -#include "scicon.h" +#include "platformstyle.h" +#include "txmempool.h" #include "walletmodel.h" #include "coincontrol.h" #include "init.h" -#include "main.h" +#include "main.h" // For minRelayTxFee #include "wallet/wallet.h" #include <boost/assign/list_of.hpp> // for 'map_list_of()' @@ -30,15 +31,15 @@ #include <QTreeWidget> #include <QTreeWidgetItem> -using namespace std; QList<CAmount> CoinControlDialog::payAmounts; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); bool CoinControlDialog::fSubtractFeeFromAmount = false; -CoinControlDialog::CoinControlDialog(QWidget *parent) : +CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::CoinControlDialog), - model(0) + model(0), + platformStyle(platformStyle) { ui->setupUi(this); @@ -118,7 +119,7 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) : // (un)select all connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked())); - // change coin control first column label due Qt4 bug. + // change coin control first column label due Qt4 bug. // see https://github.com/bitcoin/bitcoin/issues/5716 ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString()); @@ -280,7 +281,7 @@ void CoinControlDialog::lockCoin() COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); model->lockCoin(outpt); contextMenuItem->setDisabled(true); - contextMenuItem->setIcon(COLUMN_CHECKBOX, SingleColorIcon(":/icons/lock_closed")); + contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); updateLabelLocked(); } @@ -442,7 +443,7 @@ QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEsti // shows count of locked unspent outputs void CoinControlDialog::updateLabelLocked() { - vector<COutPoint> vOutpts; + std::vector<COutPoint> vOutpts; model->listLockedCoins(vOutpts); if (vOutpts.size() > 0) { @@ -461,13 +462,13 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) CAmount nPayAmount = 0; bool fDust = false; CMutableTransaction txDummy; - foreach(const CAmount &amount, CoinControlDialog::payAmounts) + Q_FOREACH(const CAmount &amount, CoinControlDialog::payAmounts) { nPayAmount += amount; if (amount > 0) { - CTxOut txout(amount, (CScript)vector<unsigned char>(24, 0)); + CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0)); txDummy.vout.push_back(txout); if (txout.IsDust(::minRelayTxFee)) fDust = true; @@ -487,13 +488,12 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) int nQuantityUncompressed = 0; bool fAllowFree = false; - vector<COutPoint> vCoinControl; - vector<COutput> vOutputs; + std::vector<COutPoint> vCoinControl; + std::vector<COutput> vOutputs; coinControl->ListSelected(vCoinControl); model->getOutputs(vCoinControl, vOutputs); - BOOST_FOREACH(const COutput& out, vOutputs) - { + BOOST_FOREACH(const COutput& out, vOutputs) { // unselect already spent, very unlikely scenario, this could happen // when selected are spent elsewhere, like rpc or another computer uint256 txhash = out.tx->GetHash(); @@ -569,7 +569,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // Never create dust outputs; if we would, just add the dust to the fee. if (nChange > 0 && nChange < CENT) { - CTxOut txout(nChange, (CScript)vector<unsigned char>(24, 0)); + CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0)); if (txout.IsDust(::minRelayTxFee)) { if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust @@ -688,11 +688,10 @@ void CoinControlDialog::updateView() int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); - map<QString, vector<COutput> > mapCoins; + std::map<QString, std::vector<COutput> > mapCoins; model->listCoins(mapCoins); - BOOST_FOREACH(PAIRTYPE(QString, vector<COutput>) coins, mapCoins) - { + BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) { QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; @@ -719,8 +718,7 @@ void CoinControlDialog::updateView() double dPrioritySum = 0; int nChildren = 0; int nInputSum = 0; - BOOST_FOREACH(const COutput& out, coins.second) - { + BOOST_FOREACH(const COutput& out, coins.second) { int nInputSize = 0; nSum += out.tx->vout[out.i].nValue; nChildren++; @@ -794,7 +792,7 @@ void CoinControlDialog::updateView() COutPoint outpt(txhash, out.i); coinControl->UnSelect(outpt); // just to be sure itemOutput->setDisabled(true); - itemOutput->setIcon(COLUMN_CHECKBOX, SingleColorIcon(":/icons/lock_closed")); + itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); } // set checkbox diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 5ec382838f..8ff1eac709 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -16,6 +16,7 @@ #include <QString> #include <QTreeWidgetItem> +class PlatformStyle; class WalletModel; class CCoinControl; @@ -32,7 +33,7 @@ class CoinControlDialog : public QDialog Q_OBJECT public: - explicit CoinControlDialog(QWidget *parent = 0); + explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); ~CoinControlDialog(); void setModel(WalletModel *model); @@ -57,6 +58,8 @@ private: QAction *lockAction; QAction *unlockAction; + const PlatformStyle *platformStyle; + QString strPad(QString, int, QString); void sortView(int, Qt::SortOrder); void updateView(); @@ -102,7 +105,7 @@ private: return column; } -private slots: +private Q_SLOTS: void showMenu(const QPoint &); void copyAmount(); void copyLabel(); diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index 13c6da8eda..d59fce2d41 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -40,7 +40,7 @@ public: QString getAddress() const; void setAddress(const QString &address); -public slots: +public Q_SLOTS: void accept(); private: diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 581d2321bc..550dbacf93 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -11,7 +11,7 @@ #include "primitives/transaction.h" #include "init.h" -#include "main.h" +#include "main.h" // For minRelayTxFee #include "protocol.h" #include "script/script.h" #include "script/standard.h" diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 55df64a256..0ac3db6327 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -169,7 +169,7 @@ namespace GUIUtil void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode); void resizeColumn(int nColumnIndex, int width); - private slots: + private Q_SLOTS: void on_sectionResized(int logicalIndex, int oldSize, int newSize); void on_geometriesChanged(); }; diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 9f72602b4d..4ab87e0f32 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -6,7 +6,6 @@ #include "ui_intro.h" #include "guiutil.h" -#include "scicon.h" #include "util.h" @@ -42,10 +41,10 @@ public: ST_ERROR }; -public slots: +public Q_SLOTS: void check(); -signals: +Q_SIGNALS: void reply(int status, const QString &message, quint64 available); private: @@ -102,7 +101,7 @@ void FreespaceChecker::check() replyStatus = ST_ERROR; replyMessage = tr("Cannot create data directory here."); } - emit reply(replyStatus, replyMessage, freeBytesAvailable); + Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable); } @@ -121,7 +120,7 @@ Intro::~Intro() { delete ui; /* Ensure thread is finished before it is deleted */ - emit stopThread(); + Q_EMIT stopThread(); thread->wait(); } @@ -168,7 +167,7 @@ void Intro::pickDataDirectory() /* If current default data directory does not exist, let the user choose one */ Intro intro; intro.setDataDirectory(dataDir); - intro.setWindowIcon(SingleColorIcon(":icons/bitcoin")); + intro.setWindowIcon(QIcon(":icons/bitcoin")); while(true) { @@ -277,7 +276,7 @@ void Intro::checkPath(const QString &dataDir) if(!signalled) { signalled = true; - emit requestCheck(); + Q_EMIT requestCheck(); } mutex.unlock(); } diff --git a/src/qt/intro.h b/src/qt/intro.h index c9735615b6..50783f7225 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -43,14 +43,14 @@ public: */ static QString getDefaultDataDirectory(); -signals: +Q_SIGNALS: void requestCheck(); void stopThread(); -public slots: +public Q_SLOTS: void setStatus(int status, const QString &message, quint64 bytesAvailable); -private slots: +private Q_SLOTS: void on_dataDirectory_textChanged(const QString &arg1); void on_ellipsisButton_clicked(); void on_dataDirDefault_clicked(); diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h index 15a6583ca4..8bd867c103 100644 --- a/src/qt/macdockiconhandler.h +++ b/src/qt/macdockiconhandler.h @@ -30,7 +30,7 @@ public: static void cleanup(); void handleDockIconClickEvent(); -signals: +Q_SIGNALS: void dockIconClicked(); private: diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index 58a0365d3d..a41d39d51e 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -130,5 +130,5 @@ void MacDockIconHandler::handleDockIconClickEvent() this->mainWindow->show(); } - emit this->dockIconClicked(); + Q_EMIT this->dockIconClicked(); } diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index e28f903b2e..4541c75886 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -5,7 +5,6 @@ #include "networkstyle.h" #include "guiconstants.h" -#include "scicon.h" #include <QApplication> diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 182e948c7d..f2a15e9c34 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -40,7 +40,7 @@ public: Critical /**< An error occurred */ }; -public slots: +public Q_SLOTS: /** Show notification message. @param[in] cls general message class @param[in] title title shown with message diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h index d5c434ba9c..28b8f56ca6 100644 --- a/src/qt/openuridialog.h +++ b/src/qt/openuridialog.h @@ -21,10 +21,10 @@ public: QString getURI(); -protected slots: +protected Q_SLOTS: void accept(); -private slots: +private Q_SLOTS: void on_selectFileButton_clicked(); private: diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index efb2bf4158..062c4540ee 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -13,7 +13,7 @@ #include "guiutil.h" #include "optionsmodel.h" -#include "main.h" // for MAX_SCRIPTCHECK_THREADS +#include "main.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS #include "netbase.h" #include "txdb.h" // for -dbcache defaults @@ -42,7 +42,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : /* Main elements init */ ui->databaseCache->setMinimum(nMinDbCache); ui->databaseCache->setMaximum(nMaxDbCache); - ui->threadsScriptVerif->setMinimum(-(int)boost::thread::hardware_concurrency()); + ui->threadsScriptVerif->setMinimum(-GetNumCores()); ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS); /* Network elements init */ @@ -73,7 +73,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : /* Display elements init */ QDir translations(":translations"); ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant("")); - foreach(const QString &langStr, translations.entryList()) + Q_FOREACH(const QString &langStr, translations.entryList()) { QLocale locale(langStr); @@ -281,7 +281,7 @@ bool OptionsDialog::eventFilter(QObject *object, QEvent *event) { if(object == ui->proxyIp) { - emit proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt()); + Q_EMIT proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt()); } } return QDialog::eventFilter(object, event); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index f4e5157595..fa983e798c 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -33,7 +33,7 @@ public: protected: bool eventFilter(QObject *object, QEvent *event); -private slots: +private Q_SLOTS: /* enable OK button */ void enableOkButton(); /* disable OK button */ @@ -48,7 +48,7 @@ private slots: void clearStatusLabel(); void doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort); -signals: +Q_SIGNALS: void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort); private: diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 41d6acf358..6191edc44c 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -13,7 +13,7 @@ #include "amount.h" #include "init.h" -#include "main.h" +#include "main.h" // For DEFAULT_SCRIPTCHECK_THREADS #include "net.h" #include "txdb.h" // for -dbcache defaults @@ -286,7 +286,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in case CoinControlFeatures: fCoinControlFeatures = value.toBool(); settings.setValue("fCoinControlFeatures", fCoinControlFeatures); - emit coinControlFeaturesChanged(fCoinControlFeatures); + Q_EMIT coinControlFeaturesChanged(fCoinControlFeatures); break; case DatabaseCache: if (settings.value("nDatabaseCache") != value) { @@ -311,7 +311,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in } } - emit dataChanged(index, index); + Q_EMIT dataChanged(index, index); return successful; } @@ -324,7 +324,7 @@ void OptionsModel::setDisplayUnit(const QVariant &value) QSettings settings; nDisplayUnit = value.toInt(); settings.setValue("nDisplayUnit", nDisplayUnit); - emit displayUnitChanged(nDisplayUnit); + Q_EMIT displayUnitChanged(nDisplayUnit); } } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index bf892768ed..fc26d65b04 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -81,7 +81,7 @@ private: /// Add option to list of GUI options overridden through command line/config file void addOverriddenOption(const std::string &option); -signals: +Q_SIGNALS: void displayUnitChanged(int unit); void coinControlFeaturesChanged(bool); }; diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 2e33b9adf8..a56c80ac63 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -10,7 +10,7 @@ #include "guiconstants.h" #include "guiutil.h" #include "optionsmodel.h" -#include "scicon.h" +#include "platformstyle.h" #include "transactionfilterproxy.h" #include "transactiontablemodel.h" #include "walletmodel.h" @@ -25,7 +25,9 @@ class TxViewDelegate : public QAbstractItemDelegate { Q_OBJECT public: - TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC) + TxViewDelegate(const PlatformStyle *platformStyle): + QAbstractItemDelegate(), unit(BitcoinUnits::BTC), + platformStyle(platformStyle) { } @@ -43,7 +45,7 @@ public: int halfheight = (mainRect.height() - 2*ypad)/2; QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight); QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight); - icon = SingleColorIcon(icon, SingleColor()); + icon = platformStyle->SingleColorIcon(icon); icon.paint(painter, decorationRect); QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime(); @@ -101,11 +103,12 @@ public: } int unit; + const PlatformStyle *platformStyle; }; #include "overviewpage.moc" -OverviewPage::OverviewPage(QWidget *parent) : +OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::OverviewPage), clientModel(0), @@ -116,13 +119,13 @@ OverviewPage::OverviewPage(QWidget *parent) : currentWatchOnlyBalance(-1), currentWatchUnconfBalance(-1), currentWatchImmatureBalance(-1), - txdelegate(new TxViewDelegate()), + txdelegate(new TxViewDelegate(platformStyle)), filter(0) { ui->setupUi(this); // use a SingleColorIcon for the "out of sync warning" icon - QIcon icon = SingleColorIcon(":/icons/warning"); + QIcon icon = platformStyle->SingleColorIcon(":/icons/warning"); icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503) ui->labelTransactionsStatus->setIcon(icon); ui->labelWalletStatus->setIcon(icon); @@ -142,7 +145,7 @@ OverviewPage::OverviewPage(QWidget *parent) : void OverviewPage::handleTransactionClicked(const QModelIndex &index) { if(filter) - emit transactionClicked(filter->mapToSource(index)); + Q_EMIT transactionClicked(filter->mapToSource(index)); } OverviewPage::~OverviewPage() diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 64cb1dc4e0..4139eb35d3 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -12,6 +12,7 @@ class ClientModel; class TransactionFilterProxy; class TxViewDelegate; +class PlatformStyle; class WalletModel; namespace Ui { @@ -28,18 +29,18 @@ class OverviewPage : public QWidget Q_OBJECT public: - explicit OverviewPage(QWidget *parent = 0); + explicit OverviewPage(const PlatformStyle *platformStyle, QWidget *parent = 0); ~OverviewPage(); void setClientModel(ClientModel *clientModel); void setWalletModel(WalletModel *walletModel); void showOutOfSyncWarning(bool fShow); -public slots: +public Q_SLOTS: void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); -signals: +Q_SIGNALS: void transactionClicked(const QModelIndex &index); private: @@ -56,7 +57,7 @@ private: TxViewDelegate *txdelegate; TransactionFilterProxy *filter; -private slots: +private Q_SLOTS: void updateDisplayUnit(); void handleTransactionClicked(const QModelIndex &index); void updateAlerts(const QString &warnings); diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 7e9729eeb9..78a783dea4 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -19,8 +19,6 @@ #include <QDebug> #include <QSslCertificate> -using namespace std; - class SSLVerifyError : public std::runtime_error { public: @@ -49,7 +47,7 @@ bool PaymentRequestPlus::parse(const QByteArray& data) return true; } -bool PaymentRequestPlus::SerializeToString(string* output) const +bool PaymentRequestPlus::SerializeToString(std::string* output) const { return paymentRequest.SerializeToString(output); } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 09e9949b10..0827d99125 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -10,7 +10,7 @@ #include "base58.h" #include "chainparams.h" -#include "main.h" +#include "main.h" // For minRelayTxFee #include "ui_interface.h" #include "util.h" #include "wallet/wallet.h" @@ -46,8 +46,6 @@ #include <QUrlQuery> #endif -using namespace std; - const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds const QString BITCOIN_IPC_PREFIX("bitcoin:"); // BIP70 payment protocol messages @@ -148,7 +146,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); - foreach (const QSslCertificate& cert, certList) { + Q_FOREACH (const QSslCertificate& cert, certList) { // Don't log NULL certificates if (cert.isNull()) continue; @@ -201,7 +199,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) // when uiReady() is called. // // Warning: ipcSendCommandLine() is called early in init, -// so don't use "emit message()", but "QMessageBox::"! +// so don't use "Q_EMIT message()", but "QMessageBox::"! // void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) { @@ -269,7 +267,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) bool PaymentServer::ipcSendCommandLine() { bool fResult = false; - foreach (const QString& r, savedPaymentRequests) + Q_FOREACH (const QString& r, savedPaymentRequests) { QLocalSocket* socket = new QLocalSocket(); socket->connectToServer(ipcServerName(), QIODevice::WriteOnly); @@ -326,7 +324,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : uriServer = new QLocalServer(this); if (!uriServer->listen(name)) { - // constructor is called early in init, so don't use "emit message()" here + // constructor is called early in init, so don't use "Q_EMIT message()" here QMessageBox::critical(0, tr("Payment request error"), tr("Cannot start bitcoin: click-to-pay handler")); } @@ -394,7 +392,7 @@ void PaymentServer::uiReady() initNetManager(); saveURIs = false; - foreach (const QString& s, savedPaymentRequests) + Q_FOREACH (const QString& s, savedPaymentRequests) { handleURIOrFile(s); } @@ -431,7 +429,7 @@ void PaymentServer::handleURIOrFile(const QString& s) else { qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl; - emit message(tr("URI handling"), + Q_EMIT message(tr("URI handling"), tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()), CClientUIInterface::ICON_WARNING); } @@ -445,14 +443,14 @@ void PaymentServer::handleURIOrFile(const QString& s) { CBitcoinAddress address(recipient.address.toStdString()); if (!address.IsValid()) { - emit message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address), + Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address), CClientUIInterface::MSG_ERROR); } else - emit receivedPaymentRequest(recipient); + Q_EMIT receivedPaymentRequest(recipient); } else - emit message(tr("URI handling"), + Q_EMIT message(tr("URI handling"), tr("URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), CClientUIInterface::ICON_WARNING); @@ -466,12 +464,12 @@ void PaymentServer::handleURIOrFile(const QString& s) SendCoinsRecipient recipient; if (!readPaymentRequestFromFile(s, request)) { - emit message(tr("Payment request file handling"), + Q_EMIT message(tr("Payment request file handling"), tr("Payment request file cannot be read! This can be caused by an invalid payment request file."), CClientUIInterface::ICON_WARNING); } else if (processPaymentRequest(request, recipient)) - emit receivedPaymentRequest(recipient); + Q_EMIT receivedPaymentRequest(recipient); return; } @@ -500,7 +498,7 @@ void PaymentServer::handleURIConnection() // // Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine() -// so don't use "emit message()", but "QMessageBox::"! +// so don't use "Q_EMIT message()", but "QMessageBox::"! // bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request) { @@ -533,7 +531,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen if (request.IsInitialized()) { // Payment request network matches client network? if (!verifyNetwork(request.getDetails())) { - emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), + Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), CClientUIInterface::MSG_ERROR); return false; @@ -542,13 +540,13 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen // Make sure any payment requests involved are still valid. // This is re-checked just before sending coins in WalletModel::sendCoins(). if (verifyExpired(request.getDetails())) { - emit message(tr("Payment request rejected"), tr("Payment request expired."), + Q_EMIT message(tr("Payment request rejected"), tr("Payment request expired."), CClientUIInterface::MSG_ERROR); return false; } } else { - emit message(tr("Payment request error"), tr("Payment request is not initialized."), + Q_EMIT message(tr("Payment request error"), tr("Payment request is not initialized."), CClientUIInterface::MSG_ERROR); return false; @@ -562,7 +560,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo(); QStringList addresses; - foreach(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) { + Q_FOREACH(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) { // Extract and check destination addresses CTxDestination dest; if (ExtractDestination(sendingTo.first, dest)) { @@ -573,7 +571,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen // Unauthenticated payment requests to custom bitcoin addresses are not supported // (there is no good way to tell the user where they are paying in a way they'd // have a chance of understanding). - emit message(tr("Payment request rejected"), + Q_EMIT message(tr("Payment request rejected"), tr("Unverified payment requests to custom payment scripts are unsupported."), CClientUIInterface::MSG_ERROR); return false; @@ -583,14 +581,14 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen // but CAmount is defined as int64_t. Because of that we need to verify that amounts are in a valid range // and no overflow has happened. if (!verifyAmount(sendingTo.second)) { - emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR); return false; } // Extract and check amounts CTxOut txOut(sendingTo.second, sendingTo.first); if (txOut.IsDust(::minRelayTxFee)) { - emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).") + Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).") .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)), CClientUIInterface::MSG_ERROR); @@ -600,7 +598,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen recipient.amount += sendingTo.second; // Also verify that the final amount is still in a valid range after adding additional amounts. if (!verifyAmount(recipient.amount)) { - emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR); return false; } } @@ -647,7 +645,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien // Create a new refund address, or re-use: QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant); std::string strAccount = account.toStdString(); - set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount); + std::set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount); if (!refundAddresses.empty()) { CScript s = GetScriptForDestination(*refundAddresses.begin()); payments::Output* refund_to = payment.add_refund_to(); @@ -694,7 +692,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) .arg(BIP70_MAX_PAYMENTREQUEST_SIZE); qWarning() << QString("PaymentServer::%1:").arg(__func__) << msg; - emit message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR); return; } @@ -704,7 +702,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) .arg(reply->errorString()); qWarning() << "PaymentServer::netRequestFinished: " << msg; - emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); return; } @@ -718,12 +716,12 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) if (!request.parse(data)) { qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request"; - emit message(tr("Payment request error"), + Q_EMIT message(tr("Payment request error"), tr("Payment request cannot be parsed!"), CClientUIInterface::MSG_ERROR); } else if (processPaymentRequest(request, recipient)) - emit receivedPaymentRequest(recipient); + Q_EMIT receivedPaymentRequest(recipient); return; } @@ -736,11 +734,11 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) .arg(reply->request().url().toString()); qWarning() << "PaymentServer::netRequestFinished: " << msg; - emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); } else { - emit receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo())); + Q_EMIT receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo())); } } } @@ -750,11 +748,11 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError> Q_UNUSED(reply); QString errString; - foreach (const QSslError& err, errs) { + Q_FOREACH (const QSslError& err, errs) { qWarning() << "PaymentServer::reportSslErrors: " << err; errString += err.errorString() + "\n"; } - emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); } void PaymentServer::setOptionsModel(OptionsModel *optionsModel) @@ -765,7 +763,7 @@ void PaymentServer::setOptionsModel(OptionsModel *optionsModel) void PaymentServer::handlePaymentACK(const QString& paymentACKMsg) { // currently we don't futher process or store the paymentACK message - emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); + Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); } bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails) diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 32ed27983e..5df0a14cf7 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -98,7 +98,7 @@ public: // Verify the payment request amount is valid static bool verifyAmount(const CAmount& requestAmount); -signals: +Q_SIGNALS: // Fired when a valid payment request is received void receivedPaymentRequest(SendCoinsRecipient); @@ -108,7 +108,7 @@ signals: // Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); -public slots: +public Q_SLOTS: // Signal this when the main window's UI is ready // to display payment requests to the user void uiReady(); @@ -119,7 +119,7 @@ public slots: // Handle an incoming URI, URI with local file scheme or file void handleURIOrFile(const QString& s); -private slots: +private Q_SLOTS: void handleURIConnection(); void netRequestFinished(QNetworkReply*); void reportSslErrors(QNetworkReply*, const QList<QSslError> &); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index f5904a4d8e..85339166b0 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -63,7 +63,7 @@ public: #if QT_VERSION >= 0x040700 cachedNodeStats.reserve(vNodes.size()); #endif - foreach (CNode* pnode, vNodes) + Q_FOREACH (CNode* pnode, vNodes) { CNodeCombinedStats stats; stats.nodeStateStats.nMisbehavior = 0; @@ -92,7 +92,7 @@ public: // build index map mapNodeRows.clear(); int row = 0; - foreach (const CNodeCombinedStats& stats, cachedNodeStats) + Q_FOREACH (const CNodeCombinedStats& stats, cachedNodeStats) mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++)); } @@ -220,9 +220,9 @@ const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx) void PeerTableModel::refresh() { - emit layoutAboutToBeChanged(); + Q_EMIT layoutAboutToBeChanged(); priv->refreshPeers(); - emit layoutChanged(); + Q_EMIT layoutChanged(); } int PeerTableModel::getRowByNodeId(NodeId nodeid) diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index bff7bb824e..5f149ea873 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -5,7 +5,7 @@ #ifndef BITCOIN_QT_PEERTABLEMODEL_H #define BITCOIN_QT_PEERTABLEMODEL_H -#include "main.h" +#include "main.h" // For CNodeStateStats #include "net.h" #include <QAbstractTableModel> @@ -68,7 +68,7 @@ public: void sort(int column, Qt::SortOrder order); /*@}*/ -public slots: +public Q_SLOTS: void refresh(); private: diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp new file mode 100644 index 0000000000..11cbc7a47c --- /dev/null +++ b/src/qt/platformstyle.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 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. + +#include "platformstyle.h" + +#include "guiconstants.h" + +#include <QApplication> +#include <QColor> +#include <QIcon> +#include <QImage> +#include <QPalette> +#include <QPixmap> + +static const struct { + const char *platformId; + /** Show images on push buttons */ + const bool imagesOnButtons; + /** Colorize single-color icons */ + const bool colorizeIcons; + /** Extra padding/spacing in transactionview */ + const bool useExtraSpacing; +} platform_styles[] = { + {"macosx", false, false, true}, + {"windows", true, false, false}, + /* Other: linux, unix, ... */ + {"other", true, true, false} +}; +static const unsigned platform_styles_count = sizeof(platform_styles)/sizeof(*platform_styles); + +namespace { +/* Local functions for colorizing single-color images */ + +void MakeSingleColorImage(QImage& img, const QColor& colorbase) +{ + img = img.convertToFormat(QImage::Format_ARGB32); + for (int x = img.width(); x--; ) + { + for (int y = img.height(); y--; ) + { + const QRgb rgb = img.pixel(x, y); + img.setPixel(x, y, qRgba(colorbase.red(), colorbase.green(), colorbase.blue(), qAlpha(rgb))); + } + } +} + +QIcon ColorizeIcon(const QIcon& ico, const QColor& colorbase) +{ + QIcon new_ico; + QSize sz; + Q_FOREACH(sz, ico.availableSizes()) + { + QImage img(ico.pixmap(sz).toImage()); + MakeSingleColorImage(img, colorbase); + new_ico.addPixmap(QPixmap::fromImage(img)); + } + return new_ico; +} + +QImage ColorizeImage(const QString& filename, const QColor& colorbase) +{ + QImage img(filename); + MakeSingleColorImage(img, colorbase); + return img; +} + +QIcon ColorizeIcon(const QString& filename, const QColor& colorbase) +{ + return QIcon(QPixmap::fromImage(ColorizeImage(filename, colorbase))); +} + +} + + +PlatformStyle::PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing): + name(name), + imagesOnButtons(imagesOnButtons), + colorizeIcons(colorizeIcons), + useExtraSpacing(useExtraSpacing), + singleColor(0,0,0), + textColor(0,0,0) +{ + // Determine icon highlighting color + if (colorizeIcons) { + const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight)); + const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText)); + const QColor colorText(QApplication::palette().color(QPalette::WindowText)); + const int colorTextLightness = colorText.lightness(); + QColor colorbase; + if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness)) + colorbase = colorHighlightBg; + else + colorbase = colorHighlightFg; + singleColor = colorbase; + } + // Determine text color + textColor = QColor(QApplication::palette().color(QPalette::WindowText)); +} + +QImage PlatformStyle::SingleColorImage(const QString& filename) const +{ + if (!colorizeIcons) + return QImage(filename); + return ColorizeImage(filename, SingleColor()); +} + +QIcon PlatformStyle::SingleColorIcon(const QString& filename) const +{ + if (!colorizeIcons) + return QIcon(filename); + return ColorizeIcon(filename, SingleColor()); +} + +QIcon PlatformStyle::SingleColorIcon(const QIcon& icon) const +{ + if (!colorizeIcons) + return icon; + return ColorizeIcon(icon, SingleColor()); +} + +QIcon PlatformStyle::TextColorIcon(const QString& filename) const +{ + return ColorizeIcon(filename, TextColor()); +} + +QIcon PlatformStyle::TextColorIcon(const QIcon& icon) const +{ + return ColorizeIcon(icon, TextColor()); +} + +const PlatformStyle *PlatformStyle::instantiate(const QString &platformId) +{ + for (unsigned x=0; x<platform_styles_count; ++x) + { + if (platformId == platform_styles[x].platformId) + { + return new PlatformStyle( + platform_styles[x].platformId, + platform_styles[x].imagesOnButtons, + platform_styles[x].colorizeIcons, + platform_styles[x].useExtraSpacing); + } + } + return 0; +} + diff --git a/src/qt/platformstyle.h b/src/qt/platformstyle.h new file mode 100644 index 0000000000..4e763e760e --- /dev/null +++ b/src/qt/platformstyle.h @@ -0,0 +1,55 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_PLATFORMSTYLE_H +#define BITCOIN_QT_PLATFORMSTYLE_H + +#include <QIcon> +#include <QPixmap> +#include <QString> + +/* Coin network-specific GUI style information */ +class PlatformStyle +{ +public: + /** Get style associated with provided platform name, or 0 if not known */ + static const PlatformStyle *instantiate(const QString &platformId); + + const QString &getName() const { return name; } + + bool getImagesOnButtons() const { return imagesOnButtons; } + bool getUseExtraSpacing() const { return useExtraSpacing; } + + QColor TextColor() const { return textColor; } + QColor SingleColor() const { return singleColor; } + + /** Colorize an image (given filename) with the icon color */ + QImage SingleColorImage(const QString& filename) const; + + /** Colorize an icon (given filename) with the icon color */ + QIcon SingleColorIcon(const QString& filename) const; + + /** Colorize an icon (given object) with the icon color */ + QIcon SingleColorIcon(const QIcon& icon) const; + + /** Colorize an icon (given filename) with the text color */ + QIcon TextColorIcon(const QString& filename) const; + + /** Colorize an icon (given object) with the text color */ + QIcon TextColorIcon(const QIcon& icon) const; + +private: + PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing); + + QString name; + bool imagesOnButtons; + bool colorizeIcons; + bool useExtraSpacing; + QColor singleColor; + QColor textColor; + /* ... more to come later */ +}; + +#endif // BITCOIN_QT_PLATFORMSTYLE_H + diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index f63568d27f..8665acda5e 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -27,11 +27,11 @@ private: bool valid; const QValidator *checkValidator; -public slots: +public Q_SLOTS: void setValid(bool valid); void setEnabled(bool enabled); -private slots: +private Q_SLOTS: void markValid(); void checkValidity(); }; diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index f73268c958..800436661f 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -27,5 +27,5 @@ void QValueComboBox::setRole(int role) void QValueComboBox::handleSelectionChanged(int idx) { - emit valueChanged(); + Q_EMIT valueChanged(); } diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h index dc85d64cb5..5b20e6a5a4 100644 --- a/src/qt/qvaluecombobox.h +++ b/src/qt/qvaluecombobox.h @@ -24,13 +24,13 @@ public: /** Specify model role to use as ordinal value (defaults to Qt::UserRole) */ void setRole(int role); -signals: +Q_SIGNALS: void valueChanged(); private: int role; -private slots: +private Q_SLOTS: void handleSelectionChanged(int idx); }; diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 28cbd3abed..7fb68cc32a 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -10,9 +10,9 @@ #include "bitcoinunits.h" #include "guiutil.h" #include "optionsmodel.h" +#include "platformstyle.h" #include "receiverequestdialog.h" #include "recentrequeststablemodel.h" -#include "scicon.h" #include "walletmodel.h" #include <QAction> @@ -22,24 +22,25 @@ #include <QScrollBar> #include <QTextDocument> -ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget *parent) : +ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveCoinsDialog), - model(0) + model(0), + platformStyle(platformStyle) { ui->setupUi(this); -#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac - ui->clearButton->setIcon(QIcon()); - ui->receiveButton->setIcon(QIcon()); - ui->showRequestButton->setIcon(QIcon()); - ui->removeRequestButton->setIcon(QIcon()); -#else - ui->clearButton->setIcon(SingleColorIcon(":/icons/remove")); - ui->receiveButton->setIcon(SingleColorIcon(":/icons/receiving_addresses")); - ui->showRequestButton->setIcon(SingleColorIcon(":/icons/edit")); - ui->removeRequestButton->setIcon(SingleColorIcon(":/icons/remove")); -#endif + if (!platformStyle->getImagesOnButtons()) { + ui->clearButton->setIcon(QIcon()); + ui->receiveButton->setIcon(QIcon()); + ui->showRequestButton->setIcon(QIcon()); + ui->removeRequestButton->setIcon(QIcon()); + } else { + ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->receiveButton->setIcon(platformStyle->SingleColorIcon(":/icons/receiving_addresses")); + ui->showRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/edit")); + ui->removeRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + } // context menu actions QAction *copyLabelAction = new QAction(tr("Copy label"), this); @@ -132,7 +133,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() if(ui->reuseAddress->isChecked()) { /* Choose existing receiving address */ - AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); + AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); dlg.setModel(model->getAddressTableModel()); if(dlg.exec()) { @@ -185,8 +186,7 @@ void ReceiveCoinsDialog::on_showRequestButton_clicked() return; QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows(); - foreach (QModelIndex index, selection) - { + Q_FOREACH (const QModelIndex& index, selection) { on_recentRequestsView_doubleClicked(index); } } diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index 70a1842fa2..eaaf129a91 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -16,6 +16,7 @@ #include <QVariant> class OptionsModel; +class PlatformStyle; class WalletModel; namespace Ui { @@ -39,12 +40,12 @@ public: MINIMUM_COLUMN_WIDTH = 130 }; - explicit ReceiveCoinsDialog(QWidget *parent = 0); + explicit ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); ~ReceiveCoinsDialog(); void setModel(WalletModel *model); -public slots: +public Q_SLOTS: void clear(); void reject(); void accept(); @@ -57,10 +58,12 @@ private: GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer; WalletModel *model; QMenu *contextMenu; + const PlatformStyle *platformStyle; + void copyColumnToClipboard(int column); virtual void resizeEvent(QResizeEvent *event); -private slots: +private Q_SLOTS: void on_receiveButton_clicked(); void on_showRequestButton_clicked(); void on_removeRequestButton_clicked(); diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 3e5f897be6..69f84ebbd7 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -32,7 +32,7 @@ public: explicit QRImageWidget(QWidget *parent = 0); QImage exportImage(); -public slots: +public Q_SLOTS: void saveImage(); void copyImage(); @@ -55,7 +55,7 @@ public: void setModel(OptionsModel *model); void setInfo(const SendCoinsRecipient &info); -private slots: +private Q_SLOTS: void on_btnCopyURI_clicked(); void on_btnCopyAddress_clicked(); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 543b977d8f..5692a7aaef 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -119,7 +119,7 @@ QVariant RecentRequestsTableModel::headerData(int section, Qt::Orientation orien void RecentRequestsTableModel::updateAmountColumnTitle() { columns[Amount] = getAmountTitle(); - emit headerDataChanged(Qt::Horizontal,Amount,Amount); + Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount); } /** Gets title for amount column including current display unit if optionsModel reference available. */ @@ -214,7 +214,7 @@ void RecentRequestsTableModel::addNewRequest(RecentRequestEntry &recipient) void RecentRequestsTableModel::sort(int column, Qt::SortOrder order) { qSort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order)); - emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex())); + Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex())); } void RecentRequestsTableModel::updateDisplayUnit() diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index 85bad126db..64faa72d45 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -89,7 +89,7 @@ public: void addNewRequest(const std::string &recipient); void addNewRequest(RecentRequestEntry &recipient); -public slots: +public Q_SLOTS: void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); void updateDisplayUnit(); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index f828ce2534..3231b392f2 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -8,9 +8,8 @@ #include "clientmodel.h" #include "guiutil.h" #include "peertablemodel.h" -#include "scicon.h" +#include "platformstyle.h" -#include "main.h" #include "chainparams.h" #include "rpcserver.h" #include "rpcclient.h" @@ -60,10 +59,10 @@ class RPCExecutor : public QObject { Q_OBJECT -public slots: +public Q_SLOTS: void request(const QString &command); -signals: +Q_SIGNALS: void reply(int category, const QString &command); }; @@ -95,7 +94,7 @@ bool parseCommandLine(std::vector<std::string> &args, const std::string &strComm STATE_ESCAPE_DOUBLEQUOTED } state = STATE_EATING_SPACES; std::string curarg; - foreach(char ch, strCommand) + Q_FOREACH(char ch, strCommand) { switch(state) { @@ -158,7 +157,7 @@ void RPCExecutor::request(const QString &command) std::vector<std::string> args; if(!parseCommandLine(args, command.toStdString())) { - emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); return; } if(args.empty()) @@ -180,7 +179,7 @@ void RPCExecutor::request(const QString &command) else strPrint = result.write(2); - emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); + Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); } catch (UniValue& objError) { @@ -188,34 +187,35 @@ void RPCExecutor::request(const QString &command) { int code = find_value(objError, "code").get_int(); std::string message = find_value(objError, "message").get_str(); - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); } catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message { // Show raw JSON object - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write())); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write())); } } catch (const std::exception& e) { - emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); } } -RPCConsole::RPCConsole(QWidget *parent) : +RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::RPCConsole), clientModel(0), historyPtr(0), cachedNodeid(-1), - contextMenu(0) + contextMenu(0), + platformStyle(platformStyle) { ui->setupUi(this); GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this); -#ifndef Q_OS_MAC - ui->openDebugLogfileButton->setIcon(SingleColorIcon(":/icons/export")); -#endif - ui->clearButton->setIcon(SingleColorIcon(":/icons/remove")); + if (platformStyle->getImagesOnButtons()) { + ui->openDebugLogfileButton->setIcon(platformStyle->SingleColorIcon(":/icons/export")); + } + ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); // Install event filter for up and down arrow ui->lineEdit->installEventFilter(this); @@ -245,7 +245,7 @@ RPCConsole::RPCConsole(QWidget *parent) : RPCConsole::~RPCConsole() { GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); - emit stopExecutor(); + Q_EMIT stopExecutor(); delete ui; } @@ -364,7 +364,7 @@ void RPCConsole::clear() ui->messagesWidget->document()->addResource( QTextDocument::ImageResource, QUrl(ICON_MAPPING[i].url), - SingleColorImage(ICON_MAPPING[i].source, SingleColor()).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + platformStyle->SingleColorImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } // Set default style sheet @@ -431,7 +431,7 @@ void RPCConsole::on_lineEdit_returnPressed() if(!cmd.isEmpty()) { message(CMD_REQUEST, cmd); - emit cmdRequest(cmd); + Q_EMIT cmdRequest(cmd); // Remove command, if already in history history.removeOne(cmd); // Append command to history diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index a309df7ba7..b94efee84a 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -13,6 +13,7 @@ #include <QWidget> class ClientModel; +class PlatformStyle; namespace Ui { class RPCConsole; @@ -29,7 +30,7 @@ class RPCConsole: public QWidget Q_OBJECT public: - explicit RPCConsole(QWidget *parent); + explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); void setClientModel(ClientModel *model); @@ -46,7 +47,7 @@ protected: virtual bool eventFilter(QObject* obj, QEvent *event); void keyPressEvent(QKeyEvent *); -private slots: +private Q_SLOTS: void on_lineEdit_returnPressed(); void on_tabWidget_currentChanged(int index); /** open the debug.log from the current datadir */ @@ -61,7 +62,7 @@ private slots: /** Show custom context menu on Peers tab */ void showMenu(const QPoint& point); -public slots: +public Q_SLOTS: void clear(); void message(int category, const QString &message, bool html = false); /** Set number of connections shown in the UI */ @@ -79,7 +80,7 @@ public slots: /** Disconnect a selected node on the Peers tab */ void disconnectSelectedNode(); -signals: +Q_SIGNALS: // For RPC command executor void stopExecutor(); void cmdRequest(const QString &command); @@ -106,6 +107,7 @@ private: int historyPtr; NodeId cachedNodeid; QMenu *contextMenu; + const PlatformStyle *platformStyle; }; #endif // BITCOIN_QT_RPCCONSOLE_H diff --git a/src/qt/scicon.cpp b/src/qt/scicon.cpp deleted file mode 100644 index c493b5569e..0000000000 --- a/src/qt/scicon.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "scicon.h" - -#include <QApplication> -#include <QColor> -#include <QIcon> -#include <QImage> -#include <QPalette> -#include <QPixmap> - -namespace { - -void MakeSingleColorImage(QImage& img, const QColor& colorbase) -{ - img = img.convertToFormat(QImage::Format_ARGB32); - for (int x = img.width(); x--; ) - { - for (int y = img.height(); y--; ) - { - const QRgb rgb = img.pixel(x, y); - img.setPixel(x, y, qRgba(colorbase.red(), colorbase.green(), colorbase.blue(), qAlpha(rgb))); - } - } -} - -} - -QImage SingleColorImage(const QString& filename, const QColor& colorbase) -{ - QImage img(filename); -#if !defined(WIN32) && !defined(MAC_OSX) - MakeSingleColorImage(img, colorbase); -#endif - return img; -} - -QIcon SingleColorIcon(const QIcon& ico, const QColor& colorbase) -{ -#if defined(WIN32) || defined(MAC_OSX) - return ico; -#else - QIcon new_ico; - QSize sz; - Q_FOREACH(sz, ico.availableSizes()) - { - QImage img(ico.pixmap(sz).toImage()); - MakeSingleColorImage(img, colorbase); - new_ico.addPixmap(QPixmap::fromImage(img)); - } - return new_ico; -#endif -} - -QIcon SingleColorIcon(const QString& filename, const QColor& colorbase) -{ - return QIcon(QPixmap::fromImage(SingleColorImage(filename, colorbase))); -} - -QColor SingleColor() -{ -#if defined(WIN32) || defined(MAC_OSX) - return QColor(0,0,0); -#else - const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight)); - const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText)); - const QColor colorText(QApplication::palette().color(QPalette::WindowText)); - const int colorTextLightness = colorText.lightness(); - QColor colorbase; - if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness)) - colorbase = colorHighlightBg; - else - colorbase = colorHighlightFg; - return colorbase; -#endif -} - -QIcon SingleColorIcon(const QString& filename) -{ - return SingleColorIcon(filename, SingleColor()); -} - -static QColor TextColor() -{ - return QColor(QApplication::palette().color(QPalette::WindowText)); -} - -QIcon TextColorIcon(const QString& filename) -{ - return SingleColorIcon(filename, TextColor()); -} - -QIcon TextColorIcon(const QIcon& ico) -{ - return SingleColorIcon(ico, TextColor()); -} diff --git a/src/qt/scicon.h b/src/qt/scicon.h deleted file mode 100644 index 1388069ddb..0000000000 --- a/src/qt/scicon.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_QT_SCICON_H -#define BITCOIN_QT_SCICON_H - -#include <QtCore> - -QT_BEGIN_NAMESPACE -class QColor; -class QIcon; -class QString; -QT_END_NAMESPACE - -QImage SingleColorImage(const QString& filename, const QColor&); -QIcon SingleColorIcon(const QIcon&, const QColor&); -QIcon SingleColorIcon(const QString& filename, const QColor&); -QColor SingleColor(); -QIcon SingleColorIcon(const QString& filename); -QIcon TextColorIcon(const QIcon&); -QIcon TextColorIcon(const QString& filename); - -#endif // BITCOIN_QT_SCICON_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 3d57711568..449a7bc5e8 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -11,14 +11,15 @@ #include "coincontroldialog.h" #include "guiutil.h" #include "optionsmodel.h" -#include "scicon.h" +#include "platformstyle.h" #include "sendcoinsentry.h" #include "walletmodel.h" #include "base58.h" #include "coincontrol.h" -#include "main.h" +#include "main.h" // mempool and minRelayTxFee #include "ui_interface.h" +#include "txmempool.h" #include "wallet/wallet.h" #include <QMessageBox> @@ -26,25 +27,26 @@ #include <QSettings> #include <QTextDocument> -SendCoinsDialog::SendCoinsDialog(QWidget *parent) : +SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SendCoinsDialog), clientModel(0), model(0), fNewRecipientAllowed(true), - fFeeMinimized(true) + fFeeMinimized(true), + platformStyle(platformStyle) { ui->setupUi(this); -#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac - ui->addButton->setIcon(QIcon()); - ui->clearButton->setIcon(QIcon()); - ui->sendButton->setIcon(QIcon()); -#else - ui->addButton->setIcon(SingleColorIcon(":/icons/add")); - ui->clearButton->setIcon(SingleColorIcon(":/icons/remove")); - ui->sendButton->setIcon(SingleColorIcon(":/icons/send")); -#endif + if (!platformStyle->getImagesOnButtons()) { + ui->addButton->setIcon(QIcon()); + ui->clearButton->setIcon(QIcon()); + ui->sendButton->setIcon(QIcon()); + } else { + ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add")); + ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send")); + } GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this); @@ -251,7 +253,7 @@ void SendCoinsDialog::on_sendButton_clicked() // Format confirmation message QStringList formatted; - foreach(const SendCoinsRecipient &rcp, currentTransaction.getRecipients()) + Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients()) { // generate bold amount string QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); @@ -305,7 +307,7 @@ void SendCoinsDialog::on_sendButton_clicked() questionString.append("<hr />"); CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; QStringList alternativeUnits; - foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) + Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); @@ -363,7 +365,7 @@ void SendCoinsDialog::accept() SendCoinsEntry *SendCoinsDialog::addEntry() { - SendCoinsEntry *entry = new SendCoinsEntry(this); + SendCoinsEntry *entry = new SendCoinsEntry(platformStyle, this); entry->setModel(model); ui->entries->addWidget(entry); connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*))); @@ -540,7 +542,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn return; } - emit message(tr("Send Coins"), msgParams.first, msgParams.second); + Q_EMIT message(tr("Send Coins"), msgParams.first, msgParams.second); } void SendCoinsDialog::minimizeFeeSection(bool fMinimize) @@ -710,7 +712,7 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked) // Coin Control: button inputs -> show actual coin control dialog void SendCoinsDialog::coinControlButtonClicked() { - CoinControlDialog dlg; + CoinControlDialog dlg(platformStyle); dlg.setModel(model); dlg.exec(); coinControlUpdateLabels(); diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index fc513bf2ba..391905ffcd 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -12,6 +12,7 @@ class ClientModel; class OptionsModel; +class PlatformStyle; class SendCoinsEntry; class SendCoinsRecipient; @@ -31,7 +32,7 @@ class SendCoinsDialog : public QDialog Q_OBJECT public: - explicit SendCoinsDialog(QWidget *parent = 0); + explicit SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); ~SendCoinsDialog(); void setClientModel(ClientModel *clientModel); @@ -45,7 +46,7 @@ public: void pasteEntry(const SendCoinsRecipient &rv); bool handlePaymentRequest(const SendCoinsRecipient &recipient); -public slots: +public Q_SLOTS: void clear(); void reject(); void accept(); @@ -60,15 +61,16 @@ private: WalletModel *model; bool fNewRecipientAllowed; bool fFeeMinimized; + const PlatformStyle *platformStyle; // Process WalletModel::SendCoinsReturn and generate a pair consisting - // of a message and message flags for use in emit message(). + // of a message and message flags for use in Q_EMIT message(). // Additional parameter msgArg can be used via .arg(msgArg). void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString()); void minimizeFeeSection(bool fMinimize); void updateFeeMinimizedLabel(); -private slots: +private Q_SLOTS: void on_sendButton_clicked(); void on_buttonChooseFee_clicked(); void on_buttonMinimizeFee_clicked(); @@ -93,7 +95,7 @@ private slots: void updateSmartFeeLabel(); void updateGlobalFeeVariables(); -signals: +Q_SIGNALS: // Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); }; diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 6eec33ffd4..44aa8ad1af 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -9,30 +9,30 @@ #include "addresstablemodel.h" #include "guiutil.h" #include "optionsmodel.h" -#include "scicon.h" +#include "platformstyle.h" #include "walletmodel.h" #include <QApplication> #include <QClipboard> -SendCoinsEntry::SendCoinsEntry(QWidget *parent) : +SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent) : QStackedWidget(parent), ui(new Ui::SendCoinsEntry), - model(0) + model(0), + platformStyle(platformStyle) { ui->setupUi(this); - ui->addressBookButton->setIcon(SingleColorIcon(":/icons/address-book")); - ui->pasteButton->setIcon(SingleColorIcon(":/icons/editpaste")); - ui->deleteButton->setIcon(SingleColorIcon(":/icons/remove")); - ui->deleteButton_is->setIcon(SingleColorIcon(":/icons/remove")); - ui->deleteButton_s->setIcon(SingleColorIcon(":/icons/remove")); + ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(":/icons/address-book")); + ui->pasteButton->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste")); + ui->deleteButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->deleteButton_is->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->deleteButton_s->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); setCurrentWidget(ui->SendCoins); -#ifdef Q_OS_MAC - ui->payToLayout->setSpacing(4); -#endif + if (platformStyle->getUseExtraSpacing()) + ui->payToLayout->setSpacing(4); #if QT_VERSION >= 0x040700 ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); #endif @@ -65,7 +65,7 @@ void SendCoinsEntry::on_addressBookButton_clicked() { if(!model) return; - AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); + AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); dlg.setModel(model->getAddressTableModel()); if(dlg.exec()) { @@ -114,7 +114,7 @@ void SendCoinsEntry::clear() void SendCoinsEntry::deleteClicked() { - emit removeEntry(this); + Q_EMIT removeEntry(this); } bool SendCoinsEntry::validate() diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index c2d1185bdd..107ab70158 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -10,6 +10,7 @@ #include <QStackedWidget> class WalletModel; +class PlatformStyle; namespace Ui { class SendCoinsEntry; @@ -25,7 +26,7 @@ class SendCoinsEntry : public QStackedWidget Q_OBJECT public: - explicit SendCoinsEntry(QWidget *parent = 0); + explicit SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent = 0); ~SendCoinsEntry(); void setModel(WalletModel *model); @@ -45,15 +46,15 @@ public: void setFocus(); -public slots: +public Q_SLOTS: void clear(); -signals: +Q_SIGNALS: void removeEntry(SendCoinsEntry *entry); void payAmountChanged(); void subtractFeeFromAmountChanged(); -private slots: +private Q_SLOTS: void deleteClicked(); void on_payTo_textChanged(const QString &address); void on_addressBookButton_clicked(); @@ -64,6 +65,7 @@ private: SendCoinsRecipient recipient; Ui::SendCoinsEntry *ui; WalletModel *model; + const PlatformStyle *platformStyle; bool updateLabel(const QString &address); }; diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index ce166f3672..60e8e36ebe 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -7,7 +7,7 @@ #include "addressbookpage.h" #include "guiutil.h" -#include "scicon.h" +#include "platformstyle.h" #include "walletmodel.h" #include "base58.h" @@ -20,21 +20,22 @@ #include <QClipboard> -SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) : +SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SignVerifyMessageDialog), - model(0) + model(0), + platformStyle(platformStyle) { ui->setupUi(this); - ui->addressBookButton_SM->setIcon(SingleColorIcon(":/icons/address-book")); - ui->pasteButton_SM->setIcon(SingleColorIcon(":/icons/editpaste")); - ui->copySignatureButton_SM->setIcon(SingleColorIcon(":/icons/editcopy")); - ui->signMessageButton_SM->setIcon(SingleColorIcon(":/icons/edit")); - ui->clearButton_SM->setIcon(SingleColorIcon(":/icons/remove")); - ui->addressBookButton_VM->setIcon(SingleColorIcon(":/icons/address-book")); - ui->verifyMessageButton_VM->setIcon(SingleColorIcon(":/icons/transaction_0")); - ui->clearButton_VM->setIcon(SingleColorIcon(":/icons/remove")); + ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book")); + ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste")); + ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy")); + ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/edit")); + ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book")); + ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/transaction_0")); + ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); #if QT_VERSION >= 0x040700 ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature")); @@ -94,7 +95,7 @@ void SignVerifyMessageDialog::on_addressBookButton_SM_clicked() { if (model && model->getAddressTableModel()) { - AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); + AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); dlg.setModel(model->getAddressTableModel()); if (dlg.exec()) { @@ -148,12 +149,12 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() return; } - CDataStream ss(SER_GETHASH, 0); + CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << ui->messageIn_SM->document()->toPlainText().toStdString(); std::vector<unsigned char> vchSig; - if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig)) + if (!key.SignCompact(ss.GetHash(), vchSig)) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>")); @@ -185,7 +186,7 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() { if (model && model->getAddressTableModel()) { - AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); + AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); dlg.setModel(model->getAddressTableModel()); if (dlg.exec()) { @@ -223,12 +224,12 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - CDataStream ss(SER_GETHASH, 0); + CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << ui->messageIn_VM->document()->toPlainText().toStdString(); CPubKey pubkey; - if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig)) + if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) { ui->signatureIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h index 27807adc84..d651d5049b 100644 --- a/src/qt/signverifymessagedialog.h +++ b/src/qt/signverifymessagedialog.h @@ -7,6 +7,7 @@ #include <QDialog> +class PlatformStyle; class WalletModel; namespace Ui { @@ -18,7 +19,7 @@ class SignVerifyMessageDialog : public QDialog Q_OBJECT public: - explicit SignVerifyMessageDialog(QWidget *parent); + explicit SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent); ~SignVerifyMessageDialog(); void setModel(WalletModel *model); @@ -34,8 +35,9 @@ protected: private: Ui::SignVerifyMessageDialog *ui; WalletModel *model; + const PlatformStyle *platformStyle; -private slots: +private Q_SLOTS: /* sign message */ void on_addressBookButton_SM_clicked(); void on_pasteButton_SM_clicked(); diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index 84e4556dd8..29d16d4eae 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -27,7 +27,7 @@ protected: void paintEvent(QPaintEvent *event); void closeEvent(QCloseEvent *event); -public slots: +public Q_SLOTS: /** Slot to call finish() method as it's not defined as slot */ void slotFinish(QWidget *mainWin); diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index e2ec439b2e..b28934cd31 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -195,7 +195,7 @@ void PaymentServerTests::paymentServerTests() QVERIFY(r.paymentRequest.IsInitialized()); // Extract address and amount from the request QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo(); - foreach (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) { + Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) { CTxDestination dest; if (ExtractDestination(sendingTo.first, dest)) QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false); diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h index c98bbf0833..71d61fcbe7 100644 --- a/src/qt/test/paymentservertests.h +++ b/src/qt/test/paymentservertests.h @@ -14,7 +14,7 @@ class PaymentServerTests : public QObject { Q_OBJECT -private slots: +private Q_SLOTS: void paymentServerTests(); }; @@ -25,7 +25,7 @@ class RecipientCatcher : public QObject { Q_OBJECT -public slots: +public Q_SLOTS: void getRecipient(SendCoinsRecipient r); public: diff --git a/src/qt/test/uritests.h b/src/qt/test/uritests.h index a0b7dc6c72..434169dcde 100644 --- a/src/qt/test/uritests.h +++ b/src/qt/test/uritests.h @@ -12,7 +12,7 @@ class URITests : public QObject { Q_OBJECT -private slots: +private Q_SLOTS: void uriTests(); }; diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 0b2eb9eaf2..9b67445bc0 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -139,10 +139,10 @@ void TrafficGraphWidget::updateRates() } float tmax = 0.0f; - foreach(float f, vSamplesIn) { + Q_FOREACH(float f, vSamplesIn) { if(f > tmax) tmax = f; } - foreach(float f, vSamplesOut) { + Q_FOREACH(float f, vSamplesOut) { if(f > tmax) tmax = f; } fMax = tmax; diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h index 4c6b17fe7e..6336a8d144 100644 --- a/src/qt/trafficgraphwidget.h +++ b/src/qt/trafficgraphwidget.h @@ -27,7 +27,7 @@ public: protected: void paintEvent(QPaintEvent *); -public slots: +public Q_SLOTS: void updateRates(); void setGraphRangeMins(int mins); void clear(); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 5662b16657..af78a51d0f 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -21,8 +21,6 @@ #include <stdint.h> #include <string> -using namespace std; - QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) { AssertLockHeld(cs_main); @@ -243,14 +241,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "<br>"; // Message from normal bitcoin:URI (bitcoin:123...?message=example) - foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm) + Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm) if (r.first == "Message") strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>"; // // PaymentRequest info: // - foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm) + Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm) { if (r.first == "PaymentRequest") { diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 34464b4075..98ad1a44b6 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -8,7 +8,7 @@ #include "guiconstants.h" #include "guiutil.h" #include "optionsmodel.h" -#include "scicon.h" +#include "platformstyle.h" #include "transactiondesc.h" #include "transactionrecord.h" #include "walletmodel.h" @@ -25,6 +25,8 @@ #include <QIcon> #include <QList> +#include <boost/foreach.hpp> + // Amount column is right-aligned it contains numbers static int column_alignments[] = { Qt::AlignLeft|Qt::AlignVCenter, /* status */ @@ -142,7 +144,7 @@ public: { parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1); int insert_idx = lowerIndex; - foreach(const TransactionRecord &rec, toInsert) + Q_FOREACH(const TransactionRecord &rec, toInsert) { cachedWallet.insert(insert_idx, rec); insert_idx += 1; @@ -220,12 +222,13 @@ public: } }; -TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *parent): +TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent): QAbstractTableModel(parent), wallet(wallet), walletModel(parent), priv(new TransactionTablePriv(wallet, this)), - fProcessingQueuedTransactions(false) + fProcessingQueuedTransactions(false), + platformStyle(platformStyle) { columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); priv->refreshWallet(); @@ -245,7 +248,7 @@ TransactionTableModel::~TransactionTableModel() void TransactionTableModel::updateAmountColumnTitle() { columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); - emit headerDataChanged(Qt::Horizontal,Amount,Amount); + Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount); } void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction) @@ -262,8 +265,8 @@ void TransactionTableModel::updateConfirmations() // Invalidate status (number of confirmations) and (possibly) description // for all rows. Qt is smart enough to only actually request the data for the // visible rows. - emit dataChanged(index(0, Status), index(priv->size()-1, Status)); - emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress)); + Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status)); + Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress)); } int TransactionTableModel::rowCount(const QModelIndex &parent) const @@ -519,7 +522,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case Qt::DecorationRole: { QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole)); - return TextColorIcon(icon); + return platformStyle->TextColorIcon(icon); } case Qt::DisplayRole: switch(index.column()) @@ -650,7 +653,7 @@ void TransactionTableModel::updateDisplayUnit() { // emit dataChanged to update Amount column with the current unit updateAmountColumnTitle(); - emit dataChanged(index(0, Amount), index(priv->size()-1, Amount)); + Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount)); } // queue notifications to show a non freezing progress dialog e.g. for rescan diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 30a15df9e6..2089f703a6 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -10,6 +10,7 @@ #include <QAbstractTableModel> #include <QStringList> +class PlatformStyle; class TransactionRecord; class TransactionTablePriv; class WalletModel; @@ -23,7 +24,7 @@ class TransactionTableModel : public QAbstractTableModel Q_OBJECT public: - explicit TransactionTableModel(CWallet* wallet, WalletModel *parent = 0); + explicit TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent = 0); ~TransactionTableModel(); enum ColumnIndex { @@ -82,6 +83,7 @@ private: QStringList columns; TransactionTablePriv *priv; bool fProcessingQueuedTransactions; + const PlatformStyle *platformStyle; void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); @@ -98,7 +100,7 @@ private: QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const; QVariant txAddressDecoration(const TransactionRecord *wtx) const; -public slots: +public Q_SLOTS: /* New transaction, or transaction changed status */ void updateTransaction(const QString &hash, int status, bool showTransaction); void updateConfirmations(); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 526940632e..54e5a82720 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -10,7 +10,7 @@ #include "editaddressdialog.h" #include "guiutil.h" #include "optionsmodel.h" -#include "scicon.h" +#include "platformstyle.h" #include "transactiondescdialog.h" #include "transactionfilterproxy.h" #include "transactionrecord.h" @@ -35,7 +35,7 @@ #include <QUrl> #include <QVBoxLayout> -TransactionView::TransactionView(QWidget *parent) : +TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), model(0), transactionProxyModel(0), transactionView(0) { @@ -44,27 +44,28 @@ TransactionView::TransactionView(QWidget *parent) : QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setContentsMargins(0,0,0,0); -#ifdef Q_OS_MAC - hlayout->setSpacing(5); - hlayout->addSpacing(26); -#else - hlayout->setSpacing(0); - hlayout->addSpacing(23); -#endif + + if (platformStyle->getUseExtraSpacing()) { + hlayout->setSpacing(5); + hlayout->addSpacing(26); + } else { + hlayout->setSpacing(0); + hlayout->addSpacing(23); + } watchOnlyWidget = new QComboBox(this); watchOnlyWidget->setFixedWidth(24); watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All); - watchOnlyWidget->addItem(SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes); - watchOnlyWidget->addItem(SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No); + watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes); + watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No); hlayout->addWidget(watchOnlyWidget); dateWidget = new QComboBox(this); -#ifdef Q_OS_MAC - dateWidget->setFixedWidth(121); -#else - dateWidget->setFixedWidth(120); -#endif + if (platformStyle->getUseExtraSpacing()) { + dateWidget->setFixedWidth(121); + } else { + dateWidget->setFixedWidth(120); + } dateWidget->addItem(tr("All"), All); dateWidget->addItem(tr("Today"), Today); dateWidget->addItem(tr("This week"), ThisWeek); @@ -75,11 +76,11 @@ TransactionView::TransactionView(QWidget *parent) : hlayout->addWidget(dateWidget); typeWidget = new QComboBox(this); -#ifdef Q_OS_MAC - typeWidget->setFixedWidth(121); -#else - typeWidget->setFixedWidth(120); -#endif + if (platformStyle->getUseExtraSpacing()) { + typeWidget->setFixedWidth(121); + } else { + typeWidget->setFixedWidth(120); + } typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES); typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) | @@ -102,11 +103,11 @@ TransactionView::TransactionView(QWidget *parent) : #if QT_VERSION >= 0x040700 amountWidget->setPlaceholderText(tr("Min amount")); #endif -#ifdef Q_OS_MAC - amountWidget->setFixedWidth(97); -#else - amountWidget->setFixedWidth(100); -#endif + if (platformStyle->getUseExtraSpacing()) { + amountWidget->setFixedWidth(97); + } else { + amountWidget->setFixedWidth(100); + } amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this)); hlayout->addWidget(amountWidget); @@ -121,11 +122,11 @@ TransactionView::TransactionView(QWidget *parent) : vlayout->setSpacing(0); int width = view->verticalScrollBar()->sizeHint().width(); // Cover scroll bar width with spacing -#ifdef Q_OS_MAC - hlayout->addSpacing(width+2); -#else - hlayout->addSpacing(width); -#endif + if (platformStyle->getUseExtraSpacing()) { + hlayout->addSpacing(width+2); + } else { + hlayout->addSpacing(width); + } // Always show scroll bar view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); view->setTabKeyNavigation(false); @@ -341,11 +342,11 @@ void TransactionView::exportClicked() writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole); if(!writer.write()) { - emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), + Q_EMIT message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), CClientUIInterface::MSG_ERROR); } else { - emit message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename), + Q_EMIT message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename), CClientUIInterface::MSG_INFORMATION); } } diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 092d919042..ac157fb98d 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -10,6 +10,7 @@ #include <QWidget> #include <QKeyEvent> +class PlatformStyle; class TransactionFilterProxy; class WalletModel; @@ -32,7 +33,7 @@ class TransactionView : public QWidget Q_OBJECT public: - explicit TransactionView(QWidget *parent = 0); + explicit TransactionView(const PlatformStyle *platformStyle, QWidget *parent = 0); void setModel(WalletModel *model); @@ -83,7 +84,7 @@ private: bool eventFilter(QObject *obj, QEvent *event); -private slots: +private Q_SLOTS: void contextualMenu(const QPoint &); void dateRangeChanged(); void showDetails(); @@ -95,13 +96,13 @@ private slots: void openThirdPartyTxUrl(QString url); void updateWatchOnlyColumn(bool fHaveWatchOnly); -signals: +Q_SIGNALS: void doubleClicked(const QModelIndex&); /** Fired when a message should be reported to the user */ void message(const QString &title, const QString &message, unsigned int style); -public slots: +public Q_SLOTS: void chooseDate(int idx); void chooseType(int idx); void chooseWatchonly(int idx); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 386cf31d73..5e26f3e01b 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -84,7 +84,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : QTextCharFormat bold; bold.setFontWeight(QFont::Bold); - foreach (const QString &line, coreOptions.split("\n")) { + Q_FOREACH (const QString &line, coreOptions.split("\n")) { if (line.startsWith(" -")) { cursor.currentTable()->appendRows(1); diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 288b985f13..47282ae2d0 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -31,7 +31,7 @@ private: Ui::HelpMessageDialog *ui; QString text; -private slots: +private Q_SLOTS: void on_okButton_accepted(); }; diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 892947bf3a..ba8c28464d 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -12,9 +12,10 @@ #include <QHBoxLayout> #include <QLabel> -WalletFrame::WalletFrame(BitcoinGUI *_gui) : +WalletFrame::WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui) : QFrame(_gui), - gui(_gui) + gui(_gui), + platformStyle(platformStyle) { // Leave HBox hook for adding a list view later QHBoxLayout *walletFrameLayout = new QHBoxLayout(this); @@ -42,7 +43,7 @@ bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0) return false; - WalletView *walletView = new WalletView(this); + WalletView *walletView = new WalletView(platformStyle, this); walletView->setBitcoinGUI(gui); walletView->setClientModel(clientModel); walletView->setWalletModel(walletModel); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index eea97defc9..9a56e97f9c 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -10,6 +10,7 @@ class BitcoinGUI; class ClientModel; +class PlatformStyle; class SendCoinsRecipient; class WalletModel; class WalletView; @@ -23,7 +24,7 @@ class WalletFrame : public QFrame Q_OBJECT public: - explicit WalletFrame(BitcoinGUI *_gui = 0); + explicit WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui = 0); ~WalletFrame(); void setClientModel(ClientModel *clientModel); @@ -45,9 +46,11 @@ private: bool bOutOfSync; + const PlatformStyle *platformStyle; + WalletView *currentWalletView(); -public slots: +public Q_SLOTS: /** Switch to overview (home) page */ void gotoOverviewPage(); /** Switch to history (transactions) page */ diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 9b8be76beb..f580853732 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -25,9 +25,9 @@ #include <QSet> #include <QTimer> -using namespace std; +#include <boost/foreach.hpp> -WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : +WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), transactionTableModel(0), recentRequestsTableModel(0), @@ -39,7 +39,7 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p fForceCheckBalanceChanged = false; addressTableModel = new AddressTableModel(wallet, this); - transactionTableModel = new TransactionTableModel(wallet, this); + transactionTableModel = new TransactionTableModel(platformStyle, wallet, this); recentRequestsTableModel = new RecentRequestsTableModel(wallet, this); // This timer will be fired repeatedly to update the balance @@ -107,7 +107,7 @@ void WalletModel::updateStatus() EncryptionStatus newEncryptionStatus = getEncryptionStatus(); if(cachedEncryptionStatus != newEncryptionStatus) - emit encryptionStatusChanged(newEncryptionStatus); + Q_EMIT encryptionStatusChanged(newEncryptionStatus); } void WalletModel::pollBalanceChanged() @@ -159,7 +159,7 @@ void WalletModel::checkBalanceChanged() cachedWatchOnlyBalance = newWatchOnlyBalance; cachedWatchUnconfBalance = newWatchUnconfBalance; cachedWatchImmatureBalance = newWatchImmatureBalance; - emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance, + Q_EMIT balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance, newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance); } } @@ -180,7 +180,7 @@ void WalletModel::updateAddressBook(const QString &address, const QString &label void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) { fHaveWatchOnly = fHaveWatchonly; - emit notifyWatchonlyChanged(fHaveWatchonly); + Q_EMIT notifyWatchonlyChanged(fHaveWatchonly); } bool WalletModel::validateAddress(const QString &address) @@ -205,7 +205,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact int nAddresses = 0; // Pre-check input data for validity - foreach(const SendCoinsRecipient &rcp, recipients) + Q_FOREACH(const SendCoinsRecipient &rcp, recipients) { if (rcp.fSubtractFeeFromAmount) fSubtractFeeFromAmount = true; @@ -285,7 +285,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact { return SendCoinsReturn(AmountWithFeeExceedsBalance); } - emit message(tr("Send Coins"), QString::fromStdString(strFailReason), + Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } @@ -306,7 +306,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran LOCK2(cs_main, wallet->cs_wallet); CWalletTx *newTx = transaction.getTransaction(); - foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) + Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) { if (rcp.paymentRequest.IsInitialized()) { @@ -337,7 +337,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran // Add addresses / update labels that we've sent to to the address book, // and emit coinsSent signal for each recipient - foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) + Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) { // Don't touch the address book when we have a payment request if (!rcp.paymentRequest.IsInitialized()) @@ -361,7 +361,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran } } } - emit coinsSent(wallet, rcp, transaction_array); + Q_EMIT coinsSent(wallet, rcp, transaction_array); } checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits @@ -521,7 +521,7 @@ WalletModel::UnlockContext WalletModel::requestUnlock() if(was_locked) { // Request UI to unlock wallet - emit requireUnlock(); + Q_EMIT requireUnlock(); } // If wallet is still locked, unlock was failed or cancelled, mark context as invalid bool valid = getEncryptionStatus() != Locked; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index e263438880..c29682e4f6 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -17,6 +17,7 @@ class AddressTableModel; class OptionsModel; +class PlatformStyle; class RecentRequestsTableModel; class TransactionTableModel; class WalletModelTransaction; @@ -100,7 +101,7 @@ class WalletModel : public QObject Q_OBJECT public: - explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0); + explicit WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0); ~WalletModel(); enum StatusCode // Returned by sendCoins @@ -227,7 +228,7 @@ private: void unsubscribeFromCoreSignals(); void checkBalanceChanged(); -signals: +Q_SIGNALS: // Signal that balance in wallet changed void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); @@ -252,7 +253,7 @@ signals: // Watch-only address added void notifyWatchonlyChanged(bool fHaveWatchonly); -public slots: +public Q_SLOTS: /* Wallet status might have changed */ void updateStatus(); /* New transaction, or transaction changed status */ diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 206bb7c774..6a9b2d5bd3 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -81,7 +81,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet) CAmount WalletModelTransaction::getTotalTransactionAmount() { CAmount totalTransactionAmount = 0; - foreach(const SendCoinsRecipient &rcp, recipients) + Q_FOREACH(const SendCoinsRecipient &rcp, recipients) { totalTransactionAmount += rcp.amount; } diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 956c8b8913..fa96f62e03 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -11,8 +11,8 @@ #include "guiutil.h" #include "optionsmodel.h" #include "overviewpage.h" +#include "platformstyle.h" #include "receivecoinsdialog.h" -#include "scicon.h" #include "sendcoinsdialog.h" #include "signverifymessagedialog.h" #include "transactiontablemodel.h" @@ -29,31 +29,32 @@ #include <QPushButton> #include <QVBoxLayout> -WalletView::WalletView(QWidget *parent): +WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent): QStackedWidget(parent), clientModel(0), - walletModel(0) + walletModel(0), + platformStyle(platformStyle) { // Create tabs - overviewPage = new OverviewPage(); + overviewPage = new OverviewPage(platformStyle); transactionsPage = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(); QHBoxLayout *hbox_buttons = new QHBoxLayout(); - transactionView = new TransactionView(this); + transactionView = new TransactionView(platformStyle, this); vbox->addWidget(transactionView); QPushButton *exportButton = new QPushButton(tr("&Export"), this); exportButton->setToolTip(tr("Export the data in the current tab to a file")); -#ifndef Q_OS_MAC // Icons on push buttons are very uncommon on Mac - exportButton->setIcon(SingleColorIcon(":/icons/export")); -#endif + if (platformStyle->getImagesOnButtons()) { + exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export")); + } hbox_buttons->addStretch(); hbox_buttons->addWidget(exportButton); vbox->addLayout(hbox_buttons); transactionsPage->setLayout(vbox); - receiveCoinsPage = new ReceiveCoinsDialog(); - sendCoinsPage = new SendCoinsDialog(); + receiveCoinsPage = new ReceiveCoinsDialog(platformStyle); + sendCoinsPage = new SendCoinsDialog(platformStyle); addWidget(overviewPage); addWidget(transactionsPage); @@ -153,7 +154,7 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int QString address = ttm->data(index, TransactionTableModel::AddressRole).toString(); QString label = ttm->data(index, TransactionTableModel::LabelRole).toString(); - emit incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label); + Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label); } void WalletView::gotoOverviewPage() @@ -182,7 +183,7 @@ void WalletView::gotoSendCoinsPage(QString addr) void WalletView::gotoSignMessageTab(QString addr) { // calls show() in showTab_SM() - SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this); + SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this); signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose); signVerifyMessageDialog->setModel(walletModel); signVerifyMessageDialog->showTab_SM(true); @@ -194,7 +195,7 @@ void WalletView::gotoSignMessageTab(QString addr) void WalletView::gotoVerifyMessageTab(QString addr) { // calls show() in showTab_VM() - SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this); + SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this); signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose); signVerifyMessageDialog->setModel(walletModel); signVerifyMessageDialog->showTab_VM(true); @@ -215,7 +216,7 @@ void WalletView::showOutOfSyncWarning(bool fShow) void WalletView::updateEncryptionStatus() { - emit encryptionStatusChanged(walletModel->getEncryptionStatus()); + Q_EMIT encryptionStatusChanged(walletModel->getEncryptionStatus()); } void WalletView::encryptWallet(bool status) @@ -239,11 +240,11 @@ void WalletView::backupWallet() return; if (!walletModel->backupWallet(filename)) { - emit message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename), + Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename), CClientUIInterface::MSG_ERROR); } else { - emit message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename), + Q_EMIT message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename), CClientUIInterface::MSG_INFORMATION); } } @@ -272,7 +273,7 @@ void WalletView::usedSendingAddresses() { if(!walletModel) return; - AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab, this); + AddressBookPage *dlg = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setModel(walletModel->getAddressTableModel()); dlg->show(); @@ -282,7 +283,7 @@ void WalletView::usedReceivingAddresses() { if(!walletModel) return; - AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this); + AddressBookPage *dlg = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setModel(walletModel->getAddressTableModel()); dlg->show(); diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 1840e21e9c..f97cf1ee80 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -12,6 +12,7 @@ class BitcoinGUI; class ClientModel; class OverviewPage; +class PlatformStyle; class ReceiveCoinsDialog; class SendCoinsDialog; class SendCoinsRecipient; @@ -34,7 +35,7 @@ class WalletView : public QStackedWidget Q_OBJECT public: - explicit WalletView(QWidget *parent); + explicit WalletView(const PlatformStyle *platformStyle, QWidget *parent); ~WalletView(); void setBitcoinGUI(BitcoinGUI *gui); @@ -64,8 +65,9 @@ private: TransactionView *transactionView; QProgressDialog *progressDialog; + const PlatformStyle *platformStyle; -public slots: +public Q_SLOTS: /** Switch to overview (home) page */ void gotoOverviewPage(); /** Switch to history (transactions) page */ @@ -105,7 +107,7 @@ public slots: /** Show progress dialog e.g. for rescan */ void showProgress(const QString &title, int nProgress); -signals: +Q_SIGNALS: /** Signal that we want to show the main window */ void showNormalIfMinimized(); /** Fired when a message should be reported to the user */ diff --git a/src/rest.cpp b/src/rest.cpp index 1fce7dfc9c..0dd238b683 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chain.h" #include "primitives/block.h" #include "primitives/transaction.h" #include "main.h" @@ -20,7 +21,7 @@ using namespace std; -static const int MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once +static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once enum RetFormat { RF_UNDEF, @@ -65,6 +66,7 @@ public: extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); +extern UniValue blockheaderToJSON(const CBlockIndex* blockindex); static RestErr RESTERR(enum HTTPStatusCode status, string message) { @@ -134,14 +136,14 @@ static bool rest_headers(AcceptedConnection* conn, if (!ParseHashStr(hashStr, hash)) throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); - std::vector<CBlockHeader> headers; + std::vector<const CBlockIndex *> headers; headers.reserve(count); { LOCK(cs_main); BlockMap::const_iterator it = mapBlockIndex.find(hash); const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : NULL; while (pindex != NULL && chainActive.Contains(pindex)) { - headers.push_back(pindex->GetBlockHeader()); + headers.push_back(pindex); if (headers.size() == (unsigned long)count) break; pindex = chainActive.Next(pindex); @@ -149,8 +151,8 @@ static bool rest_headers(AcceptedConnection* conn, } CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); - BOOST_FOREACH(const CBlockHeader &header, headers) { - ssHeader << header; + BOOST_FOREACH(const CBlockIndex *pindex, headers) { + ssHeader << pindex->GetBlockHeader(); } switch (rf) { @@ -166,6 +168,16 @@ static bool rest_headers(AcceptedConnection* conn, return true; } + case RF_JSON: { + UniValue jsonHeaders(UniValue::VARR); + BOOST_FOREACH(const CBlockIndex *pindex, headers) { + jsonHeaders.push_back(blockheaderToJSON(pindex)); + } + string strJSON = jsonHeaders.write() + "\n"; + conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; + return true; + } + default: { throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)"); } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 85229e9857..5817f0ce57 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -3,13 +3,19 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chain.h" +#include "chainparams.h" #include "checkpoints.h" +#include "coins.h" #include "consensus/validation.h" #include "main.h" #include "primitives/transaction.h" #include "rpcserver.h" +#include "streams.h" #include "sync.h" +#include "txmempool.h" #include "util.h" +#include "utilstrencodings.h" #include <stdint.h> @@ -51,6 +57,31 @@ double GetDifficulty(const CBlockIndex* blockindex) return dDiff; } +UniValue blockheaderToJSON(const CBlockIndex* blockindex) +{ + UniValue result(UniValue::VOBJ); + result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); + int confirmations = -1; + // Only report confirmations if the block is on the main chain + if (chainActive.Contains(blockindex)) + confirmations = chainActive.Height() - blockindex->nHeight + 1; + result.push_back(Pair("confirmations", confirmations)); + result.push_back(Pair("height", blockindex->nHeight)); + result.push_back(Pair("version", blockindex->nVersion)); + result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); + result.push_back(Pair("time", (int64_t)blockindex->nTime)); + result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); + result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); + result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); + + if (blockindex->pprev) + result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); + CBlockIndex *pnext = chainActive.Next(blockindex); + if (pnext) + result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); + return result; +} UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { @@ -92,7 +123,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx return result; } - UniValue getblockcount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -255,6 +285,62 @@ UniValue getblockhash(const UniValue& params, bool fHelp) return pblockindex->GetBlockHash().GetHex(); } +UniValue getblockheader(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblockheader \"hash\" ( verbose )\n" + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n" + "If verbose is true, returns an Object with information about blockheader <hash>.\n" + "\nArguments:\n" + "1. \"hash\" (string, required) The block hash\n" + "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" + "\nResult (for verbose = true):\n" + "{\n" + " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" + " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" + " \"height\" : n, (numeric) The block height or index\n" + " \"version\" : n, (numeric) The block version\n" + " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" + " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"nonce\" : n, (numeric) The nonce\n" + " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"difficulty\" : x.xxx, (numeric) The difficulty\n" + " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" + " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" + "}\n" + "\nResult (for verbose=false):\n" + "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\nExamples:\n" + + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + ); + + LOCK(cs_main); + + std::string strHash = params[0].get_str(); + uint256 hash(uint256S(strHash)); + + bool fVerbose = true; + if (params.size() > 1) + fVerbose = params[1].get_bool(); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (!fVerbose) + { + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + ssBlock << pblockindex->GetBlockHeader(); + std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); + return strHex; + } + + return blockheaderToJSON(pblockindex); +} + UniValue getblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) @@ -469,6 +555,36 @@ UniValue verifychain(const UniValue& params, bool fHelp) return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth); } +/** Implementation of IsSuperMajority with better feedback */ +static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams) +{ + int nFound = 0; + CBlockIndex* pstart = pindex; + for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++) + { + if (pstart->nVersion >= minVersion) + ++nFound; + pstart = pstart->pprev; + } + + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("status", nFound >= nRequired)); + rv.push_back(Pair("found", nFound)); + rv.push_back(Pair("required", nRequired)); + rv.push_back(Pair("window", consensusParams.nMajorityWindow)); + return rv; +} + +static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) +{ + UniValue rv(UniValue::VOBJ); + rv.push_back(Pair("id", name)); + rv.push_back(Pair("version", version)); + rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams))); + rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams))); + return rv; +} + UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -484,6 +600,21 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n" + " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n" + " \"pruneheight\": xxxxxx, (numeric) heighest block available\n" + " \"softforks\": [ (array) status of softforks in progress\n" + " {\n" + " \"id\": \"xxxx\", (string) name of softfork\n" + " \"version\": xx, (numeric) block version\n" + " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n" + " \"status\": xx, (boolean) true if threshold reached\n" + " \"found\": xx, (numeric) number of blocks with the new version found\n" + " \"required\": xx, (numeric) number of blocks required to trigger\n" + " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n" + " },\n" + " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" + " }, ...\n" + " ]\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") @@ -501,6 +632,14 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); + + const Consensus::Params& consensusParams = Params().GetConsensus(); + CBlockIndex* tip = chainActive.Tip(); + UniValue softforks(UniValue::VARR); + softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); + softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); + obj.push_back(Pair("softforks", softforks)); + if (fPruneMode) { CBlockIndex *block = chainActive.Tip(); @@ -627,6 +766,7 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp) "{\n" " \"size\": xxxxx (numeric) Current tx count\n" " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n" + " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n" "}\n" "\nExamples:\n" + HelpExampleCli("getmempoolinfo", "") @@ -636,6 +776,7 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp) UniValue ret(UniValue::VOBJ); ret.push_back(Pair("size", (int64_t) mempool.size())); ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize())); + ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage())); return ret; } diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 4c6b47e4a0..b41e960e8a 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -71,6 +71,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listunspent", 1 }, { "listunspent", 2 }, { "getblock", 1 }, + { "getblockheader", 1 }, { "gettransaction", 1 }, { "getrawtransaction", 1 }, { "createrawtransaction", 0 }, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index f332814611..b7d4ff58fc 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amount.h" +#include "chain.h" #include "chainparams.h" #include "consensus/consensus.h" #include "consensus/validation.h" @@ -14,15 +15,15 @@ #include "net.h" #include "pow.h" #include "rpcserver.h" +#include "txmempool.h" #include "util.h" +#include "utilstrencodings.h" #include "validationinterface.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif #include <stdint.h> #include <boost/assign/list_of.hpp> +#include <boost/shared_ptr.hpp> #include "univalue/univalue.h" @@ -92,7 +93,6 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp) return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } -#ifdef ENABLE_WALLET UniValue getgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -127,8 +127,6 @@ UniValue generate(const UniValue& params, bool fHelp) + HelpExampleCli("generate", "11") ); - if (pwalletMain == NULL) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); if (!Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); @@ -136,7 +134,13 @@ UniValue generate(const UniValue& params, bool fHelp) int nHeightEnd = 0; int nHeight = 0; int nGenerate = params[0].get_int(); - CReserveKey reservekey(pwalletMain); + + boost::shared_ptr<CReserveScript> coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + //throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); { // Don't keep cs_main locked LOCK(cs_main); @@ -148,9 +152,9 @@ UniValue generate(const UniValue& params, bool fHelp) UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey)); + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); @@ -166,11 +170,13 @@ UniValue generate(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); + + //mark script as important because it was used at least for one coinbase output + coinbaseScript->KeepScript(); } return blockHashes; } - UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) @@ -193,8 +199,6 @@ UniValue setgenerate(const UniValue& params, bool fHelp) + HelpExampleRpc("setgenerate", "true, 1") ); - if (pwalletMain == NULL) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); if (Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); @@ -212,12 +216,10 @@ UniValue setgenerate(const UniValue& params, bool fHelp) mapArgs["-gen"] = (fGenerate ? "1" : "0"); mapArgs ["-genproclimit"] = itostr(nGenProcLimit); - GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); + GenerateBitcoins(fGenerate, nGenProcLimit, Params()); return NullUniValue; } -#endif - UniValue getmininginfo(const UniValue& params, bool fHelp) { @@ -257,9 +259,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); -#ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); -#endif return obj; } @@ -669,16 +669,15 @@ UniValue estimatefee(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "estimatefee nblocks\n" - "\nEstimates the approximate fee per kilobyte\n" - "needed for a transaction to begin confirmation\n" - "within nblocks blocks.\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within nblocks blocks.\n" "\nArguments:\n" "1. nblocks (numeric)\n" "\nResult:\n" - "n : (numeric) estimated fee-per-kilobyte\n" + "n (numeric) estimated fee-per-kilobyte\n" "\n" - "-1.0 is returned if not enough transactions and\n" - "blocks have been observed to make an estimate.\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate.\n" "\nExample:\n" + HelpExampleCli("estimatefee", "6") ); @@ -701,16 +700,15 @@ UniValue estimatepriority(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "estimatepriority nblocks\n" - "\nEstimates the approximate priority\n" - "a zero-fee transaction needs to begin confirmation\n" - "within nblocks blocks.\n" + "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" + "confirmation within nblocks blocks.\n" "\nArguments:\n" "1. nblocks (numeric)\n" "\nResult:\n" - "n : (numeric) estimated priority\n" + "n (numeric) estimated priority\n" "\n" - "-1.0 is returned if not enough transactions and\n" - "blocks have been observed to make an estimate.\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate.\n" "\nExample:\n" + HelpExampleCli("estimatepriority", "6") ); diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index cab57d7027..82003e09b9 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -12,6 +12,7 @@ #include "rpcserver.h" #include "timedata.h" #include "util.h" +#include "utilstrencodings.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #include "wallet/walletdb.h" diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 1572b16687..ed903f9fd3 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -4,6 +4,7 @@ #include "rpcserver.h" +#include "chainparams.h" #include "clientversion.h" #include "main.h" #include "net.h" @@ -12,6 +13,7 @@ #include "sync.h" #include "timedata.h" #include "util.h" +#include "utilstrencodings.h" #include "version.h" #include <boost/foreach.hpp> @@ -515,7 +517,7 @@ UniValue setban(const UniValue& params, bool fHelp) if (params.size() == 4 && params[3].isTrue()) absolute = true; - isSubnet ? CNode::Ban(subNet, banTime, absolute) : CNode::Ban(netAddr, banTime, absolute); + isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); //disconnect possible nodes while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr))) @@ -527,6 +529,7 @@ UniValue setban(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); } + DumpBanlist(); //store banlist to disk return NullUniValue; } @@ -541,15 +544,19 @@ UniValue listbanned(const UniValue& params, bool fHelp) + HelpExampleRpc("listbanned", "") ); - std::map<CSubNet, int64_t> banMap; + banmap_t banMap; CNode::GetBanned(banMap); UniValue bannedAddresses(UniValue::VARR); - for (std::map<CSubNet, int64_t>::iterator it = banMap.begin(); it != banMap.end(); it++) + for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++) { + CBanEntry banEntry = (*it).second; UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", (*it).first.ToString())); - rec.push_back(Pair("banned_untill", (*it).second)); + rec.push_back(Pair("banned_until", banEntry.nBanUntil)); + rec.push_back(Pair("ban_created", banEntry.nCreateTime)); + rec.push_back(Pair("ban_reason", banEntry.banReasonToString())); + bannedAddresses.push_back(rec); } @@ -568,6 +575,7 @@ UniValue clearbanned(const UniValue& params, bool fHelp) ); CNode::ClearBanned(); + DumpBanlist(); //store banlist to disk return NullUniValue; } diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 89dec2977e..2e5c913734 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -6,6 +6,7 @@ #include "rpcprotocol.h" #include "clientversion.h" +#include "random.h" #include "tinyformat.h" #include "util.h" #include "utilstrencodings.h" @@ -13,6 +14,7 @@ #include "version.h" #include <stdint.h> +#include <fstream> #include <boost/algorithm/string.hpp> #include <boost/asio.hpp> @@ -287,3 +289,68 @@ UniValue JSONRPCError(int code, const string& message) error.push_back(Pair("message", message)); return error; } + +/** Username used when cookie authentication is in use (arbitrary, only for + * recognizability in debugging/logging purposes) + */ +static const std::string COOKIEAUTH_USER = "__cookie__"; +/** Default name for auth cookie file */ +static const std::string COOKIEAUTH_FILE = ".cookie"; + +boost::filesystem::path GetAuthCookieFile() +{ + boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE)); + if (!path.is_complete()) path = GetDataDir() / path; + return path; +} + +bool GenerateAuthCookie(std::string *cookie_out) +{ + unsigned char rand_pwd[32]; + GetRandBytes(rand_pwd, 32); + std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32); + + /** the umask determines what permissions are used to create this file - + * these are set to 077 in init.cpp unless overridden with -sysperms. + */ + std::ofstream file; + boost::filesystem::path filepath = GetAuthCookieFile(); + file.open(filepath.string().c_str()); + if (!file.is_open()) { + LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string()); + return false; + } + file << cookie; + file.close(); + LogPrintf("Generated RPC authentication cookie %s\n", filepath.string()); + + if (cookie_out) + *cookie_out = cookie; + return true; +} + +bool GetAuthCookie(std::string *cookie_out) +{ + std::ifstream file; + std::string cookie; + boost::filesystem::path filepath = GetAuthCookieFile(); + file.open(filepath.string().c_str()); + if (!file.is_open()) + return false; + std::getline(file, cookie); + file.close(); + + if (cookie_out) + *cookie_out = cookie; + return true; +} + +void DeleteAuthCookie() +{ + try { + boost::filesystem::remove(GetAuthCookieFile()); + } catch (const boost::filesystem::filesystem_error& e) { + LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what()); + } +} + diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index ccd2439c9f..2360ec2c60 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -14,6 +14,7 @@ #include <boost/iostreams/stream.hpp> #include <boost/asio.hpp> #include <boost/asio/ssl.hpp> +#include <boost/filesystem.hpp> #include "univalue/univalue.h" @@ -165,4 +166,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id); UniValue JSONRPCError(int code, const std::string& message); +/** Get name of RPC authentication cookie file */ +boost::filesystem::path GetAuthCookieFile(); +/** Generate a new RPC authentication cookie and write it to disk */ +bool GenerateAuthCookie(std::string *cookie_out); +/** Read the RPC authentication cookie from disk */ +bool GetAuthCookie(std::string *cookie_out); +/** Delete RPC authentication cookie from disk */ +void DeleteAuthCookie(); + #endif // BITCOIN_RPCPROTOCOL_H diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 20394fc2c1..62d2ef69ef 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -4,6 +4,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" +#include "chain.h" +#include "coins.h" #include "consensus/validation.h" #include "core_io.h" #include "init.h" @@ -11,13 +13,16 @@ #include "main.h" #include "merkleblock.h" #include "net.h" +#include "policy/policy.h" #include "primitives/transaction.h" #include "rpcserver.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" #include "script/standard.h" +#include "txmempool.h" #include "uint256.h" +#include "utilstrencodings.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #endif diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2f28971589..68091010f7 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -11,7 +11,6 @@ #include "sync.h" #include "ui_interface.h" #include "util.h" -#include "utilmoneystr.h" #include "utilstrencodings.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" @@ -121,10 +120,10 @@ void RPCTypeCheckObj(const UniValue& o, CAmount AmountFromValue(const UniValue& value) { - if (!value.isReal() && !value.isNum()) - throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number"); + if (!value.isNum() && !value.isStr()) + throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string"); CAmount amount; - if (!ParseMoney(value.getValStr(), amount)) + if (!ParseFixedPoint(value.getValStr(), 8, &amount)) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); if (!MoneyRange(amount)) throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range"); @@ -133,7 +132,12 @@ CAmount AmountFromValue(const UniValue& value) UniValue ValueFromAmount(const CAmount& amount) { - return UniValue(UniValue::VREAL, FormatMoney(amount)); + bool sign = amount < 0; + int64_t n_abs = (sign ? -amount : amount); + int64_t quotient = n_abs / COIN; + int64_t remainder = n_abs % COIN; + return UniValue(UniValue::VNUM, + strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder)); } uint256 ParseHashV(const UniValue& v, string strName) @@ -289,6 +293,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockcount", &getblockcount, true }, { "blockchain", "getblock", &getblock, true }, { "blockchain", "getblockhash", &getblockhash, true }, + { "blockchain", "getblockheader", &getblockheader, true }, { "blockchain", "getchaintips", &getchaintips, true }, { "blockchain", "getdifficulty", &getdifficulty, true }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, @@ -306,12 +311,10 @@ static const CRPCCommand vRPCCommands[] = { "mining", "prioritisetransaction", &prioritisetransaction, true }, { "mining", "submitblock", &submitblock, true }, -#ifdef ENABLE_WALLET /* Coin generation */ { "generating", "getgenerate", &getgenerate, true }, { "generating", "setgenerate", &setgenerate, true }, { "generating", "generate", &generate, true }, -#endif /* Raw transactions */ { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, @@ -598,28 +601,18 @@ void StartRPCThreads() strAllowed += subnet.ToString() + " "; LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed); - strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; - if (((mapArgs["-rpcpassword"] == "") || - (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword()) + if (mapArgs["-rpcpassword"] == "") { - unsigned char rand_pwd[32]; - GetRandBytes(rand_pwd, 32); - uiInterface.ThreadSafeMessageBox(strprintf( - _("To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file:\n" - "%s\n" - "It is recommended you use the following random password:\n" - "rpcuser=bitcoinrpc\n" - "rpcpassword=%s\n" - "(you do not need to remember this password)\n" - "The username and password MUST NOT be the same.\n" - "If the file does not exist, create it with owner-readable-only file permissions.\n" - "It is also recommended to set alertnotify so you are notified of problems;\n" - "for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@foo.com\n"), - GetConfigFile().string(), - EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)), - "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE); - StartShutdown(); - return; + LogPrintf("No rpcpassword set - using random cookie authentication\n"); + if (!GenerateAuthCookie(&strRPCUserColonPass)) { + uiInterface.ThreadSafeMessageBox( + _("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return; + } + } else { + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; } assert(rpc_io_service == NULL); @@ -759,17 +752,19 @@ void StopRPCThreads() { acceptor->cancel(ec); if (ec) - LogPrintf("%s: Warning: %s when cancelling acceptor", __func__, ec.message()); + LogPrintf("%s: Warning: %s when cancelling acceptor\n", __func__, ec.message()); } rpc_acceptors.clear(); BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr<deadline_timer>) &timer, deadlineTimers) { timer.second->cancel(ec); if (ec) - LogPrintf("%s: Warning: %s when cancelling timer", __func__, ec.message()); + LogPrintf("%s: Warning: %s when cancelling timer\n", __func__, ec.message()); } deadlineTimers.clear(); + DeleteAuthCookie(); + rpc_io_service->stop(); g_rpcSignals.Stopped(); if (rpc_worker_group != NULL) @@ -932,13 +927,6 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, if (!valRequest.read(strRequest)) throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); - // Return immediately if in warmup - { - LOCK(cs_rpcWarmup); - if (fRPCInWarmup) - throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus); - } - string strReply; // singleton request @@ -1010,6 +998,13 @@ void ServiceConnection(AcceptedConnection *conn) UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms) const { + // Return immediately if in warmup + { + LOCK(cs_rpcWarmup); + if (fRPCInWarmup) + throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus); + } + // Find method const CRPCCommand *pcmd = tableRPC[strMethod]; if (!pcmd) diff --git a/src/rpcserver.h b/src/rpcserver.h index 45af10c2a8..89d3980223 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -234,6 +234,7 @@ extern UniValue settxfee(const UniValue& params, bool fHelp); extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); extern UniValue getrawmempool(const UniValue& params, bool fHelp); extern UniValue getblockhash(const UniValue& params, bool fHelp); +extern UniValue getblockheader(const UniValue& params, bool fHelp); extern UniValue getblock(const UniValue& params, bool fHelp); extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); extern UniValue gettxout(const UniValue& params, bool fHelp); diff --git a/src/script/script.h b/src/script/script.h index c09899aabd..e39ca57f4f 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -609,4 +609,13 @@ public: } }; +class CReserveScript +{ +public: + CScript reserveScript; + virtual void KeepScript() {} + CReserveScript() {} + virtual ~CReserveScript() {} +}; + #endif // BITCOIN_SCRIPT_SCRIPT_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 4543ca303f..8b43183b6d 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -5,9 +5,10 @@ #include "script/sign.h" -#include "primitives/transaction.h" #include "key.h" #include "keystore.h" +#include "policy/policy.h" +#include "primitives/transaction.h" #include "script/standard.h" #include "uint256.h" diff --git a/src/script/standard.cpp b/src/script/standard.cpp index ce50e3aad8..66657127ab 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -180,26 +180,6 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c return -1; } -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) -{ - vector<valtype> vSolutions; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; - - if (whichType == TX_MULTISIG) - { - unsigned char m = vSolutions.front()[0]; - unsigned char n = vSolutions.back()[0]; - // Support up to x-of-3 multisig txns as standard - if (n < 1 || n > 3) - return false; - if (m < 1 || m > n) - return false; - } - - return whichType != TX_NONSTANDARD; -} - bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { vector<valtype> vSolutions; diff --git a/src/script/standard.h b/src/script/standard.h index 3b401dfe4f..46ae5f9f10 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -39,23 +39,6 @@ extern unsigned nMaxDatacarrierBytes; */ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH; -/** - * Standard script verification flags that standard transactions will comply - * with. However scripts violating these flags may still be present in valid - * blocks and we must accept those blocks. - */ -static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | - SCRIPT_VERIFY_DERSIG | - SCRIPT_VERIFY_STRICTENC | - SCRIPT_VERIFY_MINIMALDATA | - SCRIPT_VERIFY_NULLDUMMY | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | - SCRIPT_VERIFY_CLEANSTACK | - SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; - -/** For convenience, standard but not mandatory verify flags. */ -static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; - enum txnouttype { TX_NONSTANDARD, @@ -86,7 +69,6 @@ const char* GetTxnOutputType(txnouttype t); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions); -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); diff --git a/src/sync.cpp b/src/sync.cpp index a422939964..1837e8d53d 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -33,20 +33,22 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine) // struct CLockLocation { - CLockLocation(const char* pszName, const char* pszFile, int nLine) + CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn) { mutexName = pszName; sourceFile = pszFile; sourceLine = nLine; + fTry = fTryIn; } std::string ToString() const { - return mutexName + " " + sourceFile + ":" + itostr(sourceLine); + return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : ""); } std::string MutexName() const { return mutexName; } + bool fTry; private: std::string mutexName; std::string sourceFile; @@ -62,23 +64,52 @@ static boost::thread_specific_ptr<LockStack> lockstack; static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) { + // We attempt to not assert on probably-not deadlocks by assuming that + // a try lock will immediately have otherwise bailed if it had + // failed to get the lock + // We do this by, for the locks which triggered the potential deadlock, + // in either lockorder, checking that the second of the two which is locked + // is only a TRY_LOCK, ignoring locks if they are reentrant. + bool firstLocked = false; + bool secondLocked = false; + bool onlyMaybeDeadlock = false; + LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); LogPrintf("Previous lock order was:\n"); BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) { - if (i.first == mismatch.first) + if (i.first == mismatch.first) { LogPrintf(" (1)"); - if (i.first == mismatch.second) + if (!firstLocked && secondLocked && i.second.fTry) + onlyMaybeDeadlock = true; + firstLocked = true; + } + if (i.first == mismatch.second) { LogPrintf(" (2)"); + if (!secondLocked && firstLocked && i.second.fTry) + onlyMaybeDeadlock = true; + secondLocked = true; + } LogPrintf(" %s\n", i.second.ToString()); } + firstLocked = false; + secondLocked = false; LogPrintf("Current lock order is:\n"); BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) { - if (i.first == mismatch.first) + if (i.first == mismatch.first) { LogPrintf(" (1)"); - if (i.first == mismatch.second) + if (!firstLocked && secondLocked && i.second.fTry) + onlyMaybeDeadlock = true; + firstLocked = true; + } + if (i.first == mismatch.second) { LogPrintf(" (2)"); + if (!secondLocked && firstLocked && i.second.fTry) + onlyMaybeDeadlock = true; + secondLocked = true; + } LogPrintf(" %s\n", i.second.ToString()); } + assert(onlyMaybeDeadlock); } static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) @@ -101,10 +132,8 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) lockorders[p1] = (*lockstack); std::pair<void*, void*> p2 = std::make_pair(c, i.first); - if (lockorders.count(p2)) { + if (lockorders.count(p2)) potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); - break; - } } } dd_mutex.unlock(); @@ -119,7 +148,7 @@ static void pop_lock() void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) { - push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); + push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry); } void LeaveCritical() diff --git a/src/sync.h b/src/sync.h index 78b9043477..705647e4a5 100644 --- a/src/sync.h +++ b/src/sync.h @@ -101,7 +101,7 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine); /** Wrapper around boost::unique_lock<Mutex> */ template <typename Mutex> -class CMutexLock +class SCOPED_LOCKABLE CMutexLock { private: boost::unique_lock<Mutex> lock; @@ -129,7 +129,7 @@ private: } public: - CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock) + CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); @@ -137,7 +137,7 @@ public: Enter(pszName, pszFile, nLine); } - CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) + CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; @@ -148,7 +148,7 @@ public: Enter(pszName, pszFile, nLine); } - ~CMutexLock() + ~CMutexLock() UNLOCK_FUNCTION() { if (lock.owns_lock()) LeaveCritical(); diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index bf25548755..da296a0461 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -2,12 +2,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -// // Unit tests for denial-of-service detection/prevention code -// - - +#include "chainparams.h" #include "keystore.h" #include "main.h" #include "net.h" diff --git a/src/test/README.md b/src/test/README.md index 7efce6f052..e36112bd4f 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -18,4 +18,16 @@ uint256_tests.cpp. For further reading, I found the following website to be helpful in explaining how the boost unit test framework works: -[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/).
\ No newline at end of file +[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/). + +test_bitcoin has some built-in command-line arguments; for +example, to run just the getarg_tests verbosely: + + test_bitcoin --log_level=all --run_test=getarg_tests + +... or to run just the doubledash test: + + test_bitcoin --run_test=getarg_tests/doubledash + +Run test_bitcoin --help for the full list. + diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 38dcc6023c..b8d5606cc3 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -2,17 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -// // Unit tests for alert system -// #include "alert.h" #include "chain.h" #include "chainparams.h" #include "clientversion.h" #include "data/alertTests.raw.h" - -#include "main.h" +#include "main.h" // For PartitionCheck #include "serialize.h" #include "streams.h" #include "util.h" diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 0d815c27fd..69084213a2 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -88,12 +88,23 @@ void RunTest(const TestVector &test) { unsigned char data[74]; key.Encode(data); pubkey.Encode(data); + // Test private key CBitcoinExtKey b58key; b58key.SetKey(key); BOOST_CHECK(b58key.ToString() == derive.prv); + + CBitcoinExtKey b58keyDecodeCheck(derive.prv); + CExtKey checkKey = b58keyDecodeCheck.GetKey(); + assert(checkKey == key); //ensure a base58 decoded key also matches + // Test public key CBitcoinExtPubKey b58pubkey; b58pubkey.SetKey(pubkey); BOOST_CHECK(b58pubkey.ToString() == derive.pub); + + CBitcoinExtPubKey b58PubkeyDecodeCheck(derive.pub); + CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey(); + assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches + // Derive new keys CExtKey keyNew; BOOST_CHECK(key.Derive(keyNew, derive.nChild)); diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 51530c4de5..f7e2470617 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -4,7 +4,8 @@ #include "clientversion.h" #include "consensus/validation.h" -#include "main.h" +#include "main.h" // For CheckBlock +#include "primitives/block.h" #include "test/test_bitcoin.h" #include "utiltime.h" diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 34b311b804..13d848311a 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -70,9 +70,9 @@ public: // Manually recompute the dynamic usage of the whole data, and compare it. size_t ret = memusage::DynamicUsage(cacheCoins); for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) { - ret += memusage::DynamicUsage(it->second.coins); + ret += it->second.coins.DynamicMemoryUsage(); } - BOOST_CHECK_EQUAL(memusage::DynamicUsage(*this), ret); + BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret); } }; diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json index 6090421cb6..afd35af503 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/src/test/data/bitcoin-util-test.json @@ -52,7 +52,7 @@ ["-create", "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", - "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", "sign=ALL", "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], "output_cmp": "txcreatesign.hex" diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index 9def4042da..20bdbd08a5 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -137,6 +137,8 @@ ["Argument missing"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Argument negative with by-blockheight nLockTime=0"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]], @@ -145,10 +147,14 @@ ["Argument negative with by-blocktime nLockTime=500,000,000"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Input locked"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"], ["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] , @@ -158,6 +164,8 @@ ["Argument/tx height/time mismatch, both versions"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]], "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]], diff --git a/src/test/data/txcreatesign.hex b/src/test/data/txcreatesign.hex index 56ce28a865..a46fcc88cb 100644 --- a/src/test/data/txcreatesign.hex +++ b/src/test/data/txcreatesign.hex @@ -1 +1 @@ -01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d0000000000ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000 +01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000 diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 0996e13c48..2439689d7f 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -2,7 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "main.h" #include "txmempool.h" #include "util.h" diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 212be0d2d6..ad79a558c2 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -2,12 +2,17 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chainparams.h" +#include "coins.h" #include "consensus/validation.h" #include "main.h" #include "miner.h" #include "pubkey.h" +#include "script/standard.h" +#include "txmempool.h" #include "uint256.h" #include "util.h" +#include "utilstrencodings.h" #include "test/test_bitcoin.h" diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 6b189a6b55..b65c299adc 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -4,7 +4,7 @@ #include "key.h" #include "keystore.h" -#include "main.h" +#include "policy/policy.h" #include "script/script.h" #include "script/script_error.h" #include "script/interpreter.h" diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 0f5e1615c6..7154476c7c 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -143,6 +143,17 @@ BOOST_AUTO_TEST_CASE(subnet_test) BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/128").IsValid()); BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/129").IsValid()); BOOST_CHECK(!CSubNet("fuzzy").IsValid()); + + //CNetAddr constructor test + BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).IsValid()); + BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.1"))); + BOOST_CHECK(!CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.2"))); + BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).ToString() == "127.0.0.1/255.255.255.255"); + + BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).IsValid()); + BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:8"))); + BOOST_CHECK(!CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:9"))); + BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index a436749287..b6eb39bc38 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -2,8 +2,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "main.h" +#include "chain.h" +#include "chainparams.h" #include "pow.h" +#include "random.h" #include "util.h" #include "test/test_bitcoin.h" diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index c38df0ecf3..7946b02855 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -120,6 +120,29 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000"); BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990"); BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999"); + + BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000"); + BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000"); + + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001"); } static UniValue ValueFromString(const std::string &str) @@ -142,6 +165,24 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL); + + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1e-8")), COIN/100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.1e-7")), COIN/100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.01e-6")), COIN/100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68")), COIN/100000000); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("10000000000000000000000000000000000000000000000000000000000000000e-64")), COIN); + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000e64")), COIN); + + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e-9")), UniValue); //should fail + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("0.000000019")), UniValue); //should fail + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001000000")), 1LL); //should pass, cut trailing 0 + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("19e-9")), UniValue); //should fail + BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.19e-6")), 19); //should pass, leading 0 is present + + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("92233720368.54775808")), UniValue); //overflow error + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e+11")), UniValue); //overflow error + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e11")), UniValue); //overflow error signless + BOOST_CHECK_THROW(AmountFromValue(ValueFromString("93e+9")), UniValue); //overflow error } BOOST_AUTO_TEST_CASE(json_parse_errors) @@ -151,6 +192,9 @@ BOOST_AUTO_TEST_CASE(json_parse_errors) // Valid, with leading or trailing whitespace BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0); BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0); + + BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(".19e-6")), std::runtime_error); //should fail, missing leading 0, therefore invalid JSON + BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue("0.00000000000000000000000000000000000001e+30 ")), 1); // Invalid, initial garbage BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error); BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error); @@ -199,7 +243,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); - UniValue banned_until = find_value(o1, "banned_untill"); + UniValue banned_until = find_value(o1, "banned_until"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0"); BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check @@ -210,7 +254,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); - banned_until = find_value(o1, "banned_untill"); + banned_until = find_value(o1, "banned_until"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0"); int64_t now = GetTime(); BOOST_CHECK(banned_until.get_int64() > now); diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index c8cfe28729..16c9a4a868 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -5,6 +5,7 @@ #include "key.h" #include "keystore.h" #include "main.h" +#include "policy/policy.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 3733425699..37c046935f 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -8,11 +8,11 @@ #include "core_io.h" #include "key.h" #include "keystore.h" -#include "main.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" #include "util.h" +#include "utilstrencodings.h" #include "test/test_bitcoin.h" #if defined(HAVE_CONSENSUS_LIB) diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index a0797d5f3f..4b96461562 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -4,13 +4,16 @@ #include "consensus/validation.h" #include "data/sighash.json.h" -#include "main.h" +#include "hash.h" +#include "main.h" // For CheckTransaction #include "random.h" #include "script/interpreter.h" #include "script/script.h" #include "serialize.h" +#include "streams.h" #include "test/test_bitcoin.h" #include "util.h" +#include "utilstrencodings.h" #include "version.h" #include <iostream> diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 86a4bc6727..a904e3862f 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "main.h" +#include "chain.h" #include "random.h" #include "util.h" #include "test/test_bitcoin.h" diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index c727303ea1..8d81275a6f 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -6,8 +6,13 @@ #include "test_bitcoin.h" +#include "chainparams.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" #include "key.h" #include "main.h" +#include "miner.h" +#include "pubkey.h" #include "random.h" #include "txdb.h" #include "ui_interface.h" @@ -27,20 +32,22 @@ CWallet* pwalletMain; extern bool fPrintToConsole; extern void noui_connect(); -BasicTestingSetup::BasicTestingSetup() +BasicTestingSetup::BasicTestingSetup(CBaseChainParams::Network network) { ECC_Start(); SetupEnvironment(); fPrintToDebugLog = false; // don't want to write to debug.log file fCheckBlockIndex = true; - SelectParams(CBaseChainParams::MAIN); + SelectParams(network); + noui_connect(); } + BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); } -TestingSetup::TestingSetup() +TestingSetup::TestingSetup(CBaseChainParams::Network network) : BasicTestingSetup(network) { #ifdef ENABLE_WALLET bitdb.MakeMock(); @@ -86,6 +93,51 @@ TestingSetup::~TestingSetup() boost::filesystem::remove_all(pathTemp); } +TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) +{ + // Generate a 100-block chain: + coinbaseKey.MakeNewKey(true); + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + for (int i = 0; i < COINBASE_MATURITY; i++) + { + std::vector<CMutableTransaction> noTxns; + CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); + coinbaseTxns.push_back(b.vtx[0]); + } +} + +// +// Create a new block with just given transactions, coinbase paying to +// scriptPubKey, and try to add it to the current chain. +// +CBlock +TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey) +{ + CBlockTemplate *pblocktemplate = CreateNewBlock(scriptPubKey); + CBlock& block = pblocktemplate->block; + + // Replace mempool-selected txns with just coinbase plus passed-in txns: + block.vtx.resize(1); + BOOST_FOREACH(const CMutableTransaction& tx, txns) + block.vtx.push_back(tx); + // IncrementExtraNonce creates a valid coinbase and merkleRoot + unsigned int extraNonce = 0; + IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); + + while (!CheckProofOfWork(block.GetHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce; + + CValidationState state; + ProcessNewBlock(state, NULL, &block, true, NULL); + + CBlock result = block; + delete pblocktemplate; + return result; +} + +TestChain100Setup::~TestChain100Setup() +{ +} + void Shutdown(void* parg) { exit(0); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 2f75332d40..b9314d0611 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -1,6 +1,8 @@ #ifndef BITCOIN_TEST_TEST_BITCOIN_H #define BITCOIN_TEST_TEST_BITCOIN_H +#include "chainparamsbase.h" +#include "key.h" #include "txdb.h" #include <boost/filesystem.hpp> @@ -10,7 +12,7 @@ * This just configures logging and chain parameters. */ struct BasicTestingSetup { - BasicTestingSetup(); + BasicTestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN); ~BasicTestingSetup(); }; @@ -23,8 +25,30 @@ struct TestingSetup: public BasicTestingSetup { boost::filesystem::path pathTemp; boost::thread_group threadGroup; - TestingSetup(); + TestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN); ~TestingSetup(); }; +class CBlock; +struct CMutableTransaction; +class CScript; + +// +// Testing fixture that pre-creates a +// 100-block REGTEST-mode block chain +// +struct TestChain100Setup : public TestingSetup { + TestChain100Setup(); + + // Create a new block with just given transactions, coinbase paying to + // scriptPubKey, and try to add it to the current chain. + CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, + const CScript& scriptPubKey); + + ~TestChain100Setup(); + + std::vector<CTransaction> coinbaseTxns; // For convenience, coinbase transactions + CKey coinbaseKey; // private/public key needed to spend coinbase transactions +}; + #endif diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 9ce7aae966..e70ebddc2f 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -11,9 +11,11 @@ #include "core_io.h" #include "key.h" #include "keystore.h" -#include "main.h" +#include "main.h" // For CheckTransaction +#include "policy/policy.h" #include "script/script.h" #include "script/script_error.h" +#include "utilstrencodings.h" #include <map> #include <string> diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp new file mode 100644 index 0000000000..edad18644e --- /dev/null +++ b/src/test/txvalidationcache_tests.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2011-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "consensus/validation.h" +#include "key.h" +#include "main.h" +#include "miner.h" +#include "pubkey.h" +#include "txmempool.h" +#include "random.h" +#include "script/standard.h" +#include "test/test_bitcoin.h" +#include "utiltime.h" + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_SUITE(tx_validationcache_tests) + +static bool +ToMemPool(CMutableTransaction& tx) +{ + LOCK(cs_main); + + CValidationState state; + return AcceptToMemoryPool(mempool, state, tx, false, NULL, false); +} + +BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) +{ + // Make sure skipping validation of transctions that were + // validated going into the memory pool does not allow + // double-spends in blocks to pass validation when they should not. + + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + + // Create a double-spend of mature coinbase txn: + std::vector<CMutableTransaction> spends; + spends.resize(2); + for (int i = 0; i < 2; i++) + { + spends[i].vin.resize(1); + spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash(); + spends[i].vin[0].prevout.n = 0; + spends[i].vout.resize(1); + spends[i].vout[0].nValue = 11*CENT; + spends[i].vout[0].scriptPubKey = scriptPubKey; + + // Sign: + std::vector<unsigned char> vchSig; + uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL); + BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); + vchSig.push_back((unsigned char)SIGHASH_ALL); + spends[i].vin[0].scriptSig << vchSig; + } + + CBlock block; + + // Test 1: block with both of those transactions should be rejected. + block = CreateAndProcessBlock(spends, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + + // Test 2: ... and should be rejected if spend1 is in the memory pool + BOOST_CHECK(ToMemPool(spends[0])); + block = CreateAndProcessBlock(spends, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + mempool.clear(); + + // Test 3: ... and should be rejected if spend2 is in the memory pool + BOOST_CHECK(ToMemPool(spends[1])); + block = CreateAndProcessBlock(spends, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + mempool.clear(); + + // Final sanity test: first spend in mempool, second in block, that's OK: + std::vector<CMutableTransaction> oneSpend; + oneSpend.push_back(spends[0]); + BOOST_CHECK(ToMemPool(spends[1])); + block = CreateAndProcessBlock(oneSpend, scriptPubKey); + BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); + // spends[1] should have been removed from the mempool when the + // block with spends[0] is accepted: + BOOST_CHECK_EQUAL(mempool.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index 16bc8d30f6..67cb9b9623 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor) double vd = -7.21; UniValue v7(vd); - BOOST_CHECK(v7.isReal()); + BOOST_CHECK(v7.isNum()); BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); string vs("yawn"); @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(univalue_set) BOOST_CHECK_EQUAL(v.getValStr(), "zum"); BOOST_CHECK(v.setFloat(-1.01)); - BOOST_CHECK(v.isReal()); + BOOST_CHECK(v.isNum()); BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); BOOST_CHECK(v.setInt((int)1023)); @@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(univalue_object) objTypes["distance"] = UniValue::VNUM; objTypes["time"] = UniValue::VNUM; objTypes["calories"] = UniValue::VNUM; - objTypes["temperature"] = UniValue::VREAL; + objTypes["temperature"] = UniValue::VNUM; objTypes["cat1"] = UniValue::VNUM; objTypes["cat2"] = UniValue::VNUM; BOOST_CHECK(obj.checkObject(objTypes)); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 5cb5894251..e956cc5b90 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -418,4 +418,70 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion) BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/")); BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; comment2)/")); } + +BOOST_AUTO_TEST_CASE(test_ParseFixedPoint) +{ + int64_t amount = 0; + BOOST_CHECK(ParseFixedPoint("0", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 0LL); + BOOST_CHECK(ParseFixedPoint("1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 100000000LL); + BOOST_CHECK(ParseFixedPoint("0.0", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 0LL); + BOOST_CHECK(ParseFixedPoint("-0.1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -10000000LL); + BOOST_CHECK(ParseFixedPoint("1.1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 110000000LL); + BOOST_CHECK(ParseFixedPoint("1.10000000000000000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 110000000LL); + BOOST_CHECK(ParseFixedPoint("1.1e1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 1100000000LL); + BOOST_CHECK(ParseFixedPoint("1.1e-1", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 11000000LL); + BOOST_CHECK(ParseFixedPoint("1000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 100000000000LL); + BOOST_CHECK(ParseFixedPoint("-1000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -100000000000LL); + BOOST_CHECK(ParseFixedPoint("0.00000001", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 1LL); + BOOST_CHECK(ParseFixedPoint("0.0000000100000000", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 1LL); + BOOST_CHECK(ParseFixedPoint("-0.00000001", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -1LL); + BOOST_CHECK(ParseFixedPoint("1000000000.00000001", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 100000000000000001LL); + BOOST_CHECK(ParseFixedPoint("9999999999.99999999", 8, &amount)); + BOOST_CHECK_EQUAL(amount, 999999999999999999LL); + BOOST_CHECK(ParseFixedPoint("-9999999999.99999999", 8, &amount)); + BOOST_CHECK_EQUAL(amount, -999999999999999999LL); + + BOOST_CHECK(!ParseFixedPoint("", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("a-1000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-a1000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-1000a", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-01000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("00.1", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint(".1", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("--0.1", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("0.000000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-0.000000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("0.00000001000000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-10000000000.00000000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("10000000000.00000000", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-10000000000.00000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("10000000000.00000001", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-10000000000.00000009", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("10000000000.00000009", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-99999999999.99999999", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("99999909999.09999999", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("92233720368.54775807", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("92233720368.54775808", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-92233720368.54775808", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("-92233720368.54775809", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount)); + BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount)); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txdb.cpp b/src/txdb.cpp index 935b784676..21ecd65238 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -5,6 +5,7 @@ #include "txdb.h" +#include "chain.h" #include "chainparams.h" #include "hash.h" #include "main.h" diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1c16e2092e..c921dae45d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -18,7 +18,7 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(): - nFee(0), nTxSize(0), nModSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false) + nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false) { nHeight = MEMPOOL_HEIGHT; } @@ -31,6 +31,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); + nUsageSize = RecursiveDynamicUsage(tx); } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -101,6 +102,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); + cachedInnerUsage += entry.DynamicMemoryUsage(); minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); return true; @@ -146,6 +148,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem removed.push_back(tx); totalTxSize -= mapTx[hash].GetTxSize(); + cachedInnerUsage -= mapTx[hash].DynamicMemoryUsage(); mapTx.erase(hash); nTransactionsUpdated++; minerPolicyEstimator->removeTx(hash); @@ -166,7 +169,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); if (fSanityCheck) assert(coins); - if (!coins || (coins->IsCoinBase() && nMemPoolHeight - coins->nHeight < COINBASE_MATURITY)) { + if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { transactionsToRemove.push_back(tx); break; } @@ -226,6 +229,7 @@ void CTxMemPool::clear() mapTx.clear(); mapNextTx.clear(); totalTxSize = 0; + cachedInnerUsage = 0; ++nTransactionsUpdated; } @@ -237,6 +241,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); uint64_t checkTotal = 0; + uint64_t innerUsage = 0; CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins)); @@ -245,6 +250,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; checkTotal += it->second.GetTxSize(); + innerUsage += it->second.DynamicMemoryUsage(); const CTransaction& tx = it->second.GetTx(); bool fDependsWait = false; BOOST_FOREACH(const CTxIn &txin, tx.vin) { @@ -299,6 +305,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const } assert(totalTxSize == checkTotal); + assert(innerUsage == cachedInnerUsage); } void CTxMemPool::queryHashes(vector<uint256>& vtxid) @@ -341,7 +348,7 @@ CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const minerPolicyEstimator->Write(fileout); } catch (const std::exception&) { - LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)"); + LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\n"); return false; } return true; @@ -360,7 +367,7 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein) minerPolicyEstimator->Read(filein); } catch (const std::exception&) { - LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)"); + LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n"); return false; } return true; @@ -419,3 +426,8 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { return mempool.exists(txid) || base->HaveCoins(txid); } + +size_t CTxMemPool::DynamicMemoryUsage() const { + LOCK(cs); + return memusage::DynamicUsage(mapTx) + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; +} diff --git a/src/txmempool.h b/src/txmempool.h index 7271a5f603..ea36ce1ad5 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -40,6 +40,7 @@ private: CAmount nFee; //! Cached to avoid expensive parent-transaction lookups size_t nTxSize; //! ... and avoid recomputing tx size size_t nModSize; //! ... and modified size for priority + size_t nUsageSize; //! ... and total memory usage int64_t nTime; //! Local time when entering the mempool double dPriority; //! Priority when entering the mempool unsigned int nHeight; //! Chain height when entering the mempool @@ -58,6 +59,7 @@ public: int64_t GetTime() const { return nTime; } unsigned int GetHeight() const { return nHeight; } bool WasClearAtEntry() const { return hadNoDependencies; } + size_t DynamicMemoryUsage() const { return nUsageSize; } }; class CBlockPolicyEstimator; @@ -73,6 +75,7 @@ public: 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; } }; /** @@ -93,6 +96,7 @@ private: CBlockPolicyEstimator* minerPolicyEstimator; uint64_t totalTxSize; //! sum of all mempool tx' byte sizes + uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves) public: mutable CCriticalSection cs; @@ -139,6 +143,7 @@ public: LOCK(cs); return mapTx.size(); } + uint64_t GetTotalTxSize() { LOCK(cs); @@ -162,6 +167,8 @@ public: /** Write/Read estimates to disk */ bool WriteFeeEstimates(CAutoFile& fileout) const; bool ReadFeeEstimates(CAutoFile& filein); + + size_t DynamicMemoryUsage() const; }; /** diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp index 6920c44c96..1d49a2cfc9 100644 --- a/src/univalue/univalue.cpp +++ b/src/univalue/univalue.cpp @@ -86,7 +86,7 @@ bool UniValue::setFloat(double val) oss << std::setprecision(16) << val; bool ret = setNumStr(oss.str()); - typ = VREAL; + typ = VNUM; return ret; } @@ -210,7 +210,6 @@ const char *uvTypeName(UniValue::VType t) case UniValue::VARR: return "array"; case UniValue::VSTR: return "string"; case UniValue::VNUM: return "number"; - case UniValue::VREAL: return "number"; } // not reached @@ -280,7 +279,7 @@ int64_t UniValue::get_int64() const double UniValue::get_real() const { - if (typ != VREAL && typ != VNUM) + if (typ != VNUM) throw std::runtime_error("JSON value is not a number as expected"); double retval; if (!ParseDouble(getValStr(), &retval)) diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h index 54239741e2..4742b56f3d 100644 --- a/src/univalue/univalue.h +++ b/src/univalue/univalue.h @@ -16,7 +16,7 @@ class UniValue { public: - enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VREAL, VBOOL, }; + enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; UniValue() { typ = VNULL; } UniValue(UniValue::VType initialType, const std::string& initialStr = "") { @@ -78,7 +78,6 @@ public: bool isBool() const { return (typ == VBOOL); } bool isStr() const { return (typ == VSTR); } bool isNum() const { return (typ == VNUM); } - bool isReal() const { return (typ == VREAL); } bool isArray() const { return (typ == VARR); } bool isObject() const { return (typ == VOBJ); } diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp index d360c253b0..bce3997af7 100644 --- a/src/univalue/univalue_write.cpp +++ b/src/univalue/univalue_write.cpp @@ -61,13 +61,6 @@ string UniValue::write(unsigned int prettyIndent, case VSTR: s += "\"" + json_escape(val) + "\""; break; - case VREAL: - { - std::stringstream ss; - ss << std::showpoint << std::fixed << std::setprecision(8) << get_real(); - s += ss.str(); - } - break; case VNUM: s += val; break; diff --git a/src/util.cpp b/src/util.cpp index da5821e530..37d52037c0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -83,6 +83,7 @@ #include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> +#include <openssl/conf.h> // Work around clang compilation problem in Boost 1.46: // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup @@ -113,7 +114,7 @@ CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ static CCriticalSection** ppmutexOpenSSL; -void locking_callback(int mode, int i, const char* file, int line) +void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS { if (mode & CRYPTO_LOCK) { ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]); @@ -134,6 +135,13 @@ public: ppmutexOpenSSL[i] = new CCriticalSection(); CRYPTO_set_locking_callback(locking_callback); + // OpenSSL can optionally load a config file which lists optional loadable modules and engines. + // We don't use them so we don't require the config. However some of our libs may call functions + // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing + // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be + // that the config appears to have been loaded and there are no modules/engines available. + OPENSSL_no_config(); + #ifdef WIN32 // Seed OpenSSL PRNG with current contents of the screen RAND_screen(); @@ -167,23 +175,51 @@ instance_of_cinit; */ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; + /** - * We use boost::call_once() to make sure these are initialized - * in a thread-safe manner the first time called: + * We use boost::call_once() to make sure mutexDebugLog and + * vMsgsBeforeOpenLog are initialized in a thread-safe manner. + * + * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog + * are leaked on exit. This is ugly, but will be cleaned up by + * the OS/libc. When the shutdown sequence is fully audited and + * tested, explicit destruction of these objects can be implemented. */ static FILE* fileout = NULL; static boost::mutex* mutexDebugLog = NULL; +static list<string> *vMsgsBeforeOpenLog; + +static int FileWriteStr(const std::string &str, FILE *fp) +{ + return fwrite(str.data(), 1, str.size(), fp); +} static void DebugPrintInit() { - assert(fileout == NULL); assert(mutexDebugLog == NULL); + mutexDebugLog = new boost::mutex(); + vMsgsBeforeOpenLog = new list<string>; +} + +void OpenDebugLog() +{ + boost::call_once(&DebugPrintInit, debugPrintInitFlag); + boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); + assert(fileout == NULL); + assert(vMsgsBeforeOpenLog); boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; fileout = fopen(pathDebug.string().c_str(), "a"); if (fileout) setbuf(fileout, NULL); // unbuffered - mutexDebugLog = new boost::mutex(); + // dump buffered messages from before we opened the log + while (!vMsgsBeforeOpenLog->empty()) { + FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); + vMsgsBeforeOpenLog->pop_front(); + } + + delete vMsgsBeforeOpenLog; + vMsgsBeforeOpenLog = NULL; } bool LogAcceptCategory(const char* category) @@ -215,44 +251,67 @@ bool LogAcceptCategory(const char* category) return true; } +/** + * fStartedNewLine is a state variable held by the calling context that will + * suppress printing of the timestamp when multiple calls are made that don't + * end in a newline. Initialize it to true, and hold it, in the calling context. + */ +static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine) +{ + string strStamped; + + if (!fLogTimestamps) + return str; + + if (*fStartedNewLine) + strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str; + else + strStamped = str; + + if (!str.empty() && str[str.size()-1] == '\n') + *fStartedNewLine = true; + else + *fStartedNewLine = false; + + return strStamped; +} + int LogPrintStr(const std::string &str) { int ret = 0; // Returns total number of characters written + static bool fStartedNewLine = true; if (fPrintToConsole) { // print to console ret = fwrite(str.data(), 1, str.size(), stdout); fflush(stdout); } - else if (fPrintToDebugLog && AreBaseParamsConfigured()) + else if (fPrintToDebugLog) { - static bool fStartedNewLine = true; boost::call_once(&DebugPrintInit, debugPrintInitFlag); - - if (fileout == NULL) - return ret; - boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); - // reopen the log file, if requested - if (fReopenDebugLog) { - fReopenDebugLog = false; - boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; - if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) - setbuf(fileout, NULL); // unbuffered - } + string strTimestamped = LogTimestampStr(str, &fStartedNewLine); - // Debug print useful for profiling - if (fLogTimestamps && fStartedNewLine) - ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); - if (!str.empty() && str[str.size()-1] == '\n') - fStartedNewLine = true; + // buffer if we haven't opened the log yet + if (fileout == NULL) { + assert(vMsgsBeforeOpenLog); + ret = strTimestamped.length(); + vMsgsBeforeOpenLog->push_back(strTimestamped); + } else - fStartedNewLine = false; - - ret = fwrite(str.data(), 1, str.size(), fileout); + { + // reopen the log file, if requested + if (fReopenDebugLog) { + fReopenDebugLog = false; + boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) + setbuf(fileout, NULL); // unbuffered + } + + ret = FileWriteStr(strTimestamped, fileout); + } } - return ret; } @@ -756,3 +815,13 @@ void SetThreadPriority(int nPriority) #endif // PRIO_THREAD #endif // WIN32 } + +int GetNumCores() +{ +#if BOOST_VERSION >= 105600 + return boost::thread::physical_concurrency(); +#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores + return boost::thread::hardware_concurrency(); +#endif +} + diff --git a/src/util.h b/src/util.h index 6ec81698ea..afc9a378bb 100644 --- a/src/util.h +++ b/src/util.h @@ -125,6 +125,7 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif boost::filesystem::path GetTempPath(); +void OpenDebugLog(); void ShrinkDebugFile(); void runCommand(const std::string& strCommand); @@ -199,6 +200,13 @@ std::string HelpMessageGroup(const std::string& message); */ std::string HelpMessageOpt(const std::string& option, const std::string& message); +/** + * Return the number of physical cores available on the current system. + * @note This does not count virtual cores, such as those provided by HyperThreading + * when boost is newer than 1.56. + */ +int GetNumCores(); + void SetThreadPriority(int nPriority); void RenameThread(const char* name); diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 7d1de7d6a8..1f7a2cae2c 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -464,11 +464,12 @@ bool ParseDouble(const std::string& str, double *out) return false; if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed return false; - char *endp = NULL; - errno = 0; // strtod will not set errno if valid - double n = strtod(str.c_str(), &endp); - if(out) *out = n; - return endp && *endp == 0 && !errno; + std::istringstream text(str); + text.imbue(std::locale::classic()); + double result; + text >> result; + if(out) *out = result; + return text.eof() && !text.fail(); } std::string FormatParagraph(const std::string& in, size_t width, size_t indent) @@ -538,3 +539,123 @@ int atoi(const std::string& str) { return atoi(str.c_str()); } + +/** Upper bound for mantissa. + * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer. + * Larger integers cannot consist of arbitrary combinations of 0-9: + * + * 999999999999999999 1^18-1 + * 9223372036854775807 (1<<63)-1 (max int64_t) + * 9999999999999999999 1^19-1 (would overflow) + */ +static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL; + +/** Helper function for ParseFixedPoint */ +static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros) +{ + if(ch == '0') + ++mantissa_tzeros; + else { + for (int i=0; i<=mantissa_tzeros; ++i) { + if (mantissa > (UPPER_BOUND / 10LL)) + return false; /* overflow */ + mantissa *= 10; + } + mantissa += ch - '0'; + mantissa_tzeros = 0; + } + return true; +} + +bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) +{ + int64_t mantissa = 0; + int64_t exponent = 0; + int mantissa_tzeros = 0; + bool mantissa_sign = false; + bool exponent_sign = false; + int ptr = 0; + int end = val.size(); + int point_ofs = 0; + + if (ptr < end && val[ptr] == '-') { + mantissa_sign = true; + ++ptr; + } + if (ptr < end) + { + if (val[ptr] == '0') { + /* pass single 0 */ + ++ptr; + } else if (val[ptr] >= '1' && val[ptr] <= '9') { + while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) + return false; /* overflow */ + ++ptr; + } + } else return false; /* missing expected digit */ + } else return false; /* empty string or loose '-' */ + if (ptr < end && val[ptr] == '.') + { + ++ptr; + if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') + { + while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) + return false; /* overflow */ + ++ptr; + ++point_ofs; + } + } else return false; /* missing expected digit */ + } + if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E')) + { + ++ptr; + if (ptr < end && val[ptr] == '+') + ++ptr; + else if (ptr < end && val[ptr] == '-') { + exponent_sign = true; + ++ptr; + } + if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { + if (exponent > (UPPER_BOUND / 10LL)) + return false; /* overflow */ + exponent = exponent * 10 + val[ptr] - '0'; + ++ptr; + } + } else return false; /* missing expected digit */ + } + if (ptr != end) + return false; /* trailing garbage */ + + /* finalize exponent */ + if (exponent_sign) + exponent = -exponent; + exponent = exponent - point_ofs + mantissa_tzeros; + + /* finalize mantissa */ + if (mantissa_sign) + mantissa = -mantissa; + + /* convert to one 64-bit fixed-point value */ + exponent += decimals; + if (exponent < 0) + return false; /* cannot represent values smaller than 10^-decimals */ + if (exponent >= 18) + return false; /* cannot represent values larger than or equal to 10^(18-decimals) */ + + for (int i=0; i < exponent; ++i) { + if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL)) + return false; /* overflow */ + mantissa *= 10; + } + if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND) + return false; /* overflow */ + + if (amount_out) + *amount_out = mantissa; + + return true; +} + diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 58329b51bb..dcd56751f2 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -109,4 +109,11 @@ bool TimingResistantEqual(const T& a, const T& b) return accumulator == 0; } +/** Parse number as fixed point according to JSON number syntax. + * See http://json.org/number.gif + * @returns true on success, false on error. + * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger. + */ +bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); + #endif // BITCOIN_UTILSTRENCODINGS_H diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 0532da5f37..d365f03008 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -19,9 +19,13 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); + g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); + g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { + g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); + g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); @@ -31,6 +35,8 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { } void UnregisterAllValidationInterfaces() { + g_signals.BlockFound.disconnect_all_slots(); + g_signals.ScriptForMining.disconnect_all_slots(); g_signals.BlockChecked.disconnect_all_slots(); g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); diff --git a/src/validationinterface.h b/src/validationinterface.h index a911d1efeb..fb0ce0bdaa 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -7,9 +7,11 @@ #define BITCOIN_VALIDATIONINTERFACE_H #include <boost/signals2/signal.hpp> +#include <boost/shared_ptr.hpp> class CBlock; struct CBlockLocator; +class CReserveScript; class CTransaction; class CValidationInterface; class CValidationState; @@ -34,6 +36,8 @@ 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<CReserveScript>&) {}; + virtual void ResetRequestCount(const uint256 &hash) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); @@ -52,6 +56,10 @@ struct CMainSignals { boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast; /** Notifies listeners of a block validation result */ boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; + /** Notifies listeners that a key for mining is required (coinbase) */ + boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining; + /** Notifies listeners that a block has been successfully mined */ + boost::signals2::signal<void (const uint256 &)> BlockFound; }; CMainSignals& GetMainSignals(); diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index c7f7e21679..0b0fb562e0 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -186,7 +186,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) } if (keyPass && keyFail) { - LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all."); + LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); assert(false); } if (keyFail || !keyPass) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 5f800474a0..dbe36a2be1 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" +#include "chain.h" #include "rpcserver.h" #include "init.h" #include "main.h" @@ -21,6 +22,8 @@ #include "univalue/univalue.h" +#include <boost/foreach.hpp> + using namespace std; void EnsureWalletIsUnlocked(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8d88933878..342ce13af1 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5,6 +5,7 @@ #include "amount.h" #include "base58.h" +#include "chain.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -476,7 +477,6 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp) addressInfo.push_back(CBitcoinAddress(address).ToString()); addressInfo.push_back(ValueFromAmount(balances[address])); { - LOCK(pwalletMain->cs_wallet); if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index eee57900b5..dcc2983139 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -7,14 +7,21 @@ #include "base58.h" #include "checkpoints.h" +#include "chain.h" #include "coincontrol.h" #include "consensus/consensus.h" #include "consensus/validation.h" +#include "key.h" +#include "keystore.h" #include "main.h" #include "net.h" +#include "policy/policy.h" +#include "primitives/block.h" +#include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" #include "timedata.h" +#include "txmempool.h" #include "util.h" #include "utilmoneystr.h" @@ -419,6 +426,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range) const uint256& hash = it->second; CWalletTx* copyTo = &mapWallet[hash]; if (copyFrom == copyTo) continue; + if (!copyFrom->IsEquivalentTo(*copyTo)) continue; copyTo->mapValue = copyFrom->mapValue; copyTo->vOrderForm = copyFrom->vOrderForm; // fTimeReceivedIsTxTime not copied on purpose @@ -1330,6 +1338,15 @@ bool CWalletTx::IsTrusted() const return true; } +bool CWalletTx::IsEquivalentTo(const CWalletTx& 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); +} + std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime) { std::vector<uint256> result; @@ -2092,7 +2109,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) if (!wtxNew.AcceptToMemoryPool(false)) { // This must not fail. The transaction has already been signed and recorded. - LogPrintf("CommitTransaction(): Error: Transaction not valid"); + LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); return false; } wtxNew.RelayWalletTransaction(); @@ -2583,6 +2600,17 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) } } +void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script) +{ + boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this)); + CPubKey pubkey; + if (!rKey->GetReservedKey(pubkey)) + return; + + script = rKey; + script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; +} + void CWallet::LockCoin(COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b6a8e8671f..ae007e4673 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -7,10 +7,7 @@ #define BITCOIN_WALLET_WALLET_H #include "amount.h" -#include "key.h" -#include "keystore.h" -#include "primitives/block.h" -#include "primitives/transaction.h" +#include "streams.h" #include "tinyformat.h" #include "ui_interface.h" #include "utilstrencodings.h" @@ -28,6 +25,8 @@ #include <utility> #include <vector> +#include <boost/shared_ptr.hpp> + /** * Settings */ @@ -376,6 +375,9 @@ public: return (GetDebit(filter) > 0); } + // True if only scriptSigs are different + bool IsEquivalentTo(const CWalletTx& tx) const; + bool IsTrusted() const; bool WriteToDisk(CWalletDB *pwalletdb); @@ -680,6 +682,13 @@ public: } } + void GetScriptForMining(boost::shared_ptr<CReserveScript> &script); + void ResetRequestCount(const uint256 &hash) + { + LOCK(cs_wallet); + mapRequestCount[hash] = 0; + }; + unsigned int GetKeyPoolSize() { AssertLockHeld(cs_wallet); // setKeyPool @@ -735,7 +744,7 @@ public: }; /** A key allocated from the key pool. */ -class CReserveKey +class CReserveKey : public CReserveScript { protected: CWallet* pwallet; @@ -756,6 +765,7 @@ public: void ReturnKey(); bool GetReservedKey(CPubKey &pubkey); void KeepKey(); + void KeepScript() { KeepKey(); } }; diff --git a/src/wallet/wallet_ismine.h b/src/wallet/wallet_ismine.h index 5b9b0e0841..7846565f8d 100644 --- a/src/wallet/wallet_ismine.h +++ b/src/wallet/wallet_ismine.h @@ -6,9 +6,10 @@ #ifndef BITCOIN_WALLET_WALLET_ISMINE_H #define BITCOIN_WALLET_WALLET_ISMINE_H -#include "key.h" #include "script/standard.h" +#include <stdint.h> + class CKeyStore; class CScript; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f777926e72..c1eb184581 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -7,7 +7,7 @@ #include "base58.h" #include "consensus/validation.h" -#include "main.h" +#include "main.h" // For CheckTransaction #include "protocol.h" #include "serialize.h" #include "sync.h" diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index bc1a104b5b..270f826aed 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -9,7 +9,6 @@ #include "amount.h" #include "wallet/db.h" #include "key.h" -#include "keystore.h" #include <list> #include <stdint.h> |