From 98ea64cf232c34d4b1aebe738b3956191667cd76 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Mon, 28 Nov 2016 17:19:27 -0500 Subject: [PATCH 001/188] Let wallet importmulti RPC accept labels for standard scriptPubKeys Allow importmulti RPC to apply address labels when importing standard scriptPubKeys. This makes the importmulti RPC less finnicky about import formats and also simpler internally. --- src/wallet/rpcdump.cpp | 42 +++++-------------------- test/functional/wallet_import_rescan.py | 10 +++--- test/functional/wallet_importmulti.py | 27 +++++++++------- 3 files changed, 28 insertions(+), 51 deletions(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 741ea25340..caaacdd72c 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -838,6 +838,9 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 std::vector vData(ParseHex(output)); script = CScript(vData.begin(), vData.end()); + if (!ExtractDestination(script, dest) && !internal) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports."); + } } // Watchonly and private keys @@ -850,11 +853,6 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label"); } - // Not having Internal + Script - if (!internal && isScript) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set for hex scriptPubKey"); - } - // Keys / PubKeys size check. if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address"); @@ -965,21 +963,10 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubkey_dest == dest)) { + if (!(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } - // Consistency check. - if (isScript) { - CTxDestination destination; - - if (ExtractDestination(script, destination)) { - if (!(destination == pubkey_dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); - } - } - } - CScript pubKeyScript = GetScriptForDestination(pubkey_dest); if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) { @@ -1036,21 +1023,10 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 CTxDestination pubkey_dest = pubKey.GetID(); // Consistency check. - if (!isScript && !(pubkey_dest == dest)) { + if (!(pubkey_dest == dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); } - // Consistency check. - if (isScript) { - CTxDestination destination; - - if (ExtractDestination(script, destination)) { - if (!(destination == pubkey_dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed"); - } - } - } - CKeyID vchAddress = pubKey.GetID(); pwallet->MarkDirty(); pwallet->SetAddressBook(vchAddress, label, "receive"); @@ -1082,11 +1058,9 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } - if (scriptPubKey.getType() == UniValue::VOBJ) { - // add to address book or update label - if (IsValidDestination(dest)) { - pwallet->SetAddressBook(dest, label, "receive"); - } + // add to address book or update label + if (IsValidDestination(dest)) { + pwallet->SetAddressBook(dest, label, "receive"); } success = true; diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 3288ce4b60..a7095e1a24 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -26,7 +26,7 @@ import collections import enum import itertools -Call = enum.Enum("Call", "single multi") +Call = enum.Enum("Call", "single multiaddress multiscript") Data = enum.Enum("Data", "address pub priv") Rescan = enum.Enum("Rescan", "no yes late_timestamp") @@ -54,11 +54,11 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")): response = self.try_rpc(self.node.importprivkey, self.key, self.label, self.rescan == Rescan.yes) assert_equal(response, None) - elif self.call == Call.multi: + elif self.call in (Call.multiaddress, Call.multiscript): response = self.node.importmulti([{ "scriptPubKey": { "address": self.address["address"] - }, + } if self.call == Call.multiaddress else self.address["scriptPubKey"], "timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0), "pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [], "keys": [self.key] if self.data == Data.priv else [], @@ -136,7 +136,7 @@ class ImportRescanTest(BitcoinTestFramework): variant.label = "label {} {}".format(i, variant) variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label)) variant.key = self.nodes[1].dumpprivkey(variant.address["address"]) - variant.initial_amount = 10 - (i + 1) / 4.0 + variant.initial_amount = 1 - (i + 1) / 64 variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount) # Generate a block containing the initial transactions, then another @@ -166,7 +166,7 @@ class ImportRescanTest(BitcoinTestFramework): # Create new transactions sending to each address. for i, variant in enumerate(IMPORT_VARIANTS): - variant.sent_amount = 10 - (2 * i + 1) / 8.0 + variant.sent_amount = 1 - (2 * i + 1) / 128 variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount) # Generate a block containing the new transactions. diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 56ebc2622a..0b4065ed7e 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -3,6 +3,8 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the importmulti RPC.""" + +from test_framework import script from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * @@ -79,16 +81,17 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['ismine'], False) assert_equal(address_assert['timestamp'], timestamp) - # ScriptPubKey + !internal - self.log.info("Should not import a scriptPubKey without internal flag") + # Nonstandard scriptPubKey + !internal + self.log.info("Should not import a nonstandard scriptPubKey without internal flag") + nonstandardScriptPubKey = address['scriptPubKey'] + bytes_to_hex_str(script.CScript([script.OP_NOP])) address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ - "scriptPubKey": address['scriptPubKey'], + "scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", }]) assert_equal(result[0]['success'], False) assert_equal(result[0]['error']['code'], -8) - assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey') + assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.') address_assert = self.nodes[1].getaddressinfo(address['address']) assert_equal(address_assert['iswatchonly'], False) assert_equal(address_assert['ismine'], False) @@ -128,18 +131,18 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['ismine'], False) assert_equal(address_assert['timestamp'], timestamp) - # ScriptPubKey + Public key + !internal - self.log.info("Should not import a scriptPubKey without internal and with public key") + # Nonstandard scriptPubKey + Public key + !internal + self.log.info("Should not import a nonstandard scriptPubKey without internal and with public key") address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) request = [{ - "scriptPubKey": address['scriptPubKey'], + "scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", "pubkeys": [ address['pubkey'] ] }] result = self.nodes[1].importmulti(request) assert_equal(result[0]['success'], False) assert_equal(result[0]['error']['code'], -8) - assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey') + assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.') address_assert = self.nodes[1].getaddressinfo(address['address']) assert_equal(address_assert['iswatchonly'], False) assert_equal(address_assert['ismine'], False) @@ -207,17 +210,17 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['ismine'], True) assert_equal(address_assert['timestamp'], timestamp) - # ScriptPubKey + Private key + !internal - self.log.info("Should not import a scriptPubKey without internal and with private key") + # Nonstandard scriptPubKey + Private key + !internal + self.log.info("Should not import a nonstandard scriptPubKey without internal and with private key") address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ - "scriptPubKey": address['scriptPubKey'], + "scriptPubKey": nonstandardScriptPubKey, "timestamp": "now", "keys": [ self.nodes[0].dumpprivkey(address['address']) ] }]) assert_equal(result[0]['success'], False) assert_equal(result[0]['error']['code'], -8) - assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey') + assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.') address_assert = self.nodes[1].getaddressinfo(address['address']) assert_equal(address_assert['iswatchonly'], False) assert_equal(address_assert['ismine'], False) From 545e85eccc2441c6d7745bb90d88dc14718455a2 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Thu, 15 Jun 2017 14:56:35 -0400 Subject: [PATCH 002/188] Add AssertLockHeld assertions in CWallet::ListCoins --- src/wallet/test/wallet_tests.cpp | 16 +++++++++++++--- src/wallet/wallet.cpp | 12 ++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 14c5ad7214..10e6da8b13 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -317,7 +317,11 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // Confirm ListCoins initially returns 1 coin grouped under coinbaseKey // address. - auto list = wallet->ListCoins(); + std::map> list; + { + LOCK2(cs_main, wallet->cs_wallet); + list = wallet->ListCoins(); + } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U); @@ -330,7 +334,10 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // coinbaseKey pubkey, even though the change address has a different // pubkey. AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */}); - list = wallet->ListCoins(); + { + LOCK2(cs_main, wallet->cs_wallet); + list = wallet->ListCoins(); + } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); @@ -356,7 +363,10 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) } // Confirm ListCoins still returns same result as before, despite coins // being locked. - list = wallet->ListCoins(); + { + LOCK2(cs_main, wallet->cs_wallet); + list = wallet->ListCoins(); + } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7d46f02745..40ff063105 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2364,20 +2364,12 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const std::map> CWallet::ListCoins() const { - // TODO: Add AssertLockHeld(cs_wallet) here. - // - // Because the return value from this function contains pointers to - // CWalletTx objects, callers to this function really should acquire the - // cs_wallet lock before calling it. However, the current caller doesn't - // acquire this lock yet. There was an attempt to add the missing lock in - // https://github.com/bitcoin/bitcoin/pull/10340, but that change has been - // postponed until after https://github.com/bitcoin/bitcoin/pull/10244 to - // avoid adding some extra complexity to the Qt code. + AssertLockHeld(cs_main); + AssertLockHeld(cs_wallet); std::map> result; std::vector availableCoins; - LOCK2(cs_main, cs_wallet); AvailableCoins(availableCoins); for (auto& coin : availableCoins) { From 820d31f95fb6b886b38dab5d378825bea7edd49e Mon Sep 17 00:00:00 2001 From: dexX7 Date: Tue, 13 Mar 2018 11:46:22 +0100 Subject: [PATCH 003/188] Add "bip125-replaceable" flag to mempool RPCs This affects getrawmempool, getmempoolentry, getmempoolancestors and getmempooldescendants. --- src/rpc/blockchain.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 06c68ea27c..a26b8f3b45 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -376,7 +377,8 @@ std::string EntryDescriptionString() " ... ]\n" " \"spentby\" : [ (array) unconfirmed transactions spending outputs from this transaction\n" " \"transactionid\", (string) child transaction id\n" - " ... ]\n"; + " ... ]\n" + " \"bip125-replaceable\" : true|false, (boolean) Whether this transaction could be replaced due to BIP125 (replace-by-fee)\n"; } void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) @@ -419,6 +421,17 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) } info.pushKV("spentby", spent); + + // Add opt-in RBF status + bool rbfStatus = false; + RBFTransactionState rbfState = IsRBFOptIn(tx, mempool); + if (rbfState == RBFTransactionState::UNKNOWN) { + throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool"); + } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) { + rbfStatus = true; + } + + info.pushKV("bip125-replaceable", rbfStatus); } UniValue mempoolToJSON(bool fVerbose) From 870bd4c73ddf494dc23c658bf0fb672ee0109158 Mon Sep 17 00:00:00 2001 From: dexX7 Date: Tue, 13 Mar 2018 12:03:49 +0100 Subject: [PATCH 004/188] Update functional RBF test to check replaceable flag --- test/functional/feature_rbf.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index d6ab5ecc37..a9bcb8483c 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -427,6 +427,9 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx1a_hex = txToHex(tx1a) tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + # This transaction isn't shown as replaceable + assert_equal(self.nodes[0].getmempoolentry(tx1a_txid)['bip125-replaceable'], False) + # Shouldn't be able to double-spend tx1b = CTransaction() tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] @@ -467,7 +470,10 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))] tx3a_hex = txToHex(tx3a) - self.nodes[0].sendrawtransaction(tx3a_hex, True) + tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, True) + + # This transaction is shown as replaceable + assert_equal(self.nodes[0].getmempoolentry(tx3a_txid)['bip125-replaceable'], True) tx3b = CTransaction() tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)] From b16ab9af07f802cc769c2443df1c637e8e12ab80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 23 May 2018 11:53:19 +0100 Subject: [PATCH 005/188] Report progress in ReplayBlocks while rolling forward --- src/validation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/validation.cpp b/src/validation.cpp index 3971906424..c1e8ba5558 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4103,6 +4103,7 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view) for (int nHeight = nForkHeight + 1; nHeight <= pindexNew->nHeight; ++nHeight) { const CBlockIndex* pindex = pindexNew->GetAncestor(nHeight); LogPrintf("Rolling forward %s (%i)\n", pindex->GetBlockHash().ToString(), nHeight); + uiInterface.ShowProgress(_("Replaying blocks..."), (int) ((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)) , false); if (!RollforwardBlock(pindex, cache, params)) return false; } From 65a449f8e3b1bd95a0978b68cd6ce3ddda832658 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Sat, 14 Jul 2018 17:48:16 +0200 Subject: [PATCH 006/188] Explain when reindex-chainstate can be used instead of reindex --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index fe4fba8cdf..87650c3276 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -384,7 +384,7 @@ void SetupServerArgs() "Warning: Reverting this setting requires re-downloading the entire blockchain. " "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), false, OptionsCategory::OPTIONS); gArgs.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk", false, OptionsCategory::OPTIONS); - gArgs.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks", false, OptionsCategory::OPTIONS); + gArgs.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", false, OptionsCategory::OPTIONS); #ifndef WIN32 gArgs.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", false, OptionsCategory::OPTIONS); #else From 03a2d680101a9fee47c6fd818df7585cfc93ac06 Mon Sep 17 00:00:00 2001 From: Mason Simon Date: Wed, 18 Jul 2018 17:47:34 -0700 Subject: [PATCH 007/188] Tests: add usage note to check-rpc-mappings.py --- test/lint/check-rpc-mappings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/lint/check-rpc-mappings.py b/test/lint/check-rpc-mappings.py index c3cdeef580..28d08eba01 100755 --- a/test/lint/check-rpc-mappings.py +++ b/test/lint/check-rpc-mappings.py @@ -90,6 +90,10 @@ def process_mapping(fname): return cmds def main(): + if len(sys.argv) != 2: + print('Usage: {} ROOT-DIR'.format(sys.argv[0]), file=sys.stderr) + sys.exit(1) + root = sys.argv[1] # Get all commands from dispatch tables From 984d72ec659361d8c1a6f3c6864e839a807817a7 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Sun, 10 Jun 2018 22:19:07 -0700 Subject: [PATCH 008/188] Return the script type from Solver Because false is synonymous with TX_NONSTANDARD, this conveys the same information and makes the handling explicitly based on script type, simplifying each call site. Prior to this change it was common for the return value to be ignored, or for the return value and TX_NONSTANDARD to be redundantly handled. --- src/bloom.cpp | 6 ++-- src/core_write.cpp | 3 +- src/policy/policy.cpp | 23 ++++++------ src/rpc/rawtransaction.cpp | 3 +- src/script/ismine.cpp | 3 +- src/script/sign.cpp | 10 +++--- src/script/standard.cpp | 57 +++++++++++------------------- src/script/standard.h | 5 ++- src/test/script_standard_tests.cpp | 47 ++++++++++-------------- src/wallet/rpcwallet.cpp | 3 +- 10 files changed, 62 insertions(+), 98 deletions(-) diff --git a/src/bloom.cpp b/src/bloom.cpp index f8e28edded..4bc0eab011 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -164,11 +164,11 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) insert(COutPoint(hash, i)); else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY) { - txnouttype type; std::vector > vSolutions; - if (Solver(txout.scriptPubKey, type, vSolutions) && - (type == TX_PUBKEY || type == TX_MULTISIG)) + txnouttype type = Solver(txout.scriptPubKey, vSolutions); + if (type == TX_PUBKEY || type == TX_MULTISIG) { insert(COutPoint(hash, i)); + } } break; } diff --git a/src/core_write.cpp b/src/core_write.cpp index 1272266235..ec6a7d1321 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -141,8 +141,7 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address) out.pushKV("hex", HexStr(script.begin(), script.end())); std::vector> solns; - txnouttype type; - Solver(script, type, solns); + txnouttype type = Solver(script, solns); out.pushKV("type", GetTxnOutputType(type)); CTxDestination address; diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 3a592e40d3..f1ba09d4d2 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -57,11 +57,11 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) { std::vector > vSolutions; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + whichType = Solver(scriptPubKey, vSolutions); - if (whichType == TX_MULTISIG) - { + if (whichType == TX_NONSTANDARD || whichType == TX_WITNESS_UNKNOWN) { + return false; + } else 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 @@ -70,10 +70,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) if (m < 1 || m > n) return false; } else if (whichType == TX_NULL_DATA && - (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) + (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) { return false; + } - return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN; + return true; } bool IsStandardTx(const CTransaction& tx, std::string& reason) @@ -166,14 +167,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out; std::vector > vSolutions; - txnouttype whichType; - // get the scriptPubKey corresponding to this input: - const CScript& prevScript = prev.scriptPubKey; - if (!Solver(prevScript, whichType, vSolutions)) + txnouttype whichType = Solver(prev.scriptPubKey, vSolutions); + if (whichType == TX_NONSTANDARD) { return false; - - if (whichType == TX_SCRIPTHASH) - { + } else if (whichType == TX_SCRIPTHASH) { std::vector > stack; // convert the scriptSig into a stack, so we can inspect the redeemScript if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index bb94e11fea..eed70d730f 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -627,9 +627,8 @@ static UniValue decodescript(const JSONRPCRequest& request) // P2SH and witness programs cannot be wrapped in P2WSH, if this script // is a witness program, don't return addresses for a segwit programs. if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") { - txnouttype which_type; std::vector> solutions_data; - Solver(script, which_type, solutions_data); + txnouttype which_type = Solver(script, solutions_data); // Uncompressed pubkeys cannot be used with segwit checksigs. // If the script contains an uncompressed pubkey, skip encoding of a segwit program. if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) { diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 8c26866483..7e7087663a 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -60,8 +60,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineResult ret = IsMineResult::NO; std::vector vSolutions; - txnouttype whichType; - Solver(scriptPubKey, whichType, vSolutions); + txnouttype whichType = Solver(scriptPubKey, vSolutions); CKeyID keyID; switch (whichType) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index c2ae4ff2ea..f0090800aa 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -102,8 +102,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator std::vector sig; std::vector vSolutions; - if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) - return false; + whichTypeRet = Solver(scriptPubKey, vSolutions); switch (whichTypeRet) { @@ -314,9 +313,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI } // Get scripts - txnouttype script_type; std::vector> solutions; - Solver(txout.scriptPubKey, script_type, solutions); + txnouttype script_type = Solver(txout.scriptPubKey, solutions); SigVersion sigversion = SigVersion::BASE; CScript next_script = txout.scriptPubKey; @@ -327,7 +325,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI next_script = std::move(redeem_script); // Get redeemScript type - Solver(next_script, script_type, solutions); + script_type = Solver(next_script, solutions); stack.script.pop_back(); } if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) { @@ -337,7 +335,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI next_script = std::move(witness_script); // Get witnessScript type - Solver(next_script, script_type, solutions); + script_type = Solver(next_script, solutions); stack.witness.pop_back(); stack.script = std::move(stack.witness); stack.witness.clear(); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index d7b1724790..d309420d35 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -87,7 +87,7 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve return (it + 1 == script.end()); } -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet) +txnouttype Solver(const CScript& scriptPubKey, std::vector>& vSolutionsRet) { vSolutionsRet.clear(); @@ -95,33 +95,28 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); - return true; + return TX_SCRIPTHASH; } int witnessversion; std::vector witnessprogram; if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) { - typeRet = TX_WITNESS_V0_KEYHASH; vSolutionsRet.push_back(witnessprogram); - return true; + return TX_WITNESS_V0_KEYHASH; } if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) { - typeRet = TX_WITNESS_V0_SCRIPTHASH; vSolutionsRet.push_back(witnessprogram); - return true; + return TX_WITNESS_V0_SCRIPTHASH; } if (witnessversion != 0) { - typeRet = TX_WITNESS_UNKNOWN; vSolutionsRet.push_back(std::vector{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); - return true; + return TX_WITNESS_UNKNOWN; } - typeRet = TX_NONSTANDARD; - return false; + return TX_NONSTANDARD; } // Provably prunable, data-carrying output @@ -130,47 +125,39 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) { - typeRet = TX_NULL_DATA; - return true; + return TX_NULL_DATA; } std::vector data; if (MatchPayToPubkey(scriptPubKey, data)) { - typeRet = TX_PUBKEY; vSolutionsRet.push_back(std::move(data)); - return true; + return TX_PUBKEY; } if (MatchPayToPubkeyHash(scriptPubKey, data)) { - typeRet = TX_PUBKEYHASH; vSolutionsRet.push_back(std::move(data)); - return true; + return TX_PUBKEYHASH; } unsigned int required; std::vector> keys; if (MatchMultisig(scriptPubKey, required, keys)) { - typeRet = TX_MULTISIG; vSolutionsRet.push_back({static_cast(required)}); // safe as required is in range 1..16 vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end()); vSolutionsRet.push_back({static_cast(keys.size())}); // safe as size is in range 1..16 - return true; + return TX_MULTISIG; } vSolutionsRet.clear(); - typeRet = TX_NONSTANDARD; - return false; + return TX_NONSTANDARD; } bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { std::vector vSolutions; - txnouttype whichType; - if (!Solver(scriptPubKey, whichType, vSolutions)) - return false; + txnouttype whichType = Solver(scriptPubKey, vSolutions); - if (whichType == TX_PUBKEY) - { + if (whichType == TX_PUBKEY) { CPubKey pubKey(vSolutions[0]); if (!pubKey.IsValid()) return false; @@ -212,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet) { addressRet.clear(); - typeRet = TX_NONSTANDARD; std::vector vSolutions; - if (!Solver(scriptPubKey, typeRet, vSolutions)) + typeRet = Solver(scriptPubKey, vSolutions); + if (typeRet == TX_NONSTANDARD) { return false; - if (typeRet == TX_NULL_DATA){ + } else if (typeRet == TX_NULL_DATA) { // This is data, not addresses return false; } @@ -324,14 +311,12 @@ CScript GetScriptForMultisig(int nRequired, const std::vector& keys) CScript GetScriptForWitness(const CScript& redeemscript) { - txnouttype typ; std::vector > vSolutions; - if (Solver(redeemscript, typ, vSolutions)) { - if (typ == TX_PUBKEY) { - return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); - } else if (typ == TX_PUBKEYHASH) { - return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); - } + txnouttype typ = Solver(redeemscript, vSolutions); + if (typ == TX_PUBKEY) { + return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end()))); + } else if (typ == TX_PUBKEYHASH) { + return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0])); } return GetScriptForDestination(WitnessV0ScriptHash(redeemscript)); } diff --git a/src/script/standard.h b/src/script/standard.h index 1380030871..4728b056dd 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -135,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t); * script hash, for P2PKH it will contain the key hash, etc. * * @param[in] scriptPubKey Script to parse - * @param[out] typeRet The script type * @param[out] vSolutionsRet Vector of parsed pubkeys and hashes - * @return True if script matches standard template + * @return The script type. TX_NONSTANDARD represents a failed solve. */ -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); +txnouttype Solver(const CScript& scriptPubKey, std::vector>& vSolutionsRet); /** * Parse a standard scriptPubKey for the destination address. Assigns result to diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 7d4734986a..ded0a8ac1a 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -25,22 +25,19 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) } CScript s; - txnouttype whichType; std::vector > solutions; // TX_PUBKEY s.clear(); s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEY); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0])); // TX_PUBKEYHASH s.clear(); s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEYHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); @@ -48,8 +45,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) CScript redeemScript(s); // initialize with leftover P2PKH script s.clear(); s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_SCRIPTHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript))); @@ -59,8 +55,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) ToByteVector(pubkeys[0]) << ToByteVector(pubkeys[1]) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG); BOOST_CHECK_EQUAL(solutions.size(), 4U); BOOST_CHECK(solutions[0] == std::vector({1})); BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); @@ -73,8 +68,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) ToByteVector(pubkeys[1]) << ToByteVector(pubkeys[2]) << OP_3 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG); BOOST_CHECK_EQUAL(solutions.size(), 5U); BOOST_CHECK(solutions[0] == std::vector({2})); BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); @@ -88,15 +82,13 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) std::vector({0}) << std::vector({75}) << std::vector({255}); - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NULL_DATA); BOOST_CHECK_EQUAL(solutions.size(), 0U); // TX_WITNESS_V0_KEYHASH s.clear(); s << OP_0 << ToByteVector(pubkeys[0].GetID()); - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_KEYHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); @@ -107,16 +99,14 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) s.clear(); s << OP_0 << ToByteVector(scriptHash); - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_SCRIPTHASH); BOOST_CHECK_EQUAL(solutions.size(), 1U); BOOST_CHECK(solutions[0] == ToByteVector(scriptHash)); // TX_NONSTANDARD s.clear(); s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; - BOOST_CHECK(!Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); } BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) @@ -127,53 +117,52 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) pubkey = key.GetPubKey(); CScript s; - txnouttype whichType; std::vector > solutions; // TX_PUBKEY with incorrectly sized pubkey s.clear(); s << std::vector(30, 0x01) << OP_CHECKSIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_PUBKEYHASH with incorrectly sized key hash s.clear(); s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_SCRIPTHASH with incorrectly sized script hash s.clear(); s << OP_HASH160 << std::vector(21, 0x01) << OP_EQUAL; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG 0/2 s.clear(); s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG 2/1 s.clear(); s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG n = 2 with 1 pubkey s.clear(); s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_MULTISIG n = 1 with 0 pubkeys s.clear(); s << OP_1 << OP_1 << OP_CHECKMULTISIG; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_NULL_DATA with other opcodes s.clear(); s << OP_RETURN << std::vector({75}) << OP_ADD; - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); // TX_WITNESS with incorrect program size s.clear(); s << OP_0 << std::vector(19, 0x01); - BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD); } BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 73dfebf114..eb1e5ba3fb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4021,9 +4021,8 @@ public: void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const { // Always present: script type and redeemscript - txnouttype which_type; std::vector> solutions_data; - Solver(subscript, which_type, solutions_data); + txnouttype which_type = Solver(subscript, solutions_data); obj.pushKV("script", GetTxnOutputType(which_type)); obj.pushKV("hex", HexStr(subscript.begin(), subscript.end())); From 1ac3c983bfe06f75542e4f4e30142952802a46d8 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Thu, 26 Jul 2018 17:15:32 +0200 Subject: [PATCH 009/188] Mark single-argument constructors "explicit" --- src/interfaces/handler.cpp | 2 +- src/interfaces/wallet.cpp | 4 ++-- src/key_io.cpp | 2 +- src/qt/addresstablemodel.cpp | 2 +- src/qt/rpcconsole.cpp | 2 +- src/qt/transactiontablemodel.cpp | 2 +- src/test/miner_tests.cpp | 2 +- src/test/validation_block_tests.cpp | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp index 80f461f4d3..ddf9b342d8 100644 --- a/src/interfaces/handler.cpp +++ b/src/interfaces/handler.cpp @@ -15,7 +15,7 @@ namespace { class HandlerImpl : public Handler { public: - HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {} + explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {} void disconnect() override { m_connection.disconnect(); } diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 28081c7c2c..ea6f5740ac 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -31,7 +31,7 @@ namespace { class PendingWalletTxImpl : public PendingWalletTx { public: - PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {} + explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {} const CTransaction& get() override { return *m_tx; } @@ -117,7 +117,7 @@ WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int de class WalletImpl : public Wallet { public: - WalletImpl(const std::shared_ptr& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {} + explicit WalletImpl(const std::shared_ptr& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {} bool encryptWallet(const SecureString& wallet_passphrase) override { diff --git a/src/key_io.cpp b/src/key_io.cpp index c2dc511989..99a65830cd 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -24,7 +24,7 @@ private: const CChainParams& m_params; public: - DestinationEncoder(const CChainParams& params) : m_params(params) {} + explicit DestinationEncoder(const CChainParams& params) : m_params(params) {} std::string operator()(const CKeyID& id) const { diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 25b615e6f8..eb5cbd8890 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -71,7 +71,7 @@ public: QList cachedAddressTable; AddressTableModel *parent; - AddressTablePriv(AddressTableModel *_parent): + explicit AddressTablePriv(AddressTableModel *_parent): parent(_parent) {} void refreshAddressTable(interfaces::Wallet& wallet) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index f222357f27..4411bfaa33 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -82,7 +82,7 @@ class RPCExecutor : public QObject { Q_OBJECT public: - RPCExecutor(interfaces::Node& node) : m_node(node) {} + explicit RPCExecutor(interfaces::Node& node) : m_node(node) {} public Q_SLOTS: void request(const QString &command, const QString &walletID); diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 63a4afe191..dddae46c45 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -58,7 +58,7 @@ struct TxLessThan class TransactionTablePriv { public: - TransactionTablePriv(TransactionTableModel *_parent) : + explicit TransactionTablePriv(TransactionTableModel *_parent) : parent(_parent) { } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 10c7fd00e8..c98320d1a6 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -29,7 +29,7 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) // BOOST_CHECK_EXCEPTION predicates to check the specific validation error class HasReason { public: - HasReason(const std::string& reason) : m_reason(reason) {} + explicit HasReason(const std::string& reason) : m_reason(reason) {} bool operator() (const std::runtime_error& e) const { return std::string(e.what()).find(m_reason) != std::string::npos; }; diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 37c4f79133..4316f37999 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -23,7 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(validation_block_tests, RegtestingSetup) struct TestSubscriber : public CValidationInterface { uint256 m_expected_tip; - TestSubscriber(uint256 tip) : m_expected_tip(tip) {} + explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {} void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override { From 23f434378153cf764230066662f3ec3ad614ff30 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 11 Jul 2018 01:17:59 -0400 Subject: [PATCH 010/188] Add CMerkleTx::IsImmatureCoinBase method All but one call to GetBlocksToMaturity is testing it relative to 0 for the purposes of determining whether the coinbase tx is immature. In such case, the value greater than 0 implies that the tx is coinbase, so there is no need to separately test that status. This names the concept for easy singular use. --- src/wallet/rpcwallet.cpp | 4 ++-- src/wallet/wallet.cpp | 21 ++++++++++++--------- src/wallet/wallet.h | 7 +++++++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 73dfebf114..84fd55edef 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1851,7 +1851,7 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const { if (wtx.GetDepthInMainChain() < 1) entry.pushKV("category", "orphan"); - else if (wtx.GetBlocksToMaturity() > 0) + else if (wtx.IsImmatureCoinBase()) entry.pushKV("category", "immature"); else entry.pushKV("category", "generate"); @@ -2147,7 +2147,7 @@ static UniValue listaccounts(const JSONRPCRequest& request) std::list listReceived; std::list listSent; int nDepth = wtx.GetDepthInMainChain(); - if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0) + if (wtx.IsImmatureCoinBase() || nDepth < 0) continue; wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly); mapAccountBalances[strSentAccount] -= nFee; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3ec6aefaec..540a7b0fc6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1894,7 +1894,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const CAmount CWalletTx::GetCredit(const isminefilter& filter) const { // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) + if (IsImmatureCoinBase()) return 0; CAmount credit = 0; @@ -1926,8 +1926,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const { - if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) - { + if (IsImmatureCoinBase() && IsInMainChain()) { if (fUseCache && fImmatureCreditCached) return nImmatureCreditCached; nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE); @@ -1944,7 +1943,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter return 0; // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) + if (IsImmatureCoinBase()) return 0; CAmount* cache = nullptr; @@ -1985,8 +1984,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const { - if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) - { + if (IsImmatureCoinBase() && IsInMainChain()) { if (fUseCache && fImmatureWatchCreditCached) return nImmatureWatchCreditCached; nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY); @@ -2199,7 +2197,7 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons for (const auto& entry : mapWallet) { const CWalletTx& wtx = entry.second; const int depth = wtx.GetDepthInMainChain(); - if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) { + if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase()) { continue; } @@ -2259,7 +2257,7 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const if (!CheckFinalTx(*pcoin->tx)) continue; - if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + if (pcoin->IsImmatureCoinBase()) continue; int nDepth = pcoin->GetDepthInMainChain(); @@ -3521,7 +3519,7 @@ std::map CWallet::GetAddressBalances() if (!pcoin->IsTrusted()) continue; - if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + if (pcoin->IsImmatureCoinBase()) continue; int nDepth = pcoin->GetDepthInMainChain(); @@ -4397,6 +4395,11 @@ int CMerkleTx::GetBlocksToMaturity() const return std::max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain()); } +bool CMerkleTx::IsImmatureCoinBase() const +{ + // note GetBlocksToMaturity is 0 for non-coinbase tx + return GetBlocksToMaturity() > 0; +} bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 2ada233514..8253dc1eba 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -266,6 +266,12 @@ public: */ int GetDepthInMainChain() const; bool IsInMainChain() const { return GetDepthInMainChain() > 0; } + + /** + * @return number of blocks to maturity for this transaction: + * 0 : is not a coinbase transaction, or is a mature coinbase transaction + * >0 : is a coinbase transaction which matures in this many blocks + */ int GetBlocksToMaturity() const; bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); } bool isAbandoned() const { return (hashBlock == ABANDON_HASH); } @@ -273,6 +279,7 @@ public: const uint256& GetHash() const { return tx->GetHash(); } bool IsCoinBase() const { return tx->IsCoinBase(); } + bool IsImmatureCoinBase() const; }; //Get the marginal bytes of spending the specified output From ddd395f968a050be5dd0ae21ba7d189b6b7f73fd Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 28 Jul 2018 20:55:32 -0400 Subject: [PATCH 011/188] Mark CTxMemPoolEntry members that should not be modified const --- src/txmempool.cpp | 7 ++----- src/txmempool.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index d68c38ad4e..257c88e5b2 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -20,13 +20,10 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, unsigned int _entryHeight, - bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): - tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight), + bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp) + : tx(_tx), nFee(_nFee), nTxWeight(GetTransactionWeight(*tx)), nUsageSize(RecursiveDynamicUsage(tx)), nTime(_nTime), entryHeight(_entryHeight), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { - nTxWeight = GetTransactionWeight(*tx); - nUsageSize = RecursiveDynamicUsage(tx); - nCountWithDescendants = 1; nSizeWithDescendants = GetTxSize(); nModFeesWithDescendants = nFee; diff --git a/src/txmempool.h b/src/txmempool.h index 0feea08f0b..2003783952 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -64,14 +64,14 @@ class CTxMemPool; class CTxMemPoolEntry { private: - CTransactionRef tx; - CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups - size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) - size_t nUsageSize; //!< ... and total memory usage - int64_t nTime; //!< Local time when entering the mempool - unsigned int entryHeight; //!< Chain height when entering the mempool - bool spendsCoinbase; //!< keep track of transactions that spend a coinbase - int64_t sigOpCost; //!< Total sigop cost + const CTransactionRef tx; + const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups + const size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) + const size_t nUsageSize; //!< ... and total memory usage + const int64_t nTime; //!< Local time when entering the mempool + const unsigned int entryHeight; //!< Chain height when entering the mempool + const bool spendsCoinbase; //!< keep track of transactions that spend a coinbase + const int64_t sigOpCost; //!< Total sigop cost int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block LockPoints lockPoints; //!< Track the height and time at which tx was final From fe5c49766c0dc5beaf186d77b568361242b20d5e Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 28 Jul 2018 21:10:02 -0400 Subject: [PATCH 012/188] tx pool: Use the entry's hash instead of the one passed to addUnchecked --- src/txmempool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 257c88e5b2..4d04b6ef6d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -364,7 +364,7 @@ void CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, // Update transaction for any feeDelta created by PrioritiseTransaction // TODO: refactor so that the fee delta is calculated before inserting // into mapTx. - std::map::const_iterator pos = mapDeltas.find(hash); + std::map::const_iterator pos = mapDeltas.find(entry.GetTx().GetHash()); if (pos != mapDeltas.end()) { const CAmount &delta = pos->second; if (delta) { From fa587773e59721e187cadc998f4dc236ad3aef0b Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 30 Jul 2018 09:11:13 -0400 Subject: [PATCH 013/188] scripted-diff: Remove unused first argument to addUnchecked -BEGIN VERIFY SCRIPT- git grep -l addUnchecked | xargs sed --regexp-extended -i -e 's/addUnchecked\([^)][^,]+,\s*/addUnchecked(/g' -END VERIFY SCRIPT- --- src/bench/mempool_eviction.cpp | 2 +- src/test/blockencodings_tests.cpp | 6 +-- src/test/mempool_tests.cpp | 84 +++++++++++++++--------------- src/test/miner_tests.cpp | 48 ++++++++--------- src/test/policyestimator_tests.cpp | 6 +-- src/txmempool.cpp | 6 +-- src/txmempool.h | 4 +- src/validation.cpp | 2 +- 8 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index d37291b900..4c5489fdc0 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -16,7 +16,7 @@ static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& po bool spendsCoinbase = false; unsigned int sigOpCost = 4; LockPoints lp; - pool.addUnchecked(tx->GetHash(), CTxMemPoolEntry( + pool.addUnchecked(CTxMemPoolEntry( tx, nFee, nTime, nHeight, spendsCoinbase, sigOpCost, lp)); } diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index df839884fe..e33c449051 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) CBlock block(BuildBlockTestCase()); LOCK(pool.cs); - pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2])); + pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); // Do a simple ShortTxIDs RT @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) CBlock block(BuildBlockTestCase()); LOCK(pool.cs); - pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2])); + pool.addUnchecked(entry.FromTx(block.vtx[2])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); uint256 txhash; @@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) CBlock block(BuildBlockTestCase()); LOCK(pool.cs); - pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(block.vtx[1])); + pool.addUnchecked(entry.FromTx(block.vtx[1])); BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); uint256 txhash; diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index fb80599af7..b9970b9e6b 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -63,17 +63,17 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) BOOST_CHECK_EQUAL(testPool.size(), poolSize); // Just the parent: - testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); + testPool.addUnchecked(entry.FromTx(txParent)); poolSize = testPool.size(); testPool.removeRecursive(txParent); BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1); // Parent, children, grandchildren: - testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); + testPool.addUnchecked(entry.FromTx(txParent)); for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); - testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); + testPool.addUnchecked(entry.FromTx(txChild[i])); + testPool.addUnchecked(entry.FromTx(txGrandChild[i])); } // Remove Child[0], GrandChild[0] should be removed: poolSize = testPool.size(); @@ -95,8 +95,8 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) // Add children and grandchildren, but NOT the parent (simulate the parent being in a block) for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); - testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); + testPool.addUnchecked(entry.FromTx(txChild[i])); + testPool.addUnchecked(entry.FromTx(txGrandChild[i])); } // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be // put into the mempool (maybe because it is non-standard): @@ -128,28 +128,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); /* highest fee */ CMutableTransaction tx2 = CMutableTransaction(); tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN; - pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2)); /* lowest fee */ CMutableTransaction tx3 = CMutableTransaction(); tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN; - pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN; - pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4)); /* equal fee rate to tx1, but newer */ CMutableTransaction tx5 = CMutableTransaction(); @@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN; entry.nTime = 1; - pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5U); std::vector sortedOrder; @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx6.vout.resize(1); tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx6.vout[0].nValue = 20 * COIN; - pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6U); // Check that at this point, tx6 is sorted low sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); @@ -198,7 +198,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors); + pool.addUnchecked(entry.FromTx(tx7), setAncestors); BOOST_CHECK_EQUAL(pool.size(), 7U); // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx8.vout[0].nValue = 10 * COIN; setAncestors.insert(pool.mapTx.find(tx7.GetHash())); - pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); + pool.addUnchecked(entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); // Now tx8 should be sorted low, but tx6/tx both high sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); @@ -230,7 +230,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) tx9.vout.resize(1); tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx9.vout[0].nValue = 1 * COIN; - pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); + pool.addUnchecked(entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9U); @@ -256,7 +256,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors); + pool.addUnchecked(entry.FromTx(tx10), setAncestors); /** * tx8 and tx9 should both now be sorted higher @@ -301,14 +301,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); /* highest fee */ CMutableTransaction tx2 = CMutableTransaction(); tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN; - pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2)); uint64_t tx2Size = GetVirtualTransactionSize(tx2); /* lowest fee */ @@ -316,21 +316,21 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN; - pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN; - pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4)); /* equal fee rate to tx1, but newer */ CMutableTransaction tx5 = CMutableTransaction(); tx5.vout.resize(1); tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN; - pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5U); std::vector sortedOrder; @@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) tx6.vout[0].nValue = 20 * COIN; uint64_t tx6Size = GetVirtualTransactionSize(tx6); - pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); + pool.addUnchecked(entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6U); // Ties are broken by hash if (tx3.GetHash() < tx6.GetHash()) @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) /* set the fee to just below tx2's feerate when including ancestor */ CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1; - pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7)); + pool.addUnchecked(entry.Fee(fee).FromTx(tx7)); BOOST_CHECK_EQUAL(pool.size(), 7U); sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString()); CheckSort(pool, sortedOrder); @@ -413,7 +413,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) // Check that we sort by min(feerate, ancestor_feerate): // set the fee so that the ancestor feerate is above tx1/5, // but the transaction's own feerate is lower - pool.addUnchecked(tx8.GetHash(), entry.Fee(5000LL).FromTx(tx8)); + pool.addUnchecked(entry.Fee(5000LL).FromTx(tx8)); sortedOrder.insert(sortedOrder.end()-1, tx8.GetHash().ToString()); CheckSort(pool, sortedOrder); } @@ -431,7 +431,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); CMutableTransaction tx2 = CMutableTransaction(); tx2.vin.resize(1); @@ -439,7 +439,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; tx2.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(5000LL).FromTx(tx2)); pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing BOOST_CHECK(pool.exists(tx1.GetHash())); @@ -449,7 +449,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(pool.exists(tx1.GetHash())); BOOST_CHECK(!pool.exists(tx2.GetHash())); - pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2)); + pool.addUnchecked(entry.FromTx(tx2)); CMutableTransaction tx3 = CMutableTransaction(); tx3.vin.resize(1); tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0); @@ -457,7 +457,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; tx3.vout[0].nValue = 10 * COIN; - pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(20000LL).FromTx(tx3)); pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) BOOST_CHECK(!pool.exists(tx1.GetHash())); @@ -520,10 +520,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; tx7.vout[1].nValue = 10 * COIN; - pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4)); - pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5)); - pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6)); - pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7)); + pool.addUnchecked(entry.Fee(7000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(1100LL).FromTx(tx6)); + pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7)); // we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that pool.TrimToSize(pool.DynamicMemoryUsage() - 1); @@ -532,8 +532,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(!pool.exists(tx7.GetHash())); if (!pool.exists(tx5.GetHash())) - pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5)); - pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7)); + pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7)); pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 BOOST_CHECK(pool.exists(tx4.GetHash())); @@ -541,8 +541,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) BOOST_CHECK(pool.exists(tx6.GetHash())); BOOST_CHECK(!pool.exists(tx7.GetHash())); - pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5)); - pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7)); + pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5)); + pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7)); std::vector vtx; SetMockTime(42); @@ -603,7 +603,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // [tx1] // CTransactionRef tx1 = make_tx(/* output_values */ {10 * COIN}); - pool.addUnchecked(tx1->GetHash(), entry.Fee(10000LL).FromTx(tx1)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1)); // Ancestors / descendants should be 1 / 1 (itself / itself) pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants); @@ -615,7 +615,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // [tx1].0 <- [tx2] // CTransactionRef tx2 = make_tx(/* output_values */ {495 * CENT, 5 * COIN}, /* inputs */ {tx1}); - pool.addUnchecked(tx2->GetHash(), entry.Fee(10000LL).FromTx(tx2)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx2)); // Ancestors / descendants should be: // transaction ancestors descendants @@ -634,7 +634,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // [tx1].0 <- [tx2].0 <- [tx3] // CTransactionRef tx3 = make_tx(/* output_values */ {290 * CENT, 200 * CENT}, /* inputs */ {tx2}); - pool.addUnchecked(tx3->GetHash(), entry.Fee(10000LL).FromTx(tx3)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx3)); // Ancestors / descendants should be: // transaction ancestors descendants @@ -659,7 +659,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) // \---1 <- [tx4] // CTransactionRef tx4 = make_tx(/* output_values */ {290 * CENT, 250 * CENT}, /* inputs */ {tx2}, /* input_indices */ {1}); - pool.addUnchecked(tx4->GetHash(), entry.Fee(10000LL).FromTx(tx4)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tx4)); // Ancestors / descendants should be: // transaction ancestors descendants @@ -696,13 +696,13 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests) CTransactionRef& tyi = *ty[i]; tyi = make_tx(/* output_values */ {v}, /* inputs */ i > 0 ? std::vector{*ty[i - 1]} : std::vector{}); v -= 50 * CENT; - pool.addUnchecked(tyi->GetHash(), entry.Fee(10000LL).FromTx(tyi)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(tyi)); pool.GetTransactionAncestry(tyi->GetHash(), ancestors, descendants); BOOST_CHECK_EQUAL(ancestors, i+1); BOOST_CHECK_EQUAL(descendants, i+1); } CTransactionRef ty6 = make_tx(/* output_values */ {5 * COIN}, /* inputs */ {tx3, ty5}); - pool.addUnchecked(ty6->GetHash(), entry.Fee(10000LL).FromTx(ty6)); + pool.addUnchecked(entry.Fee(10000LL).FromTx(ty6)); // Ancestors / descendants should be: // transaction ancestors descendants diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index e2424f012d..5e0d08fa84 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -115,19 +115,19 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis uint256 hashParentTx = tx.GetHash(); // save this txid for later use - mempool.addUnchecked(hashParentTx, entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = 5000000000LL - 10000; uint256 hashMediumFeeTx = tx.GetHash(); - mempool.addUnchecked(hashMediumFeeTx, entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a high fee, but depends on the first transaction tx.vin[0].prevout.hash = hashParentTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee uint256 hashHighFeeTx = tx.GetHash(); - mempool.addUnchecked(hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); std::unique_ptr pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); @@ -138,7 +138,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vin[0].prevout.hash = hashHighFeeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee uint256 hashFreeTx = tx.GetHash(); - mempool.addUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx)); + mempool.addUnchecked(entry.Fee(0).FromTx(tx)); size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // Calculate a fee on child transaction that will put the package just @@ -148,7 +148,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vin[0].prevout.hash = hashFreeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; uint256 hashLowFeeTx = tx.GetHash(); - mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx)); + mempool.addUnchecked(entry.Fee(feeToUse).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; iblock.vtx.size(); ++i) { @@ -162,7 +162,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& mempool.removeRecursive(tx); tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee hashLowFeeTx = tx.GetHash(); - mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse+2).FromTx(tx)); + mempool.addUnchecked(entry.Fee(feeToUse+2).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); @@ -175,7 +175,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& tx.vout[0].nValue = 5000000000LL - 100000000; tx.vout[1].nValue = 100000000; // 1BTC output uint256 hashFreeTx2 = tx.GetHash(); - mempool.addUnchecked(hashFreeTx2, entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); // This tx can't be mined by itself tx.vin[0].prevout.hash = hashFreeTx2; @@ -183,7 +183,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& feeToUse = blockMinFeeRate.GetFee(freeTxSize); tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; uint256 hashLowFeeTx2 = tx.GetHash(); - mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. @@ -196,7 +196,7 @@ static void TestPackageSelection(const CChainParams& chainparams, const CScript& // as well. tx.vin[0].prevout.n = 1; tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee - mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx)); + mempool.addUnchecked(entry.Fee(10000).FromTx(tx)); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } @@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } @@ -292,7 +292,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); @@ -312,7 +312,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); bool spendsCoinbase = i == 0; // only first tx spends coinbase - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); @@ -320,7 +320,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // orphan in mempool, template creation fails hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); mempool.clear(); @@ -329,7 +329,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; @@ -337,7 +337,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[1].prevout.n = 0; tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); mempool.clear(); @@ -348,7 +348,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); // give it a fee so it'll get mined - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw bad-cb-multiple BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); mempool.clear(); @@ -359,10 +359,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); mempool.clear(); @@ -401,12 +401,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end()); tx.vout[0].nValue -= LOWFEE; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); + mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw block-validation-failed BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); mempool.clear(); @@ -440,7 +440,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = 0; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); + mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block @@ -450,7 +450,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block prevheights[0] = baseheight + 2; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(CheckFinalTx(tx, flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = baseheight + 3; tx.nLockTime = chainActive.Tip()->nHeight + 1; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block @@ -477,7 +477,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights.resize(1); prevheights[0] = baseheight + 4; hash = tx.GetHash(); - mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); + mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(tx, flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index e45fb6d17e..df2b1c0fc3 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); txHashes[j].push_back(hash); } } @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); txHashes[j].push_back(hash); } } @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) for (int k = 0; k < 4; k++) { // add 4 fee txs tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); - mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); + mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); CTransactionRef ptx = mpool.get(hash); if (ptx) block.push_back(ptx); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 4d04b6ef6d..e6cc9abe08 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -352,7 +352,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n) nTransactionsUpdated += n; } -void CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) +void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) { NotifyEntryAdded(entry.GetSharedTx()); // Add to memory pool without checking anything. @@ -925,13 +925,13 @@ int CTxMemPool::Expire(int64_t time) { return stage.size(); } -void CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool validFeeEstimate) +void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate) { setEntries setAncestors; uint64_t nNoLimit = std::numeric_limits::max(); std::string dummy; CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); - return addUnchecked(hash, entry, setAncestors, validFeeEstimate); + return addUnchecked(entry, setAncestors, validFeeEstimate); } void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) diff --git a/src/txmempool.h b/src/txmempool.h index 2003783952..13c993e1ba 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -539,8 +539,8 @@ public: // Note that addUnchecked is ONLY called from ATMP outside of tests // and any other callers may break wallet's in-mempool tracking (due to // lack of CValidationInterface::TransactionAddedToMempool callbacks). - void addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); - void addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); + void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); + void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); diff --git a/src/validation.cpp b/src/validation.cpp index 702a8d7e05..38469e1f9c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -974,7 +974,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); // Store transaction in memory - pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation); + pool.addUnchecked(entry, setAncestors, validForFeeEstimation); // trim mempool and check if tx was trimmed if (!bypass_limits) { From 46f83453701fc6116d97de6a16986388ba63488f Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Thu, 26 Jul 2018 17:35:52 +0800 Subject: [PATCH 014/188] contrib: Support github pull request gitian-build --- contrib/gitian-build.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py index 5b8db1e73d..0e53c3dfd5 100755 --- a/contrib/gitian-build.py +++ b/contrib/gitian-build.py @@ -135,6 +135,7 @@ def main(): parser = argparse.ArgumentParser(usage='%(prog)s [options] signer version') parser.add_argument('-c', '--commit', action='store_true', dest='commit', help='Indicate that the version argument is for a commit or branch') + parser.add_argument('-p', '--pull', action='store_true', dest='pull', help='Indicate that the version argument is the number of a github repository pull request') parser.add_argument('-u', '--url', dest='url', default='https://github.com/bitcoin/bitcoin', help='Specify the URL of the repository. Default is %(default)s') parser.add_argument('-v', '--verify', action='store_true', dest='verify', help='Verify the Gitian build') parser.add_argument('-b', '--build', action='store_true', dest='build', help='Do a Gitian build') @@ -196,13 +197,21 @@ def main(): exit(1) # Add leading 'v' for tags + if args.commit and args.pull: + raise Exception('Cannot have both commit and pull') args.commit = ('' if args.commit else 'v') + args.version - print(args.commit) if args.setup: setup() os.chdir('bitcoin') + if args.pull: + subprocess.check_call(['git', 'fetch', args.url, 'refs/pull/'+args.version+'/merge']) + os.chdir('../gitian-builder/inputs/bitcoin') + subprocess.check_call(['git', 'fetch', args.url, 'refs/pull/'+args.version+'/merge']) + args.commit = subprocess.check_output(['git', 'show', '-s', '--format=%H', 'FETCH_HEAD'], universal_newlines=True).strip() + args.version = 'pull-' + args.version + print(args.commit) subprocess.check_call(['git', 'fetch']) subprocess.check_call(['git', 'checkout', args.commit]) os.chdir(workdir) From cdf4089457856bdfe336b6f4b337d7e1ea4fdbd3 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Thu, 26 Jul 2018 16:33:45 +0200 Subject: [PATCH 015/188] Remove redundant assignments (dead stores) --- src/bench/crypto_hash.cpp | 6 ++---- src/bench/rollingbloom.cpp | 3 +-- src/test/script_tests.cpp | 8 +++++--- src/txmempool.cpp | 7 +------ 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index 7d907eaf10..3ff106cb87 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -80,18 +80,16 @@ static void SipHash_32b(benchmark::State& state) static void FastRandom_32bit(benchmark::State& state) { FastRandomContext rng(true); - uint32_t x = 0; while (state.KeepRunning()) { - x += rng.rand32(); + rng.rand32(); } } static void FastRandom_1bit(benchmark::State& state) { FastRandomContext rng(true); - uint32_t x = 0; while (state.KeepRunning()) { - x += rng.randbool(); + rng.randbool(); } } diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp index f7f72605d7..f1363557f2 100644 --- a/src/bench/rollingbloom.cpp +++ b/src/bench/rollingbloom.cpp @@ -12,7 +12,6 @@ static void RollingBloom(benchmark::State& state) CRollingBloomFilter filter(120000, 0.000001); std::vector data(32); uint32_t count = 0; - uint64_t match = 0; while (state.KeepRunning()) { count++; data[0] = count; @@ -25,7 +24,7 @@ static void RollingBloom(benchmark::State& state) data[1] = count >> 16; data[2] = count >> 8; data[3] = count; - match += filter.contains(data); + filter.contains(data); } } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 510910e149..643da90f09 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -937,17 +937,19 @@ BOOST_AUTO_TEST_CASE(script_build) } } +#ifdef UPDATE_JSON_TESTS std::string strGen; - +#endif for (TestBuilder& test : tests) { test.Test(); std::string str = JSONPrettyPrint(test.GetJSON()); -#ifndef UPDATE_JSON_TESTS +#ifdef UPDATE_JSON_TESTS + strGen += str + ",\n"; +#else if (tests_set.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); } #endif - strGen += str + ",\n"; } #ifdef UPDATE_JSON_TESTS diff --git a/src/txmempool.cpp b/src/txmempool.cpp index d68c38ad4e..88ee3a3d43 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -640,8 +640,6 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; setEntries setParentCheck; - int64_t parentSizes = 0; - int64_t parentSigOpCost = 0; for (const CTxIn &txin : tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); @@ -649,10 +647,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; - if (setParentCheck.insert(it2).second) { - parentSizes += it2->GetTxSize(); - parentSigOpCost += it2->GetSigOpCost(); - } + setParentCheck.insert(it2); } else { assert(pcoins->HaveCoin(txin.prevout)); } From dd777f3e1220dd1a76e8a29cafdd4fe6244c5c0f Mon Sep 17 00:00:00 2001 From: practicalswift Date: Thu, 2 Aug 2018 09:22:44 +0200 Subject: [PATCH 016/188] Remove unused variable --- src/test/descriptor_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index f189222be8..e739b84a48 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -64,7 +64,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std: BOOST_CHECK_EQUAL(pub, pub2); // Check that both can be serialized with private key back to the private version, but not without private key. - std::string prv1, prv2; + std::string prv1; BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1)); BOOST_CHECK_EQUAL(prv, prv1); BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1)); From 384273260a6ccbcf79dade0830011f528e5a1581 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Fri, 11 May 2018 20:17:55 -0700 Subject: [PATCH 017/188] test: Add testing of value_ret for SelectCoinsBnB Fix that the early bailout optimization tests did not test the actual selection because their utxo pool was polluted by the make_hard_case test preceding. --- src/wallet/test/coinselector_tests.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 1561760577..f36b224344 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -150,6 +150,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(1 * CENT, 1, actual_selection); BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 1 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees)); BOOST_CHECK(equal_sets(selection, actual_selection)); + BOOST_CHECK_EQUAL(value_ret, 1 * CENT); actual_selection.clear(); selection.clear(); @@ -157,6 +158,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(2 * CENT, 2, actual_selection); BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 2 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees)); BOOST_CHECK(equal_sets(selection, actual_selection)); + BOOST_CHECK_EQUAL(value_ret, 2 * CENT); actual_selection.clear(); selection.clear(); @@ -165,6 +167,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(2 * CENT, 2, actual_selection); BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 5 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees)); BOOST_CHECK(equal_sets(selection, actual_selection)); + BOOST_CHECK_EQUAL(value_ret, 5 * CENT); actual_selection.clear(); selection.clear(); @@ -181,6 +184,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(1 * CENT, 1, actual_selection); BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 10 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees)); BOOST_CHECK(equal_sets(selection, actual_selection)); + BOOST_CHECK_EQUAL(value_ret, 10 * CENT); actual_selection.clear(); selection.clear(); @@ -190,6 +194,9 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(3 * CENT, 3, actual_selection); add_coin(2 * CENT, 2, actual_selection); BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 10 * CENT, 5000, selection, value_ret, not_input_fees)); + BOOST_CHECK_EQUAL(value_ret, 10 * CENT); + // FIXME: this test is redundant with the above, because 1 Cent is selected, not "too small" + // BOOST_CHECK(equal_sets(selection, actual_selection)); // Select 0.25 Cent, not possible BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 0.25 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees)); @@ -203,6 +210,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), target, 0, selection, value_ret, not_input_fees)); // Should not exhaust // Test same value early bailout optimization + utxo_pool.clear(); add_coin(7 * CENT, 7, actual_selection); add_coin(7 * CENT, 7, actual_selection); add_coin(7 * CENT, 7, actual_selection); @@ -217,6 +225,8 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(5 * CENT, 7, utxo_pool); } BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 30 * CENT, 5000, selection, value_ret, not_input_fees)); + BOOST_CHECK_EQUAL(value_ret, 30 * CENT); + BOOST_CHECK(equal_sets(selection, actual_selection)); //////////////////// // Behavior tests // From 41b88e93375d57db12da923f45f87b9a2db8e730 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 8 Nov 2017 15:28:35 -0500 Subject: [PATCH 018/188] Add unit test for DEBUG_LOCKORDER code --- src/Makefile.test.include | 1 + src/sync.cpp | 8 +++++++- src/sync.h | 7 +++++++ src/test/sync_tests.cpp | 41 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/test/sync_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 6f401636f5..516059917c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -81,6 +81,7 @@ BITCOIN_TESTS =\ test/sigopcount_tests.cpp \ test/skiplist_tests.cpp \ test/streams_tests.cpp \ + test/sync_tests.cpp \ test/timedata_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ diff --git a/src/sync.cpp b/src/sync.cpp index 28a4e37e68..96ea61b211 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -100,7 +100,11 @@ static void potential_deadlock_detected(const std::pair& mismatch, } LogPrintf(" %s\n", i.second.ToString()); } - assert(false); + if (g_debug_lockorder_abort) { + fprintf(stderr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__); + abort(); + } + throw std::logic_error("potential deadlock detected"); } static void push_lock(void* c, const CLockLocation& locklocation) @@ -189,4 +193,6 @@ void DeleteLock(void* cs) } } +bool g_debug_lockorder_abort = true; + #endif /* DEBUG_LOCKORDER */ diff --git a/src/sync.h b/src/sync.h index 882ad5dc4c..b8cb84f79f 100644 --- a/src/sync.h +++ b/src/sync.h @@ -77,6 +77,13 @@ std::string LocksHeld(); void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs); void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); void DeleteLock(void* cs); + +/** + * Call abort() if a potential lock order deadlock bug is detected, instead of + * just logging information and throwing a logic_error. Defaults to true, and + * set to false in DEBUG_LOCKORDER unit tests. + */ +extern bool g_debug_lockorder_abort; #else void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline LeaveCritical() {} diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp new file mode 100644 index 0000000000..2e0951c3a9 --- /dev/null +++ b/src/test/sync_tests.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2012-2017 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 +#include + +#include + +BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(potential_deadlock_detected) +{ + #ifdef DEBUG_LOCKORDER + bool prev = g_debug_lockorder_abort; + g_debug_lockorder_abort = false; + #endif + + CCriticalSection mutex1, mutex2; + { + LOCK2(mutex1, mutex2); + } + bool error_thrown = false; + try { + LOCK2(mutex2, mutex1); + } catch (const std::logic_error& e) { + BOOST_CHECK_EQUAL(e.what(), "potential deadlock detected"); + error_thrown = true; + } + #ifdef DEBUG_LOCKORDER + BOOST_CHECK(error_thrown); + #else + BOOST_CHECK(!error_thrown); + #endif + + #ifdef DEBUG_LOCKORDER + g_debug_lockorder_abort = prev; + #endif +} + +BOOST_AUTO_TEST_SUITE_END() From ba1f095aadf29bddb0bd8176d2e0b908f92a5623 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Thu, 7 Dec 2017 12:01:53 -0500 Subject: [PATCH 019/188] MOVEONLY Move AnnotatedMixin declaration Move AnnotatedMixin closer to where it's used, and after the DEBUG_LOCKORDER function declarations so it can call them. --- src/sync.h | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/sync.h b/src/sync.h index b8cb84f79f..c9a950799e 100644 --- a/src/sync.h +++ b/src/sync.h @@ -46,30 +46,6 @@ LEAVE_CRITICAL_SECTION(mutex); // no RAII // // /////////////////////////////// -/** - * Template mixin that adds -Wthread-safety locking - * annotations to a subset of the mutex API. - */ -template -class LOCKABLE AnnotatedMixin : public PARENT -{ -public: - void lock() EXCLUSIVE_LOCK_FUNCTION() - { - PARENT::lock(); - } - - void unlock() UNLOCK_FUNCTION() - { - PARENT::unlock(); - } - - bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true) - { - return PARENT::try_lock(); - } -}; - #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); void LeaveCritical(); @@ -94,6 +70,30 @@ void static inline DeleteLock(void* cs) {} #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) +/** + * Template mixin that adds -Wthread-safety locking + * annotations to a subset of the mutex API. + */ +template +class LOCKABLE AnnotatedMixin : public PARENT +{ +public: + void lock() EXCLUSIVE_LOCK_FUNCTION() + { + PARENT::lock(); + } + + void unlock() UNLOCK_FUNCTION() + { + PARENT::unlock(); + } + + bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true) + { + return PARENT::try_lock(); + } +}; + /** * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. From 1382913e61f5db6ba849b1e261e8aefcd5a1ae68 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 8 Nov 2017 16:21:13 -0500 Subject: [PATCH 020/188] Make LOCK, LOCK2, TRY_LOCK work with CWaitableCriticalSection They should also work with any other mutex type which std::unique_lock supports. There is no change in behavior for current code that calls these macros with CCriticalSection mutexes. --- src/sync.h | 61 ++++++++++++++++++++++------------------- src/test/sync_tests.cpp | 29 ++++++++++++++------ 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/sync.h b/src/sync.h index c9a950799e..339a7e2c18 100644 --- a/src/sync.h +++ b/src/sync.h @@ -71,13 +71,17 @@ void static inline DeleteLock(void* cs) {} #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) /** - * Template mixin that adds -Wthread-safety locking - * annotations to a subset of the mutex API. + * Template mixin that adds -Wthread-safety locking annotations and lock order + * checking to a subset of the mutex API. */ template class LOCKABLE AnnotatedMixin : public PARENT { public: + ~AnnotatedMixin() { + DeleteLock((void*)this); + } + void lock() EXCLUSIVE_LOCK_FUNCTION() { PARENT::lock(); @@ -92,19 +96,15 @@ public: { return PARENT::try_lock(); } + + using UniqueLock = std::unique_lock; }; /** * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ -class CCriticalSection : public AnnotatedMixin -{ -public: - ~CCriticalSection() { - DeleteLock((void*)this); - } -}; +typedef AnnotatedMixin CCriticalSection; /** Wrapped mutex: supports waiting but not recursive locking */ typedef AnnotatedMixin CWaitableCriticalSection; @@ -119,20 +119,19 @@ typedef std::unique_lock WaitableLock; void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif -/** Wrapper around std::unique_lock */ -class SCOPED_LOCKABLE CCriticalBlock +/** Wrapper around std::unique_lock style lock for Mutex. */ +template +class SCOPED_LOCKABLE CCriticalBlock : public Base { private: - std::unique_lock lock; - void Enter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); + EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex())); #ifdef DEBUG_LOCKCONTENTION - if (!lock.try_lock()) { + if (!Base::try_lock()) { PrintLockContention(pszName, pszFile, nLine); #endif - lock.lock(); + Base::lock(); #ifdef DEBUG_LOCKCONTENTION } #endif @@ -140,15 +139,15 @@ private: bool TryEnter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); - lock.try_lock(); - if (!lock.owns_lock()) + EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true); + Base::try_lock(); + if (!Base::owns_lock()) LeaveCritical(); - return lock.owns_lock(); + return Base::owns_lock(); } public: - CCriticalBlock(CCriticalSection& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, std::defer_lock) + CCriticalBlock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); @@ -156,11 +155,11 @@ public: Enter(pszName, pszFile, nLine); } - CCriticalBlock(CCriticalSection* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) + CCriticalBlock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; - lock = std::unique_lock(*pmutexIn, std::defer_lock); + *static_cast(this) = Base(*pmutexIn, std::defer_lock); if (fTry) TryEnter(pszName, pszFile, nLine); else @@ -169,22 +168,28 @@ public: ~CCriticalBlock() UNLOCK_FUNCTION() { - if (lock.owns_lock()) + if (Base::owns_lock()) LeaveCritical(); } operator bool() { - return lock.owns_lock(); + return Base::owns_lock(); } }; +template +using DebugLock = CCriticalBlock::type>::type>; + #define PASTE(x, y) x ## y #define PASTE2(x, y) PASTE(x, y) -#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) -#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__) -#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) +#define LOCK(cs) DebugLock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) +#define LOCK2(cs1, cs2) \ + DebugLock criticalblock1(cs1, #cs1, __FILE__, __LINE__); \ + DebugLock criticalblock2(cs2, #cs2, __FILE__, __LINE__); +#define TRY_LOCK(cs, name) DebugLock name(cs, #cs, __FILE__, __LINE__, true) +#define WAIT_LOCK(cs, name) DebugLock name(cs, #cs, __FILE__, __LINE__) #define ENTER_CRITICAL_SECTION(cs) \ { \ diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp index 2e0951c3a9..539e2ff3ab 100644 --- a/src/test/sync_tests.cpp +++ b/src/test/sync_tests.cpp @@ -7,16 +7,10 @@ #include -BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(potential_deadlock_detected) +namespace { +template +void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2) { - #ifdef DEBUG_LOCKORDER - bool prev = g_debug_lockorder_abort; - g_debug_lockorder_abort = false; - #endif - - CCriticalSection mutex1, mutex2; { LOCK2(mutex1, mutex2); } @@ -32,6 +26,23 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected) #else BOOST_CHECK(!error_thrown); #endif +} +} // namespace + +BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(potential_deadlock_detected) +{ + #ifdef DEBUG_LOCKORDER + bool prev = g_debug_lockorder_abort; + g_debug_lockorder_abort = false; + #endif + + CCriticalSection rmutex1, rmutex2; + TestPotentialDeadLockDetected(rmutex1, rmutex2); + + CWaitableCriticalSection mutex1, mutex2; + TestPotentialDeadLockDetected(mutex1, mutex2); #ifdef DEBUG_LOCKORDER g_debug_lockorder_abort = prev; From 9c4dc597ddc66acfd58a945a5ab11f833731abba Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 8 Nov 2017 17:07:40 -0500 Subject: [PATCH 021/188] Use LOCK macros for non-recursive locks Instead of std::unique_lock. --- src/httpserver.cpp | 8 ++++---- src/init.cpp | 4 ++-- src/net.cpp | 4 ++-- src/net.h | 2 +- src/random.cpp | 7 ++++--- src/rpc/blockchain.cpp | 8 ++++---- src/rpc/mining.cpp | 2 +- src/sync.h | 3 --- src/threadinterrupt.cpp | 6 ++++-- src/threadinterrupt.h | 4 +++- src/validation.cpp | 2 +- 11 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 9daf3d1968..ceddc7c2c5 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -69,7 +69,7 @@ class WorkQueue { private: /** Mutex protects entire object */ - std::mutex cs; + CWaitableCriticalSection cs; std::condition_variable cond; std::deque> queue; bool running; @@ -88,7 +88,7 @@ public: /** Enqueue a work item */ bool Enqueue(WorkItem* item) { - std::unique_lock lock(cs); + LOCK(cs); if (queue.size() >= maxDepth) { return false; } @@ -102,7 +102,7 @@ public: while (true) { std::unique_ptr i; { - std::unique_lock lock(cs); + WAIT_LOCK(cs, lock); while (running && queue.empty()) cond.wait(lock); if (!running) @@ -116,7 +116,7 @@ public: /** Interrupt and exit loops */ void Interrupt() { - std::unique_lock lock(cs); + LOCK(cs); running = false; cond.notify_all(); } diff --git a/src/init.cpp b/src/init.cpp index 21445929dc..8ab5790aea 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -566,7 +566,7 @@ static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) { if (pBlockIndex != nullptr) { { - WaitableLock lock_GenesisWait(cs_GenesisWait); + LOCK(cs_GenesisWait); fHaveGenesis = true; } condvar_GenesisWait.notify_all(); @@ -1660,7 +1660,7 @@ bool AppInitMain() // Wait for genesis block to be processed { - WaitableLock lock(cs_GenesisWait); + WAIT_LOCK(cs_GenesisWait, lock); // We previously could hang here if StartShutdown() is called prior to // ThreadImport getting started, so instead we just wait on a timer to // check ShutdownRequested() regularly. diff --git a/src/net.cpp b/src/net.cpp index 5be91fd4f3..37b452a71e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2064,7 +2064,7 @@ void CConnman::ThreadMessageHandler() pnode->Release(); } - std::unique_lock lock(mutexMsgProc); + WAIT_LOCK(mutexMsgProc, lock); if (!fMoreWork) { condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100), [this] { return fMsgProcWake; }); } @@ -2346,7 +2346,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) flagInterruptMsgProc = false; { - std::unique_lock lock(mutexMsgProc); + LOCK(mutexMsgProc); fMsgProcWake = false; } diff --git a/src/net.h b/src/net.h index 36c2a4b8f5..5c47f9695c 100644 --- a/src/net.h +++ b/src/net.h @@ -425,7 +425,7 @@ private: bool fMsgProcWake; std::condition_variable condMsgProc; - std::mutex mutexMsgProc; + CWaitableCriticalSection mutexMsgProc; std::atomic flagInterruptMsgProc; CThreadInterrupt interruptNet; diff --git a/src/random.cpp b/src/random.cpp index fee6c2d92a..7f05bcf9a2 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -12,6 +12,7 @@ #include #endif #include // for LogPrint() +#include // for WAIT_LOCK #include // for GetTime() #include @@ -295,7 +296,7 @@ void RandAddSeedSleep() } -static std::mutex cs_rng_state; +static CWaitableCriticalSection cs_rng_state; static unsigned char rng_state[32] = {0}; static uint64_t rng_counter = 0; @@ -305,7 +306,7 @@ static void AddDataToRng(void* data, size_t len) { hasher.Write((const unsigned char*)data, len); unsigned char buf[64]; { - std::unique_lock lock(cs_rng_state); + WAIT_LOCK(cs_rng_state, lock); hasher.Write(rng_state, sizeof(rng_state)); hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); ++rng_counter; @@ -337,7 +338,7 @@ void GetStrongRandBytes(unsigned char* out, int num) // Combine with and update state { - std::unique_lock lock(cs_rng_state); + WAIT_LOCK(cs_rng_state, lock); hasher.Write(rng_state, sizeof(rng_state)); hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); ++rng_counter; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 46dec4ca6e..3aa01914a6 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -49,7 +49,7 @@ struct CUpdatedBlock int height; }; -static std::mutex cs_blockchange; +static CWaitableCriticalSection cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock; @@ -224,7 +224,7 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); block = latestblock; if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); @@ -266,7 +266,7 @@ static UniValue waitforblock(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();}); else @@ -309,7 +309,7 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) CUpdatedBlock block; { - std::unique_lock lock(cs_blockchange); + WAIT_LOCK(cs_blockchange, lock); if(timeout) cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();}); else diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index e751587dc7..59bf0c98ab 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -470,7 +470,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - WaitableLock lock(g_best_block_mutex); + WAIT_LOCK(g_best_block_mutex, lock); while (g_best_block == hashWatchedChain && IsRPCRunning()) { if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) diff --git a/src/sync.h b/src/sync.h index 339a7e2c18..7306e7285e 100644 --- a/src/sync.h +++ b/src/sync.h @@ -112,9 +112,6 @@ typedef AnnotatedMixin CWaitableCriticalSection; /** Just a typedef for std::condition_variable, can be wrapped later if desired */ typedef std::condition_variable CConditionVariable; -/** Just a typedef for std::unique_lock, can be wrapped later if desired */ -typedef std::unique_lock WaitableLock; - #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp index 7da4e136ef..1efc6f3114 100644 --- a/src/threadinterrupt.cpp +++ b/src/threadinterrupt.cpp @@ -5,6 +5,8 @@ #include +#include + CThreadInterrupt::CThreadInterrupt() : flag(false) {} CThreadInterrupt::operator bool() const @@ -20,7 +22,7 @@ void CThreadInterrupt::reset() void CThreadInterrupt::operator()() { { - std::unique_lock lock(mut); + LOCK(mut); flag.store(true, std::memory_order_release); } cond.notify_all(); @@ -28,7 +30,7 @@ void CThreadInterrupt::operator()() bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time) { - std::unique_lock lock(mut); + WAIT_LOCK(mut, lock); return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); }); } diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h index d373e3c371..8ba6b12367 100644 --- a/src/threadinterrupt.h +++ b/src/threadinterrupt.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_THREADINTERRUPT_H #define BITCOIN_THREADINTERRUPT_H +#include + #include #include #include @@ -28,7 +30,7 @@ public: private: std::condition_variable cond; - std::mutex mut; + CWaitableCriticalSection mut; std::atomic flag; }; diff --git a/src/validation.cpp b/src/validation.cpp index 702a8d7e05..2d6ac4b234 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2254,7 +2254,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar mempool.AddTransactionsUpdated(1); { - WaitableLock lock(g_best_block_mutex); + LOCK(g_best_block_mutex); g_best_block = pindexNew->GetBlockHash(); g_best_block_cv.notify_all(); } From 1c5d22585384c8bb05a27a04eab5c57b31d623fb Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Sun, 22 Jul 2018 05:58:29 +0800 Subject: [PATCH 022/188] Drop boost::scoped_array --- src/qt/guiutil.cpp | 31 +++++++------------------------ test/lint/lint-includes.sh | 1 - 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 9dde2c392c..f49d5df389 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -38,8 +38,6 @@ #include #endif -#include - #include #include #include @@ -547,40 +545,28 @@ bool SetStartOnSystemStartup(bool fAutoStart) CoInitialize(nullptr); // Get a pointer to the IShellLink interface. - IShellLink* psl = nullptr; + IShellLinkW* psl = nullptr; HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, - CLSCTX_INPROC_SERVER, IID_IShellLink, + CLSCTX_INPROC_SERVER, IID_IShellLinkW, reinterpret_cast(&psl)); if (SUCCEEDED(hres)) { // Get the current executable path - TCHAR pszExePath[MAX_PATH]; - GetModuleFileName(nullptr, pszExePath, sizeof(pszExePath)); + WCHAR pszExePath[MAX_PATH]; + GetModuleFileNameW(nullptr, pszExePath, ARRAYSIZE(pszExePath)); // Start client minimized QString strArgs = "-min"; // Set -testnet /-regtest options strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false))); -#ifdef UNICODE - boost::scoped_array args(new TCHAR[strArgs.length() + 1]); - // Convert the QString to TCHAR* - strArgs.toWCharArray(args.get()); - // Add missing '\0'-termination to string - args[strArgs.length()] = '\0'; -#endif - // Set the path to the shortcut target psl->SetPath(pszExePath); - PathRemoveFileSpec(pszExePath); + PathRemoveFileSpecW(pszExePath); psl->SetWorkingDirectory(pszExePath); psl->SetShowCmd(SW_SHOWMINNOACTIVE); -#ifndef UNICODE - psl->SetArguments(strArgs.toStdString().c_str()); -#else - psl->SetArguments(args.get()); -#endif + psl->SetArguments(strArgs.toStdWString().c_str()); // Query IShellLink for the IPersistFile interface for // saving the shortcut in persistent storage. @@ -588,11 +574,8 @@ bool SetStartOnSystemStartup(bool fAutoStart) hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast(&ppf)); if (SUCCEEDED(hres)) { - WCHAR pwsz[MAX_PATH]; - // Ensure that the string is ANSI. - MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); // Save the link by calling IPersistFile::Save. - hres = ppf->Save(pwsz, TRUE); + hres = ppf->Save(StartupShortcutPath().wstring().c_str(), TRUE); ppf->Release(); psl->Release(); CoUninitialize(); diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index 8f7a1fd76b..2e8569a509 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -65,7 +65,6 @@ EXPECTED_BOOST_INCLUDES=( boost/optional.hpp boost/preprocessor/cat.hpp boost/preprocessor/stringize.hpp - boost/scoped_array.hpp boost/signals2/connection.hpp boost/signals2/last_value.hpp boost/signals2/signal.hpp From bb6ca65f9890e8280ace32de5a37774e14705859 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Tue, 31 Jul 2018 23:03:52 +0800 Subject: [PATCH 023/188] gui: get special folder in unicode --- src/util.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util.cpp b/src/util.cpp index 2f81f50a71..c2c93d966a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1118,14 +1118,14 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate) { - char pszPath[MAX_PATH] = ""; + WCHAR pszPath[MAX_PATH] = L""; - if(SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate)) + if(SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) { return fs::path(pszPath); } - LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); + LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n"); return fs::path(""); } #endif From 0e534d4dcae91ecf7ebd7a667227f7c26b4d5755 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 8 Aug 2018 21:12:14 +0200 Subject: [PATCH 024/188] Fix incorrect Doxygen comments --- src/policy/fees.h | 90 +++++++++++++++++++++---------------------- src/qt/bitcoingui.h | 2 +- src/qt/rpcconsole.cpp | 2 +- src/wallet/wallet.h | 2 +- 4 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/policy/fees.h b/src/policy/fees.h index 8c34bee237..717eabd74b 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -22,51 +22,6 @@ class CTxMemPoolEntry; class CTxMemPool; class TxConfirmStats; -/** \class CBlockPolicyEstimator - * The BlockPolicyEstimator is used for estimating the feerate needed - * for a transaction to be included in a block within a certain number of - * blocks. - * - * At a high level the algorithm works by grouping transactions into buckets - * based on having similar feerates and then tracking how long it - * takes transactions in the various buckets to be mined. It operates under - * the assumption that in general transactions of higher feerate will be - * included in blocks before transactions of lower feerate. So for - * example if you wanted to know what feerate you should put on a transaction to - * be included in a block within the next 5 blocks, you would start by looking - * at the bucket with the highest feerate transactions and verifying that a - * sufficiently high percentage of them were confirmed within 5 blocks and - * then you would look at the next highest feerate bucket, and so on, stopping at - * the last bucket to pass the test. The average feerate of transactions in this - * bucket will give you an indication of the lowest feerate you can put on a - * transaction and still have a sufficiently high chance of being confirmed - * within your desired 5 blocks. - * - * Here is a brief description of the implementation: - * When a transaction enters the mempool, we track the height of the block chain - * at entry. All further calculations are conducted only on this set of "seen" - * transactions. Whenever a block comes in, we count the number of transactions - * in each bucket and the total amount of feerate paid in each bucket. Then we - * calculate how many blocks Y it took each transaction to be mined. We convert - * from a number of blocks to a number of periods Y' each encompassing "scale" - * blocks. This is tracked in 3 different data sets each up to a maximum - * number of periods. Within each data set we have an array of counters in each - * feerate bucket and we increment all the counters from Y' up to max periods - * representing that a tx was successfully confirmed in less than or equal to - * that many periods. We want to save a history of this information, so at any - * time we have a counter of the total number of transactions that happened in a - * given feerate bucket and the total number that were confirmed in each of the - * periods or less for any bucket. We save this history by keeping an - * exponentially decaying moving average of each one of these stats. This is - * done for a different decay in each of the 3 data sets to keep relevant data - * from different time horizons. Furthermore we also keep track of the number - * unmined (in mempool or left mempool without being included in a block) - * transactions in each bucket and for how many blocks they have been - * outstanding and use both of these numbers to increase the number of transactions - * we've seen in that feerate bucket when calculating an estimate for any number - * of confirmations below the number of blocks they've been outstanding. - */ - /* Identifier for each of the 3 different TxConfirmStats which will track * history over different time horizons. */ enum class FeeEstimateHorizon { @@ -130,7 +85,50 @@ struct FeeCalculation int returnedTarget = 0; }; -/** +/** \class CBlockPolicyEstimator + * The BlockPolicyEstimator is used for estimating the feerate needed + * for a transaction to be included in a block within a certain number of + * blocks. + * + * At a high level the algorithm works by grouping transactions into buckets + * based on having similar feerates and then tracking how long it + * takes transactions in the various buckets to be mined. It operates under + * the assumption that in general transactions of higher feerate will be + * included in blocks before transactions of lower feerate. So for + * example if you wanted to know what feerate you should put on a transaction to + * be included in a block within the next 5 blocks, you would start by looking + * at the bucket with the highest feerate transactions and verifying that a + * sufficiently high percentage of them were confirmed within 5 blocks and + * then you would look at the next highest feerate bucket, and so on, stopping at + * the last bucket to pass the test. The average feerate of transactions in this + * bucket will give you an indication of the lowest feerate you can put on a + * transaction and still have a sufficiently high chance of being confirmed + * within your desired 5 blocks. + * + * Here is a brief description of the implementation: + * When a transaction enters the mempool, we track the height of the block chain + * at entry. All further calculations are conducted only on this set of "seen" + * transactions. Whenever a block comes in, we count the number of transactions + * in each bucket and the total amount of feerate paid in each bucket. Then we + * calculate how many blocks Y it took each transaction to be mined. We convert + * from a number of blocks to a number of periods Y' each encompassing "scale" + * blocks. This is tracked in 3 different data sets each up to a maximum + * number of periods. Within each data set we have an array of counters in each + * feerate bucket and we increment all the counters from Y' up to max periods + * representing that a tx was successfully confirmed in less than or equal to + * that many periods. We want to save a history of this information, so at any + * time we have a counter of the total number of transactions that happened in a + * given feerate bucket and the total number that were confirmed in each of the + * periods or less for any bucket. We save this history by keeping an + * exponentially decaying moving average of each one of these stats. This is + * done for a different decay in each of the 3 data sets to keep relevant data + * from different time horizons. Furthermore we also keep track of the number + * unmined (in mempool or left mempool without being included in a block) + * transactions in each bucket and for how many blocks they have been + * outstanding and use both of these numbers to increase the number of transactions + * we've seen in that feerate bucket when calculating an estimate for any number + * of confirmations below the number of blocks they've been outstanding. + * * We want to be able to estimate feerates that are needed on tx's to be included in * a certain number of blocks. Every time a block is added to the best chain, this class records * stats on the transactions included in that block diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index d7ca8081d1..34f80210c4 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -202,7 +202,7 @@ private: void setEncryptionStatus(int status); /** Set the hd-enabled status as shown in the UI. - @param[in] status current hd enabled status + @param[in] hdEnabled current hd enabled status @see WalletModel::EncryptionStatus */ void setHDStatus(int hdEnabled); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index f222357f27..e3fd24b9c7 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -144,7 +144,7 @@ public: * - Within single quotes, no escaping is possible and no special interpretation takes place * * @param[in] node optional node to execute command on - * @param[out] result stringified Result from the executed command(chain) + * @param[out] strResult stringified result from the executed command(chain) * @param[in] strCommand Command line to split * @param[in] fExecute set true if you want the command to be executed * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 06a7c0a752..ac87cbd2fd 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -989,7 +989,7 @@ public: unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE}; bool m_signal_rbf{DEFAULT_WALLET_RBF}; - bool m_allow_fallback_fee{true}; // Date: Fri, 13 Jul 2018 19:15:30 -0700 Subject: [PATCH 025/188] Move BerkeleyEnvironment deletion from internal method to callsite Instead of having the object destroy itself, having the caller destroy it. --- src/wallet/db.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index d0fe51801e..536243be4f 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -697,7 +697,6 @@ void BerkeleyEnvironment::Flush(bool fShutdown) if (!fMockDb) { fs::remove_all(fs::path(strPath) / "database"); } - g_dbenvs.erase(strPath); } } } @@ -796,6 +795,10 @@ void BerkeleyDatabase::Flush(bool shutdown) { if (!IsDummy()) { env->Flush(shutdown); - if (shutdown) env = nullptr; + if (shutdown) { + LOCK(cs_db); + g_dbenvs.erase(env->Directory().string()); + env = nullptr; + } } } From 5d296ac810755dc47f105eb95b52b7e2bcb8aea8 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 20 Feb 2018 15:28:42 -0500 Subject: [PATCH 026/188] Add function to close all Db's and reload the databae environment Adds a ReloadDbEnv function to BerkeleyEnvironment in order to close all Db instances, closes the environment, resets it, and then reopens the BerkeleyEnvironment. Also adds a ReloadDbEnv function to BerkeleyDatabase that calls BerkeleyEnvironment's ReloadDbEnv. --- src/wallet/db.cpp | 34 ++++++++++++++++++++++++++++++++++ src/wallet/db.h | 4 ++++ 2 files changed, 38 insertions(+) diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 536243be4f..2d57c92ccc 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -556,6 +556,7 @@ void BerkeleyBatch::Close() LOCK(cs_db); --env->mapFileUseCount[strFile]; } + env->m_db_in_use.notify_all(); } void BerkeleyEnvironment::CloseDb(const std::string& strFile) @@ -572,6 +573,32 @@ void BerkeleyEnvironment::CloseDb(const std::string& strFile) } } +void BerkeleyEnvironment::ReloadDbEnv() +{ + // Make sure that no Db's are in use + AssertLockNotHeld(cs_db); + std::unique_lock lock(cs_db); + m_db_in_use.wait(lock, [this](){ + for (auto& count : mapFileUseCount) { + if (count.second > 0) return false; + } + return true; + }); + + std::vector filenames; + for (auto it : mapDb) { + filenames.push_back(it.first); + } + // Close the individual Db's + for (const std::string& filename : filenames) { + CloseDb(filename); + } + // Reset the environment + Flush(true); // This will flush and close the environment + Reset(); + Open(true); +} + bool BerkeleyBatch::Rewrite(BerkeleyDatabase& database, const char* pszSkip) { if (database.IsDummy()) { @@ -802,3 +829,10 @@ void BerkeleyDatabase::Flush(bool shutdown) } } } + +void BerkeleyDatabase::ReloadDbEnv() +{ + if (!IsDummy()) { + env->ReloadDbEnv(); + } +} diff --git a/src/wallet/db.h b/src/wallet/db.h index b078edab7b..467ed13b45 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -38,6 +38,7 @@ public: std::unique_ptr dbenv; std::map mapFileUseCount; std::map mapDb; + std::condition_variable_any m_db_in_use; BerkeleyEnvironment(const fs::path& env_directory); ~BerkeleyEnvironment(); @@ -75,6 +76,7 @@ public: void CheckpointLSN(const std::string& strFile); void CloseDb(const std::string& strFile); + void ReloadDbEnv(); DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) { @@ -145,6 +147,8 @@ public: void IncrementUpdateCounter(); + void ReloadDbEnv(); + std::atomic nUpdateCounter; unsigned int nLastSeen; unsigned int nLastFlushed; From d7637c5a3f1d62922594cdfb6272e30dacf60ce9 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 20 Feb 2018 16:08:36 -0500 Subject: [PATCH 027/188] After encrypting the wallet, reload the database environment Calls ReloadDbEnv after encrypting the wallet so that the database environment is flushed, closed, and reopened to prevent unencrypted keys from being saved on disk. --- src/wallet/wallet.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 597d108aef..61d0686228 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -719,6 +719,11 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) // bits of the unencrypted private key in slack space in the database file. database->Rewrite(); + // BDB seems to have a bad habit of writing old data into + // slack space in .dat files; that is bad if the old data is + // unencrypted private keys. So: + database->ReloadDbEnv(); + } NotifyStatusChanged(this); From c1dde3a949b36ce9c2155777b3fa1372e7ed97d8 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 20 Feb 2018 16:09:51 -0500 Subject: [PATCH 028/188] No longer shutdown after encrypting the wallet Since the database environment is flushed, closed, and reopened during EncryptWallet, there is no need to shut down the software anymore. --- src/qt/askpassphrasedialog.cpp | 5 ++--- src/wallet/rpcwallet.cpp | 7 +------ test/functional/rpc_fundrawtransaction.py | 6 ++---- test/functional/test_framework/test_node.py | 8 -------- test/functional/wallet_bumpfee.py | 3 +-- test/functional/wallet_dump.py | 3 +-- test/functional/wallet_encryption.py | 3 +-- test/functional/wallet_keypool.py | 4 +--- 8 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 812d2251e1..612331523e 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -123,16 +123,15 @@ void AskPassphraseDialog::accept() { QMessageBox::warning(this, tr("Wallet encrypted"), "" + - tr("%1 will close now to finish the encryption process. " + tr("Your wallet is now encrypted. " "Remember that encrypting your wallet cannot fully protect " - "your bitcoins from being stolen by malware infecting your computer.").arg(tr(PACKAGE_NAME)) + + "your bitcoins from being stolen by malware infecting your computer.") + "

" + tr("IMPORTANT: Any previous backups you have made of your wallet file " "should be replaced with the newly generated, encrypted wallet file. " "For security reasons, previous backups of the unencrypted wallet file " "will become useless as soon as you start using the new, encrypted wallet.") + "
"); - QApplication::quit(); } else { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 73dfebf114..a1d58aba05 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2729,7 +2729,6 @@ static UniValue encryptwallet(const JSONRPCRequest& request) "will require the passphrase to be set prior the making these calls.\n" "Use the walletpassphrase call for this, and then walletlock call.\n" "If the wallet is already encrypted, use the walletpassphrasechange call.\n" - "Note that this will shutdown the server.\n" "\nArguments:\n" "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n" "\nExamples:\n" @@ -2767,11 +2766,7 @@ static UniValue encryptwallet(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet."); } - // BDB seems to have a bad habit of writing old data into - // slack space in .dat files; that is bad if the old data is - // unencrypted private keys. So: - StartShutdown(); - return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup."; + return "wallet encrypted; The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup."; } static UniValue lockunspent(const JSONRPCRequest& request) diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index a806de43b4..a4985a7a18 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -475,10 +475,8 @@ class RawTransactionsTest(BitcoinTestFramework): ############################################################ # locked wallet test - self.stop_node(0) - self.nodes[1].node_encrypt_wallet("test") - self.stop_node(2) - self.stop_node(3) + self.nodes[1].encryptwallet("test") + self.stop_nodes() self.start_nodes() # This test is not meant to test fee estimation and we'd like diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 56ea110f16..792d74de51 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -268,14 +268,6 @@ class TestNode(): assert_msg = "bitcoind should have exited with expected error " + expected_msg self._raise_assertion_error(assert_msg) - def node_encrypt_wallet(self, passphrase): - """"Encrypts the wallet. - - This causes bitcoind to shutdown, so this method takes - care of cleaning up resources.""" - self.encryptwallet(passphrase) - self.wait_until_stopped() - def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs): """Add a p2p connection to the node. diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 356393cfa4..5a7a1375ae 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -36,8 +36,7 @@ class BumpFeeTest(BitcoinTestFramework): def run_test(self): # Encrypt wallet for test_locked_wallet_fails test - self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE) - self.start_node(1) + self.nodes[1].encryptwallet(WALLET_PASSPHRASE) self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) connect_nodes_bi(self.nodes, 0, 1) diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index 63316d9644..7ddfd2c808 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -121,8 +121,7 @@ class WalletDumpTest(BitcoinTestFramework): assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key #encrypt wallet, restart, unlock and dump - self.nodes[0].node_encrypt_wallet('test') - self.start_node(0) + self.nodes[0].encryptwallet('test') self.nodes[0].walletpassphrase('test', 10) # Should be a no-op: self.nodes[0].keypoolrefill() diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index cec9660259..d5e797164b 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -30,8 +30,7 @@ class WalletEncryptionTest(BitcoinTestFramework): assert_equal(len(privkey), 52) # Encrypt the wallet - self.nodes[0].node_encrypt_wallet(passphrase) - self.start_node(0) + self.nodes[0].encryptwallet(passphrase) # Test that the wallet is encrypted assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index b00649162e..1d8e0cdf32 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -20,9 +20,7 @@ class KeyPoolTest(BitcoinTestFramework): assert(addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']) # Encrypt wallet and wait to terminate - nodes[0].node_encrypt_wallet('test') - # Restart node 0 - self.start_node(0) + nodes[0].encryptwallet('test') # Keep creating keys addr = nodes[0].getnewaddress() addr_data = nodes[0].getaddressinfo(addr) From a679109be40491222c458fdbef58f68509dae0bd Mon Sep 17 00:00:00 2001 From: "lucash.dev@gmail.com" Date: Sat, 12 May 2018 09:06:38 -0700 Subject: [PATCH 029/188] Speed up knapsack_solver_test by not recreating wallet 100 times. Moved the code for creating the wallet out of the 100-times repetition loop, for the most time-consuming tests. --- src/wallet/test/coinselector_tests.cpp | 57 +++++++++++++++----------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 0776ffda9c..c04a50c12b 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -452,14 +452,19 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) BOOST_CHECK(testWallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, filter_confirmed, GroupCoins(vCoins), setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); + } - // test with many inputs - for (CAmount amt=1500; amt < COIN; amt*=10) { - empty_wallet(); - // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input) - for (uint16_t j = 0; j < 676; j++) - add_coin(amt); + // test with many inputs + for (CAmount amt=1500; amt < COIN; amt*=10) { + empty_wallet(); + // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input) + for (uint16_t j = 0; j < 676; j++) + add_coin(amt); + + // We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times. + for (int i = 0; i < RUN_TESTS; i++) { BOOST_CHECK(testWallet.SelectCoinsMinConf(2000, filter_confirmed, GroupCoins(vCoins), setCoinsRet, nValueRet, coin_selection_params, bnb_used)); + if (amt - 2000 < MIN_CHANGE) { // needs more than one input: uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt); @@ -471,14 +476,17 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) BOOST_CHECK_EQUAL(nValueRet, amt); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); } - } + } + } - // test randomness - { - empty_wallet(); - for (int i2 = 0; i2 < 100; i2++) - add_coin(COIN); + // test randomness + { + empty_wallet(); + for (int i2 = 0; i2 < 100; i2++) + add_coin(COIN); + // Again, we only create the wallet once to save time, but we still run the coin selection RUN_TESTS times. + for (int i = 0; i < RUN_TESTS; i++) { // picking 50 from 100 coins doesn't depend on the shuffle, // but does depend on randomness in the stochastic approximation code BOOST_CHECK(testWallet.SelectCoinsMinConf(50 * COIN, filter_standard, GroupCoins(vCoins), setCoinsRet , nValueRet, coin_selection_params, bnb_used)); @@ -496,17 +504,19 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) fails++; } BOOST_CHECK_NE(fails, RANDOM_REPEATS); + } - // add 75 cents in small change. not enough to make 90 cents, - // then try making 90 cents. there are multiple competing "smallest bigger" coins, - // one of which should be picked at random - add_coin(5 * CENT); - add_coin(10 * CENT); - add_coin(15 * CENT); - add_coin(20 * CENT); - add_coin(25 * CENT); + // add 75 cents in small change. not enough to make 90 cents, + // then try making 90 cents. there are multiple competing "smallest bigger" coins, + // one of which should be picked at random + add_coin(5 * CENT); + add_coin(10 * CENT); + add_coin(15 * CENT); + add_coin(20 * CENT); + add_coin(25 * CENT); - fails = 0; + for (int i = 0; i < RUN_TESTS; i++) { + int fails = 0; for (int j = 0; j < RANDOM_REPEATS; j++) { // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time @@ -517,8 +527,9 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) fails++; } BOOST_CHECK_NE(fails, RANDOM_REPEATS); - } - } + } + } + empty_wallet(); } From fa6c3dea420b6c50c164ccc34f4e9e8a7d9a8022 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 12 Aug 2018 07:55:01 -0400 Subject: [PATCH 030/188] p2p: Clarify control flow in ProcessMessage() --- src/net_processing.cpp | 117 +++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 88999ba735..c31e1c0c60 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1618,8 +1618,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } - else if (strCommand == NetMsgType::VERSION) - { + if (strCommand == NetMsgType::VERSION) { // Each connection can only send one version message if (pfrom->nVersion != 0) { @@ -1796,9 +1795,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } - - else if (pfrom->nVersion == 0) - { + if (pfrom->nVersion == 0) { // Must have a version message before anything else LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); @@ -1842,18 +1839,17 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); } pfrom->fSuccessfullyConnected = true; + return true; } - else if (!pfrom->fSuccessfullyConnected) - { + if (!pfrom->fSuccessfullyConnected) { // Must have a verack message before anything else LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); return false; } - else if (strCommand == NetMsgType::ADDR) - { + if (strCommand == NetMsgType::ADDR) { std::vector vAddr; vRecv >> vAddr; @@ -1900,16 +1896,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->fGetAddr = false; if (pfrom->fOneShot) pfrom->fDisconnect = true; + return true; } - else if (strCommand == NetMsgType::SENDHEADERS) - { + if (strCommand == NetMsgType::SENDHEADERS) { LOCK(cs_main); State(pfrom->GetId())->fPreferHeaders = true; + return true; } - else if (strCommand == NetMsgType::SENDCMPCT) - { + if (strCommand == NetMsgType::SENDCMPCT) { bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = 0; vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; @@ -1929,11 +1925,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1); } } + return true; } - - else if (strCommand == NetMsgType::INV) - { + if (strCommand == NetMsgType::INV) { std::vector vInv; vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) @@ -1987,11 +1982,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } } } + return true; } - - else if (strCommand == NetMsgType::GETDATA) - { + if (strCommand == NetMsgType::GETDATA) { std::vector vInv; vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) @@ -2009,11 +2003,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); ProcessGetData(pfrom, chainparams, connman, interruptMsgProc); + return true; } - - else if (strCommand == NetMsgType::GETBLOCKS) - { + if (strCommand == NetMsgType::GETBLOCKS) { CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; @@ -2078,11 +2071,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr break; } } + return true; } - - else if (strCommand == NetMsgType::GETBLOCKTXN) - { + if (strCommand == NetMsgType::GETBLOCKTXN) { BlockTransactionsRequest req; vRecv >> req; @@ -2128,11 +2120,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr assert(ret); SendBlockTransactions(block, req, pfrom, connman); + return true; } - - else if (strCommand == NetMsgType::GETHEADERS) - { + if (strCommand == NetMsgType::GETHEADERS) { CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; @@ -2196,11 +2187,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // in the SendMessages logic. nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + return true; } - - else if (strCommand == NetMsgType::TX) - { + if (strCommand == NetMsgType::TX) { // Stop processing the transaction early if // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) @@ -2384,10 +2374,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr Misbehaving(pfrom->GetId(), nDoS); } } + return true; } - - else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing + if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing { CBlockHeaderAndShortTxIDs cmpctblock; vRecv >> cmpctblock; @@ -2605,10 +2595,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr MarkBlockAsReceived(pblock->GetHash()); } } - + return true; } - else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing + if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing { BlockTransactions resp; vRecv >> resp; @@ -2680,10 +2670,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr mapBlockSource.erase(pblock->GetHash()); } } + return true; } - - else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing + if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing { std::vector headers; @@ -2708,7 +2698,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish); } - else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing + if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing { std::shared_ptr pblock = std::make_shared(); vRecv >> *pblock; @@ -2734,11 +2724,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(cs_main); mapBlockSource.erase(pblock->GetHash()); } + return true; } - - else if (strCommand == NetMsgType::GETADDR) - { + if (strCommand == NetMsgType::GETADDR) { // This asymmetric behavior for inbound and outbound connections was introduced // to prevent a fingerprinting attack: an attacker can send specific fake addresses // to users' AddrMan and later request them by sending getaddr messages. @@ -2762,11 +2751,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr FastRandomContext insecure_rand; for (const CAddress &addr : vAddr) pfrom->PushAddress(addr, insecure_rand); + return true; } - - else if (strCommand == NetMsgType::MEMPOOL) - { + if (strCommand == NetMsgType::MEMPOOL) { if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted) { LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId()); @@ -2783,11 +2771,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(pfrom->cs_inventory); pfrom->fSendMempool = true; + return true; } - - else if (strCommand == NetMsgType::PING) - { + if (strCommand == NetMsgType::PING) { if (pfrom->nVersion > BIP0031_VERSION) { uint64_t nonce = 0; @@ -2805,11 +2792,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // return very quickly. connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); } + return true; } - - else if (strCommand == NetMsgType::PONG) - { + if (strCommand == NetMsgType::PONG) { int64_t pingUsecEnd = nTimeReceived; uint64_t nonce = 0; size_t nAvail = vRecv.in_avail(); @@ -2862,11 +2848,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (bPingFinished) { pfrom->nPingNonceSent = 0; } + return true; } - - else if (strCommand == NetMsgType::FILTERLOAD) - { + if (strCommand == NetMsgType::FILTERLOAD) { CBloomFilter filter; vRecv >> filter; @@ -2883,11 +2868,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->pfilter->UpdateEmptyFull(); pfrom->fRelayTxes = true; } + return true; } - - else if (strCommand == NetMsgType::FILTERADD) - { + if (strCommand == NetMsgType::FILTERADD) { std::vector vData; vRecv >> vData; @@ -2908,19 +2892,19 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(cs_main); Misbehaving(pfrom->GetId(), 100); } + return true; } - - else if (strCommand == NetMsgType::FILTERCLEAR) - { + if (strCommand == NetMsgType::FILTERCLEAR) { LOCK(pfrom->cs_filter); if (pfrom->GetLocalServices() & NODE_BLOOM) { pfrom->pfilter.reset(new CBloomFilter()); } pfrom->fRelayTxes = true; + return true; } - else if (strCommand == NetMsgType::FEEFILTER) { + if (strCommand == NetMsgType::FEEFILTER) { CAmount newFeeFilter = 0; vRecv >> newFeeFilter; if (MoneyRange(newFeeFilter)) { @@ -2930,20 +2914,17 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId()); } + return true; } - else if (strCommand == NetMsgType::NOTFOUND) { + if (strCommand == NetMsgType::NOTFOUND) { // We do not care about the NOTFOUND message, but logging an Unknown Command // message would be undesirable as we transmit it ourselves. + return true; } - else { - // Ignore unknown commands for extensibility - LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId()); - } - - - + // Ignore unknown commands for extensibility + LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId()); return true; } From 611ab307fbd8b6f8f7ffc1d569bb86d1f9cb4e92 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Jul 2018 23:15:53 -0700 Subject: [PATCH 031/188] Introduce KeyOriginInfo for fingerprint + path --- src/rpc/rawtransaction.cpp | 15 ++++----------- src/script/sign.h | 32 ++++++++++++++++++++++---------- src/wallet/rpcwallet.cpp | 15 ++++++++------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 608a1b5da2..8d96add13b 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1460,11 +1460,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) UniValue keypath(UniValue::VOBJ); keypath.pushKV("pubkey", HexStr(entry.first)); - uint32_t fingerprint = entry.second.at(0); - keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint))); - - entry.second.erase(entry.second.begin()); - keypath.pushKV("path", WriteHDKeypath(entry.second)); + keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint))); + keypath.pushKV("path", WriteHDKeypath(entry.second.path)); keypaths.push_back(keypath); } in.pushKV("bip32_derivs", keypaths); @@ -1522,12 +1519,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) for (auto entry : output.hd_keypaths) { UniValue keypath(UniValue::VOBJ); keypath.pushKV("pubkey", HexStr(entry.first)); - - uint32_t fingerprint = entry.second.at(0); - keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint))); - - entry.second.erase(entry.second.begin()); - keypath.pushKV("path", WriteHDKeypath(entry.second)); + keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint))); + keypath.pushKV("path", WriteHDKeypath(entry.second.path)); keypaths.push_back(keypath); } out.pushKV("bip32_derivs", keypaths); diff --git a/src/script/sign.h b/src/script/sign.h index d2033af731..e0668f8c58 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -20,6 +20,12 @@ class CTransaction; struct CMutableTransaction; +struct KeyOriginInfo +{ + unsigned char fingerprint[4]; + std::vector path; +}; + /** An interface to be implemented by keystores that support signing. */ class SigningProvider { @@ -155,7 +161,7 @@ void UnserializeFromVector(Stream& s, X&... args) // Deserialize HD keypaths into a map template -void DeserializeHDKeypaths(Stream& s, const std::vector& key, std::map>& hd_keypaths) +void DeserializeHDKeypaths(Stream& s, const std::vector& key, std::map& hd_keypaths) { // Make sure that the key is the size of pubkey + 1 if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) { @@ -172,25 +178,31 @@ void DeserializeHDKeypaths(Stream& s, const std::vector& key, std // Read in key path uint64_t value_len = ReadCompactSize(s); - std::vector keypath; - for (unsigned int i = 0; i < value_len; i += sizeof(uint32_t)) { + if (value_len % 4 || value_len == 0) { + throw std::ios_base::failure("Invalid length for HD key path"); + } + + KeyOriginInfo keypath; + s >> keypath.fingerprint; + for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) { uint32_t index; s >> index; - keypath.push_back(index); + keypath.path.push_back(index); } // Add to map - hd_keypaths.emplace(pubkey, keypath); + hd_keypaths.emplace(pubkey, std::move(keypath)); } // Serialize HD keypaths to a stream from a map template -void SerializeHDKeypaths(Stream& s, const std::map>& hd_keypaths, uint8_t type) +void SerializeHDKeypaths(Stream& s, const std::map& hd_keypaths, uint8_t type) { for (auto keypath_pair : hd_keypaths) { SerializeToVector(s, type, MakeSpan(keypath_pair.first)); - WriteCompactSize(s, keypath_pair.second.size() * sizeof(uint32_t)); - for (auto& path : keypath_pair.second) { + WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t)); + s << keypath_pair.second.fingerprint; + for (const auto& path : keypath_pair.second.path) { s << path; } } @@ -205,7 +217,7 @@ struct PSBTInput CScript witness_script; CScript final_script_sig; CScriptWitness final_script_witness; - std::map> hd_keypaths; + std::map hd_keypaths; std::map partial_sigs; std::map, std::vector> unknown; int sighash_type = 0; @@ -413,7 +425,7 @@ struct PSBTOutput { CScript redeem_script; CScript witness_script; - std::map> hd_keypaths; + std::map hd_keypaths; std::map, std::vector> unknown; bool IsNull() const; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4aed097364..fd3b82d9ab 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4464,7 +4464,7 @@ bool ParseHDKeypath(std::string keypath_str, std::vector& keypath) return true; } -void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map>& hd_keypaths) +void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map& hd_keypaths) { CPubKey vchPubKey; if (!pwallet->GetPubKey(keyID, vchPubKey)) { @@ -4475,9 +4475,9 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::mapmapKeyMetadata.end()) { meta = it->second; } - std::vector keypath; + KeyOriginInfo info; if (!meta.hdKeypath.empty()) { - if (!ParseHDKeypath(meta.hdKeypath, keypath)) { + if (!ParseHDKeypath(meta.hdKeypath, info.path)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken"); } // Get the proper master key id @@ -4485,12 +4485,13 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::mapGetKey(meta.hd_seed_id, key); CExtKey masterKey; masterKey.SetSeed(key.begin(), key.size()); - // Add to map - keypath.insert(keypath.begin(), ReadLE32(masterKey.key.GetPubKey().GetID().begin())); + // Compute identifier + CKeyID masterid = masterKey.key.GetPubKey().GetID(); + std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint); } else { // Single pubkeys get the master fingerprint of themselves - keypath.insert(keypath.begin(), ReadLE32(vchPubKey.GetID().begin())); + std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); } - hd_keypaths.emplace(vchPubKey, keypath); + hd_keypaths.emplace(vchPubKey, std::move(info)); } bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs) From 84f1f1bfdf900cd28099e428441aa42f9d11a0ed Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Jul 2018 17:25:21 -0700 Subject: [PATCH 032/188] Make SigningProvider expose key origin information --- src/script/sign.cpp | 9 +++++++-- src/script/sign.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 1982e8a832..47931e21d9 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -645,9 +645,14 @@ bool PublicOnlySigningProvider::GetCScript(const CScriptID &scriptid, CScript& s return m_provider->GetCScript(scriptid, script); } -bool PublicOnlySigningProvider::GetPubKey(const CKeyID &address, CPubKey& pubkey) const +bool PublicOnlySigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { - return m_provider->GetPubKey(address, pubkey); + return m_provider->GetPubKey(keyid, pubkey); +} + +bool PublicOnlySigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const +{ + return m_provider->GetKeyOrigin(keyid, info); } bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); } diff --git a/src/script/sign.h b/src/script/sign.h index e0668f8c58..323fe70f34 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -34,6 +34,7 @@ public: virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; } virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; } virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; } + virtual bool GetKeyOrigin(const CKeyID& id, KeyOriginInfo& info) const { return false; } }; extern const SigningProvider& DUMMY_SIGNING_PROVIDER; @@ -47,6 +48,7 @@ public: PublicOnlySigningProvider(const SigningProvider* provider) : m_provider(provider) {} bool GetCScript(const CScriptID &scriptid, CScript& script) const; bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const; + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const; }; struct FlatSigningProvider final : public SigningProvider From 81e1dd5ce1a32114a38691ec6b55e72ab04dbbb1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 20 Jul 2018 00:04:02 -0700 Subject: [PATCH 033/188] Generalize PublicOnlySigningProvider into HidingSigningProvider --- src/script/sign.cpp | 13 ++++++++++--- src/script/sign.h | 13 ++++++++----- src/wallet/rpcwallet.cpp | 6 +----- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 47931e21d9..ae29f72b05 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -640,18 +640,25 @@ void PSBTOutput::Merge(const PSBTOutput& output) if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script; } -bool PublicOnlySigningProvider::GetCScript(const CScriptID &scriptid, CScript& script) const +bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return m_provider->GetCScript(scriptid, script); } -bool PublicOnlySigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const +bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return m_provider->GetPubKey(keyid, pubkey); } -bool PublicOnlySigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const +bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { + if (m_hide_secret) return false; + return m_provider->GetKey(keyid, key); +} + +bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const +{ + if (m_hide_origin) return false; return m_provider->GetKeyOrigin(keyid, info); } diff --git a/src/script/sign.h b/src/script/sign.h index 323fe70f34..d8334f2ea2 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -39,16 +39,19 @@ public: extern const SigningProvider& DUMMY_SIGNING_PROVIDER; -class PublicOnlySigningProvider : public SigningProvider +class HidingSigningProvider : public SigningProvider { private: + const bool m_hide_secret; + const bool m_hide_origin; const SigningProvider* m_provider; public: - PublicOnlySigningProvider(const SigningProvider* provider) : m_provider(provider) {} - bool GetCScript(const CScriptID &scriptid, CScript& script) const; - bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const; - bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const; + HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {} + bool GetCScript(const CScriptID& scriptid, CScript& script) const override; + bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; + bool GetKey(const CKeyID& keyid, CKey& key) const override; + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; }; struct FlatSigningProvider final : public SigningProvider diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fd3b82d9ab..a719e883c7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4520,11 +4520,7 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C } SignatureData sigdata; - if (sign) { - complete &= SignPSBTInput(*pwallet, *psbtx.tx, input, sigdata, i, sighash_type); - } else { - complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), *psbtx.tx, input, sigdata, i, sighash_type); - } + complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, false), *psbtx.tx, input, sigdata, i, sighash_type); if (it != pwallet->mapWallet.end()) { // Drop the unnecessary UTXO if we added both from the wallet. From 3b01efa0d1bf3d23d1b7b7e518849f1fc26314f9 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Jul 2018 17:37:19 -0700 Subject: [PATCH 034/188] [MOVEONLY] Move ParseHDKeypath to utilstrencodings --- src/utilstrencodings.cpp | 40 ++++++++++++++++++++++++++ src/utilstrencodings.h | 3 ++ src/wallet/rpcwallet.cpp | 41 --------------------------- src/wallet/test/psbt_wallet_tests.cpp | 2 -- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index a06d88cb19..e66e2c238c 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -544,3 +544,43 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) return true; } +bool ParseHDKeypath(const std::string& keypath_str, std::vector& keypath) +{ + std::stringstream ss(keypath_str); + std::string item; + bool first = true; + while (std::getline(ss, item, '/')) { + if (item.compare("m") == 0) { + if (first) { + first = false; + continue; + } + return false; + } + // Finds whether it is hardened + uint32_t path = 0; + size_t pos = item.find("'"); + if (pos != std::string::npos) { + // The hardened tick can only be in the last index of the string + if (pos != item.size() - 1) { + return false; + } + path |= 0x80000000; + item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick + } + + // Ensure this is only numbers + if (item.find_first_not_of( "0123456789" ) != std::string::npos) { + return false; + } + uint32_t number; + if (!ParseUInt32(item, &number)) { + return false; + } + path |= number; + + keypath.push_back(path); + first = false; + } + return true; +} diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 5f2211b5dc..8f29f8f322 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -183,4 +183,7 @@ bool ConvertBits(const O& outfn, I it, I end) { return true; } +/** Parse an HD keypaths like "m/7/0'/2000". */ +bool ParseHDKeypath(const std::string& keypath_str, std::vector& keypath); + #endif // BITCOIN_UTILSTRENCODINGS_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a719e883c7..aa7f5312b4 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4423,47 +4423,6 @@ UniValue sethdseed(const JSONRPCRequest& request) return NullUniValue; } -bool ParseHDKeypath(std::string keypath_str, std::vector& keypath) -{ - std::stringstream ss(keypath_str); - std::string item; - bool first = true; - while (std::getline(ss, item, '/')) { - if (item.compare("m") == 0) { - if (first) { - first = false; - continue; - } - return false; - } - // Finds whether it is hardened - uint32_t path = 0; - size_t pos = item.find("'"); - if (pos != std::string::npos) { - // The hardened tick can only be in the last index of the string - if (pos != item.size() - 1) { - return false; - } - path |= 0x80000000; - item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick - } - - // Ensure this is only numbers - if (item.find_first_not_of( "0123456789" ) != std::string::npos) { - return false; - } - uint32_t number; - if (!ParseUInt32(item, &number)) { - return false; - } - path |= number; - - keypath.push_back(path); - first = false; - } - return true; -} - void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map& hd_keypaths) { CPubKey vchPubKey; diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index 61c3fa94a6..526f2d983f 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -13,8 +13,6 @@ #include #include -extern bool ParseHDKeypath(std::string keypath_str, std::vector& keypath); - BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup) BOOST_AUTO_TEST_CASE(psbt_updater_test) From 03a99586a398ee38f40c3b72d24c6a2ba4b88579 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Jul 2018 17:56:52 -0700 Subject: [PATCH 035/188] Implement key origin lookup in CWallet --- src/wallet/rpcwallet.cpp | 21 ++------------------- src/wallet/wallet.cpp | 26 ++++++++++++++++++++++++++ src/wallet/wallet.h | 2 ++ 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index aa7f5312b4..0fcdd780a7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4429,26 +4429,9 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::mapGetPubKey(keyID, vchPubKey)) { return; } - CKeyMetadata meta; - auto it = pwallet->mapKeyMetadata.find(keyID); - if (it != pwallet->mapKeyMetadata.end()) { - meta = it->second; - } KeyOriginInfo info; - if (!meta.hdKeypath.empty()) { - if (!ParseHDKeypath(meta.hdKeypath, info.path)) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken"); - } - // Get the proper master key id - CKey key; - pwallet->GetKey(meta.hd_seed_id, key); - CExtKey masterKey; - masterKey.SetSeed(key.begin(), key.size()); - // Compute identifier - CKeyID masterid = masterKey.key.GetPubKey().GetID(); - std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint); - } else { // Single pubkeys get the master fingerprint of themselves - std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); + if (!pwallet->GetKeyOrigin(keyID, info)) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken"); } hd_keypaths.emplace(vchPubKey, std::move(info)); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5a7fdf9a85..92ffc3c108 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4466,3 +4466,29 @@ std::vector CWallet::GroupOutputs(const std::vector& outpu } return groups; } + +bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const +{ + CKeyMetadata meta; + { + LOCK(cs_wallet); + auto it = mapKeyMetadata.find(keyID); + if (it != mapKeyMetadata.end()) { + meta = it->second; + } + } + if (!meta.hdKeypath.empty()) { + if (!ParseHDKeypath(meta.hdKeypath, info.path)) return false; + // Get the proper master key id + CKey key; + GetKey(meta.hd_seed_id, key); + CExtKey masterKey; + masterKey.SetSeed(key.begin(), key.size()); + // Compute identifier + CKeyID masterid = masterKey.key.GetPubKey().GetID(); + std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint); + } else { // Single pubkeys get the master fingerprint of themselves + std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); + } + return true; +} diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 57b22c0e49..e9f6a45243 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1211,6 +1211,8 @@ public: LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...); }; + /** Implement lookup of key origin information through wallet key metadata. */ + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; }; /** A key allocated from the key pool. */ From cad5dd2368109ec398a3b79c8b9e94dfd23f0845 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Jul 2018 18:47:24 -0700 Subject: [PATCH 036/188] Pass HD path data through SignatureData --- src/script/sign.cpp | 24 +++++++++++++++++------- src/script/sign.h | 2 +- src/wallet/rpcwallet.cpp | 18 ++---------------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index ae29f72b05..4060111ff2 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -50,10 +50,6 @@ static bool GetCScript(const SigningProvider& provider, const SignatureData& sig static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey) { - if (provider.GetPubKey(address, pubkey)) { - sigdata.misc_pubkeys.emplace(pubkey.GetID(), pubkey); - return true; - } // Look for pubkey in all partial sigs const auto it = sigdata.signatures.find(address); if (it != sigdata.signatures.end()) { @@ -63,7 +59,15 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c // Look for pubkey in pubkey list const auto& pk_it = sigdata.misc_pubkeys.find(address); if (pk_it != sigdata.misc_pubkeys.end()) { - pubkey = pk_it->second; + pubkey = pk_it->second.first; + return true; + } + // Query the underlying provider + if (provider.GetPubKey(address, pubkey)) { + KeyOriginInfo info; + if (provider.GetKeyOrigin(address, info)) { + sigdata.misc_pubkeys.emplace(address, std::make_pair(pubkey, std::move(info))); + } return true; } return false; @@ -543,7 +547,7 @@ void PSBTInput::FillSignatureData(SignatureData& sigdata) const sigdata.witness_script = witness_script; } for (const auto& key_pair : hd_keypaths) { - sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first); + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); } } @@ -571,6 +575,9 @@ void PSBTInput::FromSignatureData(const SignatureData& sigdata) if (witness_script.empty() && !sigdata.witness_script.empty()) { witness_script = sigdata.witness_script; } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } } void PSBTInput::Merge(const PSBTInput& input) @@ -612,7 +619,7 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const sigdata.witness_script = witness_script; } for (const auto& key_pair : hd_keypaths) { - sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first); + sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); } } @@ -624,6 +631,9 @@ void PSBTOutput::FromSignatureData(const SignatureData& sigdata) if (witness_script.empty() && !sigdata.witness_script.empty()) { witness_script = sigdata.witness_script; } + for (const auto& entry : sigdata.misc_pubkeys) { + hd_keypaths.emplace(entry.second); + } } bool PSBTOutput::IsNull() const diff --git a/src/script/sign.h b/src/script/sign.h index d8334f2ea2..a4e1eac403 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -109,7 +109,7 @@ struct SignatureData { CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs. CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144. std::map signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness. - std::map misc_pubkeys; + std::map> misc_pubkeys; SignatureData() {} explicit SignatureData(const CScript& script) : scriptSig(script) {} diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0fcdd780a7..c2cd4ea2a0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4462,7 +4462,7 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C } SignatureData sigdata; - complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, false), *psbtx.tx, input, sigdata, i, sighash_type); + complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, sigdata, i, sighash_type); if (it != pwallet->mapWallet.end()) { // Drop the unnecessary UTXO if we added both from the wallet. @@ -4472,13 +4472,6 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C input.witness_utxo.SetNull(); } } - - // Get public key paths - if (bip32derivs) { - for (const auto& pubkey_it : sigdata.misc_pubkeys) { - AddKeypathToMap(pwallet, pubkey_it.first, input.hd_keypaths); - } - } } // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change @@ -4496,15 +4489,8 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C psbt_out.FillSignatureData(sigdata); MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1); - ProduceSignature(*pwallet, creator, out.scriptPubKey, sigdata); + ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata); psbt_out.FromSignatureData(sigdata); - - // Get public key paths - if (bip32derivs) { - for (const auto& pubkey_it : sigdata.misc_pubkeys) { - AddKeypathToMap(pwallet, pubkey_it.first, psbt_out.hd_keypaths); - } - } } return complete; } From 917353c8b0eff4cd95f9a5f7719f6756bb8338b1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 20 Jul 2018 00:23:32 -0700 Subject: [PATCH 037/188] Make SignPSBTInput operate on a private SignatureData object --- src/rpc/rawtransaction.cpp | 3 +-- src/script/sign.cpp | 13 ++++++++++++- src/script/sign.h | 2 +- src/wallet/rpcwallet.cpp | 12 +----------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 8d96add13b..4f9b399a91 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1641,8 +1641,7 @@ UniValue finalizepsbt(const JSONRPCRequest& request) for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) { PSBTInput& input = psbtx.inputs.at(i); - SignatureData sigdata; - complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, sigdata, i, 1); + complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, i, 1); } UniValue result(UniValue::VOBJ); diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 4060111ff2..ea14abce4c 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -237,7 +237,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato return sigdata.complete; } -bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash) +bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash) { // if this input has a final scriptsig or scriptwitness, don't do anything with it if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) { @@ -245,6 +245,7 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t } // Fill SignatureData with input info + SignatureData sigdata; input.FillSignatureData(sigdata); // Get UTXO @@ -276,6 +277,16 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t // Verify that a witness signature was produced in case one was required. if (require_witness_sig && !sigdata.witness) return false; input.FromSignatureData(sigdata); + + // If both UTXO types are present, drop the unnecessary one. + if (input.non_witness_utxo && !input.witness_utxo.IsNull()) { + if (sigdata.witness) { + input.non_witness_utxo = nullptr; + } else { + input.witness_utxo.SetNull(); + } + } + return sig_complete; } diff --git a/src/script/sign.h b/src/script/sign.h index a4e1eac403..160b3be75b 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -696,7 +696,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); /** Signs a PSBTInput, verifying that all provided data matches what is being signed. */ -bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1); +bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash = SIGHASH_ALL); /** Extract signature data from a transaction input, and insert it. */ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c2cd4ea2a0..b8e7b7fe0c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4461,17 +4461,7 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Specified Sighash and sighash in PSBT do not match."); } - SignatureData sigdata; - complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, sigdata, i, sighash_type); - - if (it != pwallet->mapWallet.end()) { - // Drop the unnecessary UTXO if we added both from the wallet. - if (sigdata.witness) { - input.non_witness_utxo = nullptr; - } else { - input.witness_utxo.SetNull(); - } - } + complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type); } // Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change From 321159e53e800c1df2d8dfd6ac03374f1829c327 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Tue, 14 Aug 2018 11:34:27 -0400 Subject: [PATCH 038/188] don't report minversion wallet entry as unknown --- src/wallet/walletdb.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 15c5b82c52..1b787be198 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -509,7 +509,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: Unknown non-tolerable wallet flags found"; return false; } - } else if (strType != "bestblock" && strType != "bestblock_nomerkle") { + } else if (strType != "bestblock" && strType != "bestblock_nomerkle" && + strType != "minversion") { wss.m_unknown_records++; } } catch (...) From 19efc01aec6b0d8750413fa1b721e04aaecf8f73 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 31 Jul 2018 16:53:02 -0700 Subject: [PATCH 039/188] Add PSBT documentation --- doc/README.md | 1 + doc/psbt.md | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 doc/psbt.md diff --git a/doc/README.md b/doc/README.md index 5ffff825b4..b3f875c4a4 100644 --- a/doc/README.md +++ b/doc/README.md @@ -75,6 +75,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th - [Tor Support](tor.md) - [Init Scripts (systemd/upstart/openrc)](init.md) - [ZMQ](zmq.md) +- [PSBT support](psbt.md) License --------------------- diff --git a/doc/psbt.md b/doc/psbt.md new file mode 100644 index 0000000000..95e2f7fa01 --- /dev/null +++ b/doc/psbt.md @@ -0,0 +1,132 @@ +# PSBT Howto for Bitcoin Core + +Since Bitcoin Core 0.17, an RPC interface exists for Partially Signed Bitcoin +Transactions (PSBTs, as specified in +[BIP 174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki)). + +This document describes the overall workflow for producing signed transactions +through the use of PSBT, and the specific RPC commands used in typical +scenarios. + +## PSBT in general + +PSBT is an interchange format for Bitcoin transactions that are not fully signed +yet, together with relevant metadata to help entities work towards signing it. +It is intended to simplify workflows where multiple parties need to cooperate to +produce a transaction. Examples include hardware wallets, multisig setups, and +[CoinJoin](https://bitcointalk.org/?topic=279249) transactions. + +### Overall workflow + +Overall, the construction of a fully signed Bitcoin transaction goes through the +following steps: + +- A **Creator** proposes a particular transaction to be created. They construct + a PSBT that contains certain inputs and outputs, but no additional metadata. +- For each input, an **Updater** adds information about the UTXOs being spent by + the transaction to the PSBT. They also add information about the scripts and + public keys involved in each of the inputs (and possibly outputs) of the PSBT. +- **Signers** inspect the transaction and its metadata to decide whether they + agree with the transaction. They can use amount information from the UTXOs + to assess the values and fees involved. If they agree, they produce a + partial signature for the inputs for which they have relevant key(s). +- A **Finalizer** is run for each input to convert the partial signatures and + possibly script information into a final `scriptSig` and/or `scriptWitness`. +- An **Extractor** produces a valid Bitcoin transaction (in network format) + from a PSBT for which all inputs are finalized. + +Generally, each of the above (excluding Creator and Extractor) will simply +add more and more data to a particular PSBT, until all inputs are fully signed. +In a naive workflow, they all have to operate sequentially, passing the PSBT +from one to the next, until the Extractor can convert it to a real transaction. +In order to permit parallel operation, **Combiners** can be employed which merge +metadata from different PSBTs for the same unsigned transaction. + +The names above in bold are the names of the roles defined in BIP174. They're +useful in understanding the underlying steps, but in practice, software and +hardware implementations will typically implement multiple roles simultaneously. + +## PSBT in Bitcoin Core + +### RPCs + +- **`converttopsbt` (Creator)** is a utility RPC that converts an + unsigned raw transaction to PSBT format. It ignores existing signatures. +- **`createpsbt` (Creator)** is a utility RPC that takes a list of inputs and + outputs and converts them to a PSBT with no additional information. It is + equivalent to calling `createrawtransaction` followed by `converttopsbt`. +- **`walletcreatefundedpsbt` (Creator, Updater)** is a wallet RPC that creates a + PSBT with the specified inputs and outputs, adds additional inputs and change + to it to balance it out, and adds relevant metadata. In particular, for inputs + that the wallet knows about (counting towards its normal or watch-only + balance), UTXO information will be added. For outputs and inputs with UTXO + information present, key and script information will be added which the wallet + knows about. It is equivalent to running `createrawtransaction`, followed by + `fundrawtransaction`, and `converttopsbt`. +- **`walletprocesspsbt` (Updater, Signer, Finalizer)** is a wallet RPC that takes as + input a PSBT, adds UTXO, key, and script data to inputs and outputs that miss + it, and optionally signs inputs. Where possible it also finalizes the partial + signatures. +- **`finalizepsbt` (Finalizer, Extractor)** is a utility RPC that finalizes any + partial signatures, and if all inputs are finalized, converts the result to a + fully signed transaction which can be broadcast with `sendrawtransaction`. +- **`combinepsbt` (Combiner)** is a utility RPC that implements a Combiner. It + can be used at any point in the workflow to merge information added to + different versions of the same PSBT. In particular it is useful to combine the + output of multiple Updaters or Signers. +- **`decodepsbt`** is a diagnostic utility RPC which will show all information in + a PSBT in human-readable form, as well as compute its eventual fee if known. + +### Workflows + +#### Multisig with multiple Bitcoin Core instances + +Alice, Bob, and Carol want to create a 2-of-3 multisig address. They're all using +Bitcoin Core. We assume their wallets only contain the multisig funds. In case +they also have a personal wallet, this can be accomplished through the +multiwallet feature - possibly resulting in a need to add `-rpcwallet=name` to +the command line in case `bitcoin-cli` is used. + +Setup: +- All three call `getnewaddress` to create a new address; call these addresses + *Aalice*, *Abob*, and *Acarol*. +- All three call `getaddressinfo X`, with *X* their respective address, and + remember the corresponding public keys. Call these public keys *Kalice*, + *Kbob*, and *Kcarol*. +- All three now run `addmultisigaddress 2 ["Kalice","Kbob","Kcarol"]` to teach + their wallet about the multisig script. Call the address produced by this + command *Amulti*. They may be required to explicitly specify the same + addresstype option each, to avoid constructing different versions due to + differences in configuration. +- They also run `importaddress "Amulti" "" false` to make their wallets treat + payments to *Amulti* as contributing to the watch-only balance. +- Others can verify the produced address by running + `createmultisig 2 ["Kalice","Kbob","Kcarol"]`, and expecting *Amulti* as + output. Again, it may be necessary to explicitly specify the addresstype + in order to get a result that matches. This command won't enable them to + initiate transactions later, however. +- They can now give out *D* as address others can pay to. + +Later, when *V* BTC has been received on *Amulti*, and Bob and Carol want to +move the coins in their entirety to address *Asend*, with no change. Alice +does not need to be involved. +- One of them - let's assume Carol here - initiates the creation. She runs + `walletcreatefundedpsbt [] {"Asend":V} 0 false {"subtractFeeFromOutputs":[0], "includeWatching":true}`. + We call the resulting PSBT *P*. P does not contain any signatures. +- Carol needs to sign the transaction herself. In order to do so, she runs + `walletprocesspsbt P`, and gives the resulting PSBT *P2* to Bob. +- Bob inspects the PSBT using `decodepsbt "P2"` to determine if the transaction + has indeed just the expected input, and an output to *Asend*, and the fee is + reasonable. If he agrees, he calls `walletprocesspsbt "P2"` to sign. The + resulting PSBT *P3* contains both Carol's and Bob's signature. +- Now anyone can call `finalizepsbt "P2"` to extract a fully signed transaction + *T*. +- Finally anyone can broadcast the transaction using `sendrawtransaction "T"`. + +In case there are more signers, it may be advantageous to let them all sign in +parallel, rather passing the PSBT from one signer to the next one. In the +above example this would translate to Carol handing a copy of *P* to each signer +separately. They can then all invoke `walletprocesspsbt P`, and end up with +their individually-signed PSBT structures. They then all send those back to +Carol (or anyone) who can combine them using `combinepsbt`. The last two steps +(`finalizepsbt` and `sendrawtransaction`) remain unchanged. From fa6ab8ada14dd265e224496440ab0b5d99dfd0ef Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 15 Aug 2018 13:54:36 -0400 Subject: [PATCH 040/188] rpc: Return more specific reject reason for submitblock --- src/rpc/mining.cpp | 6 +----- test/functional/mining_basic.py | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 623b0bd86a..8365f5ed42 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -750,11 +750,7 @@ static UniValue submitblock(const JSONRPCRequest& request) RegisterValidationInterface(&sc); bool accepted = ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block); UnregisterValidationInterface(&sc); - if (!new_block) { - if (!accepted) { - // TODO Maybe pass down fNewBlock to AcceptBlockHeader, so it is properly set to true in this case? - return "invalid"; - } + if (!new_block && accepted) { return "duplicate"; } if (!sc.found) { diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 15b2d7f757..ddf760c283 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -41,6 +41,12 @@ class MiningTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] + def assert_submitblock(block, result_str_1, result_str_2=None): + block.solve() + result_str_2 = result_str_2 or 'duplicate-invalid' + assert_equal(result_str_1, node.submitblock(hexdata=b2x(block.serialize()))) + assert_equal(result_str_2, node.submitblock(hexdata=b2x(block.serialize()))) + self.log.info('getmininginfo') mining_info = node.getmininginfo() assert_equal(mining_info['blocks'], 200) @@ -93,6 +99,7 @@ class MiningTest(BitcoinTestFramework): bad_block = copy.deepcopy(block) bad_block.vtx.append(bad_block.vtx[0]) assert_template(node, bad_block, 'bad-txns-duplicate') + assert_submitblock(bad_block, 'bad-txns-duplicate', 'bad-txns-duplicate') self.log.info("getblocktemplate: Test invalid transaction") bad_block = copy.deepcopy(block) @@ -101,12 +108,14 @@ class MiningTest(BitcoinTestFramework): bad_tx.rehash() bad_block.vtx.append(bad_tx) assert_template(node, bad_block, 'bad-txns-inputs-missingorspent') + assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent') self.log.info("getblocktemplate: Test nonfinal transaction") bad_block = copy.deepcopy(block) bad_block.vtx[0].nLockTime = 2 ** 32 - 1 bad_block.vtx[0].rehash() assert_template(node, bad_block, 'bad-txns-nonfinal') + assert_submitblock(bad_block, 'bad-txns-nonfinal') self.log.info("getblocktemplate: Test bad tx count") # The tx count is immediately after the block header @@ -125,24 +134,29 @@ class MiningTest(BitcoinTestFramework): bad_block = copy.deepcopy(block) bad_block.hashMerkleRoot += 1 assert_template(node, bad_block, 'bad-txnmrklroot', False) + assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot') self.log.info("getblocktemplate: Test bad timestamps") bad_block = copy.deepcopy(block) bad_block.nTime = 2 ** 31 - 1 assert_template(node, bad_block, 'time-too-new') + assert_submitblock(bad_block, 'time-too-new', 'time-too-new') bad_block.nTime = 0 assert_template(node, bad_block, 'time-too-old') + assert_submitblock(bad_block, 'time-too-old', 'time-too-old') self.log.info("getblocktemplate: Test not best block") bad_block = copy.deepcopy(block) bad_block.hashPrevBlock = 123 assert_template(node, bad_block, 'inconclusive-not-best-prevblk') + assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found') self.log.info('submitheader tests') assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * 80)) assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * 78)) assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata='ff' * 80)) + block.nTime += 1 block.solve() def chain_tip(b_hash, *, status='headers-only', branchlen=1): @@ -161,7 +175,8 @@ class MiningTest(BitcoinTestFramework): node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert chain_tip(bad_block_root.hash) in node.getchaintips() # Should still reject invalid blocks, even if we have the header: - assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'invalid') + assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') + assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') assert chain_tip(bad_block_root.hash) in node.getchaintips() # We know the header for this invalid block, so should just return early without error: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) @@ -172,7 +187,8 @@ class MiningTest(BitcoinTestFramework): bad_block_lock.vtx[0].rehash() bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root() bad_block_lock.solve() - assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'invalid') + assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'bad-txns-nonfinal') + assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'duplicate-invalid') # Build a "good" block on top of the submitted bad block bad_block2 = copy.deepcopy(block) bad_block2.hashPrevBlock = bad_block_lock.sha256 @@ -198,6 +214,7 @@ class MiningTest(BitcoinTestFramework): assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize()))) node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) + assert_equal(node.submitblock(hexdata=b2x(block.serialize())), 'duplicate') # valid if __name__ == '__main__': From 48618daf262b84c2e2f7322b5ca14375d7d68b64 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Thu, 9 Aug 2018 01:52:42 +1000 Subject: [PATCH 041/188] Add checks for settxfee reasonableness --- src/wallet/rpcwallet.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 281fd46146..46162556eb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2982,8 +2982,16 @@ static UniValue settxfee(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); CAmount nAmount = AmountFromValue(request.params[0]); + CFeeRate tx_fee_rate(nAmount, 1000); + if (tx_fee_rate == 0) { + // automatic selection + } else if (tx_fee_rate < ::minRelayTxFee) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", ::minRelayTxFee.ToString())); + } else if (tx_fee_rate < pwallet->m_min_fee) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString())); + } - pwallet->m_pay_tx_fee = CFeeRate(nAmount, 1000); + pwallet->m_pay_tx_fee = tx_fee_rate; return true; } From 18c49eb8877d8b11f763083a79a7b8250e060106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Fri, 17 Aug 2018 15:33:02 +0100 Subject: [PATCH 042/188] http: Add const modifier to HTTPRequest methods --- src/httpserver.cpp | 8 ++++---- src/httpserver.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 8962fe6a42..0fdc3e5ff3 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -536,7 +536,7 @@ HTTPRequest::~HTTPRequest() // evhttpd cleans up the request, as long as a reply was sent. } -std::pair HTTPRequest::GetHeader(const std::string& hdr) +std::pair HTTPRequest::GetHeader(const std::string& hdr) const { const struct evkeyvalq* headers = evhttp_request_get_input_headers(req); assert(headers); @@ -606,7 +606,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) req = nullptr; // transferred back to main thread } -CService HTTPRequest::GetPeer() +CService HTTPRequest::GetPeer() const { evhttp_connection* con = evhttp_request_get_connection(req); CService peer; @@ -620,12 +620,12 @@ CService HTTPRequest::GetPeer() return peer; } -std::string HTTPRequest::GetURI() +std::string HTTPRequest::GetURI() const { return evhttp_request_get_uri(req); } -HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod() +HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod() const { switch (evhttp_request_get_command(req)) { case EVHTTP_REQ_GET: diff --git a/src/httpserver.h b/src/httpserver.h index fa7cc4a5d3..67c6a88314 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -74,21 +74,21 @@ public: /** Get requested URI. */ - std::string GetURI(); + std::string GetURI() const; /** Get CService (address:ip) for the origin of the http request. */ - CService GetPeer(); + CService GetPeer() const; /** Get request method. */ - RequestMethod GetRequestMethod(); + RequestMethod GetRequestMethod() const; /** * Get the request header specified by hdr, or an empty string. * Return a pair (isPresent,string). */ - std::pair GetHeader(const std::string& hdr); + std::pair GetHeader(const std::string& hdr) const; /** * Read request body. From d9d79576f423cd9c5cef4547c7e3648dbb339460 Mon Sep 17 00:00:00 2001 From: Kostiantyn Stepaniuk Date: Mon, 20 Aug 2018 14:19:43 +0200 Subject: [PATCH 043/188] Preserve a format of RPC command definitions Currently RPC commands are formatted in a way that it's easy to read and that test/lint/check-rpc-mappings.py can parse it. To void breaking test/lint/check-rpc-mappings.py script by running clang-format, RPC command definitions should be disabled for clang-format. --- src/coins.h | 4 ++-- src/rpc/blockchain.cpp | 2 ++ src/rpc/client.cpp | 2 ++ src/rpc/mining.cpp | 2 ++ src/rpc/misc.cpp | 2 ++ src/rpc/net.cpp | 2 ++ src/rpc/rawtransaction.cpp | 2 ++ src/rpc/server.cpp | 2 ++ src/wallet/rpcwallet.cpp | 2 ++ 9 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/coins.h b/src/coins.h index 41a422f485..3867a37b39 100644 --- a/src/coins.h +++ b/src/coins.h @@ -285,8 +285,8 @@ public: * Note that lightweight clients may not know anything besides the hash of previous transactions, * so may not be able to calculate this. * - * @param[in] tx transaction for which we are checking input total - * @return Sum of value of all inputs (scriptSigs) + * @param[in] tx transaction for which we are checking input total + * @return Sum of value of all inputs (scriptSigs) */ CAmount GetValueIn(const CTransaction& tx) const; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 51bc218d39..9bc955542f 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2179,6 +2179,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) return result; } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -2214,6 +2215,7 @@ static const CRPCCommand commands[] = { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} }, { "hidden", "syncwithvalidationinterfacequeue", &syncwithvalidationinterfacequeue, {} }, }; +// clang-format on void RegisterBlockchainRPCCommands(CRPCTable &t) { diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 6738b206c9..7fb8eb9255 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -18,6 +18,7 @@ public: std::string paramName; //!< parameter name }; +// clang-format off /** * Specify a (method, idx, name) here if the argument is a non-string RPC * argument and needs to be converted from JSON. @@ -174,6 +175,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "rescanblockchain", 1, "stop_height"}, { "createwallet", 1, "disable_private_keys"}, }; +// clang-format on class CRPCConvertTable { diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 623b0bd86a..a69feb37ad 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -968,6 +968,7 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) return result; } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -986,6 +987,7 @@ static const CRPCCommand commands[] = { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} }, }; +// clang-format on void RegisterMiningRPCCommands(CRPCTable &t) { diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 40418545c1..d8a5a921ea 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -456,6 +456,7 @@ static UniValue echo(const JSONRPCRequest& request) return request.params; } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -471,6 +472,7 @@ static const CRPCCommand commands[] = { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, { "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, }; +// clang-format on void RegisterMiscRPCCommands(CRPCTable &t) { diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 610a1fee6f..c6efb63d65 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -624,6 +624,7 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) return g_connman->GetNetworkActive(); } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -640,6 +641,7 @@ static const CRPCCommand commands[] = { "network", "clearbanned", &clearbanned, {} }, { "network", "setnetworkactive", &setnetworkactive, {"state"} }, }; +// clang-format on void RegisterNetRPCCommands(CRPCTable &t) { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 608a1b5da2..0df0f97200 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1801,6 +1801,7 @@ UniValue converttopsbt(const JSONRPCRequest& request) return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); } +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -1822,6 +1823,7 @@ static const CRPCCommand commands[] = { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, }; +// clang-format on void RegisterRawTransactionRPCCommands(CRPCTable &t) { diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e46bf2f765..367a68475c 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -255,6 +255,7 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest) return GetTime() - GetStartupTime(); } +// clang-format off /** * Call Table */ @@ -266,6 +267,7 @@ static const CRPCCommand vRPCCommands[] = { "control", "stop", &stop, {} }, { "control", "uptime", &uptime, {} }, }; +// clang-format on CRPCTable::CRPCTable() { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 281fd46146..65b3235a89 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4760,6 +4760,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request); UniValue removeprunedfunds(const JSONRPCRequest& request); UniValue importmulti(const JSONRPCRequest& request); +// clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -4834,6 +4835,7 @@ static const CRPCCommand commands[] = { "generating", "generate", &generate, {"nblocks","maxtries"} }, }; +// clang-format on void RegisterWalletRPCCommands(CRPCTable &t) { From 317f2cb3f4499afbaa63e3cac80567744f12c95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Mon, 20 Aug 2018 18:34:39 +0100 Subject: [PATCH 044/188] test: Check RPC settxfee errors --- test/functional/wallet_bumpfee.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index dd95bb5e22..a49590df19 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -31,7 +31,7 @@ class BumpFeeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True - self.extra_args = [["-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i)] + self.extra_args = [["-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i), "-mintxfee=0.00002"] for i in range(self.num_nodes)] def run_test(self): @@ -190,6 +190,8 @@ def test_dust_to_fee(rbf_node, dest_address): def test_settxfee(rbf_node, dest_address): + assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.000005')) + assert_raises_rpc_error(-8, "txfee cannot be less than wallet min fee", rbf_node.settxfee, Decimal('0.000015')) # check that bumpfee reacts correctly to the use of settxfee (paytxfee) rbfid = spend_one_input(rbf_node, dest_address) requested_feerate = Decimal("0.00025000") From f78558f1e39198779bdb17e2b0e256fb99ad4b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Sun, 24 Jun 2018 16:18:22 +0100 Subject: [PATCH 045/188] qt: Use new Qt5 connect syntax --- src/qt/addressbookpage.cpp | 22 +++---- src/qt/askpassphrasedialog.cpp | 8 +-- src/qt/bitcoin.cpp | 39 ++++++------ src/qt/bitcoinamountfield.cpp | 6 +- src/qt/bitcoingui.cpp | 93 +++++++++++++++-------------- src/qt/bitcoingui.h | 10 ++-- src/qt/clientmodel.cpp | 2 +- src/qt/coincontroldialog.cpp | 40 ++++++------- src/qt/guiutil.cpp | 8 +-- src/qt/intro.cpp | 8 +-- src/qt/modaloverlay.cpp | 2 +- src/qt/optionsdialog.cpp | 46 +++++++------- src/qt/overviewpage.cpp | 14 ++--- src/qt/paymentserver.cpp | 13 ++-- src/qt/peertablemodel.cpp | 2 +- src/qt/qvalidatedlineedit.cpp | 2 +- src/qt/qvaluecombobox.cpp | 2 +- src/qt/receivecoinsdialog.cpp | 18 +++--- src/qt/receiverequestdialog.cpp | 8 +-- src/qt/recentrequeststablemodel.cpp | 2 +- src/qt/rpcconsole.cpp | 60 +++++++++---------- src/qt/rpcconsole.h | 3 +- src/qt/sendcoinsdialog.cpp | 64 ++++++++++---------- src/qt/sendcoinsentry.cpp | 14 ++--- src/qt/test/paymentservertests.cpp | 8 +-- src/qt/test/util.cpp | 2 +- src/qt/test/wallettests.cpp | 2 +- src/qt/trafficgraphwidget.cpp | 2 +- src/qt/transactiontablemodel.cpp | 2 +- src/qt/transactionview.cpp | 51 ++++++++-------- src/qt/walletframe.cpp | 6 +- src/qt/walletmodel.cpp | 2 +- src/qt/walletview.cpp | 41 +++++++------ 33 files changed, 301 insertions(+), 301 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index e1d9b1addf..26bdf60d4a 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -85,7 +85,7 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break; case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break; } - connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept())); + connect(ui->tableView, &QTableView::doubleClicked, this, &QDialog::accept); ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableView->setFocus(); ui->closeButton->setText(tr("C&hoose")); @@ -129,14 +129,14 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, contextMenu->addSeparator(); // Connect signals for context menu actions - connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked())); - connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction())); - connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction())); - connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked())); + connect(copyAddressAction, &QAction::triggered, this, &AddressBookPage::on_copyAddress_clicked); + connect(copyLabelAction, &QAction::triggered, this, &AddressBookPage::onCopyLabelAction); + connect(editAction, &QAction::triggered, this, &AddressBookPage::onEditAction); + connect(deleteAction, &QAction::triggered, this, &AddressBookPage::on_deleteAddress_clicked); - connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); + connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu); - connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept); } AddressBookPage::~AddressBookPage() @@ -154,7 +154,7 @@ void AddressBookPage::setModel(AddressTableModel *_model) proxyModel = new AddressBookSortFilterProxyModel(type, this); proxyModel->setSourceModel(_model); - connect(ui->searchLineEdit, SIGNAL(textChanged(QString)), proxyModel, SLOT(setFilterWildcard(QString))); + connect(ui->searchLineEdit, &QLineEdit::textChanged, proxyModel, &QSortFilterProxyModel::setFilterWildcard); ui->tableView->setModel(proxyModel); ui->tableView->sortByColumn(0, Qt::AscendingOrder); @@ -163,11 +163,11 @@ void AddressBookPage::setModel(AddressTableModel *_model) ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); - connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(selectionChanged())); + connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &AddressBookPage::selectionChanged); // Select row for newly created address - connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int))); + connect(_model, &AddressTableModel::rowsInserted, this, &AddressBookPage::selectNewAddress); selectionChanged(); } diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 812d2251e1..673f63a19b 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -70,10 +70,10 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) : break; } textChanged(); - connect(ui->toggleShowPasswordButton, SIGNAL(toggled(bool)), this, SLOT(toggleShowPassword(bool))); - connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); - connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); - connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(ui->toggleShowPasswordButton, &QPushButton::toggled, this, &AskPassphraseDialog::toggleShowPassword); + connect(ui->passEdit1, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged); + connect(ui->passEdit2, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged); + connect(ui->passEdit3, &QLineEdit::textChanged, this, &AskPassphraseDialog::textChanged); } AskPassphraseDialog::~AskPassphraseDialog() diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d3ec67e441..85fb88d338 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -353,7 +353,7 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) window = new BitcoinGUI(m_node, platformStyle, networkStyle, 0); pollShutdownTimer = new QTimer(window); - connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown())); + connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown); } void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) @@ -362,8 +362,8 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) // We don't hold a direct pointer to the splash screen after creation, but the splash // screen will take care of deleting itself when slotFinish happens. splash->show(); - connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*))); - connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close())); + connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::slotFinish); + connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close); } void BitcoinApplication::startThread() @@ -375,14 +375,14 @@ void BitcoinApplication::startThread() executor->moveToThread(coreThread); /* communication to and from thread */ - connect(executor, SIGNAL(initializeResult(bool)), this, SLOT(initializeResult(bool))); - connect(executor, SIGNAL(shutdownResult()), this, SLOT(shutdownResult())); - connect(executor, SIGNAL(runawayException(QString)), this, SLOT(handleRunawayException(QString))); - connect(this, SIGNAL(requestedInitialize()), executor, SLOT(initialize())); - connect(this, SIGNAL(requestedShutdown()), executor, SLOT(shutdown())); + connect(executor, &BitcoinCore::initializeResult, this, &BitcoinApplication::initializeResult); + connect(executor, &BitcoinCore::shutdownResult, this, &BitcoinApplication::shutdownResult); + connect(executor, &BitcoinCore::runawayException, this, &BitcoinApplication::handleRunawayException); + connect(this, &BitcoinApplication::requestedInitialize, executor, &BitcoinCore::initialize); + connect(this, &BitcoinApplication::requestedShutdown, executor, &BitcoinCore::shutdown); /* make sure executor object is deleted in its own thread */ - connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater())); - connect(this, SIGNAL(stopThread()), coreThread, SLOT(quit())); + connect(this, &BitcoinApplication::stopThread, executor, &QObject::deleteLater); + connect(this, &BitcoinApplication::stopThread, coreThread, &QThread::quit); coreThread->start(); } @@ -442,9 +442,9 @@ void BitcoinApplication::addWallet(WalletModel* walletModel) window->setCurrentWallet(walletModel->getWalletName()); } - connect(walletModel, SIGNAL(coinsSent(WalletModel*, SendCoinsRecipient, QByteArray)), - paymentServer, SLOT(fetchPaymentACK(WalletModel*, const SendCoinsRecipient&, QByteArray))); - connect(walletModel, SIGNAL(unload()), this, SLOT(removeWallet())); + connect(walletModel, &WalletModel::coinsSent, + paymentServer, &PaymentServer::fetchPaymentACK); + connect(walletModel, &WalletModel::unload, this, &BitcoinApplication::removeWallet); m_wallet_models.push_back(walletModel); #endif @@ -504,13 +504,12 @@ void BitcoinApplication::initializeResult(bool success) #ifdef ENABLE_WALLET // Now that initialization/startup is done, process any command-line // bitcoin: URIs or payment requests: - connect(paymentServer, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)), - window, SLOT(handlePaymentRequest(SendCoinsRecipient))); - connect(window, SIGNAL(receivedURI(QString)), - paymentServer, SLOT(handleURIOrFile(QString))); - connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)), - window, SLOT(message(QString,QString,unsigned int))); - QTimer::singleShot(100, paymentServer, SLOT(uiReady())); + connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest); + connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile); + connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) { + window->message(title, message, style); + }); + QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady); #endif pollShutdownTimer->start(200); } else { diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 6726019a3f..b68f3a439b 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -29,7 +29,7 @@ public: { setAlignment(Qt::AlignRight); - connect(lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(valueChanged())); + connect(lineEdit(), &QLineEdit::textEdited, this, &AmountSpinBox::valueChanged); } QValidator::State validate(QString &text, int &pos) const @@ -213,8 +213,8 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent) : setFocusProxy(amount); // If one if the widgets changes, the combined content changes as well - connect(amount, SIGNAL(valueChanged()), this, SIGNAL(valueChanged())); - connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int))); + connect(amount, &AmountSpinBox::valueChanged, this, &BitcoinAmountField::valueChanged); + connect(unit, static_cast(&QComboBox::currentIndexChanged), this, &BitcoinAmountField::unitChanged); // Set default based on configuration unitChanged(unit->currentIndex()); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ff0641dcf5..cefa9004ed 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -203,9 +203,9 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty modalOverlay = new ModalOverlay(this->centralWidget()); #ifdef ENABLE_WALLET if(enableWallet) { - connect(walletFrame, SIGNAL(requestedSyncWarningInfo()), this, SLOT(showModalOverlay())); - connect(labelBlocksIcon, SIGNAL(clicked(QPoint)), this, SLOT(showModalOverlay())); - connect(progressBar, SIGNAL(clicked(QPoint)), this, SLOT(showModalOverlay())); + connect(walletFrame, &WalletFrame::requestedSyncWarningInfo, this, &BitcoinGUI::showModalOverlay); + connect(labelBlocksIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showModalOverlay); + connect(progressBar, &GUIUtil::ClickableProgressBar::clicked, this, &BitcoinGUI::showModalOverlay); } #endif } @@ -270,18 +270,18 @@ void BitcoinGUI::createActions() #ifdef ENABLE_WALLET // These showNormalIfMinimized are needed because Send Coins and Receive Coins // can be triggered from the tray menu, and need to show the GUI to be useful. - connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); - connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); - connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); - connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); - connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); - connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); + connect(overviewAction, &QAction::triggered, this, static_cast(&BitcoinGUI::showNormalIfMinimized)); + connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage); + connect(sendCoinsAction, &QAction::triggered, this, static_cast(&BitcoinGUI::showNormalIfMinimized)); + connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); }); + connect(sendCoinsMenuAction, &QAction::triggered, this, static_cast(&BitcoinGUI::showNormalIfMinimized)); + connect(sendCoinsMenuAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); }); + connect(receiveCoinsAction, &QAction::triggered, this, static_cast(&BitcoinGUI::showNormalIfMinimized)); + connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); + connect(receiveCoinsMenuAction, &QAction::triggered, this, static_cast(&BitcoinGUI::showNormalIfMinimized)); + connect(receiveCoinsMenuAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); + connect(historyAction, &QAction::triggered, this, static_cast(&BitcoinGUI::showNormalIfMinimized)); + connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage); #endif // ENABLE_WALLET quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this); @@ -331,32 +331,32 @@ void BitcoinGUI::createActions() showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME))); - connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); - connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); - connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); - connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); - connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); - connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); - connect(openRPCConsoleAction, SIGNAL(triggered()), this, SLOT(showDebugWindow())); + connect(quitAction, &QAction::triggered, qApp, QApplication::quit); + connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked); + connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt); + connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked); + connect(toggleHideAction, &QAction::triggered, this, &BitcoinGUI::toggleHidden); + connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked); + connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow); // prevents an open debug window from becoming stuck/unusable on client shutdown - connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide())); + connect(quitAction, &QAction::triggered, rpcConsole, &QWidget::hide); #ifdef ENABLE_WALLET if(walletFrame) { - connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool))); - connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet())); - connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase())); - connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); - connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); - connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses())); - connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses())); - connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked())); + connect(encryptWalletAction, &QAction::triggered, walletFrame, &WalletFrame::encryptWallet); + connect(backupWalletAction, &QAction::triggered, walletFrame, &WalletFrame::backupWallet); + connect(changePassphraseAction, &QAction::triggered, walletFrame, &WalletFrame::changePassphrase); + connect(signMessageAction, &QAction::triggered, [this]{ gotoSignMessageTab(); }); + connect(verifyMessageAction, &QAction::triggered, [this]{ gotoVerifyMessageTab(); }); + connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses); + connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses); + connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked); } #endif // ENABLE_WALLET - new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this, SLOT(showDebugWindowActivateConsole())); - new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this, SLOT(showDebugWindow())); + connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole); + connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow); } void BitcoinGUI::createMenuBar() @@ -425,7 +425,7 @@ void BitcoinGUI::createToolBars() toolbar->addWidget(spacer); m_wallet_selector = new QComboBox(); - connect(m_wallet_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentWalletBySelectorIndex(int))); + connect(m_wallet_selector, static_cast(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex); m_wallet_selector_label = new QLabel(); m_wallet_selector_label->setText(tr("Wallet:") + " "); @@ -451,18 +451,20 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) // Keep up to date with client updateNetworkState(); - connect(_clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - connect(_clientModel, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool))); + connect(_clientModel, &ClientModel::numConnectionsChanged, this, &BitcoinGUI::setNumConnections); + connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive); modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime())); setNumBlocks(m_node.getNumBlocks(), QDateTime::fromTime_t(m_node.getLastBlockTime()), m_node.getVerificationProgress(), false); - connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); + connect(_clientModel, &ClientModel::numBlocksChanged, this, &BitcoinGUI::setNumBlocks); // Receive and report messages from client model - connect(_clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); + connect(_clientModel, &ClientModel::message, [this](const QString &title, const QString &message, unsigned int style){ + this->message(title, message, style); + }); // Show progress dialog - connect(_clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); + connect(_clientModel, &ClientModel::showProgress, this, &BitcoinGUI::showProgress); rpcConsole->setClientModel(_clientModel); @@ -480,7 +482,7 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) if(optionsModel) { // be aware of the tray icon disable state change reported by the OptionsModel object. - connect(optionsModel,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool))); + connect(optionsModel, &OptionsModel::hideTrayIconChanged, this, &BitcoinGUI::setTrayIconVisible); // initialize the disable state of the tray icon with the current value in the model. setTrayIconVisible(optionsModel->getHideTrayIcon()); @@ -601,8 +603,7 @@ void BitcoinGUI::createTrayIconMenu() trayIconMenu = new QMenu(this); trayIcon->setContextMenu(trayIconMenu); - connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), - this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); + connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated); #else // Note: On Mac, the dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); @@ -956,12 +957,12 @@ void BitcoinGUI::changeEvent(QEvent *e) QWindowStateChangeEvent *wsevt = static_cast(e); if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized()) { - QTimer::singleShot(0, this, SLOT(hide())); + QTimer::singleShot(0, this, &BitcoinGUI::hide); e->ignore(); } else if((wsevt->oldState() & Qt::WindowMinimized) && !isMinimized()) { - QTimer::singleShot(0, this, SLOT(show())); + QTimer::singleShot(0, this, &BitcoinGUI::show); e->ignore(); } } @@ -1276,7 +1277,7 @@ void UnitDisplayStatusBarControl::createContextMenu() menuAction->setData(QVariant(u)); menu->addAction(menuAction); } - connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*))); + connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection); } /** Lets the control know about the Options Model (and its signals) */ @@ -1287,7 +1288,7 @@ void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel) this->optionsModel = _optionsModel; // be aware of a display unit change reported by the OptionsModel object. - connect(_optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int))); + connect(_optionsModel, &OptionsModel::displayUnitChanged, this, &UnitDisplayStatusBarControl::updateDisplayUnit); // initialize the display units label with the current value in the model. updateDisplayUnit(_optionsModel->getDisplayUnit()); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 3a8ef3ad8c..61cd6f76cc 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -49,6 +49,7 @@ QT_END_NAMESPACE namespace GUIUtil { class ClickableLabel; +class ClickableProgressBar; } /** @@ -101,9 +102,9 @@ private: QLabel* labelWalletHDStatusIcon = nullptr; GUIUtil::ClickableLabel* labelProxyIcon = nullptr; GUIUtil::ClickableLabel* connectionsControl = nullptr; - QLabel* labelBlocksIcon = nullptr; + GUIUtil::ClickableLabel* labelBlocksIcon = nullptr; QLabel* progressBarLabel = nullptr; - QProgressBar* progressBar = nullptr; + GUIUtil::ClickableProgressBar* progressBar = nullptr; QProgressDialog* progressDialog = nullptr; QMenuBar* appMenuBar = nullptr; @@ -227,7 +228,7 @@ private: /** Set the proxy-enabled icon as shown in the UI. */ void updateProxyIcon(); -private Q_SLOTS: +public Q_SLOTS: #ifdef ENABLE_WALLET /** Switch to overview (home) page */ void gotoOverviewPage(); @@ -262,7 +263,8 @@ private Q_SLOTS: #endif /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ - void showNormalIfMinimized(bool fToggleHidden = false); + void showNormalIfMinimized() { showNormalIfMinimized(false); } + void showNormalIfMinimized(bool fToggleHidden); /** Simply calls showNormalIfMinimized(true) for use in SLOT() macro */ void toggleHidden(); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 7154ac14be..b2cf4b6399 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -44,7 +44,7 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO peerTableModel = new PeerTableModel(m_node, this); banTableModel = new BanTableModel(m_node, this); pollTimer = new QTimer(this); - connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer())); + connect(pollTimer, &QTimer::timeout, this, &ClientModel::updateTimer); pollTimer->start(MODEL_UPDATE_DELAY); subscribeToCoreSignals(); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index ca3598334d..68330c51fa 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -68,13 +68,13 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge contextMenu->addAction(unlockAction); // context menu signals - connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint))); - connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); - connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); - connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); - connect(copyTransactionHashAction, SIGNAL(triggered()), this, SLOT(copyTransactionHash())); - connect(lockAction, SIGNAL(triggered()), this, SLOT(lockCoin())); - connect(unlockAction, SIGNAL(triggered()), this, SLOT(unlockCoin())); + connect(ui->treeWidget, &QWidget::customContextMenuRequested, this, &CoinControlDialog::showMenu); + connect(copyAddressAction, &QAction::triggered, this, &CoinControlDialog::copyAddress); + connect(copyLabelAction, &QAction::triggered, this, &CoinControlDialog::copyLabel); + connect(copyAmountAction, &QAction::triggered, this, &CoinControlDialog::copyAmount); + connect(copyTransactionHashAction, &QAction::triggered, this, &CoinControlDialog::copyTransactionHash); + connect(lockAction, &QAction::triggered, this, &CoinControlDialog::lockCoin); + connect(unlockAction, &QAction::triggered, this, &CoinControlDialog::unlockCoin); // clipboard actions QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); @@ -85,13 +85,13 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this); QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); - connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity())); - connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(clipboardAmount())); - connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee())); - connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee())); - connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes())); - connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput())); - connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange())); + connect(clipboardQuantityAction, &QAction::triggered, this, &CoinControlDialog::clipboardQuantity); + connect(clipboardAmountAction, &QAction::triggered, this, &CoinControlDialog::clipboardAmount); + connect(clipboardFeeAction, &QAction::triggered, this, &CoinControlDialog::clipboardFee); + connect(clipboardAfterFeeAction, &QAction::triggered, this, &CoinControlDialog::clipboardAfterFee); + connect(clipboardBytesAction, &QAction::triggered, this, &CoinControlDialog::clipboardBytes); + connect(clipboardLowOutputAction, &QAction::triggered, this, &CoinControlDialog::clipboardLowOutput); + connect(clipboardChangeAction, &QAction::triggered, this, &CoinControlDialog::clipboardChange); ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); ui->labelCoinControlAmount->addAction(clipboardAmountAction); @@ -102,21 +102,21 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge ui->labelCoinControlChange->addAction(clipboardChangeAction); // toggle tree/list mode - connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool))); - connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool))); + connect(ui->radioTreeMode, &QRadioButton::toggled, this, &CoinControlDialog::radioTreeMode); + connect(ui->radioListMode, &QRadioButton::toggled, this, &CoinControlDialog::radioListMode); // click on checkbox - connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int))); + connect(ui->treeWidget, &QTreeWidget::itemChanged, this, &CoinControlDialog::viewItemChanged); // click on header ui->treeWidget->header()->setSectionsClickable(true); - connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int))); + connect(ui->treeWidget->header(), &QHeaderView::sectionClicked, this, &CoinControlDialog::headerSectionClicked); // ok button - connect(ui->buttonBox, SIGNAL(clicked( QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*))); + connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &CoinControlDialog::buttonBoxClicked); // (un)select all - connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked())); + connect(ui->pushButtonSelectAll, &QPushButton::clicked, this, &CoinControlDialog::buttonSelectAllClicked); ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84); ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110); diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index f8391b6303..bbf60d96fd 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -409,15 +409,15 @@ bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt) void TableViewLastColumnResizingFixer::connectViewHeadersSignals() { - connect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int))); - connect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged())); + connect(tableView->horizontalHeader(), &QHeaderView::sectionResized, this, &TableViewLastColumnResizingFixer::on_sectionResized); + connect(tableView->horizontalHeader(), &QHeaderView::geometriesChanged, this, &TableViewLastColumnResizingFixer::on_geometriesChanged); } // We need to disconnect these while handling the resize events, otherwise we can enter infinite loops. void TableViewLastColumnResizingFixer::disconnectViewHeadersSignals() { - disconnect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int))); - disconnect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged())); + disconnect(tableView->horizontalHeader(), &QHeaderView::sectionResized, this, &TableViewLastColumnResizingFixer::on_sectionResized); + disconnect(tableView->horizontalHeader(), &QHeaderView::geometriesChanged, this, &TableViewLastColumnResizingFixer::on_geometriesChanged); } // Setup the resize mode, handles compatibility for Qt5 and below as the method signatures changed. diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index dbba3c1b3b..b19cc17a4d 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -303,11 +303,11 @@ void Intro::startThread() FreespaceChecker *executor = new FreespaceChecker(this); executor->moveToThread(thread); - connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64))); - connect(this, SIGNAL(requestCheck()), executor, SLOT(check())); + connect(executor, &FreespaceChecker::reply, this, &Intro::setStatus); + connect(this, &Intro::requestCheck, executor, &FreespaceChecker::check); /* make sure executor object is deleted in its own thread */ - connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater())); - connect(this, SIGNAL(stopThread()), thread, SLOT(quit())); + connect(this, &Intro::stopThread, executor, &QObject::deleteLater); + connect(this, &Intro::stopThread, thread, &QThread::quit); thread->start(); } diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index dec9d78326..c5bedf007a 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -21,7 +21,7 @@ layerIsVisible(false), userClosed(false) { ui->setupUi(this); - connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked())); + connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked); if (parent) { parent->installEventFilter(this); raise(); diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index d1477d362d..b51322394f 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -46,7 +46,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : ui->pruneWarning->setStyleSheet("QLabel { color: red; }"); ui->pruneSize->setEnabled(false); - connect(ui->prune, SIGNAL(toggled(bool)), ui->pruneSize, SLOT(setEnabled(bool))); + connect(ui->prune, &QPushButton::toggled, ui->pruneSize, &QWidget::setEnabled); /* Network elements init */ #ifndef USE_UPNP @@ -61,13 +61,13 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : ui->proxyPortTor->setEnabled(false); ui->proxyPortTor->setValidator(new QIntValidator(1, 65535, this)); - connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool))); - connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool))); - connect(ui->connectSocks, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState())); + connect(ui->connectSocks, &QPushButton::toggled, ui->proxyIp, &QWidget::setEnabled); + connect(ui->connectSocks, &QPushButton::toggled, ui->proxyPort, &QWidget::setEnabled); + connect(ui->connectSocks, &QPushButton::toggled, this, &OptionsDialog::updateProxyValidationState); - connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyIpTor, SLOT(setEnabled(bool))); - connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyPortTor, SLOT(setEnabled(bool))); - connect(ui->connectSocksTor, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState())); + connect(ui->connectSocksTor, &QPushButton::toggled, ui->proxyIpTor, &QWidget::setEnabled); + connect(ui->connectSocksTor, &QPushButton::toggled, ui->proxyPortTor, &QWidget::setEnabled); + connect(ui->connectSocksTor, &QPushButton::toggled, this, &OptionsDialog::updateProxyValidationState); /* Window elements init */ #ifdef Q_OS_MAC @@ -122,10 +122,10 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : /* setup/change UI elements when proxy IPs are invalid/valid */ ui->proxyIp->setCheckValidator(new ProxyAddressValidator(parent)); ui->proxyIpTor->setCheckValidator(new ProxyAddressValidator(parent)); - connect(ui->proxyIp, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState())); - connect(ui->proxyIpTor, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState())); - connect(ui->proxyPort, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState())); - connect(ui->proxyPortTor, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState())); + connect(ui->proxyIp, &QValidatedLineEdit::validationDidChange, this, &OptionsDialog::updateProxyValidationState); + connect(ui->proxyIpTor, &QValidatedLineEdit::validationDidChange, this, &OptionsDialog::updateProxyValidationState); + connect(ui->proxyPort, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState); + connect(ui->proxyPortTor, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState); } OptionsDialog::~OptionsDialog() @@ -158,20 +158,20 @@ void OptionsDialog::setModel(OptionsModel *_model) /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */ /* Main */ - connect(ui->prune, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); - connect(ui->prune, SIGNAL(clicked(bool)), this, SLOT(togglePruneWarning(bool))); - connect(ui->pruneSize, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning())); - connect(ui->databaseCache, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning())); - connect(ui->threadsScriptVerif, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning())); + connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); + connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::togglePruneWarning); + connect(ui->pruneSize, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); + connect(ui->databaseCache, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); + connect(ui->threadsScriptVerif, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); /* Wallet */ - connect(ui->spendZeroConfChange, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); + connect(ui->spendZeroConfChange, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); /* Network */ - connect(ui->allowIncoming, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); - connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); - connect(ui->connectSocksTor, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); + connect(ui->allowIncoming, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); + connect(ui->connectSocks, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); + connect(ui->connectSocksTor, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); /* Display */ - connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning())); - connect(ui->thirdPartyTxUrls, SIGNAL(textChanged(const QString &)), this, SLOT(showRestartWarning())); + connect(ui->lang, static_cast(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); }); + connect(ui->thirdPartyTxUrls, &QLineEdit::textChanged, [this]{ showRestartWarning(); }); } void OptionsDialog::setCurrentTab(OptionsDialog::Tab tab) @@ -300,7 +300,7 @@ void OptionsDialog::showRestartWarning(bool fPersistent) ui->statusLabel->setText(tr("This change would require a client restart.")); // clear non-persistent status label after 10 seconds // Todo: should perhaps be a class attribute, if we extend the use of statusLabel - QTimer::singleShot(10000, this, SLOT(clearStatusLabel())); + QTimer::singleShot(10000, this, &OptionsDialog::clearStatusLabel); } } diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index ba47935196..1db9609979 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -133,12 +133,12 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false); - connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex))); + connect(ui->listTransactions, &QListView::clicked, this, &OverviewPage::handleTransactionClicked); // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); - connect(ui->labelWalletStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); - connect(ui->labelTransactionsStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); + connect(ui->labelWalletStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks); + connect(ui->labelTransactionsStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks); } void OverviewPage::handleTransactionClicked(const QModelIndex &index) @@ -201,7 +201,7 @@ void OverviewPage::setClientModel(ClientModel *model) if(model) { // Show warning if this is a prerelease version - connect(model, SIGNAL(alertsChanged(QString)), this, SLOT(updateAlerts(QString))); + connect(model, &ClientModel::alertsChanged, this, &OverviewPage::updateAlerts); updateAlerts(model->getStatusBarWarnings()); } } @@ -227,12 +227,12 @@ void OverviewPage::setWalletModel(WalletModel *model) interfaces::Wallet& wallet = model->wallet(); interfaces::WalletBalances balances = wallet.getBalances(); setBalance(balances); - connect(model, SIGNAL(balanceChanged(interfaces::WalletBalances)), this, SLOT(setBalance(interfaces::WalletBalances))); + connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance); - connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit); updateWatchOnlyLabels(wallet.haveWatchOnly()); - connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool))); + connect(model, &WalletModel::notifyWatchonlyChanged, this, &OverviewPage::updateWatchOnlyLabels); } // update the display unit, to not use the default ("BTC") diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 5bf2bb8a0e..bcafc8f859 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -318,8 +318,8 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : tr("Cannot start bitcoin: click-to-pay handler")); } else { - connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection())); - connect(this, SIGNAL(receivedPaymentACK(QString)), this, SLOT(handlePaymentACK(QString))); + connect(uriServer, &QLocalServer::newConnection, this, &PaymentServer::handleURIConnection); + connect(this, &PaymentServer::receivedPaymentACK, this, &PaymentServer::handlePaymentACK); } } } @@ -369,10 +369,8 @@ void PaymentServer::initNetManager() else qDebug() << "PaymentServer::initNetManager: No active proxy server found."; - connect(netManager, SIGNAL(finished(QNetworkReply*)), - this, SLOT(netRequestFinished(QNetworkReply*))); - connect(netManager, SIGNAL(sslErrors(QNetworkReply*, const QList &)), - this, SLOT(reportSslErrors(QNetworkReply*, const QList &))); + connect(netManager, &QNetworkAccessManager::finished, this, &PaymentServer::netRequestFinished); + connect(netManager, &QNetworkAccessManager::sslErrors, this, &PaymentServer::reportSslErrors); } void PaymentServer::uiReady() @@ -470,8 +468,7 @@ void PaymentServer::handleURIConnection() while (clientConnection->bytesAvailable() < (int)sizeof(quint32)) clientConnection->waitForReadyRead(); - connect(clientConnection, SIGNAL(disconnected()), - clientConnection, SLOT(deleteLater())); + connect(clientConnection, &QLocalSocket::disconnected, clientConnection, &QLocalSocket::deleteLater); QDataStream in(clientConnection); in.setVersion(QDataStream::Qt_4_0); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 715fc8b5e0..59a751fb12 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -113,7 +113,7 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, ClientModel *parent) : // set up timer for auto refresh timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), SLOT(refresh())); + connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh); timer->setInterval(MODEL_UPDATE_DELAY); // load initial data diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index de42490361..85c5a58a84 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -12,7 +12,7 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : valid(true), checkValidator(0) { - connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid())); + connect(this, &QValidatedLineEdit::textChanged, this, &QValidatedLineEdit::markValid); } void QValidatedLineEdit::setValid(bool _valid) diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index c2c0e84d65..76f94ecf85 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -7,7 +7,7 @@ QValueComboBox::QValueComboBox(QWidget *parent) : QComboBox(parent), role(Qt::UserRole) { - connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(handleSelectionChanged(int))); + connect(this, static_cast(&QComboBox::currentIndexChanged), this, &QValueComboBox::handleSelectionChanged); } QVariant QValueComboBox::value() const diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 12de189229..a7cc5da19e 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -57,13 +57,13 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWid contextMenu->addAction(copyAmountAction); // context menu signals - connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint))); - connect(copyURIAction, SIGNAL(triggered()), this, SLOT(copyURI())); - connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); - connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage())); - connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); + connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu); + connect(copyURIAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyURI); + connect(copyLabelAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyLabel); + connect(copyMessageAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyMessage); + connect(copyAmountAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAmount); - connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear); } void ReceiveCoinsDialog::setModel(WalletModel *_model) @@ -73,7 +73,7 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model) if(_model && _model->getOptionsModel()) { _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder); - connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &ReceiveCoinsDialog::updateDisplayUnit); updateDisplayUnit(); QTableView* tableView = ui->recentRequestsView; @@ -89,8 +89,8 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model) tableView->setColumnWidth(RecentRequestsTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH); connect(tableView->selectionModel(), - SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, - SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection))); + &QItemSelectionModel::selectionChanged, this, + &ReceiveCoinsDialog::recentRequestsView_selectionChanged); // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready. columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 5bc5568e9a..c561d948be 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -30,10 +30,10 @@ QRImageWidget::QRImageWidget(QWidget *parent): { contextMenu = new QMenu(this); QAction *saveImageAction = new QAction(tr("&Save Image..."), this); - connect(saveImageAction, SIGNAL(triggered()), this, SLOT(saveImage())); + connect(saveImageAction, &QAction::triggered, this, &QRImageWidget::saveImage); contextMenu->addAction(saveImageAction); QAction *copyImageAction = new QAction(tr("&Copy Image"), this); - connect(copyImageAction, SIGNAL(triggered()), this, SLOT(copyImage())); + connect(copyImageAction, &QAction::triggered, this, &QRImageWidget::copyImage); contextMenu->addAction(copyImageAction); } @@ -97,7 +97,7 @@ ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) : ui->lblQRCode->setVisible(false); #endif - connect(ui->btnSaveAs, SIGNAL(clicked()), ui->lblQRCode, SLOT(saveImage())); + connect(ui->btnSaveAs, &QPushButton::clicked, ui->lblQRCode, &QRImageWidget::saveImage); } ReceiveRequestDialog::~ReceiveRequestDialog() @@ -110,7 +110,7 @@ void ReceiveRequestDialog::setModel(WalletModel *_model) this->model = _model; if (_model) - connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(update())); + connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &ReceiveRequestDialog::update); // update the display unit if necessary update(); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index f0d2aba370..82ab48ac20 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -26,7 +26,7 @@ RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : /* These columns must match the indices in the ColumnIndex enumeration */ columns << tr("Date") << tr("Label") << tr("Message") << getAmountTitle(); - connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(walletModel->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &RecentRequestsTableModel::updateDisplayUnit); } RecentRequestsTableModel::~RecentRequestsTableModel() diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 2b0307d286..66e36f0b67 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -105,12 +105,10 @@ public: func(_func) { timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + connect(&timer, &QTimer::timeout, [this]{ func(); }); timer.start(millis); } ~QtRPCTimerBase() {} -private Q_SLOTS: - void timeout() { func(); } private: QTimer timer; std::function func; @@ -474,10 +472,10 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty ui->lineEdit->installEventFilter(this); ui->messagesWidget->installEventFilter(this); - connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); - connect(ui->fontBiggerButton, SIGNAL(clicked()), this, SLOT(fontBigger())); - connect(ui->fontSmallerButton, SIGNAL(clicked()), this, SLOT(fontSmaller())); - connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear())); + connect(ui->clearButton, &QPushButton::clicked, this, &RPCConsole::clear); + connect(ui->fontBiggerButton, &QPushButton::clicked, this, &RPCConsole::fontBigger); + connect(ui->fontSmallerButton, &QPushButton::clicked, this, &RPCConsole::fontSmaller); + connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph, &TrafficGraphWidget::clear); // disable the wallet selector by default ui->WalletSelector->setVisible(false); @@ -565,19 +563,19 @@ void RPCConsole::setClientModel(ClientModel *model) if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) { // Keep up to date with client setNumConnections(model->getNumConnections()); - connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); + connect(model, &ClientModel::numConnectionsChanged, this, &RPCConsole::setNumConnections); interfaces::Node& node = clientModel->node(); setNumBlocks(node.getNumBlocks(), QDateTime::fromTime_t(node.getLastBlockTime()), node.getVerificationProgress(), false); - connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); + connect(model, &ClientModel::numBlocksChanged, this, &RPCConsole::setNumBlocks); updateNetworkState(); - connect(model, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool))); + connect(model, &ClientModel::networkActiveChanged, this, &RPCConsole::setNetworkActive); updateTrafficStats(node.getTotalBytesRecv(), node.getTotalBytesSent()); - connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64))); + connect(model, &ClientModel::bytesChanged, this, &RPCConsole::updateTrafficStats); - connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t))); + connect(model, &ClientModel::mempoolSizeChanged, this, &RPCConsole::setMempoolSize); // set up peer table ui->peerWidget->setModel(model->getPeerTableModel()); @@ -614,23 +612,22 @@ void RPCConsole::setClientModel(ClientModel *model) signalMapper->setMapping(banAction24h, 60*60*24); signalMapper->setMapping(banAction7d, 60*60*24*7); signalMapper->setMapping(banAction365d, 60*60*24*365); - connect(banAction1h, SIGNAL(triggered()), signalMapper, SLOT(map())); - connect(banAction24h, SIGNAL(triggered()), signalMapper, SLOT(map())); - connect(banAction7d, SIGNAL(triggered()), signalMapper, SLOT(map())); - connect(banAction365d, SIGNAL(triggered()), signalMapper, SLOT(map())); - connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(banSelectedNode(int))); + connect(banAction1h, &QAction::triggered, signalMapper, static_cast(&QSignalMapper::map)); + connect(banAction24h, &QAction::triggered, signalMapper, static_cast(&QSignalMapper::map)); + connect(banAction7d, &QAction::triggered, signalMapper, static_cast(&QSignalMapper::map)); + connect(banAction365d, &QAction::triggered, signalMapper, static_cast(&QSignalMapper::map)); + connect(signalMapper, static_cast(&QSignalMapper::mapped), this, &RPCConsole::banSelectedNode); // peer table context menu signals - connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showPeersTableContextMenu(const QPoint&))); - connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode())); + connect(ui->peerWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showPeersTableContextMenu); + connect(disconnectAction, &QAction::triggered, this, &RPCConsole::disconnectSelectedNode); // peer table signal handling - update peer details when selecting new node - connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &))); + connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::peerSelected); // peer table signal handling - update peer details when new nodes are added to the model - connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged())); + connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::peerLayoutChanged); // peer table signal handling - cache selected node ids - connect(model->getPeerTableModel(), SIGNAL(layoutAboutToBeChanged()), this, SLOT(peerLayoutAboutToChange())); + connect(model->getPeerTableModel(), &PeerTableModel::layoutAboutToBeChanged, this, &RPCConsole::peerLayoutAboutToChange); // set up ban table ui->banlistWidget->setModel(model->getBanTableModel()); @@ -651,13 +648,13 @@ void RPCConsole::setClientModel(ClientModel *model) banTableContextMenu->addAction(unbanAction); // ban table context menu signals - connect(ui->banlistWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showBanTableContextMenu(const QPoint&))); - connect(unbanAction, SIGNAL(triggered()), this, SLOT(unbanSelectedNode())); + connect(ui->banlistWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showBanTableContextMenu); + connect(unbanAction, &QAction::triggered, this, &RPCConsole::unbanSelectedNode); // ban table signal handling - clear peer details when clicking a peer in the ban table - connect(ui->banlistWidget, SIGNAL(clicked(const QModelIndex&)), this, SLOT(clearSelectedNode())); + connect(ui->banlistWidget, &QTableView::clicked, this, &RPCConsole::clearSelectedNode); // ban table signal handling - ensure ban table is shown or hidden (if empty) - connect(model->getBanTableModel(), SIGNAL(layoutChanged()), this, SLOT(showOrHideBanTableIfRequired())); + connect(model->getBanTableModel(), &BanTableModel::layoutChanged, this, &RPCConsole::showOrHideBanTableIfRequired); showOrHideBanTableIfRequired(); // Provide initial values @@ -972,15 +969,16 @@ void RPCConsole::startExecutor() executor->moveToThread(&thread); // Replies from executor object must go to this object - connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString))); + connect(executor, &RPCExecutor::reply, this, static_cast(&RPCConsole::message)); + // Requests from this object must go to executor - connect(this, SIGNAL(cmdRequest(QString, QString)), executor, SLOT(request(QString, QString))); + connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request); // On stopExecutor signal // - quit the Qt event loop in the execution thread - connect(this, SIGNAL(stopExecutor()), &thread, SLOT(quit())); + connect(this, &RPCConsole::stopExecutor, &thread, &QThread::quit); // - queue executor for deletion (in execution thread) - connect(&thread, SIGNAL(finished()), executor, SLOT(deleteLater()), Qt::DirectConnection); + connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater, Qt::DirectConnection); // Default implementation of QThread::run() simply spins up an event loop in the thread, // which is what we want. diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 0671b47782..db77043951 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -96,7 +96,8 @@ public Q_SLOTS: void fontSmaller(); void setFontSize(int newSize); /** Append the message to the message widget */ - void message(int category, const QString &message, bool html = false); + void message(int category, const QString &msg) { message(category, msg, false); } + void message(int category, const QString &message, bool html); /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set network state shown in the UI */ diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index da155f872c..eed71397ab 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -72,13 +72,13 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p addEntry(); - connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry())); - connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + connect(ui->addButton, &QPushButton::clicked, this, &SendCoinsDialog::addEntry); + connect(ui->clearButton, &QPushButton::clicked, this, &SendCoinsDialog::clear); // Coin Control - connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); - connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); - connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString &)), this, SLOT(coinControlChangeEdited(const QString &))); + connect(ui->pushButtonCoinControl, &QPushButton::clicked, this, &SendCoinsDialog::coinControlButtonClicked); + connect(ui->checkBoxCoinControlChange, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlChangeChecked); + connect(ui->lineEditCoinControlChange, &QValidatedLineEdit::textEdited, this, &SendCoinsDialog::coinControlChangeEdited); // Coin Control: clipboard actions QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); @@ -88,13 +88,13 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this); QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this); QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); - connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); - connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount())); - connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee())); - connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee())); - connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes())); - connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput())); - connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange())); + connect(clipboardQuantityAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardQuantity); + connect(clipboardAmountAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAmount); + connect(clipboardFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardFee); + connect(clipboardAfterFeeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardAfterFee); + connect(clipboardBytesAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardBytes); + connect(clipboardLowOutputAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardLowOutput); + connect(clipboardChangeAction, &QAction::triggered, this, &SendCoinsDialog::coinControlClipboardChange); ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); ui->labelCoinControlAmount->addAction(clipboardAmountAction); ui->labelCoinControlFee->addAction(clipboardFeeAction); @@ -130,7 +130,7 @@ void SendCoinsDialog::setClientModel(ClientModel *_clientModel) this->clientModel = _clientModel; if (_clientModel) { - connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel())); + connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateSmartFeeLabel); } } @@ -151,13 +151,13 @@ void SendCoinsDialog::setModel(WalletModel *_model) interfaces::WalletBalances balances = _model->wallet().getBalances(); setBalance(balances); - connect(_model, SIGNAL(balanceChanged(interfaces::WalletBalances)), this, SLOT(setBalance(interfaces::WalletBalances))); - connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance); + connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::updateDisplayUnit); updateDisplayUnit(); // Coin Control - connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels())); - connect(_model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); + connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::coinControlUpdateLabels); + connect(_model->getOptionsModel(), &OptionsModel::coinControlFeaturesChanged, this, &SendCoinsDialog::coinControlFeatureChanged); ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures()); coinControlUpdateLabels(); @@ -165,16 +165,16 @@ void SendCoinsDialog::setModel(WalletModel *_model) for (const int n : confTargets) { ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n)); } - connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSmartFeeLabel())); - connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels())); - connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls())); - connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels())); - connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels())); - connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee())); - connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); - connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); - connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel())); - connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); + connect(ui->confTargetSelector, static_cast(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel); + connect(ui->confTargetSelector, static_cast(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels); + connect(ui->groupFee, static_cast(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls); + connect(ui->groupFee, static_cast(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels); + connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels); + connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::setMinimumFee); + connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateFeeSectionControls); + connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels); + connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateSmartFeeLabel); + connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels); ui->customFee->setSingleStep(model->wallet().getRequiredFee(1000)); updateFeeSectionControls(); updateMinFeeLabel(); @@ -417,10 +417,10 @@ SendCoinsEntry *SendCoinsDialog::addEntry() SendCoinsEntry *entry = new SendCoinsEntry(platformStyle, this); entry->setModel(model); ui->entries->addWidget(entry); - connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*))); - connect(entry, SIGNAL(useAvailableBalance(SendCoinsEntry*)), this, SLOT(useAvailableBalance(SendCoinsEntry*))); - connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels())); - connect(entry, SIGNAL(subtractFeeFromAmountChanged()), this, SLOT(coinControlUpdateLabels())); + connect(entry, &SendCoinsEntry::removeEntry, this, &SendCoinsDialog::removeEntry); + connect(entry, &SendCoinsEntry::useAvailableBalance, this, &SendCoinsDialog::useAvailableBalance); + connect(entry, &SendCoinsEntry::payAmountChanged, this, &SendCoinsDialog::coinControlUpdateLabels); + connect(entry, &SendCoinsEntry::subtractFeeFromAmountChanged, this, &SendCoinsDialog::coinControlUpdateLabels); // Focus the field, so that entry can start immediately entry->clear(); @@ -897,7 +897,7 @@ SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QStri setDefaultButton(QMessageBox::Cancel); yesButton = button(QMessageBox::Yes); updateYesButton(); - connect(&countDownTimer, SIGNAL(timeout()), this, SLOT(countDown())); + connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown); } int SendConfirmationDialog::exec() diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index d53f91dffa..b394ff3150 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -40,12 +40,12 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *par ui->payTo_is->setFont(GUIUtil::fixedPitchFont()); // Connect signals - connect(ui->payAmount, SIGNAL(valueChanged()), this, SIGNAL(payAmountChanged())); - connect(ui->checkboxSubtractFeeFromAmount, SIGNAL(toggled(bool)), this, SIGNAL(subtractFeeFromAmountChanged())); - connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked())); - connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked())); - connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked())); - connect(ui->useAvailableBalanceButton, SIGNAL(clicked()), this, SLOT(useAvailableBalanceClicked())); + connect(ui->payAmount, &BitcoinAmountField::valueChanged, this, &SendCoinsEntry::payAmountChanged); + connect(ui->checkboxSubtractFeeFromAmount, &QCheckBox::toggled, this, &SendCoinsEntry::subtractFeeFromAmountChanged); + connect(ui->deleteButton, &QPushButton::clicked, this, &SendCoinsEntry::deleteClicked); + connect(ui->deleteButton_is, &QPushButton::clicked, this, &SendCoinsEntry::deleteClicked); + connect(ui->deleteButton_s, &QPushButton::clicked, this, &SendCoinsEntry::deleteClicked); + connect(ui->useAvailableBalanceButton, &QPushButton::clicked, this, &SendCoinsEntry::useAvailableBalanceClicked); } SendCoinsEntry::~SendCoinsEntry() @@ -82,7 +82,7 @@ void SendCoinsEntry::setModel(WalletModel *_model) this->model = _model; if (_model && _model->getOptionsModel()) - connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsEntry::updateDisplayUnit); clear(); } diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index e92f9d7a5b..5384b9e8b0 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -39,8 +39,8 @@ X509 *parse_b64der_cert(const char* cert_data) static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector& data) { RecipientCatcher sigCatcher; - QObject::connect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)), - &sigCatcher, SLOT(getRecipient(SendCoinsRecipient))); + QObject::connect(server, &PaymentServer::receivedPaymentRequest, + &sigCatcher, &RecipientCatcher::getRecipient); // Write data to a temp file: QTemporaryFile f; @@ -57,8 +57,8 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vectorgetOptionsModel()->getDisplayUnit()); priv->refreshWallet(walletModel->wallet()); - connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(walletModel->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &TransactionTableModel::updateDisplayUnit); subscribeToCoreSignals(); } diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 23c50f55ba..6d08a3b0fb 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -176,30 +176,31 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa mapperThirdPartyTxUrls = new QSignalMapper(this); // Connect actions - connect(mapperThirdPartyTxUrls, SIGNAL(mapped(QString)), this, SLOT(openThirdPartyTxUrl(QString))); + connect(mapperThirdPartyTxUrls, static_cast(&QSignalMapper::mapped), this, &TransactionView::openThirdPartyTxUrl); - connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int))); - connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int))); - connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int))); - connect(amountWidget, SIGNAL(textChanged(QString)), amount_typing_delay, SLOT(start())); - connect(amount_typing_delay, SIGNAL(timeout()), this, SLOT(changedAmount())); - connect(search_widget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start())); - connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedSearch())); + connect(dateWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseDate); + connect(typeWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseType); + connect(watchOnlyWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseWatchonly); + connect(amountWidget, &QLineEdit::textChanged, amount_typing_delay, static_cast(&QTimer::start)); + connect(amount_typing_delay, &QTimer::timeout, this, &TransactionView::changedAmount); + connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, static_cast(&QTimer::start)); + connect(prefix_typing_delay, &QTimer::timeout, this, &TransactionView::changedSearch); - connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex))); - connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); - - connect(bumpFeeAction, SIGNAL(triggered()), this, SLOT(bumpFee())); - connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx())); - connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); - connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); - connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); - connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); - connect(copyTxHexAction, SIGNAL(triggered()), this, SLOT(copyTxHex())); - connect(copyTxPlainText, SIGNAL(triggered()), this, SLOT(copyTxPlainText())); - connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); - connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); + connect(view, &QTableView::doubleClicked, this, &TransactionView::doubleClicked); + connect(view, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu); + connect(bumpFeeAction, &QAction::triggered, this, &TransactionView::bumpFee); + connect(abandonAction, &QAction::triggered, this, &TransactionView::abandonTx); + connect(copyAddressAction, &QAction::triggered, this, &TransactionView::copyAddress); + connect(copyLabelAction, &QAction::triggered, this, &TransactionView::copyLabel); + connect(copyAmountAction, &QAction::triggered, this, &TransactionView::copyAmount); + connect(copyTxIDAction, &QAction::triggered, this, &TransactionView::copyTxID); + connect(copyTxHexAction, &QAction::triggered, this, &TransactionView::copyTxHex); + connect(copyTxPlainText, &QAction::triggered, this, &TransactionView::copyTxPlainText); + connect(editLabelAction, &QAction::triggered, this, &TransactionView::editLabel); + connect(showDetailsAction, &QAction::triggered, this, &TransactionView::showDetails); + // Double-clicking on a transaction on the transaction history page shows details + connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails); // Highlight transaction after fee bump connect(this, &TransactionView::bumpedFee, [this](const uint256& txid) { focusTransaction(txid); @@ -249,7 +250,7 @@ void TransactionView::setModel(WalletModel *_model) if (i == 0) contextMenu->addSeparator(); contextMenu->addAction(thirdPartyTxUrlAction); - connect(thirdPartyTxUrlAction, SIGNAL(triggered()), mapperThirdPartyTxUrls, SLOT(map())); + connect(thirdPartyTxUrlAction, &QAction::triggered, mapperThirdPartyTxUrls, static_cast(&QSignalMapper::map)); mapperThirdPartyTxUrls->setMapping(thirdPartyTxUrlAction, listUrls[i].trimmed()); } } @@ -259,7 +260,7 @@ void TransactionView::setModel(WalletModel *_model) updateWatchOnlyColumn(_model->wallet().haveWatchOnly()); // Watch-only signal - connect(_model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool))); + connect(_model, &WalletModel::notifyWatchonlyChanged, this, &TransactionView::updateWatchOnlyColumn); } } @@ -573,8 +574,8 @@ QWidget *TransactionView::createDateRangeWidget() dateRangeWidget->setVisible(false); // Notify on change - connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged())); - connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged())); + connect(dateFrom, &QDateTimeEdit::dateChanged, this, &TransactionView::dateRangeChanged); + connect(dateTo, &QDateTimeEdit::dateChanged, this, &TransactionView::dateRangeChanged); return dateRangeWidget; } diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index e8fd83d427..d15bd95b8e 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -68,9 +68,11 @@ bool WalletFrame::addWallet(WalletModel *walletModel) mapWalletViews[name] = walletView; // Ensure a walletView is able to show the main window - connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); + connect(walletView, &WalletView::showNormalIfMinimized, [this]{ + gui->showNormalIfMinimized(); + }); - connect(walletView, SIGNAL(outOfSyncWarningClicked()), this, SLOT(outOfSyncWarningClicked())); + connect(walletView, &WalletView::outOfSyncWarningClicked, this, &WalletFrame::outOfSyncWarningClicked); return true; } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index d91cdcdc1f..18a5bda9c3 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -44,7 +44,7 @@ WalletModel::WalletModel(std::unique_ptr wallet, interfaces: // This timer will be fired repeatedly to update the balance pollTimer = new QTimer(this); - connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged())); + connect(pollTimer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged); pollTimer->start(MODEL_UPDATE_DELAY); subscribeToCoreSignals(); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 9af29b5d60..053e951921 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -66,22 +66,20 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): addWidget(sendCoinsPage); // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page - connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); - connect(overviewPage, SIGNAL(outOfSyncWarningClicked()), this, SLOT(requestedSyncWarningInfo())); + connect(overviewPage, &OverviewPage::transactionClicked, transactionView, static_cast(&TransactionView::focusTransaction)); + + connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::requestedSyncWarningInfo); // Highlight transaction after send - connect(sendCoinsPage, SIGNAL(coinsSent(uint256)), transactionView, SLOT(focusTransaction(uint256))); - - // Double-clicking on a transaction on the transaction history page shows details - connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); + connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, static_cast(&TransactionView::focusTransaction)); // Clicking on "Export" allows to export the transaction list - connect(exportButton, SIGNAL(clicked()), transactionView, SLOT(exportClicked())); + connect(exportButton, &QPushButton::clicked, transactionView, &TransactionView::exportClicked); // Pass through messages from sendCoinsPage - connect(sendCoinsPage, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); + connect(sendCoinsPage, &SendCoinsDialog::message, this, &WalletView::message); // Pass through messages from transactionView - connect(transactionView, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); + connect(transactionView, &TransactionView::message, this, &WalletView::message); } WalletView::~WalletView() @@ -93,22 +91,24 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) if (gui) { // Clicking on a transaction on the overview page simply sends you to transaction history page - connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), gui, SLOT(gotoHistoryPage())); + connect(overviewPage, &OverviewPage::transactionClicked, gui, &BitcoinGUI::gotoHistoryPage); // Navigate to transaction history page after send - connect(sendCoinsPage, SIGNAL(coinsSent(uint256)), gui, SLOT(gotoHistoryPage())); + connect(sendCoinsPage, &SendCoinsDialog::coinsSent, gui, &BitcoinGUI::gotoHistoryPage); // Receive and report messages - connect(this, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); + connect(this, &WalletView::message, [gui](const QString &title, const QString &message, unsigned int style) { + gui->message(title, message, style); + }); // Pass through encryption status changed signals - connect(this, SIGNAL(encryptionStatusChanged()), gui, SLOT(updateWalletStatus())); + connect(this, &WalletView::encryptionStatusChanged, gui, &BitcoinGUI::updateWalletStatus); // Pass through transaction notifications - connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString,QString))); + connect(this, &WalletView::incomingTransaction, gui, &BitcoinGUI::incomingTransaction); // Connect HD enabled state signal - connect(this, SIGNAL(hdEnabledStatusChanged()), gui, SLOT(updateWalletStatus())); + connect(this, &WalletView::hdEnabledStatusChanged, gui, &BitcoinGUI::updateWalletStatus); } } @@ -135,24 +135,23 @@ void WalletView::setWalletModel(WalletModel *_walletModel) if (_walletModel) { // Receive and pass through messages from wallet model - connect(_walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); + connect(_walletModel, &WalletModel::message, this, &WalletView::message); // Handle changes in encryption status - connect(_walletModel, SIGNAL(encryptionStatusChanged()), this, SIGNAL(encryptionStatusChanged())); + connect(_walletModel, &WalletModel::encryptionStatusChanged, this, &WalletView::encryptionStatusChanged); updateEncryptionStatus(); // update HD status Q_EMIT hdEnabledStatusChanged(); // Balloon pop-up for new transaction - connect(_walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(processNewTransaction(QModelIndex,int,int))); + connect(_walletModel->getTransactionTableModel(), &TransactionTableModel::rowsInserted, this, &WalletView::processNewTransaction); // Ask for passphrase if needed - connect(_walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + connect(_walletModel, &WalletModel::requireUnlock, this, &WalletView::unlockWallet); // Show progress dialog - connect(_walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); + connect(_walletModel, &WalletModel::showProgress, this, &WalletView::showProgress); } } From 3567b247f43decb6fc102d5b0989d1746fce0441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Sun, 24 Jun 2018 18:12:07 +0100 Subject: [PATCH 046/188] test: Add lint to prevent SIGNAL/SLOT connect style --- test/lint/lint-qt.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 test/lint/lint-qt.sh diff --git a/test/lint/lint-qt.sh b/test/lint/lint-qt.sh new file mode 100755 index 0000000000..2e77682aa2 --- /dev/null +++ b/test/lint/lint-qt.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Check for SIGNAL/SLOT connect style, removed since Qt4 support drop. + +export LC_ALL=C + +EXIT_CODE=0 + +OUTPUT=$(git grep -E '(SIGNAL|, ?SLOT)\(' -- src/qt) +if [[ ${OUTPUT} != "" ]]; then + echo "Use Qt5 connect style in:" + echo "$OUTPUT" + EXIT_CODE=1 +fi + +exit ${EXIT_CODE} From 8563341714a1ec452dd3304a39dd880face49c84 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 21 Aug 2018 06:55:24 +0000 Subject: [PATCH 047/188] Bugfix: NSIS: Exclude Makefile* from docs Otherwise, the generated Makefile is included in the NSIS-installed documentation, which can lead to non-determinism (eg, if gawk is installed on some build VMs, but others only have mawk) --- share/setup.nsi.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/setup.nsi.in b/share/setup.nsi.in index dd42085a27..8cfb6d76bb 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -80,7 +80,7 @@ Section -Main SEC0000 File @abs_top_srcdir@/release/@BITCOIN_DAEMON_NAME@@EXEEXT@ File @abs_top_srcdir@/release/@BITCOIN_CLI_NAME@@EXEEXT@ SetOutPath $INSTDIR\doc - File /r @abs_top_srcdir@/doc\*.* + File /r /x Makefile* @abs_top_srcdir@/doc\*.* SetOutPath $INSTDIR WriteRegStr HKCU "${REGKEY}\Components" Main 1 SectionEnd From fa5099ceb757c9d56fa54a08d0441750df6c8869 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 22 Aug 2018 09:24:43 -0400 Subject: [PATCH 048/188] p2p: Remove dead code for nVersion=10300 --- src/net_processing.cpp | 5 +---- test/functional/test_framework/messages.py | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 88999ba735..0fad012257 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1662,8 +1662,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return false; } - if (nVersion < MIN_PEER_PROTO_VERSION) - { + if (nVersion < MIN_PEER_PROTO_VERSION) { // disconnect from peers older than this proto version LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion); if (enable_bip61) { @@ -1674,8 +1673,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return false; } - if (nVersion == 10300) - nVersion = 300; if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; if (!vRecv.empty()) { diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 7276f6b450..3cd148a02e 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -904,8 +904,6 @@ class msg_version(): def deserialize(self, f): self.nVersion = struct.unpack(" Date: Wed, 22 Aug 2018 01:33:34 +0100 Subject: [PATCH 049/188] test: Add tests for RPC help --- test/functional/rpc_help.py | 31 +++++++++++++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 32 insertions(+) create mode 100755 test/functional/rpc_help.py diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py new file mode 100755 index 0000000000..e878ded258 --- /dev/null +++ b/test/functional/rpc_help.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test RPC help output.""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_raises_rpc_error + +class HelpRpcTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def run_test(self): + node = self.nodes[0] + + # wrong argument count + assert_raises_rpc_error(-1, 'help', node.help, 'foo', 'bar') + + # invalid argument + assert_raises_rpc_error(-1, 'JSON value is not a string as expected', node.help, 0) + + # help of unknown command + assert_equal(node.help('foo'), 'help: unknown command: foo') + + # command titles + titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')] + assert_equal(titles, ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util', 'Wallet', 'Zmq']) + +if __name__ == '__main__': + HelpRpcTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index feea2a327a..13c687fd92 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -152,6 +152,7 @@ BASE_SCRIPTS = [ 'p2p_node_network_limited.py', 'feature_blocksdir.py', 'feature_config_args.py', + 'rpc_help.py', 'feature_help.py', # Don't append tests at the end to avoid merge conflicts # Put them in a random line within the section that fits their approximate run-time From 00f58f8c48db05dce9dceed73a0028482e037f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Thu, 23 Aug 2018 01:46:59 +0100 Subject: [PATCH 050/188] rpc: Avoid locking cs_main in some wallet RPC --- src/rpc/rawtransaction.cpp | 1 - src/wallet/rpcwallet.cpp | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 608a1b5da2..637c9f73ab 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -562,7 +562,6 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") ); - LOCK(cs_main); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); CMutableTransaction mtx; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4e539a85de..c0c59da7bd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -165,7 +165,7 @@ static UniValue getnewaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); } - LOCK2(cs_main, pwallet->cs_wallet); + LOCK(pwallet->cs_wallet); // Parse the label first so we don't generate a key if there's an error std::string label; @@ -276,7 +276,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); } - LOCK2(cs_main, pwallet->cs_wallet); + LOCK(pwallet->cs_wallet); if (!pwallet->IsLocked()) { pwallet->TopUpKeyPool(); @@ -331,7 +331,7 @@ static UniValue setlabel(const JSONRPCRequest& request) + HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") ); - LOCK2(cs_main, pwallet->cs_wallet); + LOCK(pwallet->cs_wallet); CTxDestination dest = DecodeDestination(request.params[0].get_str()); if (!IsValidDestination(dest)) { From e8c4a1e36969d2ef816d9dfaaee979a8cf6bfffe Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Mon, 20 Aug 2018 23:46:34 +0000 Subject: [PATCH 051/188] Add new regtest ports in doc following #10825 ports reattributions Add checkmempool and checkblockindex regtest true in doc --- src/bitcoin-cli.cpp | 3 ++- src/init.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index db713f58d2..6ae2bd0f5e 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -33,6 +33,7 @@ static void SetupCliArgs() { const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); + const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST); gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS); gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS); @@ -45,7 +46,7 @@ static void SetupCliArgs() gArgs.AddArg("-rpcconnect=", strprintf("Send commands to node running on (default: %s)", DEFAULT_RPCCONNECT), false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpccookiefile=", _("Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)"), false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcpassword=", "Password for JSON-RPC connections", false, OptionsCategory::OPTIONS); - gArgs.AddArg("-rpcport=", strprintf("Connect to JSON-RPC on (default: %u or testnet: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()), false, OptionsCategory::OPTIONS); + gArgs.AddArg("-rpcport=", strprintf("Connect to JSON-RPC on (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcuser=", "Username for JSON-RPC connections", false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcwait", "Wait for RPC server to start", false, OptionsCategory::OPTIONS); gArgs.AddArg("-rpcwallet=", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind)", false, OptionsCategory::OPTIONS); diff --git a/src/init.cpp b/src/init.cpp index 2131a6adc0..1e73263e3d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -343,8 +343,10 @@ void SetupServerArgs() { const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); + const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST); const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN); const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET); + const auto regtestChainParams = CreateChainParams(CBaseChainParams::REGTEST); // Hidden Options std::vector hidden_args = {"-rpcssl", "-benchmark", "-h", "-help", "-socks", "-tor", "-debugnet", "-whitelistalwaysrelay", @@ -416,7 +418,7 @@ void SetupServerArgs() gArgs.AddArg("-onlynet=", "Make outgoing connections only through network (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks.", false, OptionsCategory::CONNECTION); gArgs.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), false, OptionsCategory::CONNECTION); gArgs.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), false, OptionsCategory::CONNECTION); - gArgs.AddArg("-port=", strprintf("Listen for connections on (default: %u or testnet: %u)", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()), false, OptionsCategory::CONNECTION); + gArgs.AddArg("-port=", strprintf("Listen for connections on (default: %u, testnet: %u, regtest: %u)", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), false, OptionsCategory::CONNECTION); gArgs.AddArg("-proxy=", "Connect through SOCKS5 proxy", false, OptionsCategory::CONNECTION); gArgs.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), false, OptionsCategory::CONNECTION); gArgs.AddArg("-seednode=", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", false, OptionsCategory::CONNECTION); @@ -452,8 +454,8 @@ void SetupServerArgs() gArgs.AddArg("-checkblocks=", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-checklevel=", strprintf("How thorough the block verification of -checkblocks is (0-4, default: %u)", DEFAULT_CHECKLEVEL), true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. (default: %u)", defaultChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-checkmempool=", strprintf("Run checks every transactions (default: %u)", defaultChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-checkmempool=", strprintf("Run checks every transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-deprecatedrpc=", "Allows deprecated RPC method(s) to be used", true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-dropmessagestest=", "Randomly drop 1 of every network messages", true, OptionsCategory::DEBUG_TEST); @@ -507,7 +509,7 @@ void SetupServerArgs() gArgs.AddArg("-rpcbind=[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", false, OptionsCategory::RPC); gArgs.AddArg("-rpccookiefile=", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", false, OptionsCategory::RPC); gArgs.AddArg("-rpcpassword=", "Password for JSON-RPC connections", false, OptionsCategory::RPC); - gArgs.AddArg("-rpcport=", strprintf("Listen for JSON-RPC connections on (default: %u or testnet: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()), false, OptionsCategory::RPC); + gArgs.AddArg("-rpcport=", strprintf("Listen for JSON-RPC connections on (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::RPC); gArgs.AddArg("-rpcserialversion", strprintf("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)", DEFAULT_RPC_SERIALIZE_VERSION), false, OptionsCategory::RPC); gArgs.AddArg("-rpcservertimeout=", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), true, OptionsCategory::RPC); gArgs.AddArg("-rpcthreads=", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), false, OptionsCategory::RPC); From 497e90c02b96e8739e8faf3d43e41ba1ff0627b7 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Thu, 23 Aug 2018 02:57:39 -0700 Subject: [PATCH 052/188] Remove default argument to prevector constructor to remove ambiguity The call with this default argument is redundant with prevector(size_type). --- src/prevector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prevector.h b/src/prevector.h index 033952c959..7a13b98214 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -252,7 +252,7 @@ public: resize(n); } - explicit prevector(size_type n, const T& val = T()) : _size(0) { + explicit prevector(size_type n, const T& val) : _size(0) { change_capacity(n); _size += n; fill(item_ptr(0), n, val); From fa74d3d720f72c5f1184ca3e03b0c14a2bc06ed5 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 23 Aug 2018 10:10:13 -0400 Subject: [PATCH 053/188] qa: Remove unused deserialization code in msg_version --- test/functional/test_framework/messages.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 3cd148a02e..0a3907cba4 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -909,21 +909,12 @@ class msg_version(): self.addrTo = CAddress() self.addrTo.deserialize(f, False) - if self.nVersion >= 106: - self.addrFrom = CAddress() - self.addrFrom.deserialize(f, False) - self.nNonce = struct.unpack("= 209: - self.nStartingHeight = struct.unpack("= 70001: # Relay field is optional for version 70001 onwards From f1640d093fa682c98b000e377916cc32b2267e23 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Thu, 23 Aug 2018 03:17:43 -0700 Subject: [PATCH 054/188] Make IS_TRIVIALLY_CONSTRUCTIBLE consistent on GCC < 5 std::is_trivially_constructible is equivalent to std::is_trivially_default_constructible std::has_trivial_default_constructor is the GCC < 5 name for std::is_trivially_default_constructible std::is_trivial was also used when compiling with clang, due to clang's use of __GNUC__. Test __clang__ to target the intended implementations. --- src/compat.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compat.h b/src/compat.h index 19f9813fd4..d228611160 100644 --- a/src/compat.h +++ b/src/compat.h @@ -14,10 +14,10 @@ // GCC 4.8 is missing some C++11 type_traits, // https://www.gnu.org/software/gcc/gcc-5/changes.html -#if defined(__GNUC__) && __GNUC__ < 5 -#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivial +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 +#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor #else -#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_constructible +#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible #endif #ifdef WIN32 From 0d00fd5901102d9ca2b99d6f17a3bd96c946e3b7 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 23 Aug 2018 17:24:15 -0400 Subject: [PATCH 055/188] depends: allow CC/CXX to be overridden during configure --- depends/config.site.in | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/depends/config.site.in b/depends/config.site.in index 8444dc26f2..b7a5e795c8 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -61,9 +61,12 @@ fi CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" LDFLAGS="-L$depends_prefix/lib $LDFLAGS" -CC="@CC@" -CXX="@CXX@" -OBJC="${CC}" +if test -n "@CC@" -a -z "${CC}"; then + CC="@CC@" +fi +if test -n "@CXX@" -a -z "${CXX}"; then + CXX="@CXX@" +fi PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH if test -n "@AR@"; then From ddddce0e46e73d4ca369f2ce9696231cc579e1f9 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 13 Aug 2018 16:13:29 -0400 Subject: [PATCH 056/188] util: Replace boost::signals2 with std::function --- src/bench/bench_bitcoin.cpp | 2 ++ src/bitcoin-cli.cpp | 2 ++ src/bitcoin-tx.cpp | 2 ++ src/bitcoind.cpp | 2 ++ src/noui.cpp | 2 ++ src/qt/bitcoin.cpp | 10 +++------- src/qt/bitcoingui.cpp | 2 ++ src/qt/splashscreen.cpp | 4 +++- src/qt/transactiontablemodel.cpp | 4 +++- src/test/test_bitcoin.cpp | 10 ++++++---- src/test/test_bitcoin_fuzzy.cpp | 12 +++++++----- src/util.cpp | 2 -- src/util.h | 23 +++++++---------------- src/wallet/coinselection.cpp | 3 +++ 14 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 603b858e54..d7b8083e7c 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -13,6 +13,8 @@ #include +const std::function G_TRANSLATION_FUN = nullptr; + static const int64_t DEFAULT_BENCH_EVALUATIONS = 5; static const char* DEFAULT_BENCH_FILTER = ".*"; static const char* DEFAULT_BENCH_SCALING = "1.0"; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index db713f58d2..c9414e67c7 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -24,6 +24,8 @@ #include +const std::function G_TRANSLATION_FUN = nullptr; + static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; static const bool DEFAULT_NAMED=false; diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 5fef4724c9..20f0218ac1 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -31,6 +31,8 @@ static bool fCreateBlank; static std::map registers; static const int CONTINUE_EXECUTION=-1; +const std::function G_TRANSLATION_FUN = nullptr; + static void SetupBitcoinTxArgs() { gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 06f8622426..bf04d95b50 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -23,6 +23,8 @@ #include +const std::function G_TRANSLATION_FUN = nullptr; + /* Introduction text for doxygen: */ /*! \mainpage Developer documentation diff --git a/src/noui.cpp b/src/noui.cpp index e6d01e7b26..3a1ec2d050 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -12,6 +12,8 @@ #include #include +#include + static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { bool fSecure = style & CClientUIInterface::SECURE; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d3ec67e441..5da54c5b2d 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -76,13 +76,10 @@ static void InitMessage(const std::string &message) LogPrintf("init message: %s\n", message); } -/* - Translate string to current locale using Qt. - */ -static std::string Translate(const char* psz) -{ +/** Translate string to current locale using Qt. */ +const std::function G_TRANSLATION_FUN = [](const char* psz) { return QCoreApplication::translate("bitcoin-core", psz).toStdString(); -} +}; static QString GetLangTerritory() { @@ -619,7 +616,6 @@ int main(int argc, char *argv[]) // Now that QSettings are accessible, initialize translations QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); - translationInterface.Translate.connect(Translate); // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index e2488092e2..71bfe74de5 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -57,6 +57,8 @@ #include #include +#include + const std::string BitcoinGUI::DEFAULT_UIPLATFORM = #if defined(Q_OS_MAC) "macosx" diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index e438d22919..0b111cc6d7 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -14,8 +14,8 @@ #include #include #include -#include #include +#include #include #include @@ -24,6 +24,8 @@ #include #include +#include + SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) : QWidget(0, f), curAlignment(0), m_node(node) { diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index e100cac533..3443852023 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -16,10 +16,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -27,6 +27,8 @@ #include #include +#include + // Amount column is right-aligned it contains numbers static int column_alignments[] = { Qt::AlignLeft|Qt::AlignVCenter, /* status */ diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 9c3285fb0c..a89bf785f1 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -8,15 +8,17 @@ #include #include #include -#include #include #include #include -#include -#include -#include #include +#include #include